# get_job

Source: https://modulify.ai/docs/api/chat/get-job

Reads the progress of a site generation and the events it has produced since your last call.

- Title: Read generation progress
- Scope: `chat:read`
- Access: Read only
- Endpoint: `POST /v1/get_job`

Pass back the `cursor` from your previous call to receive only the new events. Leave out `jobId` to read the most recent generation of the site, and a site that has never run one answers with `state` null.

`running` means keep polling. `stalled` means the agent has sent no heartbeat for over a minute and no server is running the turn any more, and it is not an ending either: keep polling, because the platform resumes or closes a generation that has produced nothing for 15 minutes. The endings are `succeeded`, `failed` and `cancelled`, and after a failed or canceled generation, or one that ended part way through, anything queued on the site waits for `resume_queue`.

A `succeeded` generation is not always a finished one. `incomplete:true` means the agent stopped part way through the turn, `incompleteReason` says how (`terminal-reason`, `max-output-tokens`, `max-turns`, `max-budget`, `agent-error` or `no-closing-message`) and `incompleteCode` carries the matching error code. The turn was still billed and anything it already changed was kept, so continue the work rather than starting it over.

A `failed` generation whose `errorCode` is `SC-6001` ran out of AI credits part way through. It was stopped there, anything it already changed was kept, and only what the balance could cover was charged, so the workspace needs a plan or more credits before that work is sent again.

When the response has `reset:true`, the generation was retried from the start, so discard the events you collected and continue from the new `cursor`. See [When a run fails](https://modulify.ai/docs/build/site-chat#when-a-run-fails).

## Request

Call it with a `POST` to `https://api.modulify.ai/v1/get_job`, sending the inputs below as a JSON object. The token needs the `chat:read` scope.

It only reads and changes nothing, so retrying it is safe.

```bash
curl -X POST https://api.modulify.ai/v1/get_job \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"projectId":"PROJECT_ID"}'
```

Over MCP, the same method is the [get_job tool](https://modulify.ai/docs/mcp/chat/get-job).

## Inputs

| Input | Type | Required | Description |
| --- | --- | --- | --- |
| `projectId` | string | Yes | The site id. |
| `jobId` | string | No | The generation id that `send_message` returned. Leave it out for the latest generation. |
| `cursor` | integer | No | The `cursor` from your previous call. Use `0` or leave it out on the first call. |
| `limit` | integer | No | How many events to return, up to 500. Defaults to 200. |

## Response

Every call answers with the [JSON envelope](https://modulify.ai/docs/api/requests-and-responses#the-response) of `success`, `message`, `data`, `code` and `version`. `data` holds the result described above, and on a method that returns a total, `count` carries it. The [response headers](https://modulify.ai/docs/api/requests-and-responses#headers-on-every-method-call) carry the call's `X-Request-Id` and what is left of your per-minute budget in `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset`. [Errors](https://modulify.ai/docs/api/errors) explains every status code a call can answer with.