> ## 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.

# API reference

> The Partner API in one place: base URL, authentication, scopes, rate limits, every endpoint, and the error envelope.

The Partner API is a stable HTTP API. Route shapes, payloads, and error codes are
frozen: we add to them, we do not break them.

## Base URL

```text theme={null}
https://api.wpcursor.com/api/partner/v1
```

All requests and responses are JSON.

## Authentication

Send your key on every request:

```text theme={null}
X-Partner-Key: wpk_...
```

A key is issued by WPOS with a fixed set of scopes. It is shown to you once and
stored only as a hash. Treat it like a password: keep it server-side, rotate it if
it leaks (contact WPOS to revoke and reissue), and never ship it to a browser. For
in-browser experiences, mint a narrow [embed session](/partners/embed) instead.

### Scopes

| Scope       | Grants                                                            |
| ----------- | ----------------------------------------------------------------- |
| `read`      | Read accounts, sites, and job status.                             |
| `provision` | Create accounts, change plans, grant credits, set account status. |
| `handoff`   | Set white-label branding on a site.                               |
| `jobs`      | Submit, poll, and cancel build jobs.                              |
| `embed`     | Mint embedded-assistant sessions.                                 |

A call that needs a scope your key lacks returns `403 forbidden_scope`.

## Rate limits

Requests are limited per partner, at sixty per minute. Over the limit returns
`429 rate_limited`; back off and retry. Build jobs have their own capacity limits;
see [Build jobs](/partners/build-jobs#preconditions).

## Endpoints

| Method | Path                           | Scope       | Purpose                                                                                        |
| ------ | ------------------------------ | ----------- | ---------------------------------------------------------------------------------------------- |
| `GET`  | `/ping`                        | `read`      | Confirm the key and see its scopes.                                                            |
| `POST` | `/accounts`                    | `provision` | [Provision an account](/partners/accounts#provision-an-account) (idempotent on `externalRef`). |
| `GET`  | `/accounts/:id`                | `read`      | [Read an account](/partners/accounts#read-an-account).                                         |
| `POST` | `/accounts/:id/plan`           | `provision` | [Change the plan](/partners/accounts#change-the-plan).                                         |
| `POST` | `/accounts/:id/credits`        | `provision` | [Grant credits](/partners/accounts#grant-credits).                                             |
| `POST` | `/accounts/:id/status`         | `provision` | [Suspend or reactivate](/partners/accounts#suspend-or-reactivate).                             |
| `GET`  | `/accounts/:id/sites`          | `read`      | [List connected sites](/partners/accounts#list-an-accounts-sites).                             |
| `POST` | `/sites/:siteId/handoff`       | `handoff`   | [Set white-label branding](/partners/branding#set-branding-on-a-site).                         |
| `POST` | `/sites/:siteId/jobs`          | `jobs`      | [Submit a build job](/partners/build-jobs#submit-a-job).                                       |
| `GET`  | `/jobs/:jobId`                 | `jobs`      | [Poll a job](/partners/build-jobs#poll-for-the-result).                                        |
| `POST` | `/jobs/:jobId/cancel`          | `jobs`      | [Cancel a job](/partners/build-jobs#cancel-a-job).                                             |
| `POST` | `/sites/:siteId/embed-session` | `embed`     | [Mint an embed session](/partners/embed#how-it-fits-together).                                 |

## Errors

Every non-2xx response uses one envelope:

```json theme={null}
{ "error": { "code": "validation_error", "message": "email is required" } }
```

| Code                | Status | Meaning                                                                               |
| ------------------- | ------ | ------------------------------------------------------------------------------------- |
| `unauthorized`      | 401    | Missing, unknown, revoked, or expired key.                                            |
| `forbidden_scope`   | 403    | The key lacks the scope this call needs.                                              |
| `partner_suspended` | 403    | Your partner account is not active.                                                   |
| `limit_reached`     | 403    | Account cap hit, or insufficient credits for a job.                                   |
| `not_found`         | 404    | No such resource, or it is not yours. Used for cross-tenant access so ids never leak. |
| `validation_error`  | 400    | A field is missing or malformed.                                                      |
| `plan_invalid`      | 400    | Unknown `planId`.                                                                     |
| `email_conflict`    | 409    | The email already belongs to an account that is not yours.                            |
| `rate_limited`      | 429    | Over the request or job-capacity limit. Retry after backing off.                      |
| `internal_error`    | 500    | Something went wrong on our side. Retry; if it persists, contact us.                  |

<Note>
  Ownership failures answer `404 not_found`, never `403`. A request for an account,
  site, or job that is not yours is indistinguishable from one that does not exist,
  by design, so the API never reveals another partner's ids.
</Note>

## Webhooks

Events are delivered and signed as described in [Webhooks](/partners/webhooks).

## Support

Something missing or behaving unexpectedly? Email
[partners@wpos.ai](mailto:partners@wpos.ai).
