---
title: "Cancel an async job"
method: POST
path: "/v1/jobs/{jobId}/cancel"
tags: ["jobs"]
---

# Cancel an async job

`POST /v1/jobs/{jobId}/cancel`

## Request

- Base URL: `https://api.cueframe.ai`
- URL: `https://api.cueframe.ai/v1/jobs/{jobId}/cancel`
- Auth: one of:
  - HTTP bearer
  - OAuth 2 (authorization code, authorization URL `https://api.cueframe.ai/api/auth/mcp/authorize`, token URL `https://api.cueframe.ai/api/auth/mcp/token`, scopes: `projects:write`)
  - API key in header `PAYMENT-SIGNATURE`

Cancel a running async job so an agent can abort a mis-priced/runaway operation without waiting out its TTL. Cancellation is durable and never meters. Already-terminal jobs are rejected (422 job_not_cancellable).

## Path parameters

- `jobId` string, required

## Response `200`

Cancelled.

- JobResponse
  - `id` string, required: Job id — pass to GET /v1/jobs/{id} / wait_job.
  - `jobKey` string, required: Deterministic identity of the work (idempotency key, e.g. `verify-<sessionId>-<contentHash>` — the hash covers the composition AND grading inputs). Re-enqueueing the same key returns the same job while it runs.
  - `kind` string, required: Job family, e.g. `verify`.
  - `status` 'running' | 'succeeded' | 'failed' | 'cancelled', required: Poll until terminal (`succeeded` | `failed` | `cancelled`).
  - `progress` object, nullable, required: Executor heartbeat while running; null when none reported.
    - `phase` string, required
    - `percent` number
    - `message` string
  - `result` union, required: Kind-specific payload when status is `succeeded`; null otherwise.
    - PreviewFrameJobResult
      - `geometry` object, required
        - `scale` number, required
        - `compositionWidth` number
        - `compositionHeight` number
        - `width` number
        - `height` number
      - `warnings` object[]
      - `previewed` object, required
        - `source` 'inline' | 'scratch' | 'persisted', required
        - `compositionId` string
        - `etag` string
      - `listUsd` number: List price charged for this delivered capture.
      - `artifacts` object[], required
        - `id` string, required
        - `beatSec` number, required
        - `bytes` integer, required
        - `contentType` 'image/png' | 'image/jpeg', required
        - `layers` object, required
          - `video` string, nullable, required
          - `overlays` integer, required
        - `url` string, uri, required
        - `urlExpiresAt` string, required
    - union
      - ComponentPreviewImageResult
        - `artifactKind` 'image', required
        - `contentType` 'image/png' | 'image/jpeg', required
        - `cached` boolean, required
        - `listUsd` number: List price charged for this delivered preview.
        - `url` string, uri, required
        - `urlExpiresAt` string, required
      - ComponentPreviewMotionResult
        - `artifactKind` 'motion', required
        - `contentType` 'video/webm', required
        - `cached` boolean, required
        - `listUsd` number: List price charged for this delivered preview.
        - `url` string, uri, required
        - `urlExpiresAt` string, required
    - VerifyJobResult
      - `perCriterion` unknown, required
      - `composite` number, required
      - `critique` string, required
      - `checkpointId` string, required
      - `beats` unknown
      - `clientScores` unknown[]
        - unknown
      - `listUsd` number: List price charged for this delivered evaluation.
    - ExtractBrandKitResponse: POST /brand-kits/extract response — extracted brand tokens (not persisted).
      - `colors` string[], required
      - `fonts` string[], required
      - `title` string
      - `description` string
  - `error` object, nullable, required: Stable failure code + human message when status is `failed`; null otherwise. `job_timeout` = the executor died mid-run and the stall sweep reaped the job — re-enqueue to retry.
    - `code` string, required
    - `message` string, required
  - `createdAt` string, required
  - `updatedAt` string, required
  - `completedAt` string, nullable, required

## Other responses

- `400`: Bad request — validation_error / invalid_cursor / invalid_query.
- `401`: Missing or invalid Authorization header.
- `402`: Payment required. Returned when the caller presents no API key on a priced operation: the body AND the `Payment-Required` header carry the x402 v2 challenge (accepted scheme, network, USDC asset, amount, payTo). Sign the EIP-3009 authorization and retry with a `PAYMENT-SIGNATURE` header. A KEYED caller sees this status instead when their plan lacks or has exhausted the feature (`billing_required`).
- `403`: Forbidden — permission insufficient.
- `404`: Resource not found.
- `422`: Unprocessable — invalid_composition / media_in_use / session_in_use / render_not_cancellable.
- `429`: Rate limited. Retry-After header present.
- `500`: Internal error.

---

[API](https://skmtc.dev/cueframe/apis/cueframe-api.md) · [All operations](https://skmtc.dev/cueframe/apis/cueframe-api/llms.txt) · [OpenAPI document](https://skmtc.dev/cueframe/apis/cueframe-api/revisions/8f9bfe362b4a?raw)
