# Submit a prompt; the agent runs in the background.

POST https://services.leadconnectorhq.com/ai-builder-api/projects/{projectId}/runs

Returns `runId` immediately. The agent executes asynchronously:
attempt workspace restore from project's prior run → materialise
scaffold (only if no prior workspace) → loop tool calls → preflight
`pnpm build` → flush workspace to GCS → deploy via Cloud Build →
managed runtime revision replace → mark `ready` with a preview URL.

Per-project runtime services receive a stable public app hostname so the
iframe URL works without platform-session auth.

**Idempotency**: callers SHOULD send an `Idempotency-Key` header on
every retry. The server stores `(locationId, projectId, key)` →
`runId` for 24 h. Same key + same body → the original `runId` is
replayed. Same key + different body → `409 idempotency_conflict`.
Modeled after standard idempotent POST contracts; safe for browser
retries, network blips, and double-click submits.

**Attachment scope**: when `attachmentIds` are present, each id is
verified against the caller's tenant + project. Cross-project or
cross-tenant reuse is rejected with `403 attachment_not_owned`.


## Authentication

Send `Authorization: Bearer <token>` using:

- **Sub-Account token: OAuth access token or Private Integration Token.** Scopes: `clientportal-ai.write`

## Parameters

### Header Parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `Idempotency-Key` | string | No | Caller-generated key (UUID-v4 recommended) that makes this POST safe to retry. Must match the prior request body byte-for-byte on replay. Reused with a different body → `409`.  |
| `X-Correlation-Id` | string | No | Optional caller-supplied trace id. When omitted, the API mints `cid_<uuid>` and echoes it back via the response `X-Correlation-Id` header. Threaded through audit rows + logs.  |
| `Version` | string | Yes | The API version. |

### Path Parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `projectId` | string | Yes | The project's id. |

## OpenAPI Specification

```json
{
  "openapi": "3.0.0",
  "info": {
    "title": "HighLevel API",
    "version": "v3"
  },
  "servers": [
    {
      "url": "https://services.leadconnectorhq.com"
    }
  ],
  "paths": {
    "/ai-builder-api/projects/{projectId}/runs": {
      "post": {
        "summary": "Submit a prompt; the agent runs in the background.",
        "operationId": "submitAPromptTheAgentRunsInTheBackground",
        "description": "Returns `runId` immediately. The agent executes asynchronously:\nattempt workspace restore from project's prior run → materialise\nscaffold (only if no prior workspace) → loop tool calls → preflight\n`pnpm build` → flush workspace to GCS → deploy via Cloud Build →\nmanaged runtime revision replace → mark `ready` with a preview URL.\n\nPer-project runtime services receive a stable public app hostname so the\niframe URL works without platform-session auth.\n\n**Idempotency**: callers SHOULD send an `Idempotency-Key` header on\nevery retry. The server stores `(locationId, projectId, key)` →\n`runId` for 24 h. Same key + same body → the original `runId` is\nreplayed. Same key + different body → `409 idempotency_conflict`.\nModeled after standard idempotent POST contracts; safe for browser\nretries, network blips, and double-click submits.\n\n**Attachment scope**: when `attachmentIds` are present, each id is\nverified against the caller's tenant + project. Cross-project or\ncross-tenant reuse is rejected with `403 attachment_not_owned`.\n",
        "parameters": [
          {
            "in": "path",
            "name": "projectId",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^prj_[A-Za-z0-9_-]+$"
            },
            "description": "The project's id.",
            "example": "prj_5f0c2a3e"
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 255,
              "minLength": 1
            },
            "description": "Caller-generated key (UUID-v4 recommended) that makes this POST\nsafe to retry. Must match the prior request body byte-for-byte\non replay. Reused with a different body → `409`.\n",
            "example": "6d2f0a8e-1b3c-4d5e-8f9a-0b1c2d3e4f5a"
          },
          {
            "in": "header",
            "name": "X-Correlation-Id",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64,
              "minLength": 1
            },
            "description": "Optional caller-supplied trace id. When omitted, the API mints\n`cid_<uuid>` and echoes it back via the response\n`X-Correlation-Id` header. Threaded through audit rows + logs.\n",
            "example": "cid_7d9e2f1a"
          },
          {
            "name": "Version",
            "in": "header",
            "required": true,
            "description": "The API version.",
            "schema": {
              "type": "string",
              "enum": [
                "v3"
              ]
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubmitAgentRunRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted; agent is running.",
            "headers": {
              "X-Correlation-Id": {
                "description": "Correlation id used for log + audit stitching.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubmitAgentRunResponse"
                }
              }
            }
          },
          "403": {
            "description": "One or more `attachmentIds` are not owned by this project (or\nbelong to a different tenant). Code: `attachment_not_owned`.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "`Idempotency-Key` was reused with a different request body.\nCode: `idempotency_conflict`. Generate a fresh key for the\nnew payload.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": [
              "clientportal-ai.write"
            ]
          }
        ]
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearer": {
        "type": "http",
        "scheme": "bearer",
        "description": "A sub-account access token: a Marketplace app's OAuth token or a Private Integration Token."
      }
    },
    "schemas": {
      "SubmitAgentRunRequest": {
        "type": "object",
        "required": [
          "prompt"
        ],
        "properties": {
          "prompt": {
            "type": "string",
            "minLength": 1,
            "maxLength": 20000,
            "description": "What to build or change.",
            "example": "Add a page listing upcoming events"
          },
          "productTarget": {
            "description": "What the project builds; the project's own by default.",
            "type": "string",
            "enum": [
              "full_stack",
              "mobile",
              "landing_page"
            ],
            "title": "ProductTarget"
          },
          "customCode": {
            "type": "boolean",
            "default": false,
            "description": "ClientPortal-only per-run switch. When false or omitted, the agent\ncan inspect the project and apply SDUI configuration, but source-code,\nshell, dependency, and build tools are unavailable. When true, the\nexisting full custom-code tool surface is enabled. This choice does\nnot change sandbox provisioning or preview lifecycle behavior.\n",
            "example": false
          },
          "clientPortalSurface": {
            "type": "string",
            "enum": [
              "web",
              "mobile"
            ],
            "description": "ClientPortal-only context captured from the selected builder surface.\nUnqualified follow-ups default to this lane; explicit web, mobile,\nor web-and-mobile wording in the prompt takes precedence.\n",
            "example": "web"
          },
          "externalAgent": {
            "type": "boolean",
            "default": false,
            "description": "An agent outside the builder (an MCP client) writes this run's code in\nthe project's sandbox. The run skips the builder's agent: a first build\nasks the builder's intake questions (answered through the answers\nAPI), then every run checks, delivers, registers the sandbox with\nClientPortal, and seals a publishable release.\n",
            "example": true
          },
          "mobilePipeline": {
            "type": "string",
            "enum": [
              "v2-simple"
            ],
            "description": "Deprecated compatibility field for older mobile clients. New mobile\nruns use the standard builder flow with the React Native app kernel.\n",
            "example": "v2-simple"
          },
          "mobilePipelineSpeed": {
            "type": "string",
            "enum": [
              "fast",
              "slow"
            ],
            "default": "slow",
            "description": "Deprecated compatibility field. Accepted for older mobile clients but\nno longer selects a distinct generation pipeline; production mobile\ncodegen uses the single-loop Mastra path.\n",
            "example": "fast"
          },
          "modelId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "Model id from `GET /api/v1/catalog/models`. When provided, this\nsingle model is used for every phase of the agent (classify,\nplan, code). When omitted, the platform routes to its per-phase\ndefaults (Haiku → Sonnet → Opus).\n",
            "example": "claude-sonnet-4-5"
          },
          "agentId": {
            "type": "string",
            "pattern": "^agt_[A-Za-z0-9_-]+$",
            "description": "Optional id of a user-defined agent profile created via\n`POST /api/v1/agents`. The profile's `systemInstructions` and\n`skills` are appended to the platform's catalog for this run,\nand its `defaultModelId` is honoured when `modelId` is not set.\n",
            "example": "agt_4c2d1e"
          },
          "mode": {
            "type": "string",
            "enum": [
              "auto",
              "plan",
              "build",
              "plan_first"
            ],
            "default": "auto",
            "description": "Run mode. The composer's 3-way segmented control surfaces:\n\n  - `auto` (default) — agent honours the classifier's\n    `recommended_mode` and decides whether to plan, ask, or\n    build straight through.\n  - `plan`           — agent always proposes a plan first via\n    `propose_plan` and pauses for approval. The plan is\n    surfaced as a `plan_approval_request` narrator event;\n    the user POSTs an approve/refine/reject verdict to\n    `/agent-runs/{runId}/plan-approval`.\n  - `build`          — agent skips planning and goes straight\n    to file_editor (only `ask_user` when the classifier\n    flags a high-cost architectural unknown).\n  - `plan_first`     — back-compat alias for `plan`. v1\n    callers still emit it; the runtime treats it as `plan`.\n",
            "example": "auto"
          },
          "attachmentIds": {
            "type": "array",
            "maxItems": 10,
            "items": {
              "type": "string"
            },
            "description": "Optional ids of attachments previously created via\n`POST /api/v1/projects/{projectId}/attachments/upload-url`.\nSurfaced to the agent as user-provided context so generated\ncode can reference uploaded files (logos, PDFs, brand assets).\n",
            "example": [
              "att_1a2b3c"
            ]
          },
          "selectedElements": {
            "type": "array",
            "maxItems": 20,
            "description": "Visual edits (vibe apps): the elements the creator selected in the\nlive preview before sending. The agent receives them as a\n`<selected-elements>` block after the prompt, so \"this\" means the\nelement on screen. Context only: file and line are hints the agent\nchecks against the workspace.\n",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "elementType"
              ],
              "example": {
                "elementType": "h1",
                "filePath": "app/design-system/atoms/Heading.vue",
                "lineNumber": 20,
                "ownerFilePath": "app/pages/courses.vue",
                "ownerLineNumber": 16,
                "textContent": "Courses",
                "className": "font-heading text-4xl",
                "attrs": {
                  "id": "page-title"
                }
              },
              "properties": {
                "elementType": {
                  "type": "string",
                  "pattern": "^[a-z][a-z0-9-]{0,39}$",
                  "description": "Lower-case tag name of the element, e.g. `h1`.",
                  "example": "h1"
                },
                "filePath": {
                  "type": "string",
                  "maxLength": 300,
                  "pattern": "^(?!.*(?:^|/)\\.\\.(?:/|$))[A-Za-z0-9_@.()\\[\\]+~$ -][A-Za-z0-9_@.()\\[\\]+~$ /-]*$",
                  "description": "Where the element is written, relative to the app root (no `..` segment, not absolute; Nuxt route characters such as `[id]` and `(group)` allowed).",
                  "example": "pages/index.vue"
                },
                "lineNumber": {
                  "type": "integer",
                  "minimum": 1,
                  "maximum": 1000000,
                  "description": "The element's line in `filePath`.",
                  "example": 12
                },
                "ownerFilePath": {
                  "type": "string",
                  "maxLength": 300,
                  "pattern": "^(?!.*(?:^|/)\\.\\.(?:/|$))[A-Za-z0-9_@.()\\[\\]+~$ -][A-Za-z0-9_@.()\\[\\]+~$ /-]*$",
                  "description": "The page that renders the design-system component this element is the root of. Same rule as `filePath`.",
                  "example": "pages/index.vue"
                },
                "ownerLineNumber": {
                  "type": "integer",
                  "minimum": 1,
                  "maximum": 1000000,
                  "description": "The line in `ownerFilePath`.",
                  "example": 8
                },
                "textContent": {
                  "type": "string",
                  "maxLength": 500,
                  "description": "The element's visible text, with emails and phone numbers redacted by the preview.",
                  "example": "Welcome back"
                },
                "className": {
                  "type": "string",
                  "maxLength": 2000,
                  "description": "The element's CSS classes.",
                  "example": "text-3xl font-bold"
                },
                "attrs": {
                  "type": "object",
                  "maxProperties": 30,
                  "description": "A small set of the element's HTML attributes (id, role, type, name, links without their query, aria-*…).",
                  "propertyNames": {
                    "pattern": "^[A-Za-z][A-Za-z0-9:_-]{0,63}$"
                  },
                  "additionalProperties": {
                    "type": "string",
                    "maxLength": 500
                  },
                  "example": {
                    "id": "hero-title"
                  }
                }
              },
              "title": "AgentRunSelectedElement"
            },
            "example": [
              {
                "elementType": "h1",
                "filePath": "pages/index.vue",
                "lineNumber": 12
              }
            ]
          }
        },
        "title": "SubmitAgentRunRequest"
      },
      "SubmitAgentRunResponse": {
        "type": "object",
        "required": [
          "runId",
          "state"
        ],
        "properties": {
          "runId": {
            "type": "string",
            "pattern": "^run_[A-Za-z0-9_-]+$",
            "description": "The run that started.",
            "example": "run_8f3c2a91"
          },
          "state": {
            "description": "The run as it starts.",
            "type": "object",
            "required": [
              "runId",
              "projectId",
              "prompt",
              "status",
              "createdAt",
              "updatedAt"
            ],
            "properties": {
              "runId": {
                "type": "string",
                "description": "The run.",
                "example": "run_8f3c2a91"
              },
              "projectId": {
                "type": "string",
                "description": "The project the run belongs to.",
                "example": "prj_5f0c2a3e"
              },
              "prompt": {
                "type": "string",
                "description": "What the run was asked to build or change.",
                "example": "Add a page listing upcoming events"
              },
              "promptAuthor": {
                "description": "Who sent the prompt.",
                "type": "object",
                "required": [
                  "id",
                  "name"
                ],
                "additionalProperties": false,
                "properties": {
                  "id": {
                    "type": "string",
                    "description": "Authenticated user id captured when the prompt was submitted.",
                    "example": "usr_9a8b7c"
                  },
                  "name": {
                    "type": "string",
                    "description": "Display-name snapshot captured when the prompt was submitted.",
                    "example": "Jane Doe"
                  },
                  "avatarUrl": {
                    "type": "string",
                    "format": "uri",
                    "description": "Profile-image snapshot captured when the prompt was submitted.",
                    "example": "https://images.example.com/avatars/jane.png"
                  }
                },
                "title": "PromptAuthor"
              },
              "status": {
                "description": "The run's status.",
                "type": "string",
                "enum": [
                  "queued",
                  "running",
                  "deploying",
                  "ready",
                  "failed",
                  "cancelled",
                  "needs_input"
                ],
                "title": "AgentRunStatus"
              },
              "phase": {
                "type": "string",
                "description": "Internal Spec Kit phase for the active builder run. Stream-v6 maps this to user-facing `data-status.data.phase` values such as `planning`, `clarifying`, `coding`, and `building`.",
                "enum": [
                  "init",
                  "constitution",
                  "specify",
                  "clarify",
                  "plan",
                  "tasks",
                  "analyze",
                  "implement",
                  "indexing",
                  "build",
                  "deploy",
                  "ready",
                  "failed"
                ],
                "example": "plan"
              },
              "phaseStatus": {
                "type": "string",
                "description": "Phase-local status for the active Spec Kit phase.",
                "enum": [
                  "queued",
                  "running",
                  "awaiting_input",
                  "terminal"
                ],
                "example": "running"
              },
              "awaitingQuestion": {
                "description": "The question the run is paused on, while it waits for the creator.",
                "type": "object",
                "required": [
                  "capId",
                  "question",
                  "askedAt"
                ],
                "properties": {
                  "capId": {
                    "type": "string",
                    "description": "The question's id: send it back as `capId` with the answer.",
                    "example": "cap_portal_modules"
                  },
                  "question": {
                    "type": "string",
                    "description": "The question to put to the creator.",
                    "example": "Which areas should your portal have?"
                  },
                  "choices": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "The answers to offer, when it is a choice.",
                    "example": [
                      "Courses",
                      "Communities"
                    ]
                  },
                  "form": {
                    "oneOf": [
                      {
                        "type": "object",
                        "description": "The record-fields form on `awaitingQuestion.form`. The answer `value`\nis `JSON.stringify({ fields: [{ label, type, options? }], show: [label, …] })`\n(`fields` = the NEW fields, `show` = every field clients see); as the\neditor (`edit: true`) it also carries `edits` and has `show` only when\nwhat clients see changed.\n",
                        "required": [
                          "kind",
                          "fields",
                          "types"
                        ],
                        "properties": {
                          "kind": {
                            "type": "string",
                            "enum": [
                              "record_fields"
                            ],
                            "description": "Always `record_fields`.",
                            "example": "record_fields"
                          },
                          "recordType": {
                            "type": "object",
                            "required": [
                              "label",
                              "exists"
                            ],
                            "properties": {
                              "label": {
                                "type": "string",
                                "maxLength": 60,
                                "description": "Its name.",
                                "example": "Policy"
                              },
                              "exists": {
                                "type": "boolean",
                                "description": "True when the record type already exists.",
                                "example": false
                              }
                            },
                            "description": "The record type the fields belong to."
                          },
                          "existingFields": {
                            "type": "array",
                            "maxItems": 60,
                            "items": {
                              "type": "object",
                              "required": [
                                "label",
                                "type"
                              ],
                              "properties": {
                                "label": {
                                  "type": "string",
                                  "description": "The field's name.",
                                  "example": "Policy number"
                                },
                                "type": {
                                  "type": "string",
                                  "description": "The field's type.",
                                  "example": "TEXT"
                                },
                                "options": {
                                  "type": "array",
                                  "items": {
                                    "type": "string"
                                  },
                                  "description": "The choices, for a choice field.",
                                  "example": [
                                    "Active",
                                    "Lapsed"
                                  ]
                                },
                                "shown": {
                                  "type": "boolean",
                                  "description": "Clients see this field.",
                                  "example": true
                                },
                                "namesRecords": {
                                  "type": "boolean",
                                  "description": "This field names each record.",
                                  "example": true
                                }
                              }
                            },
                            "description": "The record type's fields today.",
                            "example": [
                              {
                                "label": "Policy number",
                                "type": "TEXT",
                                "shown": true
                              }
                            ]
                          },
                          "fields": {
                            "type": "array",
                            "maxItems": 30,
                            "items": {
                              "type": "object",
                              "required": [
                                "label",
                                "type"
                              ],
                              "properties": {
                                "label": {
                                  "type": "string",
                                  "maxLength": 60,
                                  "description": "The field's name.",
                                  "example": "Renewal date"
                                },
                                "type": {
                                  "type": "string",
                                  "description": "The field's type.",
                                  "example": "DATE"
                                },
                                "options": {
                                  "type": "array",
                                  "maxItems": 50,
                                  "items": {
                                    "type": "string"
                                  },
                                  "description": "The choices, for a choice field.",
                                  "example": [
                                    "Monthly",
                                    "Yearly"
                                  ]
                                }
                              }
                            },
                            "description": "The new fields proposed.",
                            "example": [
                              {
                                "label": "Renewal date",
                                "type": "DATE"
                              }
                            ]
                          },
                          "edit": {
                            "type": "boolean",
                            "enum": [
                              true
                            ],
                            "description": "Set when this is the editor for an existing record type.",
                            "example": true
                          },
                          "types": {
                            "type": "array",
                            "description": "The field types the dropdown offers (server-owned).",
                            "items": {
                              "type": "object",
                              "required": [
                                "value",
                                "label"
                              ],
                              "properties": {
                                "value": {
                                  "type": "string",
                                  "description": "The type, as an answer sends it.",
                                  "example": "TEXT"
                                },
                                "label": {
                                  "type": "string",
                                  "description": "What the creator sees.",
                                  "example": "Single line"
                                },
                                "withOptions": {
                                  "type": "boolean",
                                  "enum": [
                                    true
                                  ],
                                  "description": "This type takes a list of choices.",
                                  "example": true
                                },
                                "noConvert": {
                                  "type": "boolean",
                                  "enum": [
                                    true
                                  ],
                                  "description": "An existing field cannot be changed to this type.",
                                  "example": true
                                }
                              }
                            },
                            "example": [
                              {
                                "value": "TEXT",
                                "label": "Single line"
                              }
                            ]
                          }
                        },
                        "title": "RecordQuestionForm"
                      },
                      {
                        "type": "object",
                        "description": "The media a request needs, on `awaitingQuestion.form`: one slot each,\npicked from the creator's GHL Media Library, pasted as a link, or\n(images only) generated. The answer `value` is\n`JSON.stringify({ \"<slot key>\": [{ url, name, source }] | \"generate\" | [] })`\n(`source` is `library` or `link`; `[]` = skipped).\n",
                        "required": [
                          "kind",
                          "slots"
                        ],
                        "properties": {
                          "kind": {
                            "type": "string",
                            "enum": [
                              "media"
                            ],
                            "description": "Always `media`.",
                            "example": "media"
                          },
                          "slots": {
                            "type": "array",
                            "minItems": 1,
                            "maxItems": 8,
                            "items": {
                              "type": "object",
                              "required": [
                                "key",
                                "label",
                                "max",
                                "accepts"
                              ],
                              "properties": {
                                "key": {
                                  "type": "string",
                                  "description": "The slot's key in the answer.",
                                  "example": "hero"
                                },
                                "label": {
                                  "type": "string",
                                  "description": "What to ask for.",
                                  "example": "Hero image"
                                },
                                "purpose": {
                                  "type": "string",
                                  "description": "Where it will be used.",
                                  "example": "Top of the home page"
                                },
                                "max": {
                                  "type": "integer",
                                  "minimum": 1,
                                  "maximum": 10,
                                  "description": "How many files the slot takes.",
                                  "example": 1
                                },
                                "accepts": {
                                  "type": "string",
                                  "enum": [
                                    "image",
                                    "video",
                                    "file"
                                  ],
                                  "description": "The kind of media.",
                                  "example": "image"
                                }
                              }
                            },
                            "description": "The media to collect, one slot each.",
                            "example": [
                              {
                                "key": "hero",
                                "label": "Hero image",
                                "max": 1,
                                "accepts": "image"
                              }
                            ]
                          }
                        },
                        "title": "MediaQuestionForm"
                      }
                    ],
                    "description": "Set when the answer is a form (record fields or media) rather than a choice; its `kind` says which."
                  },
                  "details": {
                    "type": "string",
                    "description": "What the creator is agreeing to, shown under the question.",
                    "example": "Your portal will use the Courses and Communities modules."
                  },
                  "preview": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "What the builder shows the creator beside this question. Display only: its shape follows the builder's screens and may change.",
                    "example": {}
                  },
                  "multiSelect": {
                    "type": "boolean",
                    "description": "Several choices may be picked.",
                    "example": false
                  },
                  "allowOther": {
                    "type": "boolean",
                    "description": "Adds a \"Something else\" choice that opens a box.",
                    "example": true
                  },
                  "input": {
                    "type": "string",
                    "enum": [
                      "short_text",
                      "long_text"
                    ],
                    "description": "With no choices, one line or a paragraph.",
                    "example": "short_text"
                  },
                  "placeholder": {
                    "type": "string",
                    "description": "Hint text for a typed answer.",
                    "example": "e.g. Weekly yoga classes"
                  },
                  "askedAt": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When the run asked.",
                    "example": "2026-10-15T09:32:00.000Z"
                  }
                },
                "title": "AgentRunAwaitingQuestion"
              },
              "createdAt": {
                "type": "string",
                "format": "date-time",
                "description": "When the run was created.",
                "example": "2026-10-15T09:30:00.000Z"
              },
              "updatedAt": {
                "type": "string",
                "format": "date-time",
                "description": "When the run last changed.",
                "example": "2026-10-15T09:41:12.000Z"
              },
              "previewUrl": {
                "type": "string",
                "format": "uri",
                "description": "Convenience field equal to `preview.primaryUrl`. Kept for\nsingle-service callers; multi-service callers should read\n`preview.services[]` for per-service URLs. This is the\ndurable customer-facing preview URL produced after a\nsuccessful build/deploy, not the live sandbox edit URL.\n",
                "example": "https://preview.example.com/my-portal"
              },
              "preview": {
                "description": "Where to see what the run built.",
                "type": "object",
                "required": [
                  "primaryUrl",
                  "services"
                ],
                "properties": {
                  "primaryUrl": {
                    "type": "string",
                    "format": "uri",
                    "description": "The URL the user opens — for multi-service web stacks, this is the primary (frontend) URL.",
                    "example": "https://preview.example.com/my-portal"
                  },
                  "services": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "required": [
                        "name",
                        "url"
                      ],
                      "properties": {
                        "name": {
                          "type": "string",
                          "description": "Service name as declared in the stack manifest.",
                          "example": "web"
                        },
                        "url": {
                          "type": "string",
                          "format": "uri",
                          "description": "Where the service is served.",
                          "example": "https://preview.example.com/my-portal"
                        },
                        "imageUri": {
                          "type": "string",
                          "description": "The service's image.",
                          "example": "registry.example.com/apps/web:run_8f3c2a91"
                        },
                        "digest": {
                          "type": "string",
                          "description": "The image's digest.",
                          "example": "sha256:3b1f0c9e2d7a"
                        }
                      },
                      "title": "ProvisionedService"
                    },
                    "description": "Each service of the app and where it is served.",
                    "example": [
                      {
                        "name": "web",
                        "url": "https://preview.example.com/my-portal"
                      }
                    ]
                  }
                },
                "title": "RunPreview"
              },
              "livePreviewUrl": {
                "type": "string",
                "format": "uri",
                "deprecated": true,
                "description": "**Deprecated 2026-05-17. Will be removed 2026-11-17.**\nUse `sandboxUrl` instead — same value, accurate name.\n\nMisleadingly named: this is the SANDBOX URL (the agent's\nHMR/edit workshop), not the customer-facing preview. The\ncustomer preview lives at `previewUrl`. Co-populated with\n`sandboxUrl` for the deprecation window; readers should\nmigrate to `sandboxUrl`.\n",
                "example": "https://sbx-prj-5f0c2a3e.example.com"
              },
              "livePreviewStatus": {
                "type": "string",
                "enum": [
                  "starting",
                  "ready",
                  "failed",
                  "stopped"
                ],
                "deprecated": true,
                "description": "**Deprecated 2026-05-17. Will be removed 2026-11-17.**\nUse `sandboxStatus` instead.\n",
                "example": "ready"
              },
              "sandboxUrl": {
                "type": "string",
                "format": "uri",
                "description": "URL of the project sandbox runtime.\nThis is the agent's compile + HMR workshop — NOT the\ncustomer-facing preview. The customer preview is at\n`previewUrl`, which surfaces in the builder UI's right\npane after the deploy gate succeeds.\n",
                "example": "https://sbx-prj-5f0c2a3e.example.com"
              },
              "sandboxStatus": {
                "type": "string",
                "enum": [
                  "starting",
                  "ready",
                  "failed",
                  "stopped"
                ],
                "description": "Current state of the sandbox dev server.",
                "example": "ready"
              },
              "publishedUrl": {
                "type": "string",
                "format": "uri",
                "description": "URL of the production (\"Published\") runtime service for this project.\nPopulated when the project has\nbeen explicitly published at least once. Distinct from\n`previewUrl`/`preview.primaryUrl`, which always point at the\ndurable customer preview service that auto-updates on every\nsuccessful agent run. Absent for projects that have never\nbeen published — the FE renders \"Not published\" in that case.\n",
                "example": "https://my-portal.example.com"
              },
              "publishedAt": {
                "type": "string",
                "format": "date-time",
                "description": "ISO-8601 timestamp of the most recent publish, snapshotted\nonto the run at the moment it reached `ready`. Used by the\nFE to render staleness like \"Last published 5 hours ago\".\n",
                "example": "2026-10-14T18:02:00.000Z"
              },
              "runsSinceLastPublish": {
                "type": "integer",
                "minimum": 0,
                "description": "Number of successful (status=ready) runs completed since\nthe project was last published. Reset to 0 by `publish`.\nSnapshotted onto each ready run so the FE can render a\nstaleness indicator without an extra round-trip. Absent\nfor projects that have never been published.\n",
                "example": 2
              },
              "summary": {
                "type": "string",
                "description": "AI-generated 1-line checkpoint description, snapshotted onto\nthe run record at `setStatus(\"ready\")` time. Sourced from\nthe agent's `completion` narrator event when present,\notherwise falls back to a deterministic prompt-derived\nstub. Read by Timeline + chat UI so users see \"what\nchanged in this checkpoint\" at a glance. Absent on\nnon-terminal or legacy runs.\n",
                "example": "Added an events page"
              },
              "imageUri": {
                "type": "string",
                "description": "Image of the primary service.",
                "example": "registry.example.com/apps/web:run_8f3c2a91"
              },
              "imageDigest": {
                "type": "string",
                "description": "Digest of the primary service's image.",
                "example": "sha256:3b1f0c9e2d7a"
              },
              "failureMessage": {
                "type": "string",
                "description": "Why the run failed, in one line.",
                "example": "The build failed: pages/events.vue has a type error"
              },
              "failure": {
                "type": "object",
                "description": "Structured failure taxonomy for a terminated run. Set in\ntandem with `failureMessage` (which is the human-readable\nderivation). Discriminated by `category`; consumers should\nbranch on `category` + `code` to render an actionable hint\ninstead of a generic \"Internal error\".\n",
                "required": [
                  "category",
                  "code",
                  "retryable",
                  "responsibleModule"
                ],
                "properties": {
                  "category": {
                    "type": "string",
                    "enum": [
                      "user_input",
                      "config",
                      "model",
                      "build",
                      "infra",
                      "spec_kit",
                      "transport",
                      "runtime",
                      "internal"
                    ],
                    "description": "What kind of failure it was.",
                    "example": "build"
                  },
                  "code": {
                    "type": "string",
                    "description": "Category-specific failure code. See the run-runtime\n`RunFailure` discriminated union for the per-category\ncode enum.\n",
                    "example": "build_failed"
                  },
                  "retryable": {
                    "type": "boolean",
                    "description": "Sending the same request again may succeed.",
                    "example": false
                  },
                  "responsibleModule": {
                    "type": "string",
                    "enum": [
                      "runtime",
                      "dispatcher",
                      "planner",
                      "classifier",
                      "spec_kit",
                      "designer",
                      "scaffolder",
                      "builder",
                      "verifier",
                      "deployer",
                      "infra",
                      "model_provider",
                      "transport",
                      "unknown"
                    ],
                    "description": "The part of the builder that failed.",
                    "example": "runtime"
                  },
                  "userMessage": {
                    "type": "string",
                    "description": "For `category=user_input` — text safe to show the user verbatim.",
                    "example": "Describe the page you want in a sentence or two."
                  },
                  "details": {
                    "type": "string",
                    "description": "For `category=config` / `spec_kit` — operator-facing detail.",
                    "example": "No stack manifest for this template"
                  },
                  "provider": {
                    "type": "string",
                    "description": "For `category=model` — provider identifier (e.g. anthropic, openai).",
                    "example": "anthropic"
                  },
                  "attempt": {
                    "type": "integer",
                    "description": "For `category=model` — retry attempt index that ultimately gave up.",
                    "example": 3
                  },
                  "failureHead": {
                    "type": "string",
                    "description": "For `category=build` — first chunk of compiler/test stderr.",
                    "example": "pages/events.vue(12,5): error TS2339"
                  },
                  "failureTail": {
                    "type": "string",
                    "description": "For `category=build` — last chunk of compiler/test stderr.",
                    "example": "Found 1 error."
                  },
                  "cause": {
                    "type": "string",
                    "description": "For `category=infra` — short cause description.",
                    "example": "The sandbox did not become ready in time"
                  },
                  "phase": {
                    "type": "string",
                    "description": "For `category=spec_kit` — phase id where the orchestrator halted.",
                    "example": "plan"
                  },
                  "stack": {
                    "type": "string",
                    "description": "For `category=internal` — first lines of the stack trace.",
                    "example": "TypeError: Cannot read properties of undefined"
                  },
                  "message": {
                    "type": "string",
                    "description": "For `category=runtime` — text safe to show the user verbatim.",
                    "example": "The preview could not start."
                  }
                }
              },
              "metadata": {
                "type": "object",
                "additionalProperties": true,
                "description": "Reproducibility/debug metadata selected during run setup.",
                "properties": {
                  "generationFailure": {
                    "type": "object",
                    "additionalProperties": true,
                    "properties": {
                      "code": {
                        "type": "string",
                        "enum": [
                          "provider_transient",
                          "dispatch_failed",
                          "scaffold_failed",
                          "infra_failed",
                          "agent_failed",
                          "build_failed",
                          "deploy_failed",
                          "run_stalled",
                          "pipeline_failed"
                        ],
                        "description": "The failure code.",
                        "example": "provider_transient"
                      },
                      "retryable": {
                        "type": "boolean",
                        "description": "Retrying may succeed.",
                        "example": true
                      },
                      "source": {
                        "type": "string",
                        "enum": [
                          "provider",
                          "dispatch",
                          "planning",
                          "scaffold",
                          "infra",
                          "agent",
                          "build",
                          "deploy",
                          "pipeline"
                        ],
                        "description": "Where it failed.",
                        "example": "provider"
                      },
                      "detail": {
                        "type": "string",
                        "description": "Detail for support.",
                        "example": "The model provider was overloaded"
                      }
                    },
                    "description": "Why generating the app failed, when it did."
                  },
                  "failedWorkspace": {
                    "type": "object",
                    "additionalProperties": true,
                    "properties": {
                      "preservedAt": {
                        "type": "string",
                        "format": "date-time",
                        "description": "When it was kept.",
                        "example": "2026-10-15T09:45:00.000Z"
                      },
                      "uploadedFiles": {
                        "type": "integer",
                        "description": "How many files were kept.",
                        "example": 128
                      },
                      "durationMs": {
                        "type": "integer",
                        "description": "How long keeping it took, in milliseconds.",
                        "example": 2140
                      }
                    },
                    "description": "The workspace kept from a failed run, for diagnosis."
                  }
                }
              }
            },
            "title": "RunRecord"
          }
        },
        "title": "SubmitAgentRunResponse"
      },
      "ApiError": {
        "type": "object",
        "required": [
          "type",
          "title",
          "status",
          "code",
          "requestId"
        ],
        "properties": {
          "type": {
            "type": "string",
            "format": "uri",
            "example": "about:blank",
            "description": "A URI identifying the kind of error."
          },
          "title": {
            "type": "string",
            "example": "Request validation failed",
            "description": "Short summary of the kind of error."
          },
          "status": {
            "type": "integer",
            "minimum": 400,
            "maximum": 599,
            "example": 422,
            "description": "The HTTP status code."
          },
          "detail": {
            "type": "string",
            "example": "One or more fields are invalid.",
            "description": "What went wrong with this request."
          },
          "instance": {
            "type": "string",
            "example": "/api/v1/runs",
            "description": "The request path that failed."
          },
          "code": {
            "type": "string",
            "example": "validation_error",
            "description": "Stable, machine-readable error code."
          },
          "requestId": {
            "type": "string",
            "example": "req_01HXQ8Z6J9K2",
            "description": "The request's id, for support."
          },
          "fieldErrors": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "field",
                "code",
                "message"
              ],
              "properties": {
                "field": {
                  "type": "string",
                  "example": "prompt",
                  "description": "The invalid field, as a dotted path."
                },
                "code": {
                  "type": "string",
                  "example": "required",
                  "description": "Machine-readable reason."
                },
                "message": {
                  "type": "string",
                  "example": "Prompt is required.",
                  "description": "Human-readable reason."
                }
              },
              "title": "FieldError"
            },
            "description": "One entry per invalid field, when the request body was invalid.",
            "example": [
              {
                "field": "name",
                "code": "too_long",
                "message": "name must be at most 120 characters"
              }
            ]
          }
        },
        "title": "ApiError"
      }
    }
  }
}
```

## Code Examples

**cURL**

```bash
curl -L -X POST 'https://services.leadconnectorhq.com/ai-builder-api/projects/<projectId>/runs' \
  -H 'Authorization: Bearer <TOKEN>' \
  -H 'Version: v3' \
  -H 'Content-Type: application/json' \
  --data-raw '{
  "prompt": "Add a page listing upcoming events",
  "customCode": false,
  "clientPortalSurface": "web",
  "externalAgent": true,
  "mobilePipeline": "v2-simple",
  "mobilePipelineSpeed": "fast",
  "modelId": "claude-sonnet-4-5",
  "agentId": "agt_4c2d1e",
  "mode": "auto",
  "attachmentIds": [
    "att_1a2b3c"
  ],
  "selectedElements": [
    {
      "elementType": "h1",
      "filePath": "pages/index.vue",
      "lineNumber": 12
    }
  ]
}'
```

**Node.js**

```javascript
const options = {
  method: 'POST',
  headers: {
    Authorization: 'Bearer <TOKEN>',
    Version: 'v3',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
      "prompt": "Add a page listing upcoming events",
      "customCode": false,
      "clientPortalSurface": "web",
      "externalAgent": true,
      "mobilePipeline": "v2-simple",
      "mobilePipelineSpeed": "fast",
      "modelId": "claude-sonnet-4-5",
      "agentId": "agt_4c2d1e",
      "mode": "auto",
      "attachmentIds": [
        "att_1a2b3c"
      ],
      "selectedElements": [
        {
          "elementType": "h1",
          "filePath": "pages/index.vue",
          "lineNumber": 12
        }
      ]
  })
};

try {
  const response = await fetch('https://services.leadconnectorhq.com/ai-builder-api/projects/<projectId>/runs', options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

**Python**

```python
import requests

url = "https://services.leadconnectorhq.com/ai-builder-api/projects/{projectId}/runs"

headers = {
    "Authorization": "Bearer <TOKEN>",
    "Version": "v3"
}

payload = {
    "prompt": "Add a page listing upcoming events",
    "customCode": false,
    "clientPortalSurface": "web",
    "externalAgent": true,
    "mobilePipeline": "v2-simple",
    "mobilePipelineSpeed": "fast",
    "modelId": "claude-sonnet-4-5",
    "agentId": "agt_4c2d1e",
    "mode": "auto",
    "attachmentIds": [
        "att_1a2b3c"
    ],
    "selectedElements": [
        {
            "elementType": "h1",
            "filePath": "pages/index.vue",
            "lineNumber": 12
        }
    ]
}

response = requests.post(url, json=payload, headers=headers)
print(response.json())
```

**PHP**

```php
<?php
$curl = curl_init();

curl_setopt_array($curl, [
  CURLOPT_URL => 'https://services.leadconnectorhq.com/ai-builder-api/projects/<projectId>/runs',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => [
    'Authorization: Bearer <TOKEN>',
    'Version: v3',
    'Content-Type: application/json',
  ],
  CURLOPT_POSTFIELDS => '{
  "prompt": "Add a page listing upcoming events",
  "customCode": false,
  "clientPortalSurface": "web",
  "externalAgent": true,
  "mobilePipeline": "v2-simple",
  "mobilePipelineSpeed": "fast",
  "modelId": "claude-sonnet-4-5",
  "agentId": "agt_4c2d1e",
  "mode": "auto",
  "attachmentIds": [
    "att_1a2b3c"
  ],
  "selectedElements": [
    {
      "elementType": "h1",
      "filePath": "pages/index.vue",
      "lineNumber": 12
    }
  ]
}',
]);

$response = curl_exec($curl);
curl_close($curl);
echo $response;
```

**Java**

```java
HttpResponse<String> response = Unirest
  .post("https://services.leadconnectorhq.com/ai-builder-api/projects/<projectId>/runs")
  .header("Authorization", "Bearer <TOKEN>")
  .header("Version", "v3")
  .header("Content-Type", "application/json")
  .body("{\"prompt\":\"Add a page listing upcoming events\",\"customCode\":false,\"clientPortalSurface\":\"web\",\"externalAgent\":true,\"mobilePipeline\":\"v2-simple\",\"mobilePipelineSpeed\":\"fast\",\"modelId\":\"claude-sonnet-4-5\",\"agentId\":\"agt_4c2d1e\",\"mode\":\"auto\",\"attachmentIds\":[\"att_1a2b3c\"],\"selectedElements\":[{\"elementType\":\"h1\",\"filePath\":\"pages/index.vue\",\"lineNumber\":12}]}")
  .asString();
```

**Go**

```go
package main

import (
  "fmt"
  "net/http"
  "io"
  "strings"
)

func main() {
  url := "https://services.leadconnectorhq.com/ai-builder-api/projects/<projectId>/runs"
  payload := strings.NewReader(`{
  "prompt": "Add a page listing upcoming events",
  "customCode": false,
  "clientPortalSurface": "web",
  "externalAgent": true,
  "mobilePipeline": "v2-simple",
  "mobilePipelineSpeed": "fast",
  "modelId": "claude-sonnet-4-5",
  "agentId": "agt_4c2d1e",
  "mode": "auto",
  "attachmentIds": [
    "att_1a2b3c"
  ],
  "selectedElements": [
    {
      "elementType": "h1",
      "filePath": "pages/index.vue",
      "lineNumber": 12
    }
  ]
}`)
  req, _ := http.NewRequest("POST", url, payload)
  req.Header.Add("Authorization", "Bearer <TOKEN>")
  req.Header.Add("Version", "v3")

  res, _ := http.DefaultClient.Do(req)
  defer res.Body.Close()
  body, _ := io.ReadAll(res.Body)
  fmt.Println(string(body))
}
```

**Ruby**

```ruby
require 'uri'
require 'net/http'

url = URI("https://services.leadconnectorhq.com/ai-builder-api/projects/<projectId>/runs")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = "Bearer <TOKEN>"
request["Version"] = "v3"
request["Content-Type"] = "application/json"
request.body = '{
  "prompt": "Add a page listing upcoming events",
  "customCode": false,
  "clientPortalSurface": "web",
  "externalAgent": true,
  "mobilePipeline": "v2-simple",
  "mobilePipelineSpeed": "fast",
  "modelId": "claude-sonnet-4-5",
  "agentId": "agt_4c2d1e",
  "mode": "auto",
  "attachmentIds": [
    "att_1a2b3c"
  ],
  "selectedElements": [
    {
      "elementType": "h1",
      "filePath": "pages/index.vue",
      "lineNumber": 12
    }
  ]
}'

response = http.request(request)
puts response.read_body
```

**PowerShell**

```powershell
$headers = @{
  "Authorization" = "Bearer <TOKEN>"
  "Version" = "v3"
}

$body = '{
  "prompt": "Add a page listing upcoming events",
  "customCode": false,
  "clientPortalSurface": "web",
  "externalAgent": true,
  "mobilePipeline": "v2-simple",
  "mobilePipelineSpeed": "fast",
  "modelId": "claude-sonnet-4-5",
  "agentId": "agt_4c2d1e",
  "mode": "auto",
  "attachmentIds": [
    "att_1a2b3c"
  ],
  "selectedElements": [
    {
      "elementType": "h1",
      "filePath": "pages/index.vue",
      "lineNumber": 12
    }
  ]
}'

$response = Invoke-RestMethod -Uri 'https://services.leadconnectorhq.com/ai-builder-api/projects/<projectId>/runs' -Method 'POST' -Headers $headers -Body $body -ContentType 'application/json'
$response | ConvertTo-Json
```
