{
  "openapi": "3.1.0",
  "info": {
    "title": "Drex API",
    "description": "Decision-model API by Nace.AI. Send a JSON `state` and a map of typed questions (`noul`, `choice`, `score`) and receive calibrated probabilities for each. Billed per input token. Authenticate with a `nace_sk_` API key from the dashboard.",
    "version": "1.0.0",
    "contact": {
      "name": "Nace.AI Support",
      "email": "support@nace.ai"
    }
  },
  "servers": [
    {
      "url": "https://console.nace.ai",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "Evaluate",
      "description": "Evaluate typed questions against a state."
    },
    {
      "name": "Models",
      "description": "List the models this API serves."
    },
    {
      "name": "Documents",
      "description": "Run NDI's perception tools (Parse, Split, Classify, Extract, Ground) on documents, billed from the same wallet as inference."
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "nace_sk_",
        "description": "Your API key from the dashboard's API Keys page: nace_sk_ followed by 43 URL-safe characters (A-Z, a-z, 0-9, _ and -), shown once when you create it. Send it as Authorization: Bearer nace_sk_... Any other value returns 401 authentication_error. An account can hold at most 3 active keys."
      }
    },
    "schemas": {
      "RequestId": {
        "type": "string",
        "pattern": "^req_[a-f0-9]{32}$",
        "description": "Identifier of this request, `req_` plus 32 hex characters. Also sent in the `x-request-id` header, and on `/v1/systemone` and `/v1/models` in `x-typesafe-request-id` too. Quote it in support requests.",
        "examples": ["req_bd2dffad68f5f5fa4ce702e9bd516fb4"]
      },
      "ParseIssue": {
        "type": "object",
        "title": "Issue",
        "description": "One validation problem. `path` is a dotted path into the request body, for example `questions.a.criteria`, or an empty string for the body as a whole.",
        "required": ["path", "message"],
        "additionalProperties": false,
        "properties": {
          "path": {
            "type": "string",
            "description": "Dotted path to the offending field. Empty for the whole body.",
            "examples": ["questions.a.instructions", "model", "state", ""]
          },
          "message": {
            "type": "string",
            "description": "What is wrong with the field.",
            "examples": ["must be a string", "is required"]
          }
        }
      },
      "ErrorBody": {
        "type": "object",
        "title": "Error",
        "required": ["type", "message"],
        "properties": {
          "type": {
            "type": "string",
            "description": "Error class. The HTTP status follows from it: `authentication_error` 401, `insufficient_credit` 402, `payment_required` 402, `invalid_request_error` 422, `rate_limit_error` 429, `internal_error` 500, `overloaded` 529.",
            "enum": [
              "authentication_error",
              "insufficient_credit",
              "payment_required",
              "invalid_request_error",
              "rate_limit_error",
              "overloaded",
              "internal_error"
            ]
          },
          "message": {
            "type": "string",
            "description": "Human-readable description. For `invalid_request_error` it is the first issue, written as `path: message`, or only the message when the issue has no path (such as a body that isn't JSON)."
          },
          "issues": {
            "type": "array",
            "description": "Present only when `type` is `invalid_request_error`. Every validation problem found in one pass.",
            "items": {
              "$ref": "#/components/schemas/ParseIssue"
            }
          }
        }
      },
      "ErrorEnvelope": {
        "type": "object",
        "title": "Error response",
        "description": "Every non-2xx response has this shape.",
        "required": ["error", "request_id"],
        "additionalProperties": false,
        "properties": {
          "error": {
            "$ref": "#/components/schemas/ErrorBody"
          },
          "request_id": {
            "$ref": "#/components/schemas/RequestId"
          }
        }
      },
      "JsonValue": {
        "title": "State",
        "description": "Any JSON value: string, number, boolean, null, object, or array. Drex passes it to the model as is. The key must be present, but `null` is accepted.",
        "examples": [
          "I was charged twice for my March invoice. Please refund one of the charges.",
          {
            "ticket_id": "T-1042",
            "plan": "enterprise",
            "messages": [
              {
                "from": "customer",
                "text": "Our SSO login has been broken since this morning and 40 people are locked out."
              }
            ]
          }
        ]
      },
      "NoulQuestion": {
        "type": "object",
        "title": "noul (yes or no)",
        "description": "A yes-or-no question. Needs a non-empty `instructions` string, or at least one non-empty entry in `criteria`, or both. Unknown keys are ignored.",
        "required": ["type"],
        "properties": {
          "type": {
            "const": "noul"
          },
          "instructions": {
            "type": "string",
            "description": "The question to answer about the state. Must be a string when present. `null` and objects are rejected with `must be a string`.",
            "examples": ["Is the customer asking for a refund?"]
          },
          "criteria": {
            "type": "object",
            "description": "What a yes and a no look like. Keys other than `true` and `false` are ignored.",
            "properties": {
              "true": {
                "type": ["string", "null"],
                "description": "Description of a yes answer.",
                "examples": ["Many users cannot use the product"]
              },
              "false": {
                "type": ["string", "null"],
                "description": "Description of a no answer.",
                "examples": ["A single user or a question"]
              }
            }
          }
        }
      },
      "ChoiceQuestion": {
        "type": "object",
        "title": "choice (pick one label)",
        "description": "Pick one label from `criteria`. Unknown keys are ignored.",
        "required": ["type", "criteria"],
        "properties": {
          "type": {
            "const": "choice"
          },
          "instructions": {
            "type": "string",
            "description": "The question to answer about the state. Must be a string when present.",
            "examples": ["What is this support ticket about?"]
          },
          "criteria": {
            "type": "object",
            "description": "Map of label to description. At least one label. A description may be `null`.",
            "minProperties": 1,
            "additionalProperties": {
              "type": ["string", "null"]
            },
            "examples": [
              {
                "billing": "Payments, invoices, refunds, or charges",
                "technical": "Bugs, errors, or outages",
                "account": "Login, profile, or permissions",
                "other": null
              }
            ]
          }
        }
      },
      "ScoreQuestion": {
        "type": "object",
        "title": "score (ordered levels)",
        "description": "Rate the state on an ordered scale. The index of a level in `criteria` is its score, starting at 0. Unknown keys are ignored.",
        "required": ["type", "criteria"],
        "properties": {
          "type": {
            "const": "score"
          },
          "instructions": {
            "type": "string",
            "description": "The question to answer about the state. Must be a string when present.",
            "examples": ["How upset is the customer?"]
          },
          "criteria": {
            "type": "array",
            "description": "Level labels in ascending order. At least one level. Every item must be a string.",
            "minItems": 1,
            "items": {
              "type": "string"
            },
            "examples": [["Calm", "Mildly annoyed", "Frustrated", "Angry"]]
          }
        }
      },
      "Question": {
        "title": "Question",
        "description": "One of three question types, chosen by `type`.",
        "oneOf": [
          {
            "$ref": "#/components/schemas/NoulQuestion"
          },
          {
            "$ref": "#/components/schemas/ChoiceQuestion"
          },
          {
            "$ref": "#/components/schemas/ScoreQuestion"
          }
        ],
        "discriminator": {
          "propertyName": "type",
          "mapping": {
            "noul": "#/components/schemas/NoulQuestion",
            "choice": "#/components/schemas/ChoiceQuestion",
            "score": "#/components/schemas/ScoreQuestion"
          }
        }
      },
      "SystemOneRequest": {
        "type": "object",
        "title": "Evaluate request",
        "description": "Unknown top-level keys are ignored.",
        "required": ["state", "questions"],
        "properties": {
          "state": {
            "$ref": "#/components/schemas/JsonValue"
          },
          "questions": {
            "type": "object",
            "minProperties": 1,
            "maxProperties": 512,
            "additionalProperties": {
              "$ref": "#/components/schemas/Question"
            },
            "description": "Map of question id to question. Ids must be non-empty and not whitespace only. At least 1 and at most 512 questions. `state` and `questions`, serialized together as JSON, must be at most 1048576 bytes. The state must fit the model's state limit, and the state plus the longest question must fit its row limit: 131,072 and 139,264 tokens for `drex-v1.5`, 32,768 and 32,768 for `drex-v1.0`. Text only: images, audio, video and PDFs (base64 data URLs, raw base64 files, or OpenAI, Anthropic and Gemini media content parts) anywhere in `state` or `questions` are rejected with a 422."
          },
          "model": {
            "type": "string",
            "pattern": "^(?:drex|nacedm)-[A-Za-z0-9.-]+$",
            "description": "Optional. A pinned version id, such as `drex-v1.0` or `drex-v1.5`, is always served by that version. The alias `drex-latest` is served by the version it points to, currently `drex-v1.5`; it moves to a newer version only on an announced date. `GET /v1/models` lists each alias with its `alias_for`. A retired id, such as `drex-v1.1`, is served by its successor, and the response `model` reports the successor; `GET /v1/models` lists it with `alias_for` set. A registered id that is not available yet returns `422` with issue path `model`. Any other `drex-*` name, or a legacy `nacedm-*` name, is served like `drex-latest`, as is a request without `model`. Any other value, including a TypeSafe SDK default such as `jev-latest`, returns `422` with issue path `model`.",
            "examples": ["drex-v1.0", "drex-v1.5", "drex-latest"]
          }
        }
      },
      "NoulAnswer": {
        "type": "object",
        "title": "noul answer",
        "required": ["type", "noul"],
        "additionalProperties": false,
        "properties": {
          "type": {
            "const": "noul"
          },
          "noul": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Probability of a yes answer, from zero to one.",
            "examples": [0.9868]
          }
        }
      },
      "ChoiceAnswer": {
        "type": "object",
        "title": "choice answer",
        "required": ["type", "choice", "confidence", "probabilities"],
        "additionalProperties": false,
        "properties": {
          "type": {
            "const": "choice"
          },
          "choice": {
            "type": "string",
            "description": "The selected label. One of the keys of the question's `criteria`.",
            "examples": ["billing"]
          },
          "confidence": {
            "type": "number",
            "description": "Average of the confidence (probability) scores the model produced for this answer. Tracks the top value in `probabilities` but is a different number.",
            "examples": [0.986]
          },
          "probabilities": {
            "type": "object",
            "description": "Probability per label, keyed by the labels of `criteria`.",
            "additionalProperties": {
              "type": "number"
            },
            "examples": [
              {
                "billing": 0.9895,
                "technical": 0.005,
                "account": 0.0006,
                "other": 0.0049
              }
            ]
          }
        }
      },
      "ScoreAnswer": {
        "type": "object",
        "title": "score answer",
        "required": ["type", "score", "legend", "probabilities", "confidence"],
        "additionalProperties": false,
        "properties": {
          "type": {
            "const": "score"
          },
          "score": {
            "type": "number",
            "description": "Expected score: the sum of each level's index times its probability. It can fall between two levels.",
            "examples": [1.5306]
          },
          "legend": {
            "type": "array",
            "description": "The level labels from the question's `criteria`, in order. Index is score.",
            "items": {
              "type": "string"
            },
            "examples": [["Calm", "Mildly annoyed", "Frustrated", "Angry"]]
          },
          "probabilities": {
            "type": "object",
            "description": "Probability per level, keyed by the level index as a string: `\"0\"` to `\"n-1\"`.",
            "additionalProperties": {
              "type": "number"
            },
            "examples": [
              {
                "0": 0.1572,
                "1": 0.3516,
                "2": 0.2946,
                "3": 0.1966
              }
            ]
          },
          "confidence": {
            "type": "number",
            "description": "Average of the confidence (probability) scores the model produced for this answer. Lower means the model was less sure.",
            "examples": [0.7183]
          }
        }
      },
      "Answer": {
        "title": "Answer",
        "description": "Shape follows the question's `type`.",
        "oneOf": [
          {
            "$ref": "#/components/schemas/NoulAnswer"
          },
          {
            "$ref": "#/components/schemas/ChoiceAnswer"
          },
          {
            "$ref": "#/components/schemas/ScoreAnswer"
          }
        ],
        "discriminator": {
          "propertyName": "type",
          "mapping": {
            "noul": "#/components/schemas/NoulAnswer",
            "choice": "#/components/schemas/ChoiceAnswer",
            "score": "#/components/schemas/ScoreAnswer"
          }
        }
      },
      "SystemOneResponse": {
        "type": "object",
        "title": "Evaluate response",
        "required": [
          "model",
          "answers",
          "usage",
          "evaluation_time_ms",
          "request_id"
        ],
        "additionalProperties": false,
        "properties": {
          "model": {
            "type": "string",
            "enum": ["drex-v1.0", "drex-v1.5"],
            "description": "The pinned version that served the request, never an alias or a retired id. It is the version `model` named, the successor of a retired id (`drex-v1.5` for `drex-v1.1`), or the version `drex-latest` points to (currently `drex-v1.5`) when `model` is `drex-latest`, is omitted, or is another `drex-*` or `nacedm-*` name. The request is billed at this version's price."
          },
          "answers": {
            "type": "object",
            "description": "One answer per question, under the same ids as the request's `questions`.",
            "additionalProperties": {
              "$ref": "#/components/schemas/Answer"
            }
          },
          "usage": {
            "type": "object",
            "description": "Token counts from the model service. Only `input_tokens` is billed.",
            "required": ["input_tokens", "output_tokens"],
            "additionalProperties": false,
            "properties": {
              "input_tokens": {
                "type": "integer",
                "minimum": 0,
                "description": "Tokens in `state` and `questions` as counted by the model. Billed at the per-token price on the Pricing page.",
                "examples": [106]
              },
              "output_tokens": {
                "type": "integer",
                "minimum": 0,
                "description": "Tokens the model produced. Not billed.",
                "examples": [212]
              }
            }
          },
          "evaluation_time_ms": {
            "type": "number",
            "description": "Time the model service spent on this request, in milliseconds. May be fractional. Excludes network time and Drex's own checks.",
            "examples": [142.6]
          },
          "request_id": {
            "$ref": "#/components/schemas/RequestId"
          }
        }
      },
      "Model": {
        "type": "object",
        "title": "Model",
        "required": ["name", "description", "release_date", "alias_for"],
        "additionalProperties": false,
        "properties": {
          "name": {
            "type": "string",
            "description": "Value to send as `model` in an evaluate request. A pinned version id, an alias such as `drex-latest`, or a retired id that a newer version now answers.",
            "examples": ["drex-v1.0", "drex-latest", "drex-v1.1"]
          },
          "description": {
            "type": "string"
          },
          "release_date": {
            "type": "string",
            "format": "date",
            "description": "Calendar date, `YYYY-MM-DD`. For an alias, the release date of the version it points to. For a retired id, its own release date."
          },
          "alias_for": {
            "type": ["string", "null"],
            "description": "For an alias or a retired id, the pinned version that serves and bills its requests; the description of a retired id starts with `Retired on`. `null` for a pinned version.",
            "examples": ["drex-v1.5", null]
          }
        }
      },
      "ModelsResponse": {
        "type": "object",
        "title": "Models response",
        "required": ["models", "request_id"],
        "additionalProperties": false,
        "properties": {
          "models": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Model"
            }
          },
          "request_id": {
            "$ref": "#/components/schemas/RequestId"
          }
        }
      },
      "DocumentJobFileLink": {
        "type": "object",
        "description": "A signed link to one stored file a job produced.",
        "required": ["url", "expires_at"],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Signed storage URL, fetched without your API key. Treat it as a temporary credential."
          },
          "expires_at": {
            "type": "integer",
            "description": "When the link stops working, as Unix epoch seconds."
          }
        }
      },
      "DocumentErrorBody": {
        "type": "object",
        "title": "Document error",
        "required": ["type", "code", "message", "retryable"],
        "properties": {
          "type": {
            "type": "string",
            "description": "Error class to branch on.",
            "enum": [
              "authentication_error",
              "insufficient_credit",
              "payment_required",
              "invalid_request_error",
              "not_found_error",
              "conflict_error",
              "rate_limit_error",
              "overloaded",
              "service_unavailable",
              "upstream_error",
              "internal_error"
            ]
          },
          "code": {
            "type": "string",
            "description": "The exact cause: Drex's own (`invalid_api_key`, `invalid_source`, `idempotency_conflict`, `document_billing_not_configured`, `job_pending`, `rate_limited`, `service_disabled`, `not_found`, ...) or, when the document service refused the request, its code (for example `invalid_request`, `unsupported_file_type`, `job_not_cancellable`, `result_expired`)."
          },
          "message": {
            "type": "string"
          },
          "retryable": {
            "type": "boolean",
            "description": "Whether the same request can succeed later. Retry creates with the same Idempotency-Key."
          },
          "detail": {
            "description": "Validation detail from the document service, when it has one."
          }
        }
      },
      "DocumentErrorEnvelope": {
        "type": "object",
        "title": "Document error response",
        "description": "Every non-2xx response from `/v1/documents/*` has this shape.",
        "required": ["error", "request_id"],
        "properties": {
          "error": {
            "$ref": "#/components/schemas/DocumentErrorBody"
          },
          "request_id": {
            "$ref": "#/components/schemas/RequestId"
          }
        }
      },
      "DocumentJob": {
        "type": "object",
        "title": "Document job",
        "description": "The document service's job, passed through unchanged except that links to the job's own artifacts point at `/v1/documents/jobs/{id}/...`. Its fields are those of the NDI `Job` (`job_id`, `kind`, `status`, `result`, `error`, `credits`, `usage_final`, timestamps, ...).",
        "required": ["job_id", "kind", "status"],
        "additionalProperties": true,
        "properties": {
          "job_id": {
            "type": "string",
            "format": "uuid"
          },
          "kind": {
            "type": "string",
            "enum": ["parse", "split", "classify", "extract", "ground"]
          },
          "status": {
            "type": "string",
            "enum": ["queued", "running", "succeeded", "failed", "cancelled"]
          },
          "result": {
            "description": "The operation's result. Usually present once `status` is `succeeded`. Never on the items of `GET /v1/documents/jobs`. Classify may include a `result` while still `running`, with optional `reason_status` (`pending`, `complete`, `failed`, `not_requested`). Absent `reason_status` is the older complete payload. When labels were published before the reason, the classify result may include `labels_at` (ISO 8601 UTC, NDI's clock). Null or absent when labels and the reason arrived together."
          },
          "credits": {
            "type": ["integer", "null"],
            "description": "Credits the job used; final once `usage_final` is true. Drex charges `credits` times the operation's price once."
          },
          "usage_final": {
            "type": "boolean"
          }
        }
      },
      "DocumentJobList": {
        "type": "object",
        "required": ["items", "next_cursor"],
        "properties": {
          "items": {
            "type": "array",
            "description": "The account's jobs, newest first, without `result`.",
            "items": {
              "$ref": "#/components/schemas/DocumentJob"
            }
          },
          "next_cursor": {
            "type": ["string", "null"],
            "description": "Pass as `cursor` for the next page; null on the last page."
          }
        }
      },
      "ExtractionSchema": {
        "type": "object",
        "required": [
          "schema_id",
          "name",
          "version",
          "owner",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "schema_id": {
            "type": "string",
            "description": "Stable id of the schema across its versions (`sch_...`)."
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": ["string", "null"]
          },
          "version": {
            "type": "integer",
            "minimum": 1
          },
          "owner": {
            "type": "string",
            "enum": ["account", "platform"],
            "description": "`account` for a schema this account saved."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "schema": {
            "type": "object",
            "additionalProperties": true,
            "description": "The version's JSON Schema. Always present on a single schema, a version and a list of versions; `GET /v1/extraction-schemas` leaves it out."
          }
        }
      },
      "ExtractionSchemaList": {
        "type": "object",
        "required": ["items", "next_cursor"],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ExtractionSchema"
            }
          },
          "next_cursor": {
            "type": ["string", "null"],
            "description": "Pass as `cursor` for the next page. `null` once a page holds fewer than `limit` items; a full last page still has one, and the page after it is empty."
          },
          "total_count": {
            "type": "integer",
            "minimum": 0
          }
        }
      }
    },
    "headers": {
      "X-Request-Id": {
        "description": "The request id. When the body has a `request_id` (every error, and every `/v1/systemone` and `/v1/models` response), it is the same value.",
        "schema": {
          "$ref": "#/components/schemas/RequestId"
        }
      },
      "X-Typesafe-Request-Id": {
        "description": "The same request id, under the header name TypeSafe SDK clients read.",
        "schema": {
          "$ref": "#/components/schemas/RequestId"
        }
      },
      "Access-Control-Expose-Headers": {
        "description": "Always `retry-after, retry-after-ms, x-request-id, x-typesafe-request-id`, so browser clients can read those headers.",
        "schema": {
          "type": "string"
        }
      },
      "Retry-After": {
        "description": "Whole seconds to wait before retrying: `retry-after-ms` divided by 1000 and rounded up.",
        "schema": {
          "type": "integer",
          "minimum": 1
        }
      },
      "Retry-After-Ms": {
        "description": "Milliseconds to wait before retrying. 1000 for a concurrency limit, the time until the window frees up (never below 1000) for a per-minute limit, 2000 for capacity or a model-service failure, 30000 when the API is paused.",
        "schema": {
          "type": "integer",
          "minimum": 1000
        }
      },
      "Server-Timing": {
        "description": "Per-phase timings for a successful evaluation, for example `auth;dur=1.2, limit;dur=3.4, ndm;dur=140.1`.",
        "schema": {
          "type": "string"
        }
      },
      "X-Drex-Document-Job": {
        "description": "Drex's internal id for the billed document job. Quote it in support requests about a charge.",
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "The `Authorization` header is missing, is not `Bearer nace_sk_...` with 43 URL-safe characters, or names a key that does not exist or was revoked.",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/X-Request-Id"
          },
          "x-typesafe-request-id": {
            "$ref": "#/components/headers/X-Typesafe-Request-Id"
          },
          "access-control-expose-headers": {
            "$ref": "#/components/headers/Access-Control-Expose-Headers"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "invalid_key": {
                "summary": "Missing or invalid key (real capture)",
                "value": {
                  "error": {
                    "type": "authentication_error",
                    "message": "Invalid API key. Pass a nace_sk_ key as `Authorization: Bearer <key>`."
                  },
                  "request_id": "req_bd2dffad68f5f5fa4ce702e9bd516fb4"
                }
              }
            }
          }
        }
      },
      "PaymentRequired": {
        "description": "The account has no spendable credit (`insufficient_credit`) or an unpaid invoice (`payment_required`). Top up or pay the invoice on the dashboard Billing page. `GET /v1/models` does not return this.",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/X-Request-Id"
          },
          "x-typesafe-request-id": {
            "$ref": "#/components/headers/X-Typesafe-Request-Id"
          },
          "access-control-expose-headers": {
            "$ref": "#/components/headers/Access-Control-Expose-Headers"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "no_credit": {
                "summary": "No spendable credit",
                "value": {
                  "error": {
                    "type": "insufficient_credit",
                    "message": "This account has no spendable credit. Top up to keep going."
                  },
                  "request_id": "req_0123456789abcdef0123456789abcdef"
                }
              },
              "unpaid_invoice": {
                "summary": "Unpaid invoice",
                "value": {
                  "error": {
                    "type": "payment_required",
                    "message": "This account has an unpaid invoice. Pay it on the Billing page to keep going."
                  },
                  "request_id": "req_0123456789abcdef0123456789abcdef"
                }
              }
            }
          }
        }
      },
      "UnprocessableEntity": {
        "description": "The body is not JSON, fails validation, is over the byte limit, or is over the model's token limit. `error.issues` lists every problem. The request is not billed.",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/X-Request-Id"
          },
          "x-typesafe-request-id": {
            "$ref": "#/components/headers/X-Typesafe-Request-Id"
          },
          "access-control-expose-headers": {
            "$ref": "#/components/headers/Access-Control-Expose-Headers"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "wrong_model": {
                "summary": "TypeSafe default model",
                "value": {
                  "error": {
                    "type": "invalid_request_error",
                    "message": "model: unknown model \"jev-latest\"; use \"drex-v1.0\", \"drex-v1.5\" or \"drex-latest\"",
                    "issues": [
                      {
                        "path": "model",
                        "message": "unknown model \"jev-latest\"; use \"drex-v1.0\", \"drex-v1.5\" or \"drex-latest\""
                      }
                    ]
                  },
                  "request_id": "req_0123456789abcdef0123456789abcdef"
                }
              },
              "two_issues": {
                "summary": "instructions was an object",
                "value": {
                  "error": {
                    "type": "invalid_request_error",
                    "message": "questions.a.instructions: must be a string",
                    "issues": [
                      {
                        "path": "questions.a.instructions",
                        "message": "must be a string"
                      },
                      {
                        "path": "questions.a.instructions",
                        "message": "noul needs instructions or criteria"
                      }
                    ]
                  },
                  "request_id": "req_0123456789abcdef0123456789abcdef"
                }
              },
              "too_many_bytes": {
                "summary": "Over the byte limit",
                "value": {
                  "error": {
                    "type": "invalid_request_error",
                    "message": "request body must be at most 1048576 bytes",
                    "issues": [
                      {
                        "path": "",
                        "message": "request body must be at most 1048576 bytes"
                      }
                    ]
                  },
                  "request_id": "req_0123456789abcdef0123456789abcdef"
                }
              },
              "too_many_tokens": {
                "summary": "Over the model row limit",
                "value": {
                  "error": {
                    "type": "invalid_request_error",
                    "message": "Request too long: the state plus its longest question exceed the 139,264-token limit of drex-v1.5. Shorten the state or that question.",
                    "issues": [
                      {
                        "path": "state",
                        "message": "exceeds the 139,264-token limit"
                      }
                    ]
                  },
                  "request_id": "req_0123456789abcdef0123456789abcdef"
                }
              },
              "state_too_long": {
                "summary": "Over the model state limit",
                "value": {
                  "error": {
                    "type": "invalid_request_error",
                    "message": "Request too long: the state exceeds the 131,072-token state limit of drex-v1.5. Shorten the state.",
                    "issues": [
                      {
                        "path": "state",
                        "message": "exceeds the 131,072-token state limit"
                      }
                    ]
                  },
                  "request_id": "req_0123456789abcdef0123456789abcdef"
                }
              }
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "The account is over its requests-per-minute or in-flight limit. Limits are per account and shared by all its keys and the Playground. Wait `retry-after-ms` and retry.",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/X-Request-Id"
          },
          "x-typesafe-request-id": {
            "$ref": "#/components/headers/X-Typesafe-Request-Id"
          },
          "access-control-expose-headers": {
            "$ref": "#/components/headers/Access-Control-Expose-Headers"
          },
          "retry-after": {
            "$ref": "#/components/headers/Retry-After"
          },
          "retry-after-ms": {
            "$ref": "#/components/headers/Retry-After-Ms"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "rpm": {
                "summary": "Requests per minute",
                "value": {
                  "error": {
                    "type": "rate_limit_error",
                    "message": "Requests per minute exceeded for this account."
                  },
                  "request_id": "req_0123456789abcdef0123456789abcdef"
                }
              },
              "concurrency": {
                "summary": "Too many in flight",
                "value": {
                  "error": {
                    "type": "rate_limit_error",
                    "message": "Too many concurrent requests for this account."
                  },
                  "request_id": "req_0123456789abcdef0123456789abcdef"
                }
              }
            }
          }
        }
      },
      "InternalError": {
        "description": "An unexpected failure inside Drex. Retry once, then contact support with the `request_id`. The request is not billed.",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/X-Request-Id"
          },
          "x-typesafe-request-id": {
            "$ref": "#/components/headers/X-Typesafe-Request-Id"
          },
          "access-control-expose-headers": {
            "$ref": "#/components/headers/Access-Control-Expose-Headers"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "exception": {
                "summary": "Unhandled exception",
                "value": {
                  "error": {
                    "type": "internal_error",
                    "message": "Something went wrong on our side."
                  },
                  "request_id": "req_0123456789abcdef0123456789abcdef"
                }
              }
            }
          }
        }
      },
      "Overloaded": {
        "description": "Not caused by the request. The API is paused, a shared capacity pool is full, the rate limiter is unreachable, or the model service did not answer. The response never includes upstream status or detail. Wait `retry-after-ms` and retry the same request.",
        "headers": {
          "x-request-id": {
            "$ref": "#/components/headers/X-Request-Id"
          },
          "x-typesafe-request-id": {
            "$ref": "#/components/headers/X-Typesafe-Request-Id"
          },
          "access-control-expose-headers": {
            "$ref": "#/components/headers/Access-Control-Expose-Headers"
          },
          "retry-after": {
            "$ref": "#/components/headers/Retry-After"
          },
          "retry-after-ms": {
            "$ref": "#/components/headers/Retry-After-Ms"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "paused": {
                "summary": "API paused (retry-after-ms 30000)",
                "value": {
                  "error": {
                    "type": "overloaded",
                    "message": "Drex is temporarily unavailable. Retry after 30 seconds."
                  },
                  "request_id": "req_0123456789abcdef0123456789abcdef"
                }
              },
              "capacity": {
                "summary": "Shared pool full or limiter unreachable (retry-after-ms 2000)",
                "value": {
                  "error": {
                    "type": "overloaded",
                    "message": "Drex is at capacity. Retry shortly."
                  },
                  "request_id": "req_0123456789abcdef0123456789abcdef"
                }
              },
              "upstream": {
                "summary": "Model service timeout or failure (retry-after-ms 2000)",
                "value": {
                  "error": {
                    "type": "overloaded",
                    "message": "Drex is temporarily unavailable. Retry shortly."
                  },
                  "request_id": "req_0123456789abcdef0123456789abcdef"
                }
              }
            }
          }
        }
      }
    }
  },
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/v1/systemone": {
      "post": {
        "operationId": "systemOne",
        "tags": ["Evaluate"],
        "summary": "Evaluate questions",
        "description": "Send any JSON `state` and one to 512 typed questions. Each question gets an answer with calibrated probabilities under the same id.\n\n- **Billing:** only a `200` is billed, at the per-input-token price.\n- **Unknown keys:** top-level keys Drex doesn't know are ignored.\n\nChecks run in this order and stop at the first failure:\n\n1. API pause (`529`)\n2. Key and credit (`401`, `402`)\n3. Rate limits (`429`, `529`)\n4. Body validation (`422`)\n5. Model evaluation (`422` for too many tokens, `529` when the model service does not answer within 55 seconds)",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SystemOneRequest"
              },
              "examples": {
                "support_ticket": {
                  "summary": "Three question types on one support ticket",
                  "value": {
                    "model": "drex-v1.0",
                    "state": "I was charged twice for my March invoice. Please refund one of the charges.",
                    "questions": {
                      "category": {
                        "type": "choice",
                        "instructions": "What is this support ticket about?",
                        "criteria": {
                          "billing": "Payments, invoices, refunds, or charges",
                          "technical": "Bugs, errors, or outages",
                          "account": "Login, profile, or permissions",
                          "other": null
                        }
                      },
                      "sentiment": {
                        "type": "score",
                        "instructions": "How upset is the customer?",
                        "criteria": [
                          "Calm",
                          "Mildly annoyed",
                          "Frustrated",
                          "Angry"
                        ]
                      },
                      "wants_refund": {
                        "type": "noul",
                        "instructions": "Is the customer asking for a refund?"
                      }
                    }
                  }
                },
                "json_state": {
                  "summary": "Object state with noul criteria",
                  "value": {
                    "state": {
                      "ticket_id": "T-1042",
                      "plan": "enterprise",
                      "messages": [
                        {
                          "from": "customer",
                          "text": "Our SSO login has been broken since this morning and 40 people are locked out."
                        }
                      ]
                    },
                    "questions": {
                      "is_outage": {
                        "type": "noul",
                        "instructions": "Does this describe a service outage?",
                        "criteria": {
                          "true": "Many users cannot use the product",
                          "false": "A single user or a question"
                        }
                      },
                      "priority": {
                        "type": "choice",
                        "instructions": "Which priority should this ticket get?",
                        "criteria": {
                          "p0": "Production down for many users",
                          "p1": "Major feature broken",
                          "p2": "Minor issue",
                          "p3": "Question or request"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Every question answered. `usage.input_tokens` is debited from the account's credit after the response is sent.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "x-typesafe-request-id": {
                "$ref": "#/components/headers/X-Typesafe-Request-Id"
              },
              "access-control-expose-headers": {
                "$ref": "#/components/headers/Access-Control-Expose-Headers"
              },
              "server-timing": {
                "$ref": "#/components/headers/Server-Timing"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SystemOneResponse"
                },
                "examples": {
                  "support_ticket": {
                    "summary": "Answers for the support ticket example (real capture)",
                    "value": {
                      "model": "drex-v1.0",
                      "answers": {
                        "category": {
                          "type": "choice",
                          "choice": "billing",
                          "confidence": 0.986,
                          "probabilities": {
                            "billing": 0.9895,
                            "technical": 0.005,
                            "account": 0.0006,
                            "other": 0.0049
                          }
                        },
                        "sentiment": {
                          "type": "score",
                          "score": 1.5306,
                          "legend": [
                            "Calm",
                            "Mildly annoyed",
                            "Frustrated",
                            "Angry"
                          ],
                          "probabilities": {
                            "0": 0.1572,
                            "1": 0.3516,
                            "2": 0.2946,
                            "3": 0.1966
                          },
                          "confidence": 0.7183
                        },
                        "wants_refund": {
                          "type": "noul",
                          "noul": 0.9868
                        }
                      },
                      "usage": {
                        "input_tokens": 106,
                        "output_tokens": 212
                      },
                      "evaluation_time_ms": 142.6,
                      "request_id": "req_0123456789abcdef0123456789abcdef"
                    }
                  },
                  "json_state": {
                    "summary": "Answers for the object-state example (real capture)",
                    "value": {
                      "model": "drex-v1.0",
                      "answers": {
                        "is_outage": {
                          "type": "noul",
                          "noul": 0.7632
                        },
                        "priority": {
                          "type": "choice",
                          "choice": "p0",
                          "confidence": 0.8621,
                          "probabilities": {
                            "p0": 0.8966,
                            "p1": 0.1007,
                            "p2": 0.0021,
                            "p3": 0.0007
                          }
                        }
                      },
                      "usage": {
                        "input_tokens": 103,
                        "output_tokens": 103
                      },
                      "evaluation_time_ms": 133,
                      "request_id": "req_0123456789abcdef0123456789abcdef"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "529": {
            "$ref": "#/components/responses/Overloaded"
          }
        }
      }
    },
    "/v1/models": {
      "get": {
        "operationId": "listModels",
        "tags": ["Models"],
        "summary": "List models",
        "description": "Returns the models this API serves. Requires a valid API key. Does not check credit, so it works while the account is at zero, and does not count toward rate limits.",
        "responses": {
          "200": {
            "description": "The model list.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "x-typesafe-request-id": {
                "$ref": "#/components/headers/X-Typesafe-Request-Id"
              },
              "access-control-expose-headers": {
                "$ref": "#/components/headers/Access-Control-Expose-Headers"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ModelsResponse"
                },
                "examples": {
                  "models": {
                    "summary": "Current catalog",
                    "value": {
                      "models": [
                        {
                          "name": "drex-v1.0",
                          "description": "Drex System One decision model. Typed questions in, calibrated probabilities out.",
                          "release_date": "2026-09-24",
                          "alias_for": null
                        },
                        {
                          "name": "drex-v1.5",
                          "description": "Drex 1.5 decision model. Typed questions in, calibrated probabilities out; states up to 131,072 tokens.",
                          "release_date": "2026-09-28",
                          "alias_for": null
                        },
                        {
                          "name": "drex-latest",
                          "description": "Points to drex-v1.5 (Drex 1.5). Moves to a newer version only on an announced date.",
                          "release_date": "2026-09-28",
                          "alias_for": "drex-v1.5"
                        },
                        {
                          "name": "drex-v1.1",
                          "description": "Retired on 2026-09-28. Requests that name it are served by drex-v1.5 (Drex 1.5) at its price.",
                          "release_date": "2026-09-25",
                          "alias_for": "drex-v1.5"
                        }
                      ],
                      "request_id": "req_0123456789abcdef0123456789abcdef"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "529": {
            "$ref": "#/components/responses/Overloaded"
          }
        }
      }
    },
    "/v1/documents/parse": {
      "post": {
        "operationId": "documentsParse",
        "tags": ["Documents"],
        "summary": "Parse a document",
        "description": "Converts a document to Markdown, text or layout blocks.\n\n- **Body:** the document service's request for this operation. [Parse](/docs/ndi/parse) lists its options and result.\n- **`source`:** a `url`, a `parse_result` of one of your own jobs, or a `workspace_file` in your own workspace. Upload one with `POST /v1/documents/upload-grants`.\n- **Billing:** admitted only while the account's balance is positive. The job's final credits are charged once, when it finishes.\n- **Retries:** the same `Idempotency-Key` with the same body returns the same job. With a different body, it answers `409`.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Up to 200 characters, unique per account. Retry with the same key and body to get the same job instead of a second one.",
            "schema": {
              "type": "string",
              "maxLength": 200
            }
          },
          {
            "name": "wait_seconds",
            "in": "query",
            "required": false,
            "description": "Hold the request open until the job finishes, up to this many seconds. `0` (default) returns at once; a value above 60 waits 60.",
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["source"],
                "additionalProperties": true,
                "properties": {
                  "source": {
                    "description": "`{\"type\":\"url\",\"url\":\"https://...\",\"file_name\":\"a.pdf\"}`, `{\"type\":\"parse_result\",\"job_id\":\"...\"}` or `{\"type\":\"workspace_file\",\"workspace_id\":\"...\",\"file_id\":\"...\"}`.",
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The job finished within `wait_seconds`, or this is a replay of its Idempotency-Key.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "x-drex-document-job": {
                "$ref": "#/components/headers/X-Drex-Document-Job"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentJob"
                }
              }
            }
          },
          "202": {
            "description": "The job was created and is running. Poll `GET /v1/documents/jobs/{id}`.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "x-drex-document-job": {
                "$ref": "#/components/headers/X-Drex-Document-Job"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentJob"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key (`authentication_error`, code `invalid_api_key`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "402": {
            "description": "The account has no spendable credit (`insufficient_credit`) or an unpaid invoice (`payment_required`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "409": {
            "description": "The Idempotency-Key was already used for a different request (`conflict_error`, code `idempotency_conflict`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "413": {
            "description": "The request body is over 1,000,000 bytes (`invalid_request_error`, code `payload_too_large`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "422": {
            "description": "The body is not valid JSON, names a source the account doesn't own (code `invalid_source`), or the document service refused it (`invalid_request_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Over the account's requests per minute for document routes, or the document service is throttling this account (`rate_limit_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "description": "Something failed on Drex's side (`internal_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "The document service refused Drex's own request (`upstream_error`, code `ndi_refused_drex`). Retry later.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "503": {
            "description": "Document billing is not configured (code `document_billing_not_configured`), the job is not confirmed yet (code `job_pending`; retry with the same key), or the document service is unavailable.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "504": {
            "description": "The document service timed out (`upstream_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "529": {
            "description": "The public API is paused (code `service_disabled`) or Drex's rate limiter is unreachable (code `limiter_unavailable`) (`overloaded`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/v1/documents/split": {
      "post": {
        "operationId": "documentsSplit",
        "tags": ["Documents"],
        "summary": "Split a document",
        "description": "Splits a multi-document file into the documents it contains, by your classes.\n\n- **Body:** the document service's request for this operation. [Split](/docs/ndi/split) lists its options and result.\n- **`source`:** a `url`, a `parse_result` of one of your own jobs, or a `workspace_file` in your own workspace. Upload one with `POST /v1/documents/upload-grants`.\n- **Billing:** admitted only while the account's balance is positive. The job's final credits are charged once, when it finishes.\n- **Retries:** the same `Idempotency-Key` with the same body returns the same job. With a different body, it answers `409`.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Up to 200 characters, unique per account. Retry with the same key and body to get the same job instead of a second one.",
            "schema": {
              "type": "string",
              "maxLength": 200
            }
          },
          {
            "name": "wait_seconds",
            "in": "query",
            "required": false,
            "description": "Hold the request open until the job finishes, up to this many seconds. `0` (default) returns at once; a value above 60 waits 60.",
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["source"],
                "additionalProperties": true,
                "properties": {
                  "source": {
                    "description": "`{\"type\":\"url\",\"url\":\"https://...\",\"file_name\":\"a.pdf\"}`, `{\"type\":\"parse_result\",\"job_id\":\"...\"}` or `{\"type\":\"workspace_file\",\"workspace_id\":\"...\",\"file_id\":\"...\"}`.",
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The job finished within `wait_seconds`, or this is a replay of its Idempotency-Key.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "x-drex-document-job": {
                "$ref": "#/components/headers/X-Drex-Document-Job"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentJob"
                }
              }
            }
          },
          "202": {
            "description": "The job was created and is running. Poll `GET /v1/documents/jobs/{id}`.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "x-drex-document-job": {
                "$ref": "#/components/headers/X-Drex-Document-Job"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentJob"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key (`authentication_error`, code `invalid_api_key`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "402": {
            "description": "The account has no spendable credit (`insufficient_credit`) or an unpaid invoice (`payment_required`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "409": {
            "description": "The Idempotency-Key was already used for a different request (`conflict_error`, code `idempotency_conflict`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "413": {
            "description": "The request body is over 1,000,000 bytes (`invalid_request_error`, code `payload_too_large`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "422": {
            "description": "The body is not valid JSON, names a source the account doesn't own (code `invalid_source`), or the document service refused it (`invalid_request_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Over the account's requests per minute for document routes, or the document service is throttling this account (`rate_limit_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "description": "Something failed on Drex's side (`internal_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "The document service refused Drex's own request (`upstream_error`, code `ndi_refused_drex`). Retry later.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "503": {
            "description": "Document billing is not configured (code `document_billing_not_configured`), the job is not confirmed yet (code `job_pending`; retry with the same key), or the document service is unavailable.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "504": {
            "description": "The document service timed out (`upstream_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "529": {
            "description": "The public API is paused (code `service_disabled`) or Drex's rate limiter is unreachable (code `limiter_unavailable`) (`overloaded`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/v1/documents/classify": {
      "post": {
        "operationId": "documentsClassify",
        "tags": ["Documents"],
        "summary": "Classify a document",
        "description": "Classifies a document, or each page, into your classes.\n\n- **Body:** the document service's request for this operation. [Classify](/docs/ndi/classify) lists its options and result.\n- **`source`:** a `url`, or a `workspace_file` in your own workspace. Classify reads the original file, so a `parse_result` source answers `422`. Upload one with `POST /v1/documents/upload-grants`.\n- **Billing:** admitted only while the account's balance is positive. The job's final credits are charged once, when it finishes.\n- **Retries:** the same `Idempotency-Key` with the same body returns the same job. With a different body, it answers `409`.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Up to 200 characters, unique per account. Retry with the same key and body to get the same job instead of a second one.",
            "schema": {
              "type": "string",
              "maxLength": 200
            }
          },
          {
            "name": "wait_seconds",
            "in": "query",
            "required": false,
            "description": "Hold the request open until the job finishes, up to this many seconds. `0` (default) returns at once; a value above 60 waits 60.",
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["source"],
                "additionalProperties": true,
                "properties": {
                  "source": {
                    "description": "`{\"type\":\"url\",\"url\":\"https://...\",\"file_name\":\"a.pdf\"}` or `{\"type\":\"workspace_file\",\"workspace_id\":\"...\",\"file_id\":\"...\"}`. Classify reads the original file, so it doesn't take a `parse_result` source (`422`).",
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The job finished within `wait_seconds`, or this is a replay of its Idempotency-Key.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "x-drex-document-job": {
                "$ref": "#/components/headers/X-Drex-Document-Job"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentJob"
                }
              }
            }
          },
          "202": {
            "description": "The job was created and is running. Poll `GET /v1/documents/jobs/{id}`.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "x-drex-document-job": {
                "$ref": "#/components/headers/X-Drex-Document-Job"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentJob"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key (`authentication_error`, code `invalid_api_key`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "402": {
            "description": "The account has no spendable credit (`insufficient_credit`) or an unpaid invoice (`payment_required`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "409": {
            "description": "The Idempotency-Key was already used for a different request (`conflict_error`, code `idempotency_conflict`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "413": {
            "description": "The request body is over 1,000,000 bytes (`invalid_request_error`, code `payload_too_large`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "422": {
            "description": "The body is not valid JSON, names a source the account doesn't own (code `invalid_source`), or the document service refused it (`invalid_request_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Over the account's requests per minute for document routes, or the document service is throttling this account (`rate_limit_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "description": "Something failed on Drex's side (`internal_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "The document service refused Drex's own request (`upstream_error`, code `ndi_refused_drex`). Retry later.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "503": {
            "description": "Document billing is not configured (code `document_billing_not_configured`), the job is not confirmed yet (code `job_pending`; retry with the same key), or the document service is unavailable.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "504": {
            "description": "The document service timed out (`upstream_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "529": {
            "description": "The public API is paused (code `service_disabled`) or Drex's rate limiter is unreachable (code `limiter_unavailable`) (`overloaded`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/v1/documents/extract": {
      "post": {
        "operationId": "documentsExtract",
        "tags": ["Documents"],
        "summary": "Extract fields",
        "description": "Extracts structured fields from a document with a JSON schema.\n\n- **Schema:** send it inline as `schema`, or save it with `POST /v1/extraction-schemas` and name it with `schema_id`. Add `schema_version` to pin one version.\n- **Body:** the document service's request for this operation. [Extract](/docs/ndi/extract) lists its options and result.\n- **`source`:** a `url`, a `parse_result` of one of your own jobs, or a `workspace_file` in your own workspace. Upload one with `POST /v1/documents/upload-grants`.\n- **Billing:** admitted only while the account's balance is positive. The job's final credits are charged once, when it finishes.\n- **Retries:** the same `Idempotency-Key` with the same body returns the same job. With a different body, it answers `409`.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Up to 200 characters, unique per account. Retry with the same key and body to get the same job instead of a second one.",
            "schema": {
              "type": "string",
              "maxLength": 200
            }
          },
          {
            "name": "wait_seconds",
            "in": "query",
            "required": false,
            "description": "Hold the request open until the job finishes, up to this many seconds. `0` (default) returns at once; a value above 60 waits 60.",
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["source"],
                "additionalProperties": true,
                "properties": {
                  "source": {
                    "description": "`{\"type\":\"url\",\"url\":\"https://...\",\"file_name\":\"a.pdf\"}`, `{\"type\":\"parse_result\",\"job_id\":\"...\"}` or `{\"type\":\"workspace_file\",\"workspace_id\":\"...\",\"file_id\":\"...\"}`.",
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The job finished within `wait_seconds`, or this is a replay of its Idempotency-Key.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "x-drex-document-job": {
                "$ref": "#/components/headers/X-Drex-Document-Job"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentJob"
                }
              }
            }
          },
          "202": {
            "description": "The job was created and is running. Poll `GET /v1/documents/jobs/{id}`.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "x-drex-document-job": {
                "$ref": "#/components/headers/X-Drex-Document-Job"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentJob"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key (`authentication_error`, code `invalid_api_key`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "402": {
            "description": "The account has no spendable credit (`insufficient_credit`) or an unpaid invoice (`payment_required`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "409": {
            "description": "The Idempotency-Key was already used for a different request (`conflict_error`, code `idempotency_conflict`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "413": {
            "description": "The request body is over 1,000,000 bytes (`invalid_request_error`, code `payload_too_large`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "422": {
            "description": "The body is not valid JSON, names a source the account doesn't own (code `invalid_source`), or the document service refused it (`invalid_request_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Over the account's requests per minute for document routes, or the document service is throttling this account (`rate_limit_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "description": "Something failed on Drex's side (`internal_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "The document service refused Drex's own request (`upstream_error`, code `ndi_refused_drex`). Retry later.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "503": {
            "description": "Document billing is not configured (code `document_billing_not_configured`), the job is not confirmed yet (code `job_pending`; retry with the same key), or the document service is unavailable.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "504": {
            "description": "The document service timed out (`upstream_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "529": {
            "description": "The public API is paused (code `service_disabled`) or Drex's rate limiter is unreachable (code `limiter_unavailable`) (`overloaded`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/v1/documents/ground": {
      "post": {
        "operationId": "documentsGround",
        "tags": ["Documents"],
        "summary": "Ground claims",
        "description": "Finds where each of your claims or targets appears in a document.\n\n- **Body:** the document service's request for this operation. [Ground](/docs/ndi/ground) lists its options and result.\n- **`source`:** a `url`, a `parse_result` of one of your own jobs, or a `workspace_file` in your own workspace. Upload one with `POST /v1/documents/upload-grants`.\n- **Billing:** admitted only while the account's balance is positive. The job's final credits are charged once, when it finishes.\n- **Retries:** the same `Idempotency-Key` with the same body returns the same job. With a different body, it answers `409`.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Up to 200 characters, unique per account. Retry with the same key and body to get the same job instead of a second one.",
            "schema": {
              "type": "string",
              "maxLength": 200
            }
          },
          {
            "name": "wait_seconds",
            "in": "query",
            "required": false,
            "description": "Hold the request open until the job finishes, up to this many seconds. `0` (default) returns at once; a value above 60 waits 60.",
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["source"],
                "additionalProperties": true,
                "properties": {
                  "source": {
                    "description": "`{\"type\":\"url\",\"url\":\"https://...\",\"file_name\":\"a.pdf\"}`, `{\"type\":\"parse_result\",\"job_id\":\"...\"}` or `{\"type\":\"workspace_file\",\"workspace_id\":\"...\",\"file_id\":\"...\"}`.",
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The job finished within `wait_seconds`, or this is a replay of its Idempotency-Key.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "x-drex-document-job": {
                "$ref": "#/components/headers/X-Drex-Document-Job"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentJob"
                }
              }
            }
          },
          "202": {
            "description": "The job was created and is running. Poll `GET /v1/documents/jobs/{id}`.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "x-drex-document-job": {
                "$ref": "#/components/headers/X-Drex-Document-Job"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentJob"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key (`authentication_error`, code `invalid_api_key`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "402": {
            "description": "The account has no spendable credit (`insufficient_credit`) or an unpaid invoice (`payment_required`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "409": {
            "description": "The Idempotency-Key was already used for a different request (`conflict_error`, code `idempotency_conflict`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "413": {
            "description": "The request body is over 1,000,000 bytes (`invalid_request_error`, code `payload_too_large`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "422": {
            "description": "The body is not valid JSON, names a source the account doesn't own (code `invalid_source`), or the document service refused it (`invalid_request_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Over the account's requests per minute for document routes, or the document service is throttling this account (`rate_limit_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "description": "Something failed on Drex's side (`internal_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "The document service refused Drex's own request (`upstream_error`, code `ndi_refused_drex`). Retry later.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "503": {
            "description": "Document billing is not configured (code `document_billing_not_configured`), the job is not confirmed yet (code `job_pending`; retry with the same key), or the document service is unavailable.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "504": {
            "description": "The document service timed out (`upstream_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "529": {
            "description": "The public API is paused (code `service_disabled`) or Drex's rate limiter is unreachable (code `limiter_unavailable`) (`overloaded`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/v1/documents/jobs": {
      "get": {
        "operationId": "listDocumentJobs",
        "tags": ["Documents"],
        "summary": "List document jobs",
        "description": "The account's own jobs, newest first by when Drex received each request. `created_at` is when the job started, so jobs sent within a moment of each other can list a little out of `created_at` order. Readable at any balance. A job you deleted is not listed.",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 20
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "`next_cursor` from the previous page.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "operation",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": ["parse", "split", "classify", "extract", "ground"]
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Filters on the job status Drex last recorded; a job that has moved on since is left off the page.",
            "schema": {
              "type": "string",
              "enum": ["queued", "running", "succeeded", "failed", "cancelled"]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of jobs.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentJobList"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key (`authentication_error`, code `invalid_api_key`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "422": {
            "description": "A query parameter is invalid (`invalid_request_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Over the account's requests per minute for document routes, or the document service is throttling this account (`rate_limit_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "description": "Something failed on Drex's side (`internal_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "The document service refused Drex's own request (`upstream_error`, code `ndi_refused_drex`). Retry later.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "503": {
            "description": "The document service is unavailable (`service_unavailable`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "504": {
            "description": "The document service timed out (`upstream_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "529": {
            "description": "The public API is paused (code `service_disabled`) or Drex's rate limiter is unreachable (code `limiter_unavailable`) (`overloaded`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/v1/documents/jobs/{id}": {
      "get": {
        "operationId": "getDocumentJob",
        "tags": ["Documents"],
        "summary": "Get a document job",
        "description": "The job with its result once it has finished. Readable at any balance. Links to the job's artifacts point at `/v1/documents/jobs/{id}/...` and need the same API key.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The job's `job_id`, as returned when it was created.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The job.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentJob"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key (`authentication_error`, code `invalid_api_key`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "No job with this id for this account (`not_found_error`). Another account's job id answers the same.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "410": {
            "description": "The job was created before 2026-10-03, and its results are no longer available (`not_found_error`, code `job_unavailable`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Over the account's requests per minute for document routes, or the document service is throttling this account (`rate_limit_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "description": "Something failed on Drex's side (`internal_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "The document service refused Drex's own request (`upstream_error`, code `ndi_refused_drex`). Retry later.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "503": {
            "description": "The document service is unavailable (`service_unavailable`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "504": {
            "description": "The document service timed out (`upstream_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "529": {
            "description": "The public API is paused (code `service_disabled`) or Drex's rate limiter is unreachable (code `limiter_unavailable`) (`overloaded`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteDocumentJob",
        "tags": ["Documents"],
        "summary": "Delete a document job",
        "description": "Cancels the job if it is still running and removes it from the list. It stays readable by id, and its usage up to then is still charged.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The job's `job_id`, as returned when it was created.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key (`authentication_error`, code `invalid_api_key`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "No job with this id for this account (`not_found_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "409": {
            "description": "The document service refused the delete (`conflict_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Over the account's requests per minute for document routes, or the document service is throttling this account (`rate_limit_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "description": "Something failed on Drex's side (`internal_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "The document service refused Drex's own request (`upstream_error`, code `ndi_refused_drex`). Retry later.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "503": {
            "description": "The document service is unavailable (`service_unavailable`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "504": {
            "description": "The document service timed out (`upstream_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "529": {
            "description": "The public API is paused (code `service_disabled`) or Drex's rate limiter is unreachable (code `limiter_unavailable`) (`overloaded`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/v1/documents/jobs/{id}/{path}": {
      "get": {
        "operationId": "getDocumentJobResource",
        "tags": ["Documents"],
        "summary": "Get a job artifact",
        "description": "A file the job produced (parse images, transcripts, ground crops, converted files), its `request` echo, or its `events` stream, at the path the job body links to. `path` may span several segments.\n\n- **Stored files** (`ground-crops`, `ground-transcript`, `parse-images`, `parse-transcript`, `converted-pdf`, `spreadsheet-cell-maps`) answer `302` with a signed storage link that works for 5 minutes without your API key. With `redirect=false`, they answer `200` with that link as JSON.\n- **Everything else** (`request`, `events`, `document-content`, `spreadsheet-content`, `spreadsheet-rows`) is streamed.\n- **Rate limits:** file downloads don't count against the per-minute limit; `events` and `request` do.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The job's `job_id`, as returned when it was created.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "path",
            "in": "path",
            "required": true,
            "description": "The rest of the link, for example `parse-images/<ref>`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "redirect",
            "in": "query",
            "required": false,
            "description": "For a stored file, `false` (or `0`) returns the signed link as JSON instead of redirecting to it. Browser code needs this: it can't read a cross-origin redirect, and storage sends no CORS headers.",
            "schema": {
              "type": "string",
              "enum": ["true", "false", "0", "1"],
              "default": "true"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A streamed artifact, in its own content type; for a stored file with `redirect=false`, its signed link as a `DocumentJobFileLink`.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/DocumentJobFileLink"
                    },
                    {
                      "description": "A streamed JSON artifact, such as the `request` echo."
                    }
                  ]
                }
              },
              "*/*": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "202": {
            "description": "The artifact is still being prepared; retry shortly.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "206": {
            "description": "Part of a streamed artifact, for a `Range` request the artifact supports. The `request` echo ignores `Range` and answers `200` with all of it.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "302": {
            "description": "A stored file: follow `location` to a signed storage link, valid for 5 minutes. It needs no API key, so don't send yours to it.",
            "headers": {
              "location": {
                "description": "The signed link.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key (`authentication_error`, code `invalid_api_key`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "No such job for this account, or no such artifact (`not_found_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "410": {
            "description": "The artifact has expired (`not_found_error`, code `result_expired`), or the job was created before 2026-10-03 and its results are no longer available (code `job_unavailable`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Over the account's requests per minute for document routes, or the document service is throttling this account (`rate_limit_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "description": "Something failed on Drex's side (`internal_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "The document service refused Drex's own request (`upstream_error`, code `ndi_refused_drex`). Retry later.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "503": {
            "description": "The document service is unavailable (`service_unavailable`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "504": {
            "description": "The document service timed out (`upstream_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "529": {
            "description": "The public API is paused (code `service_disabled`) or Drex's rate limiter is unreachable (code `limiter_unavailable`) (`overloaded`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/v1/documents/upload-grants": {
      "post": {
        "operationId": "createDocumentUploadGrant",
        "tags": ["Documents"],
        "summary": "Create an upload grant",
        "description": "A short-lived token for uploading one file straight to the document service, into your account's own workspace (created on first use). Free, and works at any balance.\n\n1. `POST` the file to `upload_url` as multipart form data, with the header `X-Upload-Token: <token>` and two parts:\n   - `file`: the file.\n   - `metadata` (required): JSON such as `{\"path\": \"...\"}`. Add `total_size_bytes` for files of 32 MiB or more.\n2. The upload's response carries the file under `result.file`.\n3. Pass its `workspace_id` and `file_id` as the job's source: `{\"type\":\"workspace_file\",\"workspace_id\":...,\"file_id\":...}`.\n\nThe bytes never pass through Drex, so there is no 4.5 MB limit.",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "path": {
                    "type": "string",
                    "description": "Pin the upload to exactly this path in the workspace."
                  },
                  "max_bytes": {
                    "type": "integer",
                    "minimum": 1,
                    "description": "Refuse uploads larger than this."
                  },
                  "total_size_bytes": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "The exact size the upload must have."
                  },
                  "ttl_seconds": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 3600,
                    "default": 3600,
                    "description": "How long the token works."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The grant.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "workspace_id",
                    "upload_url",
                    "token",
                    "expires_at",
                    "max_bytes"
                  ],
                  "properties": {
                    "workspace_id": {
                      "type": "string",
                      "format": "uuid",
                      "description": "Your account's workspace."
                    },
                    "upload_url": {
                      "type": "string",
                      "format": "uri",
                      "description": "Where to `POST` the file. A document-service URL, not Drex's."
                    },
                    "token": {
                      "type": "string",
                      "description": "Send as `X-Upload-Token`. Meant for one upload."
                    },
                    "expires_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "max_bytes": {
                      "type": ["integer", "null"],
                      "description": "The cap you set, or null for the document service's cap for the file type."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key (`authentication_error`, code `invalid_api_key`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "422": {
            "description": "The body is not a JSON object or has an unknown field, or the document service refused it (`invalid_request_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Over the account's requests per minute for document routes, or the document service is throttling this account (`rate_limit_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "description": "Something failed on Drex's side (`internal_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "The document service refused Drex's own request (`upstream_error`, code `ndi_refused_drex`). Retry later.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "503": {
            "description": "The document service is unavailable (`service_unavailable`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "504": {
            "description": "The document service timed out (`upstream_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "529": {
            "description": "The public API is paused (code `service_disabled`) or Drex's rate limiter is unreachable (code `limiter_unavailable`) (`overloaded`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/v1/documents/upload-sessions": {
      "post": {
        "operationId": "createDocumentUploadSession",
        "tags": ["Documents"],
        "summary": "Start a chunked upload",
        "description": "A resumable upload of a large file into your account's workspace, in parts of `chunk_size` bytes. Takes an `Idempotency-Key` header.\n\nSend each call below straight to the document service, with `X-Upload-Token: <session_token>`:\n\n1. `PUT {upload_session_url}/parts/{n}` for each part, numbered from 0.\n2. `POST {upload_session_url}/complete?wait_seconds=60` with an `Idempotency-Key`. It assembles the file in the background and answers `202` while it runs.\n3. Repeat step 2 with the same key until it answers `200` with `result.file` (`workspace_id`, `file_id`).\n\n`GET {upload_session_url}` shows progress, and `DELETE {upload_session_url}` aborts.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "description": "Scoped to your account. Retry with the same key to get the same session."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["path", "total_size_bytes"],
                "additionalProperties": true,
                "properties": {
                  "path": {
                    "type": "string"
                  },
                  "total_size_bytes": {
                    "type": "integer",
                    "minimum": 1
                  },
                  "ttl_seconds": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 5400
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The session.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "properties": {
                    "workspace_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "session_id": {
                      "type": "string"
                    },
                    "session_token": {
                      "type": "string"
                    },
                    "chunk_size": {
                      "type": "integer"
                    },
                    "total_parts": {
                      "type": "integer"
                    },
                    "expires_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "upload_session_url": {
                      "type": "string",
                      "format": "uri"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key (`authentication_error`, code `invalid_api_key`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "422": {
            "description": "The body is not a JSON object or has an unknown field, or the document service refused it (`invalid_request_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Over the account's requests per minute for document routes, or the document service is throttling this account (`rate_limit_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "description": "Something failed on Drex's side (`internal_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "The document service refused Drex's own request (`upstream_error`, code `ndi_refused_drex`). Retry later.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "503": {
            "description": "The document service is unavailable (`service_unavailable`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "504": {
            "description": "The document service timed out (`upstream_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "529": {
            "description": "The public API is paused (code `service_disabled`) or Drex's rate limiter is unreachable (code `limiter_unavailable`) (`overloaded`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/v1/extraction-schemas": {
      "get": {
        "operationId": "listExtractionSchemas",
        "tags": ["Documents"],
        "summary": "List saved extraction schemas",
        "description": "The latest version of each of the account's saved schemas. Free, and works at any balance.",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "`next_cursor` from the previous page.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of schemas.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExtractionSchemaList"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key (`authentication_error`, code `invalid_api_key`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Over the account's requests per minute for document routes, or the document service is throttling this account (`rate_limit_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "description": "Something failed on Drex's side (`internal_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "The document service refused Drex's own request (`upstream_error`, code `ndi_refused_drex`). Retry later.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "503": {
            "description": "The document service is unavailable (`service_unavailable`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createExtractionSchema",
        "tags": ["Documents"],
        "summary": "Save an extraction schema",
        "description": "Saves version 1 of a new schema under a generated `schema_id`. `POST /v1/documents/extract` can then name it with `schema_id` instead of sending `schema` inline. Free, and works at any balance.\n\n- **Access:** only this account can see or use it.\n- **Changes:** schemas can't be edited or deleted. Add a version instead.\n- **Retries:** a retried create saves a second schema.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["name", "schema"],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 128
                  },
                  "description": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 2000
                  },
                  "schema": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "The JSON Schema of the fields to extract, as `schema` takes it on an extract."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The saved schema.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExtractionSchema"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key (`authentication_error`, code `invalid_api_key`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "413": {
            "description": "The body is over 1 MB (`invalid_request_error`, code `payload_too_large`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "422": {
            "description": "The body is not a valid schema request, or the schema is not one Extract can use (`invalid_request_error`). Code `invalid_request` lists the fields that failed in `detail.errors`; code `invalid_schema` names the problem in `message`.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Over the account's requests per minute for document routes, or the document service is throttling this account (`rate_limit_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "description": "Something failed on Drex's side (`internal_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "The document service refused Drex's own request (`upstream_error`, code `ndi_refused_drex`). Retry later.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "503": {
            "description": "The document service is unavailable (`service_unavailable`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/v1/extraction-schemas/{id}": {
      "get": {
        "operationId": "getExtractionSchema",
        "tags": ["Documents"],
        "summary": "Get a saved extraction schema",
        "description": "The schema's latest version. Free, and works at any balance.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The schema's `schema_id` (`sch_...`). An id longer than 128 characters answers `404` with code `not_found`, not `schema_not_found`.",
            "schema": {
              "type": "string",
              "maxLength": 128
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The latest version.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExtractionSchema"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key (`authentication_error`, code `invalid_api_key`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "No schema (or version) with this id for this account (`not_found_error`, code `schema_not_found`). Another account's schema id answers the same.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Over the account's requests per minute for document routes, or the document service is throttling this account (`rate_limit_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "description": "Something failed on Drex's side (`internal_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "The document service refused Drex's own request (`upstream_error`, code `ndi_refused_drex`). Retry later.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "503": {
            "description": "The document service is unavailable (`service_unavailable`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/v1/extraction-schemas/{id}/versions": {
      "get": {
        "operationId": "listExtractionSchemaVersions",
        "tags": ["Documents"],
        "summary": "List a schema's versions",
        "description": "Every version of one of the account's schemas. Free, and works at any balance.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The schema's `schema_id` (`sch_...`). An id longer than 128 characters answers `404` with code `not_found`, not `schema_not_found`.",
            "schema": {
              "type": "string",
              "maxLength": 128
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "`next_cursor` from the previous page.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of versions.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExtractionSchemaList"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key (`authentication_error`, code `invalid_api_key`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "No schema (or version) with this id for this account (`not_found_error`, code `schema_not_found`). Another account's schema id answers the same.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Over the account's requests per minute for document routes, or the document service is throttling this account (`rate_limit_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "description": "Something failed on Drex's side (`internal_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "The document service refused Drex's own request (`upstream_error`, code `ndi_refused_drex`). Retry later.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "503": {
            "description": "The document service is unavailable (`service_unavailable`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createExtractionSchemaVersion",
        "tags": ["Documents"],
        "summary": "Add a schema version",
        "description": "Saves the next version of one of the account's schemas. Free, and works at any balance.\n\n- **Earlier versions** stay as they were, so an extract that names `schema_version` keeps getting the same schema.\n- **`name` and `description`**, when left out, carry over from the previous version.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The schema's `schema_id` (`sch_...`). An id longer than 128 characters answers `404` with code `not_found`, not `schema_not_found`.",
            "schema": {
              "type": "string",
              "maxLength": 128
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["schema"],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 128
                  },
                  "description": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 2000
                  },
                  "schema": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "The new version's JSON Schema."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The new version.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExtractionSchema"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key (`authentication_error`, code `invalid_api_key`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "No schema (or version) with this id for this account (`not_found_error`, code `schema_not_found`). Another account's schema id answers the same.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "413": {
            "description": "The body is over 1 MB (`invalid_request_error`, code `payload_too_large`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "422": {
            "description": "The body is not a valid schema request, or the schema is not one Extract can use (`invalid_request_error`). Code `invalid_request` lists the fields that failed in `detail.errors`; code `invalid_schema` names the problem in `message`.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Over the account's requests per minute for document routes, or the document service is throttling this account (`rate_limit_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "description": "Something failed on Drex's side (`internal_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "The document service refused Drex's own request (`upstream_error`, code `ndi_refused_drex`). Retry later.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "503": {
            "description": "The document service is unavailable (`service_unavailable`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/v1/extraction-schemas/{id}/versions/{version}": {
      "get": {
        "operationId": "getExtractionSchemaVersion",
        "tags": ["Documents"],
        "summary": "Get a schema version",
        "description": "One version of one of the account's schemas. A version never changes. Free, and works at any balance.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The schema's `schema_id` (`sch_...`). An id longer than 128 characters answers `404` with code `not_found`, not `schema_not_found`.",
            "schema": {
              "type": "string",
              "maxLength": 128
            }
          },
          {
            "name": "version",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The version.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExtractionSchema"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key (`authentication_error`, code `invalid_api_key`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "No schema (or version) with this id for this account (`not_found_error`, code `schema_not_found`). Another account's schema id answers the same.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "429": {
            "description": "Over the account's requests per minute for document routes, or the document service is throttling this account (`rate_limit_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "description": "Something failed on Drex's side (`internal_error`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "502": {
            "description": "The document service refused Drex's own request (`upstream_error`, code `ndi_refused_drex`). Retry later.",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          },
          "503": {
            "description": "The document service is unavailable (`service_unavailable`).",
            "headers": {
              "x-request-id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "retry-after": {
                "description": "Whole seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentErrorEnvelope"
                }
              }
            }
          }
        }
      }
    }
  }
}
