{
  "openapi": "3.1.0",
  "info": {
    "title": "VeraGen API",
    "version": "1.0.0",
    "summary": "Run and read your VeraGen AI Hub account from your own code.",
    "description": "The VeraGen API lets a program act on one VeraGen account: list and run its workflows, follow its runs, read its projects and Data Management items, create pages, list, read, create and update its Thrive contacts, and read its billed usage. Every request is authenticated with an API key that an owner or admin creates in the hub under Account → API keys.",
    "contact": {
      "name": "VeraGen support",
      "email": "hello@veragen.ai",
      "url": "https://veragen.ai"
    },
    "x-live": false,
    "x-rate-limits": {
      "default_tier": "team",
      "window_seconds": 60,
      "failed_auth_per_minute_per_ip": 20,
      "tiers": {
        "solo": {
          "requests_per_minute_per_key": 60,
          "run_starts_per_minute_per_account": 6,
          "concurrent_runs_per_account": 2
        },
        "team": {
          "requests_per_minute_per_key": 120,
          "run_starts_per_minute_per_account": 12,
          "concurrent_runs_per_account": 5
        },
        "business": {
          "requests_per_minute_per_key": 300,
          "run_starts_per_minute_per_account": 30,
          "concurrent_runs_per_account": 10
        },
        "enterprise": {
          "requests_per_minute_per_key": 1000,
          "run_starts_per_minute_per_account": null,
          "concurrent_runs_per_account": null
        }
      }
    },
    "x-max-body-bytes": 1048576
  },
  "servers": [
    {
      "url": "https://api.veragen.ai/v1"
    }
  ],
  "security": [
    {
      "bearer": []
    }
  ],
  "tags": [
    {
      "name": "Workflows",
      "description": "The agentic workflows in the account, across every project."
    },
    {
      "name": "Runs",
      "description": "Start a workflow and follow it. Runs are asynchronous: starting one answers at once with a queued run, and the run begins within about a minute. Read it back with Get a run until its status is final."
    },
    {
      "name": "Usage",
      "description": "What the account has been billed, by day and by feature, and its balance."
    },
    {
      "name": "Projects",
      "description": "The projects in the account. Data Management items, and the workflows that write into them, belong to a project."
    },
    {
      "name": "Contacts",
      "description": "The people in Thrive, the account's CRM: list, read, create and update them. A key reaches every contact in the account. Contacts created through the API are unassigned until someone in Thrive assigns them. The API never deletes a contact, never lifts a do-not-contact or an email opt-out, and never sends anything."
    },
    {
      "name": "Items",
      "description": "What is in a project's Data Management: pages, files, datasets, images and links. Read any item's details and a page's text, and create pages. Files can be listed and described but not uploaded or downloaded in v1."
    }
  ],
  "x-scopes": {
    "workflows:read": "List and read workflows and their runs.",
    "workflows:run": "Start workflow runs. Runs spend the account's AI credit.",
    "content:read": "Read projects and Data Management items.",
    "content:write": "Create pages in Data Management.",
    "contacts:read": "Read Thrive contacts.",
    "contacts:write": "Create and update Thrive contacts.",
    "usage:read": "Read the account's billed usage."
  },
  "x-error-codes": [
    {
      "status": 400,
      "type": "invalid_request",
      "code": "invalid_parameter",
      "description": "A query parameter has a value it cannot take. `param` names it."
    },
    {
      "status": 400,
      "type": "invalid_request",
      "code": "unknown_parameter",
      "description": "A query parameter this endpoint does not accept. Unknown parameters are refused, never ignored."
    },
    {
      "status": 400,
      "type": "invalid_request",
      "code": "invalid_id",
      "description": "An id that is not a UUID."
    },
    {
      "status": 400,
      "type": "invalid_request",
      "code": "invalid_cursor",
      "description": "The `cursor` is not one this endpoint gave out."
    },
    {
      "status": 400,
      "type": "invalid_request",
      "code": "invalid_json",
      "description": "The body is not valid JSON."
    },
    {
      "status": 400,
      "type": "invalid_request",
      "code": "missing_idempotency_key",
      "description": "Starting a run needs an `Idempotency-Key` header."
    },
    {
      "status": 400,
      "type": "invalid_request",
      "code": "missing_field",
      "description": "A required body field is missing. `param` names it."
    },
    {
      "status": 400,
      "type": "invalid_request",
      "code": "invalid_idempotency_key",
      "description": "The `Idempotency-Key` is not 8 to 64 printable characters without spaces."
    },
    {
      "status": 401,
      "type": "authentication",
      "code": "invalid_api_key",
      "description": "No API key, a malformed one, or one that does not exist."
    },
    {
      "status": 401,
      "type": "authentication",
      "code": "api_key_revoked",
      "description": "The key was revoked in the hub."
    },
    {
      "status": 401,
      "type": "authentication",
      "code": "api_key_expired",
      "description": "The key passed the expiry date it was created with."
    },
    {
      "status": 402,
      "type": "insufficient_credit",
      "code": "account_out_of_credit",
      "description": "The account is out of AI credit, so no run was started. An owner, or an admin with billing access, adds credit in Account → Billing."
    },
    {
      "status": 402,
      "type": "insufficient_credit",
      "code": "key_spend_cap_reached",
      "description": "This key has used its monthly spend cap. An owner or admin can raise it in Account → API keys."
    },
    {
      "status": 403,
      "type": "permission",
      "code": "insufficient_scope",
      "description": "The key does not hold the scope this endpoint needs. The message names it."
    },
    {
      "status": 403,
      "type": "permission",
      "code": "account_suspended",
      "description": "The account is suspended. Contact VeraGen support."
    },
    {
      "status": 403,
      "type": "permission",
      "code": "account_closed",
      "description": "The account has been closed."
    },
    {
      "status": 404,
      "type": "not_found",
      "code": "resource_not_found",
      "description": "Nothing with that id in this account. An id that belongs to another account gives exactly this answer."
    },
    {
      "status": 404,
      "type": "not_found",
      "code": "route_not_found",
      "description": "No endpoint at that path."
    },
    {
      "status": 404,
      "type": "not_found",
      "code": "api_not_available",
      "description": "The API is not open on this service yet. Every request gets this answer until it is."
    },
    {
      "status": 405,
      "type": "invalid_request",
      "code": "method_not_allowed",
      "description": "The path exists but not with that method. The `Allow` header lists the methods it takes."
    },
    {
      "status": 409,
      "type": "conflict",
      "code": "idempotency_in_progress",
      "description": "A request with this `Idempotency-Key` is still being handled. Retry with the same key in a few seconds."
    },
    {
      "status": 409,
      "type": "conflict",
      "code": "idempotency_outcome_unknown",
      "description": "The first request with this `Idempotency-Key` did not finish (it timed out or failed part way), so whether it started the run or created the page is unknown. It is never run again: list the workflow's runs or the project's items to see whether it did, and use a new key if it did not."
    },
    {
      "status": 409,
      "type": "conflict",
      "code": "contact_exists",
      "description": "Another contact in this account already has that email address. `resource_id` is its id: update it with PATCH instead."
    },
    {
      "status": 409,
      "type": "conflict",
      "code": "contact_do_not_contact",
      "description": "The address belongs to someone who was erased from Thrive at their request. They stay on do-not-contact: the API cannot add them again or change them."
    },
    {
      "status": 409,
      "type": "conflict",
      "code": "opt_out_locked",
      "description": "The contact has opted out of email. The API cannot opt them back in; a person can, in Thrive."
    },
    {
      "status": 413,
      "type": "invalid_request",
      "code": "body_too_large",
      "description": "The body is larger than 1 MB."
    },
    {
      "status": 413,
      "type": "invalid_request",
      "code": "page_too_large",
      "description": "The page would be larger than a page can be once converted to HTML. Split it into two pages."
    },
    {
      "status": 415,
      "type": "invalid_request",
      "code": "unsupported_media_type",
      "description": "A body that is not `application/json`."
    },
    {
      "status": 422,
      "type": "invalid_request",
      "code": "unknown_field",
      "description": "The body has a field this endpoint does not take. `param` names it. Unknown fields are refused, never ignored."
    },
    {
      "status": 422,
      "type": "invalid_request",
      "code": "invalid_body",
      "description": "The body is not a JSON object."
    },
    {
      "status": 422,
      "type": "invalid_request",
      "code": "invalid_field",
      "description": "A body field has a value it cannot take. `param` names it."
    },
    {
      "status": 422,
      "type": "invalid_request",
      "code": "workflow_empty",
      "description": "The workflow has no blocks, so there is nothing to run."
    },
    {
      "status": 422,
      "type": "invalid_request",
      "code": "idempotency_key_reused",
      "description": "This `Idempotency-Key` was already used for a different request. Use a new key for a new request."
    },
    {
      "status": 429,
      "type": "rate_limit",
      "code": "rate_limited",
      "description": "Too many requests for this key in the current minute. Wait for `Retry-After` seconds."
    },
    {
      "status": 429,
      "type": "rate_limit",
      "code": "too_many_failed_auth",
      "description": "Too many requests with a wrong key from one address in a minute."
    },
    {
      "status": 429,
      "type": "rate_limit",
      "code": "run_rate_limited",
      "description": "The account has started as many runs through the API in the last minute as its plan allows."
    },
    {
      "status": 429,
      "type": "rate_limit",
      "code": "concurrency_limited",
      "description": "The account already has as many API runs queued or running as its plan allows. Start another when one finishes."
    },
    {
      "status": 500,
      "type": "api_error",
      "code": "internal_error",
      "description": "Something went wrong on our side. Retry with backoff; quote the `request_id` to support."
    }
  ],
  "paths": {
    "/workflows": {
      "get": {
        "operationId": "listWorkflows",
        "tags": [
          "Workflows"
        ],
        "summary": "List workflows",
        "description": "Every workflow in the account, across all its projects, most recently updated first. Each one carries its most recent run, if it has been run.",
        "x-scope": "workflows:read",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only workflows with this status.",
            "schema": {
              "type": "string",
              "enum": [
                "draft",
                "active",
                "paused"
              ]
            }
          },
          {
            "name": "project_id",
            "in": "query",
            "required": false,
            "description": "Only the workflows in this project.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of workflows.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowList"
                },
                "example": {
                  "data": [
                    {
                      "id": "3f6c1d2e-8a4b-4f7e-9c21-5d0e7a1b2c3d",
                      "name": "Weekly competitor digest",
                      "description": "Reads five competitor blogs and writes a summary page.",
                      "status": "active",
                      "project_id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
                      "updated_at": "2026-10-02T15:04:05.123Z",
                      "last_run": {
                        "id": "c0ffee00-1234-4abc-9def-0123456789ab",
                        "status": "succeeded",
                        "at": "2026-10-03T06:00:00.000Z"
                      }
                    },
                    {
                      "id": "7b2e9f40-6c1d-4e8a-b3f5-2a9d0c7e1f64",
                      "name": "Lead enrichment",
                      "description": "",
                      "status": "draft",
                      "project_id": null,
                      "updated_at": "2026-09-30T09:12:44.000Z",
                      "last_run": null
                    }
                  ],
                  "has_more": true,
                  "next_cursor": "WyIyMDI2LTA5LTMwVDA5OjEyOjQ0LjAwMDAwMFoiLCI3YjJlOWY0MC02YzFkLTRlOGEtYjNmNS0yYTlkMGM3ZTFmNjQiXQ"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/workflows/{id}": {
      "get": {
        "operationId": "getWorkflow",
        "tags": [
          "Workflows"
        ],
        "summary": "Get a workflow",
        "description": "One workflow, with its most recent run.",
        "x-scope": "workflows:read",
        "parameters": [
          {
            "$ref": "#/components/parameters/WorkflowId"
          }
        ],
        "responses": {
          "200": {
            "description": "The workflow.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Workflow"
                },
                "example": {
                  "id": "3f6c1d2e-8a4b-4f7e-9c21-5d0e7a1b2c3d",
                  "name": "Weekly competitor digest",
                  "description": "Reads five competitor blogs and writes a summary page.",
                  "status": "active",
                  "project_id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
                  "updated_at": "2026-10-02T15:04:05.123Z",
                  "last_run": {
                    "id": "c0ffee00-1234-4abc-9def-0123456789ab",
                    "status": "succeeded",
                    "at": "2026-10-03T06:00:00.000Z"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/workflows/{id}/runs": {
      "post": {
        "operationId": "startRun",
        "tags": [
          "Runs"
        ],
        "summary": "Start a run",
        "description": "Queues a run of the workflow and answers at once with `202` and the queued run. The run begins within about a minute and runs for up to two minutes; follow it with Get a run. It runs with everything in the account the key can reach, and its AI use is billed to the account like any other run, under Agentic workflows. A key with a monthly spend cap stops a run that reaches it.\n\n**`Idempotency-Key` is required.** Send a new unique value (a UUID is ideal) for each run you mean to start, and the same value again if you retry: a retry with the same key and the same request returns the first answer, with `Idempotent-Replay: true`, and never starts a second run. If the first request did not finish, the retry answers `409 idempotency_outcome_unknown` and nothing is run again; list the workflow's runs to see whether it started. Keys are remembered for 24 hours.\n\nRuns take no inputs in v1, so the body is `{}` or empty. A run that stops at a Human checkpoint waits for someone to approve it in the hub.",
        "x-scope": "workflows:run",
        "parameters": [
          {
            "$ref": "#/components/parameters/WorkflowId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": false,
          "description": "Empty, or `{}`.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StartRunRequest"
              },
              "example": {}
            }
          }
        },
        "responses": {
          "202": {
            "description": "The run is queued.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "Idempotent-Replay": {
                "$ref": "#/components/headers/Idempotent-Replay"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RunStarted"
                },
                "example": {
                  "id": "4b7e1c2d-3f5a-4b6c-8d7e-9f0a1b2c3d4e",
                  "workflow_id": "3f6c1d2e-8a4b-4f7e-9c21-5d0e7a1b2c3d",
                  "status": "queued",
                  "trigger": "api",
                  "created_at": "2026-10-03T14:20:00.000Z"
                }
              }
            }
          },
          "400": {
            "description": "The request is not valid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "invalid_request",
                    "code": "missing_idempotency_key",
                    "message": "Send an Idempotency-Key header (8 to 64 characters) with every run you start, and the same one again if you retry it.",
                    "param": "Idempotency-Key",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "description": "Not enough credit to start a run.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "insufficient_credit",
                    "code": "account_out_of_credit",
                    "message": "This account is out of AI credit. An owner, or an admin with billing access, can add credit in Account → Billing.",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key may not do this.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "permission",
                    "code": "insufficient_scope",
                    "message": "This API key does not have the workflows:run scope.",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not found in this account.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "not_found",
                    "code": "resource_not_found",
                    "message": "No workflow with that id.",
                    "param": "id",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "409": {
            "description": "The Idempotency-Key is busy, or its first request did not finish.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "conflict",
                    "code": "idempotency_outcome_unknown",
                    "message": "The first request with this Idempotency-Key did not finish, so whether it started a run is unknown. It will not be run again. List the workflow's runs to see whether it did.",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body, the workflow or the Idempotency-Key cannot be used.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "invalid_request",
                    "code": "idempotency_key_reused",
                    "message": "This Idempotency-Key was already used for a different request. Use a new key for a new request.",
                    "param": "Idempotency-Key",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many requests, or too many runs.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "rate_limit",
                    "code": "concurrency_limited",
                    "message": "This account already has 5 API runs queued or running. Start another when one finishes.",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "get": {
        "operationId": "listRuns",
        "tags": [
          "Runs"
        ],
        "summary": "List a workflow's runs",
        "description": "The workflow's runs, newest first, however they were started: from the hub, on a schedule, by chat or through the API.",
        "x-scope": "workflows:read",
        "parameters": [
          {
            "$ref": "#/components/parameters/WorkflowId"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of runs.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RunList"
                },
                "example": {
                  "data": [
                    {
                      "id": "4b7e1c2d-3f5a-4b6c-8d7e-9f0a1b2c3d4e",
                      "workflow_id": "3f6c1d2e-8a4b-4f7e-9c21-5d0e7a1b2c3d",
                      "status": "succeeded",
                      "trigger": "api",
                      "summary": "Completed 3 steps (3 ran).",
                      "created_at": "2026-10-03T14:20:00.000Z",
                      "started_at": "2026-10-03T14:20:00.000Z",
                      "finished_at": "2026-10-03T14:21:04.512Z"
                    }
                  ],
                  "has_more": false,
                  "next_cursor": null
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/runs/{id}": {
      "get": {
        "operationId": "getRun",
        "tags": [
          "Runs"
        ],
        "summary": "Get a run",
        "description": "A run, its blocks and what it was billed. Poll it (every few seconds is plenty) until `status` is final: `succeeded`, `failed`, `partial` (stopped at a time, step or spend limit), `rejected` or `cancelled`. `awaiting_approval` means it stopped at a Human checkpoint and waits for someone in the hub.",
        "x-scope": "workflows:read",
        "parameters": [
          {
            "$ref": "#/components/parameters/RunId"
          }
        ],
        "responses": {
          "200": {
            "description": "The run.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Run"
                },
                "example": {
                  "id": "4b7e1c2d-3f5a-4b6c-8d7e-9f0a1b2c3d4e",
                  "workflow_id": "3f6c1d2e-8a4b-4f7e-9c21-5d0e7a1b2c3d",
                  "status": "succeeded",
                  "trigger": "api",
                  "summary": "Completed 3 steps (3 ran).",
                  "created_at": "2026-10-03T14:20:00.000Z",
                  "started_at": "2026-10-03T14:20:00.000Z",
                  "finished_at": "2026-10-03T14:21:04.512Z",
                  "billed_micros": 41250,
                  "steps": [
                    {
                      "node_id": "n1",
                      "node_kind": "crawl",
                      "status": "succeeded",
                      "ms": 8120,
                      "error": null
                    },
                    {
                      "node_id": "n2",
                      "node_kind": "agent",
                      "status": "succeeded",
                      "ms": 15433,
                      "error": null
                    },
                    {
                      "node_id": "n3",
                      "node_kind": "output",
                      "status": "succeeded",
                      "ms": 210,
                      "error": null
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "Not found in this account.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "not_found",
                    "code": "resource_not_found",
                    "message": "No run with that id.",
                    "param": "id",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/usage": {
      "get": {
        "operationId": "getUsage",
        "tags": [
          "Usage"
        ],
        "summary": "Get usage",
        "description": "What the account was billed between two dates (UTC, both included), in total, per day and per feature, and its balance now. The default is this month so far. Amounts are what the account is charged, in micros (1,000,000 = US$1); the `_usd` strings are the same amounts rounded to the cent. Only days with usage are listed. At most 366 days per request.",
        "x-scope": "usage:read",
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "First day, YYYY-MM-DD (UTC). Default: the first of this month.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Last day, YYYY-MM-DD (UTC), included. Default: today.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Usage for the window.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Usage"
                },
                "example": {
                  "from": "2026-10-01",
                  "to": "2026-10-03",
                  "currency": "usd",
                  "total_micros": 2731500,
                  "total_usd": "2.73",
                  "balance_micros": 47268500,
                  "balance_usd": "47.27",
                  "by_day": [
                    {
                      "day": "2026-10-01",
                      "micros": 912000
                    },
                    {
                      "day": "2026-10-02",
                      "micros": 1384250
                    },
                    {
                      "day": "2026-10-03",
                      "micros": 435250
                    }
                  ],
                  "by_feature": [
                    {
                      "feature": "workflow",
                      "micros": 1953000
                    },
                    {
                      "feature": "studio_chat",
                      "micros": 640500
                    },
                    {
                      "feature": "compute",
                      "micros": 138000
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request is not valid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "invalid_request",
                    "code": "invalid_parameter",
                    "message": "from must be a date written YYYY-MM-DD.",
                    "param": "from",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The key may not do this.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "permission",
                    "code": "insufficient_scope",
                    "message": "This API key does not have the usage:read scope.",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "404": {
            "description": "No endpoint at that path.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "not_found",
                    "code": "route_not_found",
                    "message": "There is no endpoint at GET /v1/usages.",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/projects": {
      "get": {
        "operationId": "listProjects",
        "tags": [
          "Projects"
        ],
        "summary": "List projects",
        "description": "The account's projects, newest first. Archived projects are left out; read one by its id to see it.",
        "x-scope": "content:read",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of projects.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProjectList"
                },
                "example": {
                  "data": [
                    {
                      "id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
                      "name": "Market research",
                      "description": "Competitors, pricing and interviews.",
                      "archived": false,
                      "created_at": "2026-08-14T09:30:00.000Z",
                      "updated_at": "2026-10-02T15:04:05.123Z"
                    }
                  ],
                  "has_more": false,
                  "next_cursor": null
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The key may not do this.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "permission",
                    "code": "insufficient_scope",
                    "message": "This API key does not have the content:read scope.",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "404": {
            "description": "No endpoint at that path.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "not_found",
                    "code": "route_not_found",
                    "message": "There is no endpoint at GET /v1/project.",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/projects/{id}": {
      "get": {
        "operationId": "getProject",
        "tags": [
          "Projects"
        ],
        "summary": "Get a project",
        "description": "One project, archived or not.",
        "x-scope": "content:read",
        "parameters": [
          {
            "$ref": "#/components/parameters/ProjectId"
          }
        ],
        "responses": {
          "200": {
            "description": "The project.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Project"
                },
                "example": {
                  "id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
                  "name": "Market research",
                  "description": "Competitors, pricing and interviews.",
                  "archived": false,
                  "created_at": "2026-08-14T09:30:00.000Z",
                  "updated_at": "2026-10-02T15:04:05.123Z"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The key may not do this.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "permission",
                    "code": "insufficient_scope",
                    "message": "This API key does not have the content:read scope.",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not found in this account.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "not_found",
                    "code": "resource_not_found",
                    "message": "No project with that id.",
                    "param": "id",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/projects/{id}/items": {
      "get": {
        "operationId": "listItems",
        "tags": [
          "Items"
        ],
        "summary": "List a project's items",
        "description": "The items in a project's Data Management, newest first, in every folder unless `folder_id` is given. Deleted items are left out. A list item carries no body: read a page with Get an item.",
        "x-scope": "content:read",
        "parameters": [
          {
            "$ref": "#/components/parameters/ProjectId"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "name": "kind",
            "in": "query",
            "required": false,
            "description": "Only items of this kind.",
            "schema": {
              "type": "string",
              "enum": [
                "page",
                "file",
                "dataset",
                "image",
                "link"
              ]
            }
          },
          {
            "name": "folder_id",
            "in": "query",
            "required": false,
            "description": "Only the items directly in this folder (not in its subfolders). Items carry their `folder_id`.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Only items whose name contains this text, ignoring case (1 to 120 characters).",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 120
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of items.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ItemList"
                },
                "example": {
                  "data": [
                    {
                      "id": "5d4c3b2a-1f0e-4d9c-8b7a-6e5f4d3c2b1a",
                      "project_id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
                      "folder_id": null,
                      "name": "Competitor digest",
                      "kind": "page",
                      "ext": "html",
                      "size_bytes": 1834,
                      "status": "ready",
                      "grounding": true,
                      "created_at": "2026-10-03T06:01:12.000Z",
                      "updated_at": "2026-10-03T06:01:12.000Z"
                    },
                    {
                      "id": "2a3b4c5d-6e7f-4a8b-9c0d-1e2f3a4b5c6d",
                      "project_id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
                      "folder_id": "8f7e6d5c-4b3a-4c2d-9e1f-0a9b8c7d6e5f",
                      "name": "Pricing survey.pdf",
                      "kind": "file",
                      "ext": "pdf",
                      "size_bytes": 482113,
                      "status": "ready",
                      "grounding": true,
                      "created_at": "2026-09-20T11:00:00.000Z",
                      "updated_at": "2026-09-20T11:02:40.000Z"
                    }
                  ],
                  "has_more": false,
                  "next_cursor": null
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The key may not do this.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "permission",
                    "code": "insufficient_scope",
                    "message": "This API key does not have the content:read scope.",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not found in this account.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "not_found",
                    "code": "resource_not_found",
                    "message": "No folder with that id in this project.",
                    "param": "folder_id",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "post": {
        "operationId": "createPage",
        "tags": [
          "Items"
        ],
        "summary": "Create a page",
        "description": "Creates a page in the project's Data Management, at the top of the project or in `folder_id`, and answers `201` with it. Send the text as Markdown or HTML. It is cleaned exactly as a page saved in the hub is: scripts, event handlers, styles and anything else a page cannot hold are removed, so what you read back can differ from what you sent. Markdown is stored as HTML, so the page reads back with `format: \"html\"`. The page has a first version in its history, and is searched by Chat & Research and Odin like any other page once it has been indexed, which is billed as indexing any page is.\n\n`Idempotency-Key` is optional here and recommended: a retry with the same key and the same request returns the first answer, with `Idempotent-Replay: true`, and never makes a second page. Files cannot be uploaded in v1.",
        "x-scope": "content:write",
        "parameters": [
          {
            "$ref": "#/components/parameters/ProjectId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "The page.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePageRequest"
              },
              "example": {
                "name": "Q3 board summary",
                "format": "markdown",
                "content": "# Q3 board summary\n\nRevenue grew **12%** on Q2.",
                "folder_id": null
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The page was created.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "Idempotent-Replay": {
                "$ref": "#/components/headers/Idempotent-Replay"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Item"
                },
                "example": {
                  "id": "5d4c3b2a-1f0e-4d9c-8b7a-6e5f4d3c2b1a",
                  "project_id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
                  "folder_id": null,
                  "name": "Q3 board summary",
                  "kind": "page",
                  "ext": "html",
                  "size_bytes": 72,
                  "status": "ready",
                  "grounding": true,
                  "created_at": "2026-10-03T06:01:12.000Z",
                  "updated_at": "2026-10-03T06:01:12.000Z",
                  "body": {
                    "format": "html",
                    "content": "<h1>Q3 board summary</h1>\n<p>Revenue grew <strong>12%</strong> on Q2.</p>\n"
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request is not valid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "invalid_request",
                    "code": "missing_field",
                    "message": "content is required.",
                    "param": "content",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The key may not do this.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "permission",
                    "code": "insufficient_scope",
                    "message": "This API key does not have the content:write scope.",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not found in this account.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "not_found",
                    "code": "resource_not_found",
                    "message": "No project with that id.",
                    "param": "id",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "409": {
            "description": "The Idempotency-Key is busy, or its first request did not finish.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "conflict",
                    "code": "idempotency_in_progress",
                    "message": "A request with this Idempotency-Key is still being handled. Retry in a few seconds.",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "413": {
            "description": "The page is too large.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "invalid_request",
                    "code": "page_too_large",
                    "message": "This page is too large to store (more than 900000 bytes once converted to HTML). Split it into two pages.",
                    "param": "content",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "422": {
            "description": "A body field cannot be used.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "invalid_request",
                    "code": "unknown_field",
                    "message": "A page takes name, format, content and folder_id; \"title\" is not one of them.",
                    "param": "title",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/items/{id}": {
      "get": {
        "operationId": "getItem",
        "tags": [
          "Items"
        ],
        "summary": "Get an item",
        "description": "One item. For a page, `body` holds its text, as HTML (or Markdown, for a page that was stored as Markdown); images in a page are references (`<img data-vg-item=\"…\">`), not links. For a file, dataset, image or link, `body` is null in v1.",
        "x-scope": "content:read",
        "parameters": [
          {
            "$ref": "#/components/parameters/ItemId"
          }
        ],
        "responses": {
          "200": {
            "description": "The item.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Item"
                },
                "example": {
                  "id": "5d4c3b2a-1f0e-4d9c-8b7a-6e5f4d3c2b1a",
                  "project_id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
                  "folder_id": null,
                  "name": "Competitor digest",
                  "kind": "page",
                  "ext": "html",
                  "size_bytes": 1834,
                  "status": "ready",
                  "grounding": true,
                  "created_at": "2026-10-03T06:01:12.000Z",
                  "updated_at": "2026-10-03T06:01:12.000Z",
                  "body": {
                    "format": "html",
                    "content": "<h1>Competitor digest</h1>\n<p>Three launches this week.</p>\n"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The key may not do this.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "permission",
                    "code": "insufficient_scope",
                    "message": "This API key does not have the content:read scope.",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not found in this account.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "not_found",
                    "code": "resource_not_found",
                    "message": "No item with that id.",
                    "param": "id",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/contacts": {
      "get": {
        "operationId": "listContacts",
        "tags": [
          "Contacts"
        ],
        "summary": "List contacts",
        "description": "The account's contacts in Thrive, newest first. Deleted (archived) contacts are left out. Filters combine: `q` searches names, emails, titles and company names; `email` finds the one contact with that address; `updated_since` returns only contacts changed at or after a time, for keeping another system in step.",
        "x-scope": "contacts:read",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Contains this text, ignoring case (1 to 100 characters).",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            }
          },
          {
            "name": "email",
            "in": "query",
            "required": false,
            "description": "Exactly this email address, ignoring case.",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 254
            }
          },
          {
            "name": "lifecycle",
            "in": "query",
            "required": false,
            "description": "Only contacts at this lifecycle stage.",
            "schema": {
              "type": "string",
              "enum": [
                "subscriber",
                "lead",
                "marketing_qualified",
                "sales_qualified",
                "opportunity",
                "customer",
                "evangelist",
                "other"
              ]
            }
          },
          {
            "name": "updated_since",
            "in": "query",
            "required": false,
            "description": "Only contacts changed at or after this time: a date (YYYY-MM-DD, UTC) or an ISO-8601 date and time with a zone.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of contacts.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactList"
                },
                "example": {
                  "data": [
                    {
                      "id": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
                      "full_name": "Maya Lindqvist",
                      "first_name": "Maya",
                      "last_name": "Lindqvist",
                      "title": "Head of Operations",
                      "email": "maya@northwind.example",
                      "phone": "+1 415 555 0134",
                      "company_id": "6e5d4c3b-2a1f-4e0d-9c8b-7a6f5e4d3c2b",
                      "status": "active",
                      "lifecycle_stage": "sales_qualified",
                      "lead_source": "Website form",
                      "email_opt_out": false,
                      "created_at": "2026-09-28T16:42:10.000Z",
                      "updated_at": "2026-10-03T09:15:00.000Z"
                    }
                  ],
                  "has_more": false,
                  "next_cursor": null
                }
              }
            }
          },
          "400": {
            "description": "The request is not valid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "invalid_request",
                    "code": "invalid_parameter",
                    "message": "lifecycle must be one of: subscriber, lead, marketing_qualified, sales_qualified, opportunity, customer, evangelist, other.",
                    "param": "lifecycle",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The key may not do this.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "permission",
                    "code": "insufficient_scope",
                    "message": "This API key does not have the contacts:read scope.",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "404": {
            "description": "No endpoint at that path.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "not_found",
                    "code": "route_not_found",
                    "message": "There is no endpoint at GET /v1/contact.",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "post": {
        "operationId": "createContact",
        "tags": [
          "Contacts"
        ],
        "summary": "Create a contact",
        "description": "Adds a contact to Thrive and answers `201` with it. It needs a name: `full_name`, or `first_name` and `last_name`. It is unassigned (no owner) until someone in Thrive assigns it, and its history says it was created through the API.\n\n**One contact per email address.** If a contact in the account already has the address, nothing is created or changed: the answer is `409 contact_exists` with that contact's id in `resource_id`, so you can update it with PATCH. An address that belongs to someone erased from Thrive at their request is refused with `409 contact_do_not_contact`.\n\n`Idempotency-Key` is optional and recommended: a retry with the same key and the same request returns the first answer, with `Idempotent-Replay: true`, and never makes a second contact.",
        "x-scope": "contacts:write",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKeyOptional"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "The contact.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateContactRequest"
              },
              "example": {
                "first_name": "Maya",
                "last_name": "Lindqvist",
                "email": "maya@northwind.example",
                "title": "Head of Operations",
                "lead_source": "Website form"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The contact was created.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "Idempotent-Replay": {
                "$ref": "#/components/headers/Idempotent-Replay"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Contact"
                },
                "example": {
                  "id": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
                  "full_name": "Maya Lindqvist",
                  "first_name": "Maya",
                  "last_name": "Lindqvist",
                  "title": "Head of Operations",
                  "email": "maya@northwind.example",
                  "phone": "+1 415 555 0134",
                  "company_id": "6e5d4c3b-2a1f-4e0d-9c8b-7a6f5e4d3c2b",
                  "status": "active",
                  "lifecycle_stage": "sales_qualified",
                  "lead_source": "Website form",
                  "email_opt_out": false,
                  "created_at": "2026-09-28T16:42:10.000Z",
                  "updated_at": "2026-10-03T09:15:00.000Z"
                }
              }
            }
          },
          "400": {
            "description": "The request is not valid.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "invalid_request",
                    "code": "missing_field",
                    "message": "A contact needs a name: full_name, or first_name and last_name.",
                    "param": "full_name",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The key may not do this.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "permission",
                    "code": "insufficient_scope",
                    "message": "This API key does not have the contacts:write scope.",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not found in this account.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "not_found",
                    "code": "resource_not_found",
                    "message": "No company with that id.",
                    "param": "company_id",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "409": {
            "description": "A contact already has that email address, or the Idempotency-Key is busy.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "conflict",
                    "code": "contact_exists",
                    "message": "A contact with that email address already exists. Update it with PATCH /v1/contacts/1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f.",
                    "param": "email",
                    "resource_id": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "422": {
            "description": "A body field cannot be used.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "invalid_request",
                    "code": "unknown_field",
                    "message": "A contact takes full_name, first_name, last_name, title, email, phone, company_id, lifecycle_stage, lead_source, email_opt_out; \"owner\" is not one of them.",
                    "param": "owner",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/contacts/{id}": {
      "get": {
        "operationId": "getContact",
        "tags": [
          "Contacts"
        ],
        "summary": "Get a contact",
        "description": "One contact. A deleted (archived) contact is not found.",
        "x-scope": "contacts:read",
        "parameters": [
          {
            "$ref": "#/components/parameters/ContactId"
          }
        ],
        "responses": {
          "200": {
            "description": "The contact.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Contact"
                },
                "example": {
                  "id": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
                  "full_name": "Maya Lindqvist",
                  "first_name": "Maya",
                  "last_name": "Lindqvist",
                  "title": "Head of Operations",
                  "email": "maya@northwind.example",
                  "phone": "+1 415 555 0134",
                  "company_id": "6e5d4c3b-2a1f-4e0d-9c8b-7a6f5e4d3c2b",
                  "status": "active",
                  "lifecycle_stage": "sales_qualified",
                  "lead_source": "Website form",
                  "email_opt_out": false,
                  "created_at": "2026-09-28T16:42:10.000Z",
                  "updated_at": "2026-10-03T09:15:00.000Z"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The key may not do this.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "permission",
                    "code": "insufficient_scope",
                    "message": "This API key does not have the contacts:read scope.",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not found in this account.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "not_found",
                    "code": "resource_not_found",
                    "message": "No contact with that id.",
                    "param": "id",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "patch": {
        "operationId": "updateContact",
        "tags": [
          "Contacts"
        ],
        "summary": "Update a contact",
        "description": "Changes only the fields you send; every other field is left as it is. Send `null` to clear a field (not `full_name`, which a contact always has). Changing `first_name` or `last_name` does not change `full_name`: send it too if it should change. An empty body changes nothing and returns the contact.\n\nThe API cannot lift an email opt-out (`email_opt_out: false` on a contact that has opted out is `409 opt_out_locked`), and cannot change someone erased from Thrive at their request (`409 contact_do_not_contact`). Moving a contact to an email address another contact has is `409 contact_exists`.",
        "x-scope": "contacts:write",
        "parameters": [
          {
            "$ref": "#/components/parameters/ContactId"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "The fields to change.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateContactRequest"
              },
              "example": {
                "lifecycle_stage": "customer",
                "title": "COO",
                "phone": null
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The contact, as it is now.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Contact"
                },
                "example": {
                  "id": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
                  "full_name": "Maya Lindqvist",
                  "first_name": "Maya",
                  "last_name": "Lindqvist",
                  "title": "COO",
                  "email": "maya@northwind.example",
                  "phone": null,
                  "company_id": "6e5d4c3b-2a1f-4e0d-9c8b-7a6f5e4d3c2b",
                  "status": "active",
                  "lifecycle_stage": "customer",
                  "lead_source": "Website form",
                  "email_opt_out": false,
                  "created_at": "2026-09-28T16:42:10.000Z",
                  "updated_at": "2026-10-03T09:15:00.000Z"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The key may not do this.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "permission",
                    "code": "insufficient_scope",
                    "message": "This API key does not have the contacts:write scope.",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not found in this account.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "not_found",
                    "code": "resource_not_found",
                    "message": "No contact with that id.",
                    "param": "id",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "409": {
            "description": "The change is not allowed for this contact.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "conflict",
                    "code": "opt_out_locked",
                    "message": "This contact has opted out of email. The API cannot opt them back in; a person can, in Thrive.",
                    "param": "email_opt_out",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "422": {
            "description": "A body field cannot be used.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "type": "invalid_request",
                    "code": "invalid_field",
                    "message": "Lifecycle stage must be one of: subscriber, lead, marketing_qualified, sales_qualified, opportunity, customer, evangelist, other.",
                    "param": "lifecycle_stage",
                    "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearer": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "vg_live_…",
        "description": "An API key from Account → API keys, sent as `Authorization: Bearer vg_live_…`."
      }
    },
    "headers": {
      "X-Request-Id": {
        "description": "Identifies this request. Quote it to support.",
        "schema": {
          "type": "string"
        }
      },
      "RateLimit-Limit": {
        "description": "Requests this key may make in the current minute.",
        "schema": {
          "type": "integer"
        }
      },
      "RateLimit-Remaining": {
        "description": "Requests left in the current minute.",
        "schema": {
          "type": "integer"
        }
      },
      "RateLimit-Reset": {
        "description": "Seconds until the minute ends and the count starts again.",
        "schema": {
          "type": "integer"
        }
      },
      "Retry-After": {
        "description": "Seconds to wait before trying again.",
        "schema": {
          "type": "integer"
        }
      },
      "Idempotent-Replay": {
        "description": "`true` when this is the stored answer to an earlier request with the same `Idempotency-Key`.",
        "schema": {
          "type": "string"
        }
      }
    },
    "parameters": {
      "Limit": {
        "name": "limit",
        "in": "query",
        "required": false,
        "description": "How many to return.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100,
          "default": 25
        }
      },
      "WorkflowId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "The workflow's id.",
        "example": "3f6c1d2e-8a4b-4f7e-9c21-5d0e7a1b2c3d",
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "RunId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "The run's id.",
        "example": "4b7e1c2d-3f5a-4b6c-8d7e-9f0a1b2c3d4e",
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": true,
        "description": "A unique value for this run, 8 to 64 printable characters (a UUID is ideal). Send the same value again to retry safely.",
        "example": "6f1d2c3b-run-2026-10-03-1420",
        "schema": {
          "type": "string"
        }
      },
      "IdempotencyKeyOptional": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "description": "Optional: a unique value for this request, 8 to 64 printable characters (a UUID is ideal). Send the same value again to retry without creating a second one.",
        "example": "6f1d2c3b-page-2026-10-03-1420",
        "schema": {
          "type": "string"
        }
      },
      "ProjectId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "The project's id.",
        "example": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "ItemId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "The item's id.",
        "example": "5d4c3b2a-1f0e-4d9c-8b7a-6e5f4d3c2b1a",
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "ContactId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "The contact's id.",
        "example": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "Cursor": {
        "name": "cursor",
        "in": "query",
        "required": false,
        "description": "The `next_cursor` from the previous page. Leave it out for the first page.",
        "schema": {
          "type": "string"
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "type",
              "code",
              "message",
              "request_id"
            ],
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "invalid_request",
                  "authentication",
                  "insufficient_credit",
                  "permission",
                  "not_found",
                  "conflict",
                  "rate_limit",
                  "api_error"
                ]
              },
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "param": {
                "type": "string"
              },
              "resource_id": {
                "type": "string",
                "format": "uuid",
                "description": "On contact_exists: the id of the contact that already has the address."
              },
              "request_id": {
                "type": "string"
              }
            }
          }
        }
      },
      "RunSummary": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "status",
          "at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "description": "queued, running, succeeded, failed, awaiting_approval or cancelled."
          },
          "at": {
            "type": "string",
            "format": "date-time",
            "description": "When the run was created (UTC)."
          }
        }
      },
      "Workflow": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "name",
          "description",
          "status",
          "project_id",
          "updated_at",
          "last_run"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "active",
              "paused"
            ]
          },
          "project_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "null for a workflow not yet in a project."
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "last_run": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/RunSummary"
              },
              {
                "type": "null"
              }
            ]
          }
        }
      },
      "StartRunRequest": {
        "type": "object",
        "additionalProperties": false,
        "properties": {},
        "description": "No fields in v1. Any field is refused with 422 unknown_field."
      },
      "RunStarted": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "workflow_id",
          "status",
          "trigger",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "workflow_id": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "enum": [
              "queued"
            ]
          },
          "trigger": {
            "type": "string",
            "enum": [
              "api"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "RunListItem": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "workflow_id",
          "status",
          "trigger",
          "summary",
          "created_at",
          "started_at",
          "finished_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "workflow_id": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "description": "queued, running, succeeded, failed, partial, awaiting_approval, rejected or cancelled."
          },
          "trigger": {
            "type": "string",
            "description": "How it was started: api, manual (from the hub), schedule or chat."
          },
          "summary": {
            "type": "string",
            "description": "One line on how it went."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "started_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "finished_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "null until the run ends."
          }
        }
      },
      "Run": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "workflow_id",
          "status",
          "trigger",
          "summary",
          "created_at",
          "started_at",
          "finished_at",
          "billed_micros",
          "steps"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "workflow_id": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "description": "queued, running, succeeded, failed, partial, awaiting_approval, rejected or cancelled."
          },
          "trigger": {
            "type": "string",
            "description": "How it was started: api, manual (from the hub), schedule or chat."
          },
          "summary": {
            "type": "string",
            "description": "One line on how it went."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "started_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "finished_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "null until the run ends."
          },
          "billed_micros": {
            "type": "integer",
            "minimum": 0,
            "description": "What the run has been billed so far, in micros (1,000,000 = US$1)."
          },
          "steps": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RunStep"
            },
            "description": "One per block, in the order they ran."
          }
        }
      },
      "RunStep": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "node_id",
          "node_kind",
          "status",
          "ms",
          "error"
        ],
        "properties": {
          "node_id": {
            "type": "string",
            "description": "The block's id in the workflow."
          },
          "node_kind": {
            "type": "string",
            "description": "What kind of block it is."
          },
          "status": {
            "type": "string",
            "description": "queued, running, succeeded, failed, skipped or awaiting."
          },
          "ms": {
            "type": "integer",
            "minimum": 0,
            "description": "How long the block took."
          },
          "error": {
            "type": [
              "string",
              "null"
            ],
            "description": "Why the block failed, or null."
          }
        }
      },
      "RunList": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "data",
          "has_more",
          "next_cursor"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RunListItem"
            }
          },
          "has_more": {
            "type": "boolean"
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "Usage": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "from",
          "to",
          "currency",
          "total_micros",
          "total_usd",
          "balance_micros",
          "balance_usd",
          "by_day",
          "by_feature"
        ],
        "properties": {
          "from": {
            "type": "string",
            "format": "date"
          },
          "to": {
            "type": "string",
            "format": "date"
          },
          "currency": {
            "type": "string",
            "enum": [
              "usd"
            ]
          },
          "total_micros": {
            "type": "integer",
            "minimum": 0,
            "description": "Billed in the window, in micros."
          },
          "total_usd": {
            "type": "string",
            "description": "The same, in US dollars, rounded to the cent."
          },
          "balance_micros": {
            "type": "integer",
            "description": "The account's prepaid balance now, in micros."
          },
          "balance_usd": {
            "type": "string"
          },
          "by_day": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "day",
                "micros"
              ],
              "properties": {
                "day": {
                  "type": "string",
                  "format": "date"
                },
                "micros": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            }
          },
          "by_feature": {
            "type": "array",
            "description": "Largest first. `feature` is the name Observability shows each line under.",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "feature",
                "micros"
              ],
              "properties": {
                "feature": {
                  "type": "string"
                },
                "micros": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            }
          }
        }
      },
      "Project": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "name",
          "description",
          "archived",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "archived": {
            "type": "boolean"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ProjectList": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "data",
          "has_more",
          "next_cursor"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Project"
            }
          },
          "has_more": {
            "type": "boolean"
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "ItemListItem": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "project_id",
          "folder_id",
          "name",
          "kind",
          "ext",
          "size_bytes",
          "status",
          "grounding",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "project_id": {
            "type": "string",
            "format": "uuid"
          },
          "folder_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "The folder it is in, or null at the top of the project."
          },
          "name": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "description": "page, file, dataset, image or link."
          },
          "ext": {
            "type": [
              "string",
              "null"
            ],
            "description": "The file extension, such as pdf or csv; html or md for a page."
          },
          "size_bytes": {
            "type": "integer",
            "minimum": 0
          },
          "status": {
            "type": "string",
            "description": "ready, queued or processing while a file is being read, or failed."
          },
          "grounding": {
            "type": "boolean",
            "description": "Whether Chat & Research and Odin use it when answering."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Item": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "project_id",
          "folder_id",
          "name",
          "kind",
          "ext",
          "size_bytes",
          "status",
          "grounding",
          "created_at",
          "updated_at",
          "body"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "project_id": {
            "type": "string",
            "format": "uuid"
          },
          "folder_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "The folder it is in, or null at the top of the project."
          },
          "name": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "description": "page, file, dataset, image or link."
          },
          "ext": {
            "type": [
              "string",
              "null"
            ],
            "description": "The file extension, such as pdf or csv; html or md for a page."
          },
          "size_bytes": {
            "type": "integer",
            "minimum": 0
          },
          "status": {
            "type": "string",
            "description": "ready, queued or processing while a file is being read, or failed."
          },
          "grounding": {
            "type": "boolean",
            "description": "Whether Chat & Research and Odin use it when answering."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "body": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/ItemBody"
              },
              {
                "type": "null"
              }
            ],
            "description": "A page's text; null for anything that is not a page."
          }
        }
      },
      "ItemBody": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "format",
          "content"
        ],
        "properties": {
          "format": {
            "type": "string",
            "enum": [
              "html",
              "markdown"
            ]
          },
          "content": {
            "type": "string"
          }
        }
      },
      "ItemList": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "data",
          "has_more",
          "next_cursor"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ItemListItem"
            }
          },
          "has_more": {
            "type": "boolean"
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "CreatePageRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "name",
          "format",
          "content"
        ],
        "description": "Any other field is refused with 422 unknown_field.",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 300,
            "description": "The page's name in Data Management."
          },
          "format": {
            "type": "string",
            "enum": [
              "markdown",
              "html"
            ],
            "description": "What `content` is written in."
          },
          "content": {
            "type": "string",
            "description": "The page's text. At most about 900 KB once converted to HTML (and the whole request at most 1 MB)."
          },
          "folder_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "A folder in this project. Leave it out, or null, for the top of the project."
          }
        }
      },
      "Contact": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "full_name",
          "first_name",
          "last_name",
          "title",
          "email",
          "phone",
          "company_id",
          "status",
          "lifecycle_stage",
          "lead_source",
          "email_opt_out",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "full_name": {
            "type": "string"
          },
          "first_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "last_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "title": {
            "type": [
              "string",
              "null"
            ]
          },
          "email": {
            "type": [
              "string",
              "null"
            ]
          },
          "phone": {
            "type": [
              "string",
              "null"
            ]
          },
          "company_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "dormant",
              "do_not_contact"
            ],
            "description": "`do_not_contact`: never contact them. Set in Thrive only; the API cannot change it."
          },
          "lifecycle_stage": {
            "type": [
              "string",
              "null"
            ]
          },
          "lead_source": {
            "type": [
              "string",
              "null"
            ]
          },
          "email_opt_out": {
            "type": "boolean",
            "description": "true when they have opted out of email."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ContactList": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "data",
          "has_more",
          "next_cursor"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Contact"
            }
          },
          "has_more": {
            "type": "boolean"
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "CreateContactRequest": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "full_name": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 200,
            "description": "The name shown in Thrive. On create, leave it out to make it from first_name and last_name."
          },
          "first_name": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 100,
            "description": "First name."
          },
          "last_name": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 100,
            "description": "Last name."
          },
          "title": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 200,
            "description": "Job title."
          },
          "email": {
            "type": [
              "string",
              "null"
            ],
            "format": "email",
            "maxLength": 254,
            "description": "Their email address. One contact per address in an account."
          },
          "phone": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 60,
            "description": "Phone number."
          },
          "company_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "A company in Thrive in this account."
          },
          "lifecycle_stage": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "subscriber",
              "lead",
              "marketing_qualified",
              "sales_qualified",
              "opportunity",
              "customer",
              "evangelist",
              "other",
              null
            ],
            "description": "Where they are in the funnel."
          },
          "lead_source": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 80,
            "description": "Where they came from, in your words (at most 80 characters)."
          },
          "email_opt_out": {
            "type": "boolean",
            "description": "true when they have opted out of email. The API can set it to true but cannot set it back to false on a contact that has opted out."
          }
        },
        "description": "Needs full_name, or first_name and last_name. Any other field is refused with 422 unknown_field."
      },
      "UpdateContactRequest": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "full_name": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 200,
            "description": "The name shown in Thrive. On create, leave it out to make it from first_name and last_name."
          },
          "first_name": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 100,
            "description": "First name."
          },
          "last_name": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 100,
            "description": "Last name."
          },
          "title": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 200,
            "description": "Job title."
          },
          "email": {
            "type": [
              "string",
              "null"
            ],
            "format": "email",
            "maxLength": 254,
            "description": "Their email address. One contact per address in an account."
          },
          "phone": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 60,
            "description": "Phone number."
          },
          "company_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "A company in Thrive in this account."
          },
          "lifecycle_stage": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "subscriber",
              "lead",
              "marketing_qualified",
              "sales_qualified",
              "opportunity",
              "customer",
              "evangelist",
              "other",
              null
            ],
            "description": "Where they are in the funnel."
          },
          "lead_source": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 80,
            "description": "Where they came from, in your words (at most 80 characters)."
          },
          "email_opt_out": {
            "type": "boolean",
            "description": "true when they have opted out of email. The API can set it to true but cannot set it back to false on a contact that has opted out."
          }
        },
        "description": "Only the fields sent change; null clears one. Any other field is refused with 422 unknown_field."
      },
      "WorkflowList": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "data",
          "has_more",
          "next_cursor"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Workflow"
            }
          },
          "has_more": {
            "type": "boolean"
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "The request is not valid.",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/X-Request-Id"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "type": "invalid_request",
                "code": "invalid_cursor",
                "message": "cursor is not valid",
                "param": "cursor",
                "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
              }
            }
          }
        }
      },
      "Unauthorized": {
        "description": "No valid API key.",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/X-Request-Id"
          },
          "WWW-Authenticate": {
            "description": "Always `Bearer`.",
            "schema": {
              "type": "string"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "type": "authentication",
                "code": "invalid_api_key",
                "message": "The API key is missing or not valid.",
                "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
              }
            }
          }
        }
      },
      "Forbidden": {
        "description": "The key may not do this.",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/X-Request-Id"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "type": "permission",
                "code": "insufficient_scope",
                "message": "This API key does not have the workflows:read scope.",
                "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
              }
            }
          }
        }
      },
      "NotFound": {
        "description": "Not found in this account.",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/X-Request-Id"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "type": "not_found",
                "code": "resource_not_found",
                "message": "No project with that id.",
                "param": "project_id",
                "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
              }
            }
          }
        }
      },
      "RateLimited": {
        "description": "Too many requests.",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/X-Request-Id"
          },
          "RateLimit-Limit": {
            "$ref": "#/components/headers/RateLimit-Limit"
          },
          "RateLimit-Remaining": {
            "$ref": "#/components/headers/RateLimit-Remaining"
          },
          "RateLimit-Reset": {
            "$ref": "#/components/headers/RateLimit-Reset"
          },
          "Retry-After": {
            "$ref": "#/components/headers/Retry-After"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "type": "rate_limit",
                "code": "rate_limited",
                "message": "Too many requests for this API key. Try again in 12 seconds.",
                "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
              }
            }
          }
        }
      },
      "InternalError": {
        "description": "Something went wrong on our side.",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/X-Request-Id"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "type": "api_error",
                "code": "internal_error",
                "message": "Something went wrong on our end. Please try again.",
                "request_id": "req_5f0c2a9e1b7d4c3a8e6f1d20"
              }
            }
          }
        }
      }
    }
  }
}
