# Background jobs

> Work that takes longer than a request, and how to know when it's done.

Source: https://app.getoatmilk.com/docs/async-work

Reading a receipt, matching a bank line or preparing an export can take longer than one request should. Actions that start this kind of work answer right away with the job's ID and its current status, and the work carries on in the background.

```json
{
  "data": {
    "submissionId": "4d5e6f7a-8b9c-4d0e-8f1a-2b3c4d5e6f7a",
    "jobId": "2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
    "generation": 1,
    "status": "queued"
  }
}
```

## Following a job

There are two ways to know when a job finishes:

1. **Ask.** Call the job's status action, such as `jobs.get` for receipts, every few seconds until `status` is `completed` or `failed`. Wait a little longer between each check.
2. **Listen.** Subscribe to a [webhook](https://app.getoatmilk.com/docs/webhooks.md), such as `receipt.processed`, and Oatmilk tells you when it's done.

```json
{
  "data": {
    "id": "2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
    "submission_id": "4d5e6f7a-8b9c-4d0e-8f1a-2b3c4d5e6f7a",
    "status": "queued",
    "stage": "preserve",
    "generation": 1,
    "attempts": 0,
    "error_code": null,
    "next_attempt_at": "2026-09-30T14:00:05Z"
  }
}
```

```json
{
  "data": {
    "id": "2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
    "submission_id": "4d5e6f7a-8b9c-4d0e-8f1a-2b3c4d5e6f7a",
    "status": "processing",
    "stage": "extract",
    "generation": 1,
    "attempts": 1,
    "error_code": null,
    "next_attempt_at": "2026-09-30T14:00:05Z"
  }
}
```

```json
{
  "data": {
    "id": "2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
    "submission_id": "4d5e6f7a-8b9c-4d0e-8f1a-2b3c4d5e6f7a",
    "status": "completed",
    "stage": "match",
    "generation": 1,
    "attempts": 1,
    "error_code": null,
    "next_attempt_at": "2026-09-30T14:00:05Z"
  }
}
```

## What the statuses mean

| Status | Means |
| --- | --- |
| `queued` | Accepted and waiting its turn. Nothing is finished yet. |
| `processing` | Being worked on now. `stage` says which step. |
| `completed` | Done. Read the record to see the result. |
| `failed` | Stopped after its retries. `error_code` says why; a person can retry it in Oatmilk. |

> [!WARNING]
> A queued or processing job hasn't changed your books yet. Don't tell a person their receipt is filed until its job is `completed`.
