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

# Jobs

> Every packet is a job: statuses, waiting, idempotency, options, limits and erasure.

`POST /v1/parse` (or an email) creates a job and answers `202` at once. The job runs in the background:

```
queued → running → completed | review_required | failed
```

| Status | Meaning |
| - | - |
| `completed` | Every check passed. |
| `review_required` | The result is usable; `review_reasons` name what a person should check (a statement that did not verify, a missing month, an excluded document, a fraud signal). |
| `failed` | Nothing could be processed; `error` says why. |

Every finished job sends a [webhook event](/guides/webhooks). A job still running after an hour fails, with its
event.

## Waiting for a result

* **Webhooks** are the recommended way.
* **Long polling**: `GET /v1/jobs/{id}?wait=60` holds the request until the job finishes or the seconds pass
  (at most 600). `POST /v1/parse?wait=60` does the same at submission.
* **Listing**: `GET /v1/jobs` lists jobs newest first, filtered by `status`, `source`, `since` (created at or
  after), `end_user_id` and `external_business_id`, and paged with `cursor` (the previous page's `next_cursor`,
  with the same filters). Each row carries the job's `intake`.
* **Polling for finished jobs**: `GET /v1/jobs?finished_since=` lists the jobs that finished (completed,
  review\_required or failed) at or after a time, oldest finish first. Each finished job appears once across the
  pages, so it is the fallback for a missed webhook. See the
  [sync recipe](/guides/platform-integration#never-miss-a-job).

## Intake and files

Every job, whatever its status, carries `intake`: its source and when it arrived, the broker, the merchant
details and ids the request declared (`business_name`, `business_ein`, `external_business_id`, `end_user_id`,
`contact_email`, `requested_advance_amount`), an emailed job's envelope (sender, recipients, subject, message id,
mailbox, thread, routing) and its files. A failed job has it too, and so does every job event. See
[Integrating a platform](/guides/platform-integration#open-a-deal-for-every-job-failed-ones-included).

`GET /v1/jobs/{id}/files` lists the files the job was sent (position, filename, content type, SHA-256, size,
whether it was an email attachment) and `GET /v1/jobs/{id}/files/{position}` returns one's bytes, as sent. For an
emailed job, `intake.email.email_id` is the [tracked email](/guides/emails) that started it, and its raw message
is `GET /v1/emails/{email_id}/raw`; `intake.email.thread_id` lists the whole thread.

## Idempotency

Send an `Idempotency-Key` header (for example your deal id) with `POST /v1/parse`. Resending with the same key
returns the same job: `202` with `created: false` while it runs, the finished job once it is done. The same key
with different files, file order, metadata or options is refused with `409`; use a new key for a new packet.

## Options

The multipart field `options` takes JSON:

| Option | Default | Effect |
| - | - | - |
| `include_transactions` | `true` | Return every transaction row. |
| `include_unverified` | `false` | Also return ledgers that failed verification, flagged. They are still never used in the metrics. |
| `include_partial_months` | `false` | Count partial and month-to-date months in revenue averages. |
| `score` | none | A pre-approval score (0 to 100) that selects the score band for the withhold. |
| `factor_rate` | `1.49` | The factor rate used to size capacity. |
| `max_cost_usd` | the tenant's cap | A spend cap for this job's model calls; it can lower the tenant's per-job cap, never raise it. |
| `use_cache` | `true` | Reuse cached reads of documents already seen. |

```bash theme={null}
curl -sS -X POST "$API/v1/parse" -H "X-API-Key: $KEY" -F files=@march.pdf -F 'options={"score": 85, "include_unverified": true}'
```

## Limits

* A tenant may have `max_active_jobs` (20 by default) jobs queued or running; one more is `429` with
  `Retry-After`.
* Each job has a spend cap (`max_cost_usd_per_job`, \$2.00 by default), and a tenant can have a monthly budget;
  once it is spent, new jobs are `429` until the month turns.

## Erasure

`DELETE /v1/jobs/{id}` (`jobs:delete`) erases a finished job and everything derived from it, at once: its request
and result, its input files, the cached reads of its documents, the model answers it paid for, its metering,
its corrections, email thread entries, the [emails that fed it](/guides/emails#erasure-and-retention) with their raw messages, and
webhook events. This is how a merchant's deletion request is honoured: erase each of
its jobs. `DELETE /v1/jobs?end_user_id=` erases every finished job submitted with that `end_user_id` the same
way, and lists the ones still running, to erase once they end
([details](/guides/platform-integration#erase-an-end-users-data)). Erasures are recorded in the audit log. A tenant can also set a retention period
(`PATCH /v1/tenant/settings`), after which old jobs and emails are erased automatically.

## Corrections

A reviewer can correct a finished job: re-categorize a row, override a position's status, payment, frequency,
funder or kind, or leave a month, or one account's part of a month, out of the averages. The corrections are saved on the job, and
`GET /v1/jobs/{id}` returns the result with them applied (`result.corrections` says what changed;
`?view=computed` returns the machine's result). They never change the job's status or `review_reasons`. See
[Review and corrections](/guides/review-and-corrections).

## Re-running the underwriting

`POST /v1/underwriting/withhold` recomputes withhold, EBITDA and capacity from months and positions you send,
without reading the documents again or saving anything on a job. To keep a reviewer's changes on the job
instead, use [corrections](/guides/review-and-corrections).


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