# Cedar Public API

This document is the machine-readable integration reference for external applications and AI agents
that call Cedar. It describes the public HTTP API used to register callers, upload workflow input
files, start AI workflow runs, poll run status, and cancel runs.

The public API is versioned under `/api/v1`. The API contract is intentionally stable. Treat the
request and response shapes in this document as the source of truth for calling applications.

## Agent instructions

If you are an AI coding agent, use this document to generate a small app-local Cedar client in the
language and framework requested by the host application. Use only the endpoints and shapes in this
contract.

Your generated client should:

- Accept Cedar workflow manifests from the host app: base URL, application ID, alias, route style,
  workflow metadata, output kind, result contract, usage plans, and API key.
- Keep the application API key in protected secret storage.
- Register or renew external callers before they start workflow runs.
- Upload private or local files through Cedar upload URLs before starting a run.
- Start workflow runs, poll until a terminal status, and return the final `result` object to the
  host app.
- Support Developer Mode for build-time and testing flows by using the reserved
  `X-Cedar-External-Caller-Id: __developer__` caller identity when the developer asks for it.
- Model workflow outputs as a discriminated union keyed by `outputKind`.
- Preserve Cedar error responses for the host app instead of replacing them with vague errors.
- For multiple Cedar workflows, create one shared client and a local workflow registry keyed by
  workflow handle.
- Do not invent a separate Developer Mode endpoint, auth scheme, request body, or polling flow.
  Developer Mode uses the same public workflow routes as normal caller runs.
- For repeated Cedar work, create a local project skill or instruction file from this document and
  the copied workflow manifests when the host coding agent supports that.
- In Codex, the developer may use `/skill` and point it at this Cedar AI Reference plus one or more
  workflow manifests to create a reusable local Cedar integration skill.
- In Claude Code, Cursor, or similar agents, create the equivalent local project skill, rule, or
  instruction from the same guide and manifests.
- Never include real Cedar API keys in generated skills, project instructions, source control, or
  public repositories. Keep real keys in the host application's protected secret storage.

## Integration inputs

Use these values to generate a complete client entry for a specific workflow:

| Input                   | Required       | Source                            | Notes                                                                                                                                                              |
| ----------------------- | -------------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `cedarBaseUrl`          | Yes            | Cedar Admin or deployment origin  | Do not include a trailing slash.                                                                                                                                   |
| `applicationId`         | Yes            | Cedar Admin application public ID | Used as `{appId}` in every path.                                                                                                                                   |
| `alias`                 | Yes            | Cedar workflow config             | Route handle from the manifest. When `routeStyle` is `alias`, this is an active workflow alias. When `routeStyle` is `workflowId`, this is the workflow public ID. |
| `routeStyle`            | Yes            | Cedar workflow config             | `alias` or `workflowId`; use the style supplied by Cedar Admin.                                                                                                    |
| `workflowName`          | Yes            | Cedar Admin workflow              | Use for generated method names, logs, and UI labels.                                                                                                               |
| `workflowDescription`   | No             | Cedar Admin workflow              | Use to understand app-facing intent.                                                                                                                               |
| `outputKind`            | Yes            | Cedar Admin workflow              | Determines the completed run `result` shape.                                                                                                                       |
| `resultContract`        | Yes            | Cedar Admin workflow manifest     | Result contract for the configured `outputKind`.                                                                                                                   |
| `usagePlans`            | Yes            | Cedar workflow config             | Available usage plans for caller registration or renewal. The calling application chooses the public ID that matches the caller's entitlement.                     |
| `apiKey`                | Yes            | Secret storage                    | Send as `Authorization: Bearer {apiKey}`.                                                                                                                          |
| `externalCallerId`      | Yes at runtime | Host app                          | Stable user, account, tenant, device, or subject ID.                                                                                                               |
| `developerModeCallerId` | No             | Cedar convention                  | Reserved build-time caller ID. Default to `__developer__` when the host app does not provide a value.                                                              |

Recommended workflow manifest shape:

```json
{
  "cedarBaseUrl": "https://cedar.example.com",
  "applicationId": "11111111-1111-4111-8111-111111111111",
  "alias": "production-copy",
  "routeStyle": "alias",
  "workflowName": "Production Copy",
  "workflowDescription": "Writes launch-ready product copy.",
  "outputKind": "text",
  "resultContract": {
    "type": "object",
    "additionalProperties": false,
    "required": ["outputKind", "text"],
    "properties": {
      "outputKind": { "const": "text" },
      "text": { "type": "string" }
    }
  },
  "usagePlans": [
    {
      "publicId": "33333333-3333-4333-8333-333333333333",
      "name": "Starter",
      "description": "Starter customer allowance.",
      "creditAllowance": 100,
      "renewalCadence": "monthly"
    }
  ],
  "developerModeCallerId": "__developer__",
  "apiKey": "{CEDAR_API_KEY}"
}
```

`routeStyle` tells the client how to interpret the manifest's `alias` value. If `routeStyle` is
`alias`, use it as an alias route segment. If `routeStyle` is `workflowId`, use it as a workflow
public ID route segment. Load `apiKey` from the host app's protected secret storage rather than
hard-coding it.

Cedar workflow manifests describe how to call a workflow and interpret its configured output kind.
They do not define workflow-specific input schemas. All workflows use the public run input
contract: `input` is required and may be a string or JSON object, and `files` is optional for
uploaded private or local files.

`resultContract` describes the result shape for the configured `outputKind`. It is
output-kind-specific, not a custom per-workflow output schema.

When the developer provides another workflow manifest later, update the same shared Cedar client and
add a new registry entry or app-facing wrapper. Do not duplicate caller registration, upload, run,
polling, cancellation, or error-handling code for each workflow.

## Client generation checklist

When generating client code, include these functions or equivalent methods:

| Client method                                            | Cedar interaction                                                     |
| -------------------------------------------------------- | --------------------------------------------------------------------- |
| `registerCaller(externalCallerId)`                       | `POST /api/v1/applications/{appId}/callers`                           |
| `renewCaller(externalCallerId)`                          | `PUT /api/v1/applications/{appId}/callers`                            |
| `createUploadUrl(fileName, contentType, workflowHandle)` | `POST /api/v1/applications/{appId}/files/upload-url`                  |
| `uploadFile(uploadUrl, bytes, contentType)`              | `PUT <uploadUrl>`                                                     |
| `startRun(externalCallerId, input, files)`               | `POST /api/v1/applications/{appId}/{workflowRef}/run`                 |
| `getRun(externalCallerId, runId)`                        | `GET /api/v1/applications/{appId}/{workflowRef}/runs/{runId}`         |
| `cancelRun(externalCallerId, runId)`                     | `POST /api/v1/applications/{appId}/{workflowRef}/runs/{runId}/cancel` |
| `runAndWait(externalCallerId, input, files)`             | Start, poll, handle terminal status, return `result`.                 |

Do not expose lower-level HTTP details to the host app unless the host app explicitly needs them.
The normal host-app API should be one method that accepts app input and returns the completed Cedar
workflow result.

## Compact endpoint spec

| Purpose                           | Method | Path                                                            | Caller header | Success               |
| --------------------------------- | ------ | --------------------------------------------------------------- | ------------- | --------------------- |
| Register caller                   | `POST` | `/api/v1/applications/{appId}/callers`                          | No            | `200` or `201`        |
| Renew caller                      | `PUT`  | `/api/v1/applications/{appId}/callers`                          | No            | `201`                 |
| Create upload URL                 | `POST` | `/api/v1/applications/{appId}/files/upload-url`                 | Yes           | `200`                 |
| Upload bytes                      | `PUT`  | `<uploadUrl>`                                                   | No            | Provider-specific 2xx |
| Start run with alias route        | `POST` | `/api/v1/applications/{appId}/{alias}/run`                      | Yes           | `202`                 |
| Start run with workflow ID route  | `POST` | `/api/v1/applications/{appId}/{workflowId}/run`                 | Yes           | `202`                 |
| Poll run with alias route         | `GET`  | `/api/v1/applications/{appId}/{alias}/runs/{runId}`             | Yes           | `200`                 |
| Poll run with workflow ID route   | `GET`  | `/api/v1/applications/{appId}/{workflowId}/runs/{runId}`        | Yes           | `200`                 |
| Cancel run with alias route       | `POST` | `/api/v1/applications/{appId}/{alias}/runs/{runId}/cancel`      | Yes           | `200`                 |
| Cancel run with workflow ID route | `POST` | `/api/v1/applications/{appId}/{workflowId}/runs/{runId}/cancel` | Yes           | `200`                 |

Use the route style supplied by the Cedar workflow manifest. If `routeStyle` is `alias`, use the
alias route segment. If `routeStyle` is `workflowId`, use the workflow public ID route segment.

## Run lifecycle

Workflow runs are asynchronous.

1. Ensure the external caller has an active usage plan with caller registration or renewal.
2. Upload any private/local files and keep the returned `file` objects.
3. Start the run.
4. Poll the run every `1000ms` while the status is `queued`, `running`, or `recovering`.
5. Treat `completed` as success and return `result`.
6. Treat `failed` and `canceled` as terminal non-success states.

Terminal status handling:

| Status       | Terminal | Client behavior                                |
| ------------ | -------- | ---------------------------------------------- |
| `queued`     | No       | Keep polling.                                  |
| `running`    | No       | Keep polling.                                  |
| `recovering` | No       | Keep polling.                                  |
| `completed`  | Yes      | Return `result`.                               |
| `failed`     | Yes      | Throw or return a typed failure using `error`. |
| `canceled`   | Yes      | Throw or return a typed cancellation.          |

## Developer Mode

Developer Mode is a build-time workflow testing aid. When it is enabled for a workflow in Cedar
Admin, Cedar can replay matching pinned completed runs for the reserved developer caller instead of
starting fresh inference.

Developer Mode does not add a separate public API. Use the normal application API key, normal
workflow run routes, normal upload route, and normal polling lifecycle. The only caller-side rule is
that Developer Mode requests must send:

```http
X-Cedar-External-Caller-Id: __developer__
```

Developer Mode setup and use:

1. Create or identify at least one active usage plan for the Cedar application.
2. Enable Developer Mode for the workflow in Cedar Admin. Cedar creates or reuses the reserved
   `__developer__` caller and enrolls it in an active usage plan.
3. Start build-time API runs through the normal run endpoint with
   `X-Cedar-External-Caller-Id: __developer__`.
4. Poll the normal `/runs/{runId}` endpoint until the run reaches a terminal status.
5. Pin completed runs from the `__developer__` caller in Cedar Admin.
6. Keep sending the same normalized input and file names with the `__developer__` caller while
   Developer Mode is enabled to receive replayed completed results.

Developer Mode run example:

```http
POST /api/v1/applications/{appId}/{workflowRef}/run
Authorization: Bearer <application API key>
Content-Type: application/json
X-Cedar-External-Caller-Id: __developer__

{
  "input": "Draft a concise support reply."
}
```

The start response still uses the normal `202` queued shape. Clients should poll
`GET /api/v1/applications/{appId}/{workflowRef}/runs/{runId}` and treat replayed runs like ordinary
completed runs. Production and customer traffic must use real stable external caller IDs, not
`__developer__`.

## Caller spending reservations

Caller runs require a verified text/JSON spending profile. Before provider execution Cedar atomically holds a conservative maximum based on full model input capacity and a bounded output budget. The remaining allocation minus all unexpired holds must cover the new hold. Multiple requests can run concurrently across workflows. Actual trustworthy usage settles once against the original allocation.

Caller image output and paid xAI web/X search return `409` before inference until verified spending profiles exist. These capabilities remain available in admin testing. A workflow that works in admin testing may therefore be unavailable to callers. Invalid output limits and insufficient available credits also return `409`; preserve the error message.

Terminal requests without usable usage release their hold automatically. Abandoned holds expire after 15 minutes without requiring a customer action or waiting for scheduled cleanup. Released or expired holds cannot be charged by late completion events. Do not automatically resubmit a request with an unknown outcome. Authenticated status polling remains available after depletion or expiry and never performs billing. Allocation renewal can proceed while older requests settle against their original allocation.

## Output result shapes

Every completed run has a `result` object with an `outputKind` discriminator. A workflow manifest
from Cedar Admin may narrow this to one configured output kind. Image output is retained for admin testing; caller image runs currently return `409` before execution.

```ts
type CedarWorkflowResult =
  | { outputKind: "text"; text: string }
  | { outputKind: "json"; json: unknown }
  | {
      outputKind: "image";
      artifact: CedarArtifactWithImageVariants;
      revisedPrompt?: string | null;
    };
```

## API conventions

### Base URL

Use the Cedar deployment URL as the origin, then call the paths shown below.

Example:

```text
https://cedar.example.com/api/v1/applications/{appId}/{workflowRef}/run
```

### Identifiers

- `{appId}` is the Cedar application public ID.
- `{workflowId}` is the public workflow identifier.
- `{alias}` is an active workflow alias when the manifest's `routeStyle` is `alias`.
- `{workflowRef}` is the route segment selected from the manifest: `{alias}` when `routeStyle` is
  `alias`, or `{workflowId}` when `routeStyle` is `workflowId`.
- `{runId}` is returned by a workflow run start request.
- `externalCallerId` is the calling application user, account, tenant, device, or other stable
  external subject that Cedar should meter and authorize.
- `usagePlanPublicId` is the public ID of the Cedar usage plan to allocate to a caller.

### Authentication

Every Cedar public API request requires an application API key. Send it with this header:

```http
Authorization: Bearer <application API key>
```

Caller-scoped endpoints also require:

```http
X-Cedar-External-Caller-Id: <external caller id>
```

The caller identity header is required for file upload URL creation, workflow run creation, workflow
run status polling, and workflow run cancellation.

### Request and response format

All Cedar API request bodies are JSON unless the endpoint explicitly says otherwise. Send:

```http
Content-Type: application/json
```

Successful Cedar API responses are JSON. Errors use this stable envelope:

```json
{
  "error": "Human readable error message."
}
```

Common authentication and caller errors:

- `401 { "error": "Application API key is required." }`
- `401 { "error": "Invalid application API key." }`
- `403 { "error": "Application is not active." }`
- `403 { "error": "Application API key is not active." }`
- `403 { "error": "Application API key is expired." }`
- `400 { "error": "X-Cedar-External-Caller-Id header is required." }`
- `400 { "error": "Invalid request body." }`
- `404 { "error": "Caller not found." }`
- `409 { "error": "Caller does not have an active usage plan." }`

### CORS

The public `/api/v1` API is callable from browsers, mobile apps, and other calling applications.
Browser callers are supported through CORS preflight responses that allow:

- Methods: `GET, POST, PUT, OPTIONS`
- Headers: `Authorization, Content-Type, X-Cedar-External-Caller-Id`
- Exposed headers: `x-cedar-request-id`

## Caller registration

Register a calling-application subject with Cedar and allocate an active usage plan.

```http
POST /api/v1/applications/{appId}/callers
```

Required headers:

```http
Authorization: Bearer <application API key>
Content-Type: application/json
```

Request body:

```json
{
  "externalCallerId": "customer-a",
  "usagePlanPublicId": "33333333-3333-4333-8333-333333333333"
}
```

Fields:

- `externalCallerId` is required and must be a non-empty string after trimming.
- `usagePlanPublicId` is required and must be a non-empty string after trimming.

Success status:

- `201` when Cedar creates a caller or enrollment.
- `200` when the caller already has the same active usage plan.

Success response:

```json
{
  "status": "active",
  "applicationPublicId": "11111111-1111-4111-8111-111111111111",
  "usagePlanPublicId": "33333333-3333-4333-8333-333333333333"
}
```

Important errors:

- `404 { "error": "Usage plan not found." }`
- `403 { "error": "Usage plan is blocked." }`
- `409 { "error": "Caller already has an active usage plan." }`
- `409 { "error": "Caller does not have an active usage plan. Use the renewal endpoint to allocate fresh credits." }`

## Caller usage plan renewal

Renew or reallocate credits for an existing caller when the current allocation is eligible for public
renewal.

```http
PUT /api/v1/applications/{appId}/callers
```

Required headers:

```http
Authorization: Bearer <application API key>
Content-Type: application/json
```

Request body:

```json
{
  "externalCallerId": "customer-a",
  "usagePlanPublicId": "33333333-3333-4333-8333-333333333333"
}
```

Success status:

- `201`

Success response:

```json
{
  "status": "active",
  "applicationPublicId": "11111111-1111-4111-8111-111111111111",
  "usagePlanPublicId": "33333333-3333-4333-8333-333333333333"
}
```

Renewal rules:

- Credit-based plans can renew only after the current allocation is depleted.
- Weekly, monthly, and annual plans can renew only after the current allocation period expires.
- Cedar rejects renewal while the caller already has an active allocation.

Important errors:

- `404 { "error": "Usage plan not found." }`
- `403 { "error": "Usage plan is blocked." }`
- `409 { "error": "Caller already has an active usage allocation." }`

## File upload URL creation

Create a temporary upload URL for an input file that will be attached to a workflow run.
File uploads are optional. If source files are openly available on the Internet, include their URLs
or references in the workflow input instead of uploading them to Cedar. Use this endpoint for files
that are private, local to the caller, generated at runtime, or otherwise unavailable to Cedar.

```http
POST /api/v1/applications/{appId}/files/upload-url
```

Required headers:

```http
Authorization: Bearer <application API key>
Content-Type: application/json
X-Cedar-External-Caller-Id: customer-a
```

Request body:

```json
{
  "fileName": "input.png",
  "contentType": "image/png",
  "workflowId": "33333333-3333-4333-8333-333333333333"
}
```

Fields:

- `fileName` is required and is sanitized by Cedar before being stored.
- `contentType` is required and must be one of Cedar's supported MIME types.
- `workflowId` is required and resolves the target workflow or active alias.

Success status:

- `200`

Success response:

```json
{
  "key": "incoming/app-11111111-1111-4111-8111-111111111111/workflow-33333333-3333-4333-8333-333333333333/caller-22222222-2222-4222-8222-222222222222/18be1e74-03be-4a72-8ac8-3f02852af5dc/input.png",
  "uploadUrl": "https://upload.cedar.example.com/signed-upload-url",
  "file": {
    "key": "incoming/app-11111111-1111-4111-8111-111111111111/workflow-33333333-3333-4333-8333-333333333333/caller-22222222-2222-4222-8222-222222222222/18be1e74-03be-4a72-8ac8-3f02852af5dc/input.png",
    "mimeType": "image/png",
    "fileName": "input.png"
  },
  "limits": {
    "maxFiles": 5,
    "maxTotalBytes": 10485760,
    "retentionSeconds": 172800
  }
}
```

Upload the file bytes to the returned `uploadUrl`:

```http
PUT <uploadUrl>
Content-Type: image/png
```

Use the returned `file` object when starting the workflow run.

Supported input file MIME types:

- `application/json`
- `application/pdf`
- `application/rtf`
- `audio/flac`
- `audio/mpeg`
- `audio/mp3`
- `audio/ogg`
- `audio/opus`
- `audio/wav`
- `audio/webm`
- `image/gif`
- `image/heic`
- `image/heif`
- `image/jpeg`
- `image/png`
- `image/webp`
- `text/csv`
- `text/markdown`
- `text/plain`
- `text/tab-separated-values`

Important errors:

- `400 { "error": "contentType is required" }`
- `400 { "error": "Unsupported file content type \"<mimeType>\"." }`
- `404 { "error": "Caller not found." }`

## Start a workflow run

Start an asynchronous Cedar AI workflow run for a registered caller.

Alias route:

```http
POST /api/v1/applications/{appId}/{alias}/run
```

Workflow ID route:

```http
POST /api/v1/applications/{appId}/{workflowId}/run
```

Required headers:

```http
Authorization: Bearer <application API key>
Content-Type: application/json
X-Cedar-External-Caller-Id: customer-a
```

Request body with text input:

```json
{
  "input": "Draft a concise support reply."
}
```

Request body with structured input and files:

```json
{
  "input": {
    "subject": "Refund request",
    "message": "The customer would like a refund for order A123."
  },
  "files": [
    {
      "key": "incoming/app-11111111-1111-4111-8111-111111111111/workflow-33333333-3333-4333-8333-333333333333/caller-22222222-2222-4222-8222-222222222222/18be1e74-03be-4a72-8ac8-3f02852af5dc/input.png",
      "mimeType": "image/png",
      "fileName": "input.png"
    }
  ]
}
```

Fields:

- `input` is required. It may be a string or a JSON object.
- `files` is optional. It may contain up to `5` files.
- Each file requires `mimeType` and either `key` or `fileKey`.
- File keys must come from the upload URL endpoint for the same application, workflow, and caller.

Success status:

- `202`

Success response:

```json
{
  "runId": "run_123",
  "status": "queued",
  "createdAt": "2026-05-10T00:00:00.000Z"
}
```

Important errors:

- `400 { "error": "Invalid request body." }`
- `400 { "error": "X-Cedar-External-Caller-Id header is required." }`
- `404 { "error": "Caller not found." }`
- `409 { "error": "Caller does not have an active usage plan." }`
- `409 { "error": "Insufficient available credits." }`
- `409 { "error": "This workflow does not have a verified caller spending bound." }`
- `409 { "error": "Caller spending reservations do not support paid search tools." }`

## Get workflow run status

Poll the status and result for a workflow run.

Alias route:

```http
GET /api/v1/applications/{appId}/{alias}/runs/{runId}
```

Workflow ID route:

```http
GET /api/v1/applications/{appId}/{workflowId}/runs/{runId}
```

Required headers:

```http
Authorization: Bearer <application API key>
X-Cedar-External-Caller-Id: customer-a
```

Success status:

- `200`

Success response:

```json
{
  "runId": "run_123",
  "status": "completed",
  "createdAt": "2026-05-10T00:00:00.000Z",
  "updatedAt": "2026-05-10T00:02:00.000Z",
  "endedAt": "2026-05-10T00:02:00.000Z",
  "result": {
    "outputKind": "text",
    "text": "Done"
  },
  "error": null,
  "usage": {
    "promptTokens": 10,
    "cachedPromptTokens": null,
    "completionTokens": 20,
    "totalTokens": 30,
    "creditsUsed": 30
  }
}
```

Response fields:

- `status` is the current run state, such as `queued`, `running`, `recovering`, `completed`,
  `failed`, or `canceled`.
- `result` is `null` until a result is available.
- `error` is `null` unless the run failed.
- `usage` is `null` until Cedar has usage data. Public API usage does not expose estimated cost.

Important errors:

- `404 { "error": "Run not found." }`

## Cancel a workflow run

Cancel a workflow run for the caller.

Alias route:

```http
POST /api/v1/applications/{appId}/{alias}/runs/{runId}/cancel
```

Workflow ID route:

```http
POST /api/v1/applications/{appId}/{workflowId}/runs/{runId}/cancel
```

Required headers:

```http
Authorization: Bearer <application API key>
X-Cedar-External-Caller-Id: customer-a
```

Request body:

No request body is required.

Success status:

- `200`

Success response:

```json
{
  "runId": "run_123",
  "status": "canceled"
}
```

Important errors:

- `404 { "error": "Run not found." }`

## Recommended integration sequence

1. Create an application API key in Cedar Admin.
2. Create or identify a Cedar usage plan and keep its public ID available to the calling app.
3. Register each external caller with `POST /api/v1/applications/{appId}/callers`.
4. For private or local file inputs, call `POST /api/v1/applications/{appId}/files/upload-url`,
   then `PUT` the file bytes to the returned `uploadUrl`. Publicly reachable source files can be
   referenced in the workflow input instead.
5. Start a run with `POST /api/v1/applications/{appId}/{workflowRef}/run`, where `workflowRef`
   follows the manifest's `routeStyle`.
6. Poll `GET /api/v1/applications/{appId}/{workflowRef}/runs/{runId}` until the run reaches a
   terminal status.
7. If the caller needs a fresh allocation after depletion or period expiry, call
   `PUT /api/v1/applications/{appId}/callers`.

## Minimal fetch examples

Register a caller:

```ts
await fetch(
  "https://cedar.example.com/api/v1/applications/11111111-1111-4111-8111-111111111111/callers",
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${cedarApiKey}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      externalCallerId: "customer-a",
      usagePlanPublicId: "33333333-3333-4333-8333-333333333333",
    }),
  },
);
```

Start a run:

```ts
const response = await fetch(
  "https://cedar.example.com/api/v1/applications/11111111-1111-4111-8111-111111111111/production-copy/run",
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${cedarApiKey}`,
      "Content-Type": "application/json",
      "X-Cedar-External-Caller-Id": "customer-a",
    },
    body: JSON.stringify({
      input: "Draft a concise support reply.",
    }),
  },
);

const run = await response.json();
```

Poll a run:

```ts
const response = await fetch(
  `https://cedar.example.com/api/v1/applications/11111111-1111-4111-8111-111111111111/production-copy/runs/${run.runId}`,
  {
    headers: {
      Authorization: `Bearer ${cedarApiKey}`,
      "X-Cedar-External-Caller-Id": "customer-a",
    },
  },
);

const status = await response.json();
```
