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

# Build jobs

> Run the WPOS agent headlessly on a customer site: submit an instruction, poll for a structured result, and cancel when you need to.

A build job is one headless run of the WPOS agent against one site. You send a
plain-language instruction plus optional structured context, WPOS runs the agent
with no human in the loop, and you get back a structured result: a summary, the
changes it made, and any warnings. Every call needs the `jobs` scope.

## Submit a job

`POST /sites/:siteId/jobs`.

```bash theme={null}
curl -X POST https://api.wpcursor.com/api/partner/v1/sites/site_.../jobs \
  -H "X-Partner-Key: $WPOS_PARTNER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "instructions": "Create an About page from the brief in context, publish it, and link it in the main menu.",
    "context": { "brief": "Family-run bakery since 1998, three locations, known for sourdough." },
    "externalRef": "job_about_001",
    "model": "sonnet",
    "timeoutMinutes": 15
  }'
```

| Field            | Required | Notes                                                                                                                            |
| ---------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `instructions`   | yes      | Plain-language task, up to 10,000 characters.                                                                                    |
| `context`        | no       | Structured data passed to the agent verbatim as JSON, up to 20,000 characters serialized. Briefs, approved copy, audit findings. |
| `externalRef`    | no       | Your own id. Makes the submission idempotent.                                                                                    |
| `model`          | no       | `sonnet` (default) or `opus`.                                                                                                    |
| `timeoutMinutes` | no       | 5 to 30, default 15. A run that exceeds it ends with status `timeout`.                                                           |

A new job returns `202`; a repeat of the same `externalRef` returns `200` with the
existing job.

```json theme={null}
{ "success": true, "job": { "id": "job_...", "status": "queued", "pollUrl": "/api/partner/v1/jobs/job_..." } }
```

<Note>
  Jobs run with no human in the loop. The agent never pauses to ask a question, so
  put everything it needs in `instructions` and `context`. Structured context in
  the `context` field beats stuffing data into the instruction prose.
</Note>

## Preconditions

A job is accepted only when the site belongs to you and is active, the account is
active, and the account has credits. Insufficient credits returns `403
limit_reached`. There are caps on concurrency: a small number of partner jobs run
at once globally, and one running job per site. At capacity you get `429
rate_limited`; retry shortly.

## Poll for the result

`GET /jobs/:jobId`. Poll until `status` is terminal: `succeeded`, `failed`,
`timeout`, or `cancelled`.

```json theme={null}
{
  "success": true,
  "job": {
    "id": "job_...",
    "siteId": "site_...",
    "externalRef": "job_about_001",
    "status": "succeeded",
    "model": "sonnet",
    "result": {
      "summary": "Created and published an About page and added it to the main menu.",
      "changes": [
        { "type": "page_created", "pageId": 42, "url": "https://customer.com/about", "title": "About" }
      ],
      "warnings": []
    },
    "creditsConsumed": 6,
    "createdAt": "2026-08-08T...",
    "startedAt": "2026-08-08T...",
    "finishedAt": "2026-08-08T..."
  }
}
```

### The result shape

On success, `result` is the agent's structured report:

* `summary`: one line describing what it did.
* `changes`: an array of `{ type, pageId?, url?, title? }`. `type` is one of
  `page_created`, `page_updated`, `widget`, or `other`.
* `warnings`: anything the agent flagged but did not treat as failure.

If the agent finished but its final report could not be parsed, `result` is
`{ "raw": "..." }` with the raw text, and `status` is still `succeeded`.

<Tip>
  Rather than polling, register a webhook and handle the
  [`job.completed` event](/partners/webhooks#events), which fires on every terminal
  status and carries the same result. Use polling for interactive flows, webhooks
  for everything else.
</Tip>

## Cancel a job

`POST /jobs/:jobId/cancel` is best-effort: a queued job becomes `cancelled`, a
running job is stopped and becomes `cancelled`, and a job already finished returns
`200` with its current status unchanged.

```bash theme={null}
curl -X POST https://api.wpcursor.com/api/partner/v1/jobs/job_.../cancel \
  -H "X-Partner-Key: $WPOS_PARTNER_KEY"
```

## Credits and cost

After a job finishes, WPOS converts its cost to credits and consumes them from the
account, recording both `creditsConsumed` and the underlying `cost_usd` on the
job. Any run that actually started consumes at least one credit. Watch spend per
account in the [dashboard](/partners/dashboard).

## Next

<CardGroup cols={2}>
  <Card title="Embed the assistant" icon="window" href="/partners/embed">
    The same agent, driven by your customers in your UI.
  </Card>

  <Card title="Webhooks" icon="webhook" href="/partners/webhooks">
    Get told when a job finishes.
  </Card>
</CardGroup>
