> ## Documentation Index
> Fetch the complete documentation index at: https://docs.xquik.com/llms.txt
> Use this file to discover all available pages before exploring further.

# X job listing API for descriptions & salary data

> Retrieve 1 public X job listing by ID or URL. Get its full description as text and Markdown, salary, seniority, work type, and apply link. 1 credit per call.

<Panel>
  <Tabs defaultTabIndex={0} sync={false}>
    <Tab title="200" id="response-x-get-job-200">
      ```json theme={null}
      {
        "job": {
          "id": "1899202395210649861",
          "title": "Engineer",
          "url": "https://x.com/i/jobs/1899202395210649861",
          "applyUrl": "https://xquik.com/example",
          "location": "United States"
        }
      }
      ```
    </Tab>

    <Tab title="400" id="response-x-get-job-400">
      ```json theme={null}
      {
        "error": "invalid_job_id",
        "message": "Send a job ID or job URL, such as x.com/i/jobs/123."
      }
      ```
    </Tab>

    <Tab title="401" id="response-x-get-job-401">
      ```json theme={null}
      {
        "error": "unauthenticated",
        "message": "Authentication required."
      }
      ```
    </Tab>

    <Tab title="402" id="response-x-get-job-402">
      ```json theme={null}
      {
        "error": "insufficient_credits",
        "message": "Insufficient credits. Top up or subscribe to continue."
      }
      ```
    </Tab>

    <Tab title="404" id="response-x-get-job-404">
      ```json theme={null}
      {
        "error": "job_not_found",
        "message": "Job not found. Check the job ID or x.com/i/jobs URL."
      }
      ```
    </Tab>

    <Tab title="424" id="response-x-get-job-424">
      ```json theme={null}
      {
        "error": "x_api_unavailable",
        "message": "X data source temporarily unavailable. Try again later."
      }
      ```
    </Tab>

    <Tab title="429" id="response-x-get-job-429">
      ```json theme={null}
      {
        "error": "rate_limit_exceeded",
        "message": "Too many requests. Try again later.",
        "retryAfter": 60
      }
      ```
    </Tab>

    <Tab title="502" id="response-x-get-job-502">
      ```json theme={null}
      {
        "error": "x_api_unavailable",
        "message": "X data source temporarily unavailable. Try again later."
      }
      ```
    </Tab>

    <Tab title="503" id="response-x-get-job-503">
      ```json theme={null}
      {
        "error": "x_api_unavailable",
        "message": "Xquik is busy right now. Retry shortly."
      }
      ```
    </Tab>
  </Tabs>
</Panel>

<blockquote className="agent-llms-directive">
  For the complete documentation index, see <a href="/llms.txt">llms.txt</a>.
</blockquote>

Read 1 public job listing on X with its full description. Pass a job ID or a job URL.

<Callout icon="coins" color="#5c3327">
  **1 credit per call** · [All plans](https://xquik.com/#pricing) from \$0.00012/credit
</Callout>

<CodeGroup>
  ```bash cURL theme={null}
  curl https://xquik.com/api/v1/x/jobs/1899202395210649861 \
    -H "x-api-key: xq_your_api_key_here" | jq
  ```

  ```javascript Node.js theme={null}
  const jobId = "1899202395210649861";
  const response = await fetch(`https://xquik.com/api/v1/x/jobs/${jobId}`, {
    headers: { "x-api-key": "xq_your_api_key_here" },
  });
  const { job } = await response.json();
  const jobRecord = {
    job_id: job.id,
    title: job.title ?? null,
    job_url: job.url,
    apply_url: job.applyUrl ?? null,
    location: job.location ?? null,
    location_type: job.locationType ?? null,
    employment_type: job.employmentType ?? null,
    seniority_level: job.seniorityLevel ?? null,
    salary: job.formattedSalary ?? null,
    employer: job.company?.name ?? job.account?.name ?? null,
    description: job.description ?? null,
  };

  process.stdout.write(JSON.stringify(jobRecord, null, 2));
  ```

  ```python Python theme={null}
  import json
  import requests

  job_id = "1899202395210649861"
  response = requests.get(
      f"https://xquik.com/api/v1/x/jobs/{job_id}",
      headers={"x-api-key": "xq_your_api_key_here"},
  )
  job = response.json()["job"]
  job_record = {
      "job_id": job["id"],
      "title": job.get("title"),
      "job_url": job["url"],
      "apply_url": job.get("applyUrl"),
      "location": job.get("location"),
      "location_type": job.get("locationType"),
      "employment_type": job.get("employmentType"),
      "seniority_level": job.get("seniorityLevel"),
      "salary": job.get("formattedSalary"),
      "employer": (job.get("company") or job.get("account") or {}).get("name"),
      "description": job.get("description"),
  }

  print(json.dumps(job_record, indent=2))
  ```
</CodeGroup>

## Find a job ID

Use [job search](/api-reference/x/search-jobs) to find listings by keyword. Each result carries its `id` and its `url` on X.

The path also takes a job URL such as `x.com/i/jobs/1899202395210649861`. URL-encode it first. Anything else returns `400 invalid_job_id`.

## Read the description

The listing returns its description in 2 forms. `description` is plain text with 1 line per paragraph. `descriptionMarkdown` keeps headings, lists, links, bold, and italics. It holds no HTML, and it escapes characters that would read as Markdown, such as `[`, `*` and a `-` that starts a line.

Use the Markdown form to show the listing. Use the plain text for search indexes and classifiers.

## Handle a closed job

X removes a listing when the employer closes it. The lookup then returns `404 job_not_found` and costs nothing. Drop the job from your store, or mark it closed.

## Path parameters

<ParamField path="id" type="string" required>
  Job ID, or URL-encoded job URL such as `x.com/i/jobs/1899202395210649861`.
</ParamField>

## Headers

<ParamField header="x-api-key" type="string">
  Full account key. Sessions and OAuth also work.
</ParamField>

<ParamField header="Authorization" type="string">
  `Bearer xq_your_guest_key_here` for `paid_reads`.
</ParamField>

## Response

### 200 OK

X leaves out a field that a job lacks. Only `id` and `url` are always present.

<ResponseField name="job" type="object">
  The job listing.
  **Job object fields.**

  <ResponseField name="id" type="string">
    Job ID.
  </ResponseField>

  <ResponseField name="title" type="string">
    Job title.
  </ResponseField>

  <ResponseField name="url" type="string">
    The job page on X.
  </ResponseField>

  <ResponseField name="applyUrl" type="string">
    Where applicants apply, off X.
  </ResponseField>

  <ResponseField name="location" type="string">
    Location as the employer wrote it.
  </ResponseField>

  <ResponseField name="locationType" type="string">
    Where the work happens: `onsite`, `remote`, or `hybrid`.
  </ResponseField>

  <ResponseField name="employmentType" type="string">
    Contract type: `full_time`, `full_time_contract`, `part_time`, or `contract_to_hire`.
  </ResponseField>

  <ResponseField name="seniorityLevel" type="string">
    Seniority, from `intern` to `executive`.
  </ResponseField>

  <ResponseField name="jobFunction" type="string">
    Job function, such as `software_engineering`.
  </ResponseField>

  <ResponseField name="team" type="string">
    Team inside the company.
  </ResponseField>

  <ResponseField name="postedAt" type="string">
    When the employer posted the job, in ISO 8601.
  </ResponseField>

  <ResponseField name="formattedSalary" type="string">
    Salary as X shows it, such as `Starting at $225K`.
  </ResponseField>

  <ResponseField name="salaryMin" type="number">
    Lowest salary, in `salaryCurrencyCode` per `salaryInterval`.
  </ResponseField>

  <ResponseField name="salaryMax" type="number">
    Highest salary, in `salaryCurrencyCode` per `salaryInterval`.
  </ResponseField>

  <ResponseField name="salaryCurrencyCode" type="string">
    ISO 4217 currency code of the salary.
  </ResponseField>

  <ResponseField name="salaryInterval" type="string">
    Pay period of the salary: `annually` or `hourly`.
  </ResponseField>

  <ResponseField name="featured" type="boolean">
    Whether X features the job.
  </ResponseField>

  <ResponseField name="shortDescription" type="string">
    Short summary of the job, as plain text.
  </ResponseField>

  <ResponseField name="description" type="string">
    Full description as plain text, 1 line per paragraph.
  </ResponseField>

  <ResponseField name="descriptionMarkdown" type="string">
    Full description as Markdown, with headings, lists, links, bold, and italics.
  </ResponseField>

  <ResponseField name="company" type="object">
    Company profile with `id`, `name`, and `logoUrl`. Present on jobs X imported from a job board.
  </ResponseField>

  <ResponseField name="account" type="object">
    The X account that posted the job, with `id`, `username`, `name`, `verified`, `verifiedType`,
    `description`, `profilePicture`, and `profileImageShape`. A job has none when X imported it from a
    job board or no longer shows the account.
  </ResponseField>
</ResponseField>

```json theme={null}
{
  "job": {
    "id": "1899202395210649861",
    "title": "Engineer",
    "url": "https://x.com/i/jobs/1899202395210649861",
    "applyUrl": "https://xquik.com/example",
    "location": "United States",
    "locationType": "remote",
    "employmentType": "full_time",
    "seniorityLevel": "lead",
    "jobFunction": "software_engineering",
    "formattedSalary": "Starting at $225K",
    "salaryMin": 225000,
    "salaryCurrencyCode": "USD",
    "salaryInterval": "annually",
    "featured": true,
    "shortDescription": "Commonware is hiring founding engineers.",
    "description": "What is Commonware? We build open primitives.",
    "descriptionMarkdown": "# What is Commonware?",
    "account": {
      "id": "1812126202804711425",
      "username": "commonwarexyz",
      "name": "commonware",
      "verified": true,
      "verifiedType": "Business"
    }
  }
}
```

### 400 Invalid job ID

```json theme={null}
{ "error": "invalid_job_id" }
```

Send a job ID or a job URL, such as `x.com/i/jobs/123`.

### 401 Unauthenticated

Anonymous requests get `WWW-Authenticate: Bearer` and a guest wallet checkout action. This is not a Payment challenge.

```json theme={null}
{ "error": "unauthenticated" }
```

### 402 Payment required

Account keys get account options. Guest keys get guest top-up only.
No checkout starts automatically. Confirm any payment action.

### 404 Job not found

```json theme={null}
{ "error": "job_not_found" }
```

The job closed or the ID is wrong. This answer is free.

### 502 X API unavailable

```json theme={null}
{ "error": "x_api_unavailable" }
```

The read service returned an error. Retry after a short delay.

### 503 Service busy

```json theme={null}
{ "error": "x_api_unavailable" }
```

X failed the job lookup, or Xquik is busy. Wait for `Retry-After`, then retry. The request costs nothing.

### 429 Rate limit exceeded

```json theme={null}
{ "error": "rate_limit_exceeded", "retryAfter": 60 }
```

You exceeded your tier rate limit. Wait for the `Retry-After` header before retrying.

### 424 Dependency failed

```json theme={null}
{ "error": "x_api_unavailable" }
```

The normalized v1 response contract can return 424 when the read service is unavailable.

<Note>
  **Next steps.** [Search job listings](/api-reference/x/search-jobs) to find more jobs, or [get the hiring account's profile](/api-reference/x/twitter-profile-lookup) with the `account.username`, when the job has an `account`.
</Note>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.