{
  "openapi": "3.1.0",
  "info": {
    "title": "anex.sh batch inference API",
    "version": "1",
    "summary": "Batch inference for open models: submit a file with one prompt per row, approve a cost estimate, download one result file with a response per row.",
    "description": "The normal flow is: createInput (then upload the file to the presigned target if you did not give a source_url), createJob, poll getJob until the status is cost_ready, approveJob, poll getJob until the status is done, then getJobResult for a download link. Payment is prepaid credits; an approved job never costs more than the estimate that was approved. Prose reference: https://anex.sh/docs/api. Model ids and their exact weights: https://anex.sh/docs/api#models. Pricing: https://anex.sh/docs/pricing. A realtime surface lives at a second server, https://api.anex.sh/realtime/v1, and takes the same API keys: OpenAI-compatible embeddings, and typed decisions (one answer per question about a text, with a probability per option). EU data routing keeps an organization's batch data (the inputs, prompts, results, embedding inputs and vectors of its uploads and jobs) inside the EEA (European Economic Area). It is enabled per organization on request; once on, uploads and jobs default to eu and data_residency world keeps a single one in the world region. A request for eu from an organization without it answers 403. That data is served by the EU API, at the second batch server https://api-eu.anex.sh/batch/v1; a request for it sent to the main API answers 421 naming the API to use. Details: https://anex.sh/docs/residency. With EU data routing on, its keys may also use the EU realtime server https://api-eu.anex.sh/realtime/v1, which processes requests inside the EEA for the models its GET /models lists; other organizations get 403 there.",
    "termsOfService": "https://anex.sh/terms",
    "contact": {
      "name": "anex.sh support",
      "email": "support@anex.sh",
      "url": "https://anex.sh/support"
    }
  },
  "servers": [
    {
      "url": "https://api.anex.sh/batch/v1",
      "description": "Batch API"
    },
    {
      "url": "https://api-eu.anex.sh/batch/v1",
      "description": "Batch API for data kept in the EEA"
    }
  ],
  "security": [
    {
      "apiKey": []
    }
  ],
  "tags": [
    {
      "name": "inputs",
      "description": "Getting an input file into storage."
    },
    {
      "name": "jobs",
      "description": "Submitting, approving, cancelling and downloading batch jobs."
    },
    {
      "name": "realtime",
      "description": "Single-request embeddings (OpenAI-compatible) and typed decisions, at https://api.anex.sh/realtime/v1."
    }
  ],
  "externalDocs": {
    "description": "API reference (prose)",
    "url": "https://anex.sh/docs/api"
  },
  "paths": {
    "/inputs": {
      "post": {
        "operationId": "createInput",
        "tags": [
          "inputs"
        ],
        "summary": "Create an input: ingest a file from an HTTPS URL, or get a presigned target to upload one directly",
        "description": "With source_url, the API copies the file into storage from that URL (a presigned GET on your own bucket is the simplest source) and the response's status goes pending, copying, ready (or failed with an error; a ready input later expires with its file's 7-day retention). Without source_url the response is instead a presigned S3 POST target: send every entry of `fields` as a form field and the file itself as the `file` field, last, before expires_at; format is then required. Requires a positive credit balance (402 otherwise). Keep the returned id: it is the input_id for createJob, which settles a just-finished upload itself, so no poll is needed.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateInputRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The input was created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Input"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed: a non-HTTPS URL, a source_url or callback_url pointing at an address the service refuses to talk to (the pre-flight check names it), a missing format on a direct upload, or a callback_url in upload mode.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "The API key is invalid or no longer active.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "The organization's credit balance is zero or below.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "The source advertises a size over the input cap.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The request body failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "The balance could not be checked; try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "421": {
            "description": "The data this request reads or stores is kept in the other region (body: MisdirectedError). Send the same request to the API its api field names.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MisdirectedError"
                }
              }
            }
          },
          "403": {
            "description": "The organization is suspended because of a billing issue (body: OrgSuspendedError, error org_suspended). Every API key of the organization is refused until it is resolved; jobs already running finish. Contact support@anex.sh. Also: data_residency is eu. The organization does not have EU data routing; it is enabled per organization on request. Body: {\"detail\": \"EU data routing is not enabled for this organization. Contact us to enable it.\"}",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/OrgSuspendedError"
                    },
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ]
                }
              }
            }
          }
        },
        "callbacks": {
          "inputEvent": {
            "{$request.body#/callback_url}": {
              "post": {
                "summary": "input.ready or input.failed, once the copy finishes",
                "description": "Sent once, best effort, when an input created with a callback_url reaches ready or failed; the input stays pollable either way. Signed the way job webhooks are (https://anex.sh/docs/api#webhooks) with the ingest's own callback_secret: the headers webhook-id, webhook-timestamp (unix seconds) and webhook-signature, the last a 'v1,<base64>' HMAC-SHA256 over '{webhook-id}.{webhook-timestamp}.' followed by the raw body, keyed with the secret base64-decoded after its whsec_ prefix.",
                "requestBody": {
                  "required": true,
                  "content": {
                    "application/json": {
                      "schema": {
                        "$ref": "#/components/schemas/InputCallback"
                      }
                    }
                  }
                },
                "responses": {
                  "2XX": {
                    "description": "Counts as delivered."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/inputs/{id}": {
      "get": {
        "operationId": "getInput",
        "tags": [
          "inputs"
        ],
        "summary": "Get an input's status",
        "description": "Poll until status is ready (or failed, with an error). A direct upload reports awaiting_upload until the object lands. A ready input reports expired once its file's 7-day retention lapses (expires_at names the deadline). An id of another organization answers 404.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The input id returned by createInput.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The input's current state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Input"
                }
              }
            }
          },
          "401": {
            "description": "The API key is invalid or no longer active.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such input in this organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "421": {
            "description": "The data this request reads or stores is kept in the other region (body: MisdirectedError). Send the same request to the API its api field names.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MisdirectedError"
                }
              }
            }
          },
          "403": {
            "description": "The organization is suspended because of a billing issue (body: OrgSuspendedError, error org_suspended). Every API key of the organization is refused until it is resolved; jobs already running finish. Contact support@anex.sh.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrgSuspendedError"
                }
              }
            }
          }
        }
      }
    },
    "/jobs": {
      "post": {
        "operationId": "createJob",
        "tags": [
          "jobs"
        ],
        "summary": "Submit a job: an input plus a model",
        "description": "Checks the input's size and the response_format before the job exists, then returns it in status submitted. A JSONL input's rows, inline media and context length are checked while the job is estimated (status estimating), and a violation fails the job with failure_code invalid_input naming the row rather than answering this call. The job then waits at cost_ready for approveJob, unless the organization has auto-approve on. Give exactly one of input_id and input_s3_uri. Model ids: https://anex.sh/docs/api#models.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateJobRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The job was created (status submitted).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            }
          },
          "400": {
            "description": "The input file failed validation: over the size cap, a file that is not JSONL, or a malformed response_format.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "The API key is invalid or no longer active.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "The organization's credit balance is zero or below. An organization billed by monthly invoice gets 'credit limit reached - contact support@anex.sh' when the new spend would pass its credit limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such input in this organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "The input is not ready yet.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The request does not fit the model or itself: an unknown model; neither or both of input_id and input_s3_uri; max_tokens and max_output_tokens set to different values (max_tokens is the former name); the retired instruction_column or input_column; a field that does not apply to the model (max_output_tokens, reasoning, reasoning_budget, reasoning_effort, response_format, temperature or video_fps on an embedding or decision model, dimensions on any other, reasoning on a model with no trace, video_fps on a model that takes none or above its ceiling); max_output_tokens above the model's ceiling; reasoning_budget with reasoning false, or together with response_format, or not at least 64 below max_output_tokens; reasoning_effort on a model without levels, outside the model's levels, or with reasoning false; an input stored in the other region's bucket than the job's data residency.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Either too many jobs awaiting approval in this organization (approve or cancel some first; the message names the approval queue; body: Error) or requests arriving faster than the edge accepts (body: RateLimitError, error.code rate_limit_exceeded). Both carry Retry-After with the seconds to wait.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    },
                    {
                      "$ref": "#/components/schemas/RateLimitError"
                    }
                  ]
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying the request.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          },
          "503": {
            "description": "The balance could not be checked (body: Error; try again), or The API is frozen for maintenance (body: FrozenError). Reading an input's status and downloading a result keep working; retry the rest later.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    },
                    {
                      "$ref": "#/components/schemas/FrozenError"
                    }
                  ]
                }
              }
            }
          },
          "421": {
            "description": "The data this request reads or stores is kept in the other region (body: MisdirectedError). Send the same request to the API its api field names.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MisdirectedError"
                }
              }
            }
          },
          "403": {
            "description": "The organization is suspended because of a billing issue (body: OrgSuspendedError, error org_suspended). Every API key of the organization is refused until it is resolved; jobs already running finish. Contact support@anex.sh. Also: data_residency is eu. The organization does not have EU data routing; it is enabled per organization on request. Body: {\"detail\": \"EU data routing is not enabled for this organization. Contact us to enable it.\"}",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/OrgSuspendedError"
                    },
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/jobs/{id}": {
      "get": {
        "operationId": "getJob",
        "tags": [
          "jobs"
        ],
        "summary": "Poll a job for its status, estimate and row counts",
        "description": "status moves submitted, estimating, cost_ready, in_progress, finalizing, done; or ends failed / cancelled. At cost_ready the estimate fields are set: est_cost_cents is the amount held on approval and the cost ceiling. The row counts are null until the job has finished (done, failed or cancelled). data_expires_at is when the job's data is deleted; the record itself stays queryable.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The job id returned by createJob.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The job's current state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            }
          },
          "401": {
            "description": "The API key is invalid or no longer active.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such job in this organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "The API is frozen for maintenance (body: FrozenError). Reading an input's status and downloading a result keep working; retry the rest later.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FrozenError"
                }
              }
            }
          },
          "403": {
            "description": "The organization is suspended because of a billing issue (body: OrgSuspendedError, error org_suspended). Every API key of the organization is refused until it is resolved; jobs already running finish. Contact support@anex.sh.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrgSuspendedError"
                }
              }
            }
          }
        }
      }
    },
    "/jobs/{id}/approve": {
      "post": {
        "operationId": "approveJob",
        "tags": [
          "jobs"
        ],
        "summary": "Approve a job's estimate, which starts paid GPU work",
        "description": "Holds est_cost_cents against the prepaid balance. The job must be in cost_ready; a job left there for 24 hours is cancelled automatically, free of charge. With auto-approve on for the organization this call is made for you.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The job id returned by createJob.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Approved: status is now in_progress.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            }
          },
          "401": {
            "description": "The API key is invalid or no longer active.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "The balance does not cover the estimate; add credits and approve again. An organization billed by monthly invoice gets 'credit limit reached - contact support@anex.sh' when the new spend would pass its credit limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such job in this organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "The job is not awaiting approval.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "The balance could not be checked, so no approval was made (body: Error; try again), or The API is frozen for maintenance (body: FrozenError). Reading an input's status and downloading a result keep working; retry the rest later.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    },
                    {
                      "$ref": "#/components/schemas/FrozenError"
                    }
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The organization is suspended because of a billing issue (body: OrgSuspendedError, error org_suspended). Every API key of the organization is refused until it is resolved; jobs already running finish. Contact support@anex.sh.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrgSuspendedError"
                }
              }
            }
          }
        }
      }
    },
    "/jobs/{id}/cancel": {
      "post": {
        "operationId": "cancelJob",
        "tags": [
          "jobs"
        ],
        "summary": "Cancel a job",
        "description": "A job with no work in flight stops at once (status cancelled, nothing billed). A job that has started answers cancelling: no new work starts, rows already running finish, and the job settles as cancelled with the completed rows downloadable as a partial result and billed. A job that is estimating, finalizing or already terminal answers 409.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The job id returned by createJob.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "status is cancelled or cancelling.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            }
          },
          "401": {
            "description": "The API key is invalid or no longer active.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such job in this organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Too early (estimating) or too late (finalizing or terminal) to cancel.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "The API is frozen for maintenance (body: FrozenError). Reading an input's status and downloading a result keep working; retry the rest later.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FrozenError"
                }
              }
            }
          },
          "403": {
            "description": "The organization is suspended because of a billing issue (body: OrgSuspendedError, error org_suspended). Every API key of the organization is refused until it is resolved; jobs already running finish. Contact support@anex.sh.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrgSuspendedError"
                }
              }
            }
          }
        }
      }
    },
    "/jobs/{id}/result": {
      "get": {
        "operationId": "getJobResult",
        "tags": [
          "jobs"
        ],
        "summary": "Get a presigned download link for the result file",
        "description": "Available for a done job, and for a failed or cancelled job that delivered the rows it had finished (partial true). result_url is valid for expires_in seconds; call again for a fresh link. The file's contents are described at https://anex.sh/docs/output. Results are deleted 30 days after the job finishes, or earlier through deleteJobData; 410 afterwards.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The job id returned by createJob.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A download link.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobResult"
                }
              }
            }
          },
          "401": {
            "description": "The API key is invalid or no longer active.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such job in this organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "No result exists yet (the job is not finished, or finished with nothing to deliver).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "410": {
            "description": "The result has been deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "421": {
            "description": "The data this request reads or stores is kept in the other region (body: MisdirectedError). Send the same request to the API its api field names.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MisdirectedError"
                }
              }
            }
          },
          "403": {
            "description": "The organization is suspended because of a billing issue (body: OrgSuspendedError, error org_suspended). Every API key of the organization is refused until it is resolved; jobs already running finish. Contact support@anex.sh.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrgSuspendedError"
                }
              }
            }
          }
        }
      }
    },
    "/jobs/{id}/data": {
      "delete": {
        "operationId": "deleteJobData",
        "tags": [
          "jobs"
        ],
        "summary": "Delete a job's input and result data now",
        "description": "Removes the job's input file, result file and every intermediate object, instead of at the 30-day retention mark. The job record (statuses, counts, cost) stays; getJob then reports data_deleted_at and getJobResult answers 410. A finished job (done, failed, cancelled) is purged at once: 200. A job still in flight is first cancelled exactly as cancelJob would (rows already completed are delivered and billed) and its data is deleted automatically once it has stopped: 202, with data_deleted_at null and a message saying so; poll getJob for data_deleted_at. Idempotent: repeating it answers 200 with the original data_deleted_at (or 202 again while the job is still stopping). Download the result before calling this; nothing can bring the data back.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The job id returned by createJob.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The data is gone (now, or earlier).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobDataDeletion"
                }
              }
            }
          },
          "202": {
            "description": "The job is being cancelled; its data is deleted once it stops (data_deleted_at null, message set).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobDataDeletion"
                }
              }
            }
          },
          "401": {
            "description": "The API key is invalid or no longer active.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such job in this organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "The API is frozen for maintenance (body: FrozenError). Reading an input's status and downloading a result keep working; retry the rest later.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FrozenError"
                }
              }
            }
          },
          "403": {
            "description": "The organization is suspended because of a billing issue (body: OrgSuspendedError, error org_suspended). Every API key of the organization is refused until it is resolved; jobs already running finish. Contact support@anex.sh.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrgSuspendedError"
                }
              }
            }
          }
        }
      }
    },
    "/models": {
      "servers": [
        {
          "url": "https://api.anex.sh/realtime/v1",
          "description": "Realtime API"
        },
        {
          "url": "https://api-eu.anex.sh/realtime/v1",
          "description": "Realtime API inside the EEA; serves only the models its GET /models lists"
        }
      ],
      "get": {
        "operationId": "listRealtimeModels",
        "tags": [
          "realtime"
        ],
        "summary": "List the models served by the realtime API",
        "description": "OpenAI-compatible; served at https://api.anex.sh/realtime/v1/models. Each entry's task says which route takes it: embed (createEmbedding) or decide (createDecision). The batch API has no list-models endpoint: its model ids are at https://anex.sh/docs/api#models. No API key is needed for this one call.",
        "security": [],
        "responses": {
          "200": {
            "description": "The realtime models.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ModelList"
                }
              }
            }
          }
        }
      }
    },
    "/embeddings": {
      "servers": [
        {
          "url": "https://api.anex.sh/realtime/v1",
          "description": "Realtime API"
        },
        {
          "url": "https://api-eu.anex.sh/realtime/v1",
          "description": "Realtime API inside the EEA; serves only the models its GET /models lists"
        }
      ],
      "post": {
        "operationId": "createEmbedding",
        "tags": [
          "realtime"
        ],
        "summary": "Embed one text or a short list of texts, at request time",
        "description": "OpenAI-compatible; served at https://api.anex.sh/realtime/v1/embeddings and usable through the OpenAI SDK with that base_url. Text only (embed images and video with a batch job on the same model; the vectors share one space). At most 128 inputs, 262,144 characters per input and 2,097,152 across the request. Vectors are last-token pooled and L2 normalized; no instruction or chat template is added to your text (write your own into the string: see /docs/api#embedding-instructions).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmbeddingRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The vectors, one per input.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmbeddingResponse"
                }
              }
            }
          },
          "400": {
            "description": "Too many inputs, an input too long, non-text content, an encoding_format other than float, or a model of another task (a decision model; the message names the route to send it to).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "The API key is invalid or no longer active.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "The organization's credit balance is zero or below. An organization billed by monthly invoice gets 'credit limit reached - contact support@anex.sh' when the new spend would pass its credit limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Unknown model.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 8 requests in flight for this organization (Retry-After: 1), or the model's backend is rate limiting (Retry-After when the backend named one).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying the request.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          },
          "501": {
            "description": "The model exists but is not served in realtime; use the batch API.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "The embedding service failed to answer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "The realtime API is frozen or billing is unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The organization is suspended because of a billing issue (body: OrgSuspendedError, error org_suspended). Every API key of the organization is refused until it is resolved; jobs already running finish. Contact support@anex.sh. Also: Sent to the EU realtime server. The organization does not have EU data routing; it is enabled per organization on request. Body: {\"detail\": \"EU data routing is not enabled for this organization. Contact us to enable it.\"}",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/OrgSuspendedError"
                    },
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/systemone": {
      "servers": [
        {
          "url": "https://api.anex.sh/realtime/v1",
          "description": "Realtime API"
        },
        {
          "url": "https://api-eu.anex.sh/realtime/v1",
          "description": "Realtime API inside the EEA; serves only the models its GET /models lists"
        }
      ],
      "post": {
        "operationId": "createDecision",
        "tags": [
          "realtime"
        ],
        "summary": "Answer typed questions about one text, at request time",
        "description": "Served at https://api.anex.sh/realtime/v1/systemone. The model reads the state (a string, or a JSON object it reads as text) and answers every question in one pass with a probability per option; no text is generated and usage.output_tokens is always 0. At most 64 questions and 50,000 characters of state per request (400 past either); a question the model refuses answers 422 with the model's own message. Billed per input token, the state counted once per question: usage.input_tokens is the billed count. The same body minus model is the body of one JSONL row of a batch decision job (url /v1/systemone, JSONL input only; see https://anex.sh/docs/api#decisions), whose result carries the same DecisionResponse per row as the JSONL row's response.body.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DecisionRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "One answer per question.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DecisionResponse"
                }
              }
            }
          },
          "400": {
            "description": "Too many questions, a state over 50,000 characters or of another type, an empty questions object, or a model of another task (the message names the route to send it to).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "The API key is invalid or no longer active.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "The organization's credit balance is zero or below. An organization billed by monthly invoice gets 'credit limit reached - contact support@anex.sh' when the new spend would pass its credit limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "A question the model refused: a missing instructions, a noul question whose criteria carry a key other than true or false, an option set that cannot fit its 192-token budget at all. The message names the question.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Unknown model.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "More than 8 requests in flight for this organization; Retry-After: 1.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying the request.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          },
          "501": {
            "description": "The model exists but is not served in realtime; use the batch API.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "The decision service failed to answer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "The realtime API is frozen or billing is unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The organization is suspended because of a billing issue (body: OrgSuspendedError, error org_suspended). Every API key of the organization is refused until it is resolved; jobs already running finish. Contact support@anex.sh. Also: Sent to the EU realtime server. The organization does not have EU data routing; it is enabled per organization on request. Body: {\"detail\": \"EU data routing is not enabled for this organization. Contact us to enable it.\"}",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/OrgSuspendedError"
                    },
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ]
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "An API key from the console's Keys page (https://anex.sh/docs/console#keys), sent as 'Authorization: Bearer <api-key>'. Keys belong to the organization, not to a person."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "description": "Every error the API itself answers with carries detail. Three bodies carry an error field instead: FrozenError, RateLimitError and OrgSuspendedError.",
        "properties": {
          "detail": {
            "type": "string",
            "description": "What went wrong."
          }
        },
        "required": [
          "detail"
        ]
      },
      "OrgSuspendedError": {
        "type": "object",
        "description": "The 403 answered to every API key of an organization suspended because of a billing issue.",
        "properties": {
          "error": {
            "type": "string",
            "const": "org_suspended"
          },
          "message": {
            "type": "string"
          }
        },
        "required": [
          "error",
          "message"
        ]
      },
      "FrozenError": {
        "type": "object",
        "description": "The 503 answered while an operator has the API frozen for maintenance.",
        "properties": {
          "error": {
            "type": "string",
            "const": "frozen"
          },
          "message": {
            "type": "string"
          }
        },
        "required": [
          "error",
          "message"
        ]
      },
      "RateLimitError": {
        "type": "object",
        "description": "The 429 the edge answers when requests arrive faster than it accepts; the request never reaches the API. Retry-After carries the wait.",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string",
                "const": "rate_limit_exceeded"
              },
              "message": {
                "type": "string"
              },
              "type": {
                "type": "string",
                "const": "rate_limit_error"
              }
            },
            "required": [
              "code",
              "message"
            ]
          }
        },
        "required": [
          "error"
        ]
      },
      "InputCallback": {
        "type": "object",
        "description": "The body of an input callback: the event, the delivery's own id and unix-seconds timestamp (the values signed in the headers), and the input's state.",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "input.ready",
              "input.failed"
            ]
          },
          "timestamp": {
            "type": "integer",
            "description": "Unix seconds."
          },
          "id": {
            "type": "string",
            "description": "The delivery id, also sent as webhook-id."
          },
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "The input id."
              },
              "status": {
                "type": "string",
                "enum": [
                  "ready",
                  "failed"
                ]
              },
              "input_s3_uri": {
                "type": "string",
                "description": "On input.ready: where the file landed."
              },
              "error": {
                "type": "string",
                "description": "On input.failed: why the copy failed."
              }
            },
            "required": [
              "id",
              "status"
            ]
          }
        },
        "required": [
          "type",
          "timestamp",
          "id",
          "data"
        ]
      },
      "CreateInputRequest": {
        "type": "object",
        "properties": {
          "source_url": {
            "type": "string",
            "format": "uri",
            "description": "HTTPS URL to copy the input file from. Omit it to get a presigned upload target instead."
          },
          "format": {
            "type": "string",
            "enum": [
              "jsonl"
            ],
            "description": "The input file's format. Optional with source_url, required for a direct upload. A decision job (a decide model) takes one DecisionRequest minus model per row's body."
          },
          "callback_url": {
            "type": "string",
            "format": "uri",
            "description": "HTTPS endpoint to notify (input.ready / input.failed) when the copy finishes. source_url mode only."
          },
          "data_residency": {
            "type": "string",
            "enum": [
              "world",
              "eu"
            ],
            "description": "Where the input file is stored: world, or eu for storage in Frankfurt (eu-central-1). Both modes take it, source_url and direct upload. Omitted, it is eu for an organization with EU data routing and world otherwise; eu without EU data routing answers 403. An eu input is created through https://api-eu.anex.sh/batch/v1; the main API answers 421."
          }
        }
      },
      "Input": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "copying",
              "ready",
              "failed",
              "awaiting_upload",
              "expired"
            ]
          },
          "input_s3_uri": {
            "type": "string",
            "description": "Where the file lives in storage; accepted by createJob in place of input_id."
          },
          "error": {
            "type": [
              "string",
              "null"
            ],
            "description": "Why the copy failed, when status is failed."
          },
          "callback_secret": {
            "type": [
              "string",
              "null"
            ],
            "description": "HMAC secret for verifying the callback; returned once, on create, only with a callback_url."
          },
          "upload_url": {
            "type": [
              "string",
              "null"
            ],
            "description": "Direct upload only: the presigned POST target."
          },
          "fields": {
            "type": [
              "object",
              "null"
            ],
            "description": "Direct upload only: the form fields to send with the file, returned only on create.",
            "additionalProperties": {
              "type": "string"
            }
          },
          "expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "The nearest deadline: while awaiting_upload, when the upload window closes; while ready, when the file's 7-day retention may delete it."
          }
        },
        "required": [
          "id",
          "status",
          "input_s3_uri"
        ]
      },
      "CreateJobRequest": {
        "type": "object",
        "properties": {
          "input_id": {
            "type": "string",
            "format": "uuid",
            "description": "An input from createInput. Give exactly one of input_id and input_s3_uri."
          },
          "input_s3_uri": {
            "type": "string",
            "description": "The input_s3_uri of an input, instead of its id."
          },
          "model": {
            "type": "string",
            "description": "A model id from https://anex.sh/docs/api#models."
          },
          "max_output_tokens": {
            "type": "integer",
            "minimum": 1,
            "maximum": 32768,
            "description": "Per-row output cap. Omit it and the cap is estimated from a sample of the rows (the default); set it to fix the cap and the price basis yourself."
          },
          "max_tokens": {
            "type": "integer",
            "minimum": 1,
            "maximum": 32768,
            "deprecated": true,
            "description": "Former name of max_output_tokens; still accepted. Give one of the two."
          },
          "reasoning": {
            "type": "boolean",
            "description": "Job-level thinking default on a reasoning model. Omit for the model's own default; true on a model with no reasoning trace is refused (422)."
          },
          "reasoning_budget": {
            "type": "integer",
            "minimum": 0,
            "maximum": 32768,
            "description": "Cap on thinking tokens per row on a reasoning model. Omit = estimated, 0 = no cap. Counts inside max_output_tokens. Needs thinking on: 1+ with reasoning false is refused (422), and a JSONL row with enable_thinking false fails the job."
          },
          "reasoning_effort": {
            "type": "string",
            "minLength": 1,
            "description": "Thinking effort level on a model that offers levels (qwen3.8-27b: low, medium or xhigh, the default). Omit for the model's default. A JSONL row's chat_template_kwargs.reasoning_effort wins for that row. Refused (422) on a model without levels, outside its levels, or with reasoning false."
          },
          "temperature": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "maximum": 2,
            "description": "Job-wide sampling temperature for every row that does not set its own. Omit for the model's default. Generation models only."
          },
          "video_fps": {
            "type": [
              "number",
              "null"
            ],
            "exclusiveMinimum": 0,
            "maximum": 60,
            "description": "Video sampling rate in frames per second for every video row of the job. Only on the models that take one, and at most each one's ceiling; both are listed at https://anex.sh/docs/api#models. Omitted: the model's default rate. Each sampled frame becomes input tokens, so a higher rate costs more per second of clip (the per-second fee stays the same) and shortens the longest clip that fits the row context."
          },
          "response_format": {
            "type": "object",
            "description": "Applied to every row: {\"type\":\"json_object\"} or {\"type\":\"json_schema\",\"json_schema\":{...}}. See https://anex.sh/docs/output#structured-output."
          },
          "dimensions": {
            "type": "integer",
            "minimum": 32,
            "description": "Embedding models: truncate the output vectors to this width (Matryoshka). Omit for the model's full width."
          },
          "data_residency": {
            "type": "string",
            "enum": [
              "world",
              "eu"
            ],
            "description": "Where the job's payload is stored and processed: world, or eu to store and process the job's input and output inside the EEA. Omitted, it is eu for an organization with EU data routing and world otherwise; eu without EU data routing answers 403. The input must be stored in the same region (422 otherwise). An eu job on a model whose output length cannot be estimated inside the EEA needs max_output_tokens, and reasoning_budget too with reasoning on (422 without them). An eu job is submitted through https://api-eu.anex.sh/batch/v1; the main API answers 421."
          }
        },
        "required": [
          "model"
        ]
      },
      "Job": {
        "type": "object",
        "description": "createJob, approveJob and cancelJob return only id and status; getJob returns every field.",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "enum": [
              "submitted",
              "estimating",
              "cost_ready",
              "in_progress",
              "cancelling",
              "finalizing",
              "done",
              "failed",
              "cancelled"
            ]
          },
          "est_input_tok": {
            "type": [
              "integer",
              "null"
            ]
          },
          "est_output_tok": {
            "type": [
              "integer",
              "null"
            ]
          },
          "est_cost_cents": {
            "type": [
              "integer",
              "null"
            ],
            "description": "The approval hold and the cost ceiling, in cents. Set at cost_ready."
          },
          "est_processing_seconds": {
            "type": [
              "integer",
              "null"
            ],
            "description": "The expected wall-clock time to completion once approved."
          },
          "success_rows": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Rows that produced an answer. Every row count is null until the job has finished."
          },
          "error_rows": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Rows that failed. Null until the job has finished."
          },
          "format_error_rows": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Rows refused because of their own input: a response_format the generation could not satisfy, a refused decision question, or a media file that fails media_length_mismatch or media_unreadable. Null until the job has finished."
          },
          "truncated_rows": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Rows cut off at max_output_tokens. Null until the job has finished."
          },
          "pending_rows": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Rows none of the other counts account for. Null until the job has finished."
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "approved_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "data_expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the job's data is deleted; null until the job is terminal."
          },
          "data_deleted_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the data was actually deleted (retention, or deleteJobData); null while it still exists."
          },
          "partial": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "True on a failed or cancelled job that still delivered the rows it finished."
          },
          "failure_code": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "invalid_input",
              "internal_error",
              null
            ]
          },
          "failure_reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "max_output_tokens": {
            "type": [
              "integer",
              "null"
            ],
            "description": "The effective per-row output cap (yours, or the estimate)."
          },
          "max_tokens": {
            "type": [
              "integer",
              "null"
            ],
            "deprecated": true,
            "description": "Former name of max_output_tokens, echoed alongside it."
          },
          "reasoning_budget": {
            "type": [
              "integer",
              "null"
            ]
          },
          "temperature": {
            "type": [
              "number",
              "null"
            ],
            "description": "The job-wide temperature set at submit; null means the model's default."
          },
          "video_fps": {
            "type": [
              "number",
              "null"
            ],
            "description": "The job's video sampling rate when it set one; null when its video rows ran at the model's default rate."
          },
          "model": {
            "type": [
              "string",
              "null"
            ]
          },
          "reasoning": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "reasoning_effort": {
            "type": [
              "string",
              "null"
            ],
            "description": "The job-level thinking effort level; null when the model's default applied."
          },
          "task_type": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "chat",
              "embed",
              "decide",
              null
            ]
          },
          "format": {
            "type": [
              "string",
              "null"
            ],
            "description": "The input file's format, jsonl for every new job."
          },
          "response_format": {
            "type": [
              "object",
              "null"
            ]
          },
          "dimensions": {
            "type": [
              "integer",
              "null"
            ]
          },
          "data_residency": {
            "type": "string",
            "enum": [
              "world",
              "eu"
            ],
            "description": "Where the job's payload is stored and processed."
          }
        },
        "required": [
          "id",
          "status"
        ]
      },
      "JobDataDeletion": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "enum": [
              "submitted",
              "estimating",
              "cost_ready",
              "in_progress",
              "cancelling",
              "finalizing",
              "done",
              "failed",
              "cancelled"
            ]
          },
          "data_deleted_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the data was deleted; null on a 202, where the deletion follows once the job has stopped."
          },
          "message": {
            "type": [
              "string",
              "null"
            ],
            "description": "Set on a 202 only: the job is being cancelled and its data will be deleted once it stops."
          }
        },
        "required": [
          "id",
          "status"
        ]
      },
      "JobResult": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "enum": [
              "submitted",
              "estimating",
              "cost_ready",
              "in_progress",
              "cancelling",
              "finalizing",
              "done",
              "failed",
              "cancelled"
            ]
          },
          "result_url": {
            "type": "string",
            "format": "uri",
            "description": "Presigned GET link to the result file."
          },
          "expires_in": {
            "type": "integer",
            "description": "Seconds the link stays valid."
          },
          "partial": {
            "type": "boolean"
          },
          "row_count": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Rows actually in the file."
          }
        },
        "required": [
          "id",
          "status",
          "result_url",
          "expires_in"
        ]
      },
      "ModelList": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "const": "list"
          },
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "object": {
                  "type": "string",
                  "const": "model"
                },
                "task": {
                  "type": "string",
                  "enum": [
                    "embed",
                    "decide"
                  ],
                  "description": "Which route takes the model: embed for createEmbedding, decide for createDecision."
                },
                "embedding_dims": {
                  "type": [
                    "integer",
                    "null"
                  ],
                  "description": "The native vector width of an embed model; null on a decide model."
                },
                "min_embedding_dims": {
                  "type": [
                    "integer",
                    "null"
                  ],
                  "description": "The narrowest dimensions an embed model accepts; a decide model reports the default."
                }
              },
              "required": [
                "id"
              ]
            }
          }
        }
      },
      "EmbeddingRequest": {
        "type": "object",
        "properties": {
          "model": {
            "type": "string",
            "description": "A realtime model id from listRealtimeModels."
          },
          "input": {
            "description": "One text, or up to 128 texts.",
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "maxItems": 128,
                "items": {
                  "type": "string"
                }
              }
            ]
          },
          "dimensions": {
            "type": "integer",
            "minimum": 32,
            "description": "Truncate the vectors to this width: from the model's min_embedding_dims (32 or 64, per model, as listRealtimeModels reports) up to its embedding_dims."
          },
          "encoding_format": {
            "type": "string",
            "enum": [
              "float"
            ]
          }
        },
        "required": [
          "model",
          "input"
        ]
      },
      "EmbeddingResponse": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "const": "list"
          },
          "model": {
            "type": "string"
          },
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "object": {
                  "type": "string",
                  "const": "embedding"
                },
                "index": {
                  "type": "integer"
                },
                "embedding": {
                  "type": "array",
                  "items": {
                    "type": "number"
                  }
                }
              }
            }
          },
          "usage": {
            "type": "object",
            "properties": {
              "prompt_tokens": {
                "type": "integer"
              },
              "total_tokens": {
                "type": "integer"
              }
            }
          }
        }
      },
      "DecisionQuestion": {
        "type": "object",
        "description": "One typed question about the state. Fields beyond these are passed to the model as given (for example labels on a noul question).",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "choice",
              "noul",
              "score"
            ],
            "description": "choice: one option out of several; noul: yes or no; score: a level on an ordered scale."
          },
          "instructions": {
            "type": "string",
            "description": "The question itself, as the model reads it."
          },
          "criteria": {
            "description": "choice: an object of option key to description (both are read by the model). noul: optional, keyed true and false with a description of what each answer means. score: an array of level descriptions, lowest first. A question's option texts share a 192-token budget.",
            "oneOf": [
              {
                "type": "object",
                "additionalProperties": {
                  "description": "A description, or null to use the key alone; a structured value is rendered as JSON."
                }
              },
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            ]
          }
        },
        "required": [
          "type",
          "instructions"
        ]
      },
      "DecisionRequest": {
        "type": "object",
        "description": "The body of createDecision, and minus model the body of one JSONL row of a batch decision job.",
        "properties": {
          "model": {
            "type": "string",
            "description": "A realtime model id from listRealtimeModels whose task is decide."
          },
          "state": {
            "description": "The text the questions are about: a string, or a JSON object the model reads as text. At most 50,000 characters, an object counted as its JSON rendering.",
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "object"
              }
            ]
          },
          "questions": {
            "type": "object",
            "minProperties": 1,
            "maxProperties": 64,
            "description": "Question name to question. The names key the answers.",
            "additionalProperties": {
              "$ref": "#/components/schemas/DecisionQuestion"
            }
          },
          "lang": {
            "type": "string",
            "description": "Optional language code (for example de) that settles which internal checkpoint reads the text, whatever its script: en, eng or english (with or without a region, such as en-US) means the English checkpoint, any other value, a language name included, the multilingual one. A blank value is no hint."
          }
        },
        "required": [
          "model",
          "state",
          "questions"
        ]
      },
      "DecisionAnswer": {
        "type": "object",
        "description": "One answer. The value field follows type: choice carries choice (the most probable option key) and probabilities per option key; noul carries noul, the probability of yes; score carries score (the expected level, 0 to the index of the last level), probabilities per level index and legend. Further fields are the model's own.",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "choice",
              "noul",
              "score"
            ]
          },
          "choice": {
            "type": "string"
          },
          "noul": {
            "type": "number",
            "minimum": 0,
            "maximum": 1
          },
          "score": {
            "type": "number",
            "minimum": 0
          },
          "probabilities": {
            "type": "object",
            "additionalProperties": {
              "type": "number"
            }
          },
          "legend": {
            "type": "object",
            "description": "score only: level index to its description.",
            "additionalProperties": {
              "type": "string"
            }
          },
          "confidence": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "How concentrated the distribution is; indicative, not a calibrated guarantee."
          },
          "answer_confidence": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "The probability of the reported answer, comparable across the three types."
          }
        },
        "required": [
          "type",
          "confidence"
        ]
      },
      "DecisionResponse": {
        "type": "object",
        "properties": {
          "model": {
            "type": "string"
          },
          "answers": {
            "type": "object",
            "description": "One entry per question, under the name the request gave it.",
            "additionalProperties": {
              "$ref": "#/components/schemas/DecisionAnswer"
            }
          },
          "usage": {
            "type": "object",
            "properties": {
              "input_tokens": {
                "type": "integer",
                "description": "The billed count: the state once per question plus each question's words."
              },
              "output_tokens": {
                "type": "integer",
                "const": 0
              }
            }
          },
          "routing": {
            "type": "object",
            "description": "The internal checkpoint that answered and why; informational.",
            "properties": {
              "model": {
                "type": "string"
              },
              "reason": {
                "type": "string"
              }
            }
          }
        },
        "required": [
          "model",
          "answers",
          "usage"
        ]
      },
      "MisdirectedError": {
        "type": "object",
        "description": "The 421 answered for data kept in the other region.",
        "properties": {
          "detail": {
            "type": "string",
            "description": "What went wrong, naming the region and the API to use."
          },
          "residency": {
            "type": "string",
            "enum": [
              "world",
              "eu"
            ],
            "description": "Where the data is kept."
          },
          "api": {
            "type": "string",
            "format": "uri",
            "description": "The origin of the API that serves this data; keep the path, change the origin."
          }
        },
        "required": [
          "detail",
          "residency",
          "api"
        ]
      }
    }
  }
}
