# MonstarX Platform API

Create an app from a brief, request changes, follow asynchronous jobs, and explicitly publish an approved revision. Use ordinary HTTP from a server, CI pipeline, or automation tool. The API uses the same application operations, usage allowance, and project runner as MonstarX's MCP server.

Base URL: `https://monstarx.com/api/v1`

[OpenAPI 3.1 reference](https://monstarx.com/api/v1/openapi.json) · [Account API keys](https://monstarx.com/settings/api) · [MCP documentation](https://monstarx.com/docs/mcp)

## Authentication

Sign in and open **Settings → API & MCP → API keys**. Create a named key for each integration and copy it immediately; its value is shown once. Use the key as `Authorization: Bearer bck_…`. Revoke it in Settings to prevent new requests and queued work from starting. An AI turn already accepted by the project runner may finish; stop it in the workspace if needed.

Account keys act on projects owned by their account. Version 1 keys grant read, build, and publish access across those projects; there are no per-key permissions or project restrictions yet. Keep keys in your server's secrets, never in browser code or a mobile bundle. MCP OAuth access tokens and project data API keys (`mxapi_…`) are not accepted here. This API operates MonstarX itself; **Admin → APIs** separately exposes a generated app's data.

```bash
export MONSTARX_API_KEY='your-account-key'
export MONSTARX_API_BASE='https://monstarx.com/api/v1'
curl --fail-with-body "$MONSTARX_API_BASE/account" \
  -H "Authorization: Bearer $MONSTARX_API_KEY"
```

## Create an app

```bash
curl --fail-with-body "$MONSTARX_API_BASE/projects" \
  -H "Authorization: Bearer $MONSTARX_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: client-brief-2026-001' \
  -d '{"name":"Client portal","prompt":"Build a client portal with a project list and a contact form.","mode":"build"}'
```

A `202 Accepted` response means the job was saved, not that the app is ready. `Location` and `status_url` identify the status endpoint. For example:

```json
{
  "id": "job_0123456789abcdef0123456789abcdef",
  "operation": "create",
  "status": "queued",
  "project_id": "exampleprojectid12345",
  "request_id": "api_0123456789abcdef0123456789abcdef",
  "workspace_url": "https://monstarx.com/p/exampleprojectid12345",
  "status_url": "https://monstarx.com/api/v1/jobs/job_0123456789abcdef0123456789abcdef",
  "created_at": "2026-10-21T00:00:00.000Z",
  "updated_at": "2026-10-21T00:00:00.000Z",
  "result": null,
  "error": null
}
```

Optional `file_urls` accepts up to 10 public HTTPS document or image URLs, with the same attachment limits as MCP. A `name` is optional (up to 80 characters). The prompt uses the normal MonstarX request-size limit and must fit within the API's 64 KB JSON body limit. Use attachments for larger briefs. `mode` is `build` (default) or `plan`; plan mode may ask for answers before building. Use `GET /account` to check the current usage allowance. A job accepted with 202 can still fail later because of usage limits, invalid attachments, or setup requirements.

## Follow a job

```bash
curl --fail-with-body "$MONSTARX_API_BASE/jobs/JOB_ID" \
  -H "Authorization: Bearer $MONSTARX_API_KEY"
```

Poll no more often than every five seconds, or register a webhook before submitting work. A completed build returns its reply text, available usage details, and the files `revision` and latest `snapshot_id` observed when the job is reconciled under `result`. Other work may have advanced the project by then; review the current workspace before publishing. The `workspace_url` opens the project and its interactive preview; it is not a public deployment URL.

| Status | Meaning |
| --- | --- |
| `queued` | Saved and awaiting admission to the project runner. |
| `running` | Submitted to the runner; it may be waiting in the project's own queue. |
| `succeeded` | The requested AI turn finished, or the deployment is live. A completed turn is not a guarantee of app correctness. |
| `needs_input` | Questions, setup, or usage limits require attention. Open `workspace_url` to continue; this job is terminal. |
| `failed` | The operation failed; inspect `error` and the workspace before submitting new work. |
| `cancelled` | The request was stopped or removed, or its account, key, or project access changed. |

Job state survives site deploys. Builds run in the existing project runner, independently of the HTTP connection. Job admission and callback delivery recover through the existing maintenance pass every five minutes, so callbacks can arrive several minutes after completion. A crash during admission may leave a lease until it expires (up to 15 minutes). Unfinished jobs become failed after 24 hours when reconciled; this does not automatically stop a runner already working. Stop or resume work in the workspace in version 1.

## Request changes

Find IDs with `GET /projects?limit=30&query=portal`, and inspect one with `GET /projects/PROJECT_ID`.

```bash
curl --fail-with-body "$MONSTARX_API_BASE/projects/PROJECT_ID/builds" \
  -H "Authorization: Bearer $MONSTARX_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: client-portal-add-calendar-001' \
  -d '{"message":"Add a shared calendar page.","mode":"build"}'
```

Build requests accept `message`, optional `file_urls`, and `mode`: `build`, `plan`, or `chat`. They return a job with the same lifecycle. Requests enter the normal project queue and use the account's usual plan allowance. To answer a `needs_input` job, continue in the workspace, then submit a new API request when ready. Retrying the old job key returns that original job.

## Publish an approved revision

Building does not publish an app. Fetch `GET /projects/PROJECT_ID`, review the workspace preview, and use the returned `revision` and `latest_version.id` as the deployment confirmation. A completed build's `result.revision` and `result.snapshot_id` are also available, but another edit may already have advanced the project.

```bash
curl --fail-with-body "$MONSTARX_API_BASE/projects/PROJECT_ID/deployments" \
  -H "Authorization: Bearer $MONSTARX_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: publish-approved-client-portal-001' \
  -d '{"revision":"r123","snapshot_id":"REVIEWED_SNAPSHOT_ID"}'
```

The project coordinator checks the revision and snapshot before publishing. If they changed, the job fails instead of publishing unreviewed edits. Inspect the current project, review it again, and submit a new job with a new idempotency key. A successful deployment job returns `result.url` and `result.deployment_id`.

Version 1 supports publishing through MonstarX or a connected Cloudflare account. Apps requiring another host or unsupported hosting targets must be published through their existing workflow. Upload, GitHub import, secret management, and deleting projects remain in the workspace and MCP for this version.

## Signed webhooks

Register an account-wide callback before submitting work. Generate a separate random signing secret of at least 32 characters (for example, `openssl rand -hex 32`), store it in your receiver's secrets, and supply it as `signing_secret`. MonstarX encrypts it at rest and never returns it. Do not use your account API key as the signing secret.

```bash
curl --fail-with-body "$MONSTARX_API_BASE/webhooks" \
  -H "Authorization: Bearer $MONSTARX_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"url":"https://automation.example.com/monstarx","signing_secret":"REPLACE_WITH_YOUR_RANDOM_SIGNING_SECRET"}'
```

The answer contains `id`, `url`, and `created_at`. Every registered endpoint receives new terminal API job events for its account: `job.succeeded`, `job.failed`, `job.cancelled`, and `job.needs_input`. Existing completed jobs and jobs created through MCP or the workspace do not generate retroactive events.

Payloads contain `{ "id": "EVENT_ID", "type": "job.succeeded", "created_at": "ISO_TIMESTAMP", "data": JOB_OBJECT }`. `data` has the same shape as the job status response. Headers include `MonstarX-Event-Id` and `MonstarX-Signature: t=UNIX_SECONDS,v1=HEX_HMAC`.

Verify the HMAC-SHA256 signature over `timestamp + "." + raw_request_body` using your signing secret. Check the timestamp is within five minutes, then parse JSON. This Node.js example verifies the exact body bytes (collect raw bytes before any JSON middleware):

```javascript
import { createHmac, timingSafeEqual } from 'node:crypto';

export function verifyMonstarXWebhook(rawBody, signatureHeader, signingSecret) {
  const match = /^t=(\d{1,15}),v1=([a-f0-9]{64})$/.exec(signatureHeader ?? '');
  if (!match || Math.abs(Date.now() / 1000 - Number(match[1])) > 300) {
    throw new Error('Invalid or expired webhook signature');
  }
  const expected = createHmac('sha256', signingSecret)
    .update(match[1] + '.')
    .update(rawBody)
    .digest();
  if (!timingSafeEqual(expected, Buffer.from(match[2], 'hex'))) {
    throw new Error('Invalid webhook signature');
  }
  return JSON.parse(rawBody.toString('utf8'));
}
```

Persist or enqueue a verified event, then respond promptly with any 2xx status. Delivery is **at least once**: deduplicate durably by payload `id`, and do not assume events across different jobs arrive in order. Each attempt gets a fresh signature timestamp but keeps the same payload and event ID. If your response is lost after accepting it, MonstarX may send it again.

A non-2xx response, timeout, DNS failure, or redirect triggers a retry. Deliveries stop after eight attempts, with exponential delays starting at five minutes; the maintenance schedule may add delay. Destinations must use public HTTPS hostnames. Local/private addresses and automatic redirects are refused. Each attempt has a 10-second deadline. Poll the job if your receiver is unavailable.

Manage callbacks with:

- `GET /webhooks`: list endpoints, without signing secrets.
- `GET /webhooks/WEBHOOK_ID/deliveries`: latest 50 deliveries, with attempt counts, last HTTP status, and next attempt time.
- `DELETE /webhooks/WEBHOOK_ID`: remove the endpoint and cancel its outstanding deliveries. Rotate a signing secret by registering a replacement and deleting the old endpoint.

## Retries, limits, and errors

Creation, build, and deployment requests require `Idempotency-Key` (1–200 characters). Keys are scoped to the account and operation/project. Repeating the same validated request returns the original job, including after completion; it never creates another app, AI turn, or deployment. Reusing a key with different content returns **409**. Preserve the key after timeouts and network errors. Use a new key only for genuinely new work. Version 1 keeps these job identities until the account is deleted.

Limits: 120 authenticated requests per minute per account, 10 active API jobs per account, 10 webhook endpoints per account, 64 KB JSON bodies. List projects returns up to 100 results (default 30); `query` filters by name or description. Rate-limited requests return **429** and `Retry-After`. API jobs share normal billing and usage limits with the workspace and MCP; creating a key does not grant extra usage.

Errors use this shape:

```json
{"error":{"code":"idempotency_conflict","message":"This Idempotency-Key was already used with different input."},"request_id":"TRACE_ID"}
```

**400** invalid request or missing retry key; **401** missing, expired, or revoked account key; **404** unknown endpoint or inaccessible project/job/webhook; **409** conflicting retry key or webhook limit; **413** body too large; **415** incorrect content type; **429** rate or concurrency limit; **500** unexpected server failure. Responses include `X-Request-Id` for support. A 202 response followed by a failed job is an asynchronous failure, not an HTTP submission error.

The API is versioned at `/api/v1`. Use the [OpenAPI document](https://monstarx.com/api/v1/openapi.json) in Postman or to generate a client. Requests use account keys from Settings; the API does not create account keys for other callers.
