Errors

The API reports failures with a small, fixed set of error codes. Each code has one HTTP status and one message, so you can branch on error.code without parsing text.

On this page

The error envelope

json
{
  "error": {
    "code": "forbidden",
    "message": "This credential may not perform this operation. The token may not include the scope it needs, or the account that issued it may not have access to this data, for example because that account is not yet linked to a worker or billing entity. A program admin can check the account's access."
  },
  "request_id": "…"
}
  • error.code is one of the six codes below.
  • error.message is fixed text for that code. It never contains details about your request, your workspace or any record.
  • request_id matches the x-request-id response header. Quote it when you contact support.
  • retry_after_seconds appears only on rate_limited. See Rate limits and quotas.

Every error response carries cache-control: no-store.

Some problems are not errors. An operation that declines a request for a reason it names, such as an invalid cursor, returns 200 with data.status: "refused". See Named refusals are data.

Error codes

CodeHTTPMessage
unauthorized401The credential is missing, malformed, expired or revoked.
not_enabled403Agent access is not available for this credential.
forbidden403This credential may not perform this operation. The token may not include the scope it needs, or the account that issued it may not have access to this data, for example because that account is not yet linked to a worker or billing entity. A program admin can check the account's access.
not_found404 (also 405 and 413)No such operation, or the request did not match its arguments.
rate_limited429The rate limit for this credential was exceeded. Retry later.
internal_error500The operation could not be completed. Retry later.

What causes each code

401 unauthorized

The Authorization header is missing or not in the form Bearer <token>, the token is malformed, expired or revoked, or the account that issued it has been deactivated. The response includes WWW-Authenticate: Bearer realm="agent-gateway". On a documented REST endpoint, VendOrca checks the token before the method and the arguments, so a request without a valid token gets 401 even if its method is also wrong. Only an oversized body is checked earlier; see 413.

403 not_enabled

The token is valid, but agent access is not available to its workspace right now. Agent access may be off or paused, a Program Admin may need to review an updated disclosure, or the workspace's plan may not include agent access. Existing tokens start working again once the workspace is back on, with no need to reissue them.

403 forbidden

The token is valid and agent access is on, but this call isn't allowed. The token may lack the scope the operation needs, the issuer's role may not be able to open the matching page in the app, or a Worker or Billing Entity sign-in may not yet be linked to its record, which the person's Program Admin arranges. See Scopes.

404 not_found

Over MCP, the tool name doesn't exist. Over REST and MCP, the arguments didn't match the operation, for example a value of the wrong type or out of range. Over REST, an unknown or repeated query parameter and a POST body that isn't valid JSON also get 404. Over MCP, a body that isn't valid JSON gets HTTP 400 with JSON-RPC error -32700 instead; see JSON-RPC errors. Read the operation's parameters on its resource page and fix the request.

405 with Allow

The path exists but not for this method, for example a POST to /api/v1/workers. The status is 405, the body code is not_found, and the Allow header lists the method to use:

http
HTTP/1.1 405 Method Not Allowed
allow: GET
content-type: application/json; charset=utf-8
cache-control: no-store
x-request-id: …

{"error":{"code":"not_found","message":"No such operation, or the request did not match its arguments."},"request_id":"…"}

413 payload too large

The request body is larger than 64 KiB. The body code is not_found. Real requests are a few hundred bytes, so a 413 usually means the wrong data was sent.

429 rate_limited

The token or its workspace used up a request quota. The response has a Retry-After header and a retry_after_seconds field with the same number of seconds. See Rate limits and quotas.

500 internal_error

VendOrca couldn't complete the operation. Retry with backoff. If it keeps failing, contact support with the request_id.

Errors over MCP

The MCP endpoint reports problems in two ways. Problems with the HTTP request itself, including a bad token, come back as a JSON-RPC error with an HTTP error status. Problems with a single tool call come back as a tool result with isError: true.

JSON-RPC errors

SituationHTTPJSON-RPC codemessage
Missing or invalid token401-32001unauthorized, with data.request_id and a WWW-Authenticate header
Body larger than 64 KiB413-32600request_too_large
Body is not valid JSON, or is JSON but not a JSON-RPC message400-32700parse_error for invalid JSON. A body that isn't a JSON-RPC message gets the MCP transport's own text.
Unsupported protocol version400-32602unsupported_protocol_version, with data.supported listing the versions you can use
Accept doesn't list both application/json and text/event-stream, or Content-Type isn't application/json406 or 415-32000Set by the MCP transport
Server failure500-32603internal_error, with data.request_id (a failure inside tools/list arrives at HTTP 200 without data)

Any HTTP method other than POST or OPTIONS returns 405 with Allow: POST and an empty body.

Tool results with isError

When a tool call is denied, for example for a missing scope, a quota or agent access being off, the HTTP status is 200 and the JSON-RPC call succeeds. The tool result has isError: true, and its text is the same error envelope REST returns:

json
{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "isError": true,
    "content": [
      {
        "type": "text",
        "text": "{\"error\":{\"code\":\"rate_limited\",\"message\":\"The rate limit for this credential was exceeded. Retry later.\"},\"request_id\":\"…\",\"retry_after_seconds\":12}"
      }
    ]
  }
}

Parse content[0].text as JSON and handle error.code the same way you would for REST.

Handling errors

CodeRetry?What to do
unauthorizedNoStop. Get a new token from the person who owns the agent.
not_enabledNoStop and tell the user. A Program Admin needs to check Agent access.
forbiddenNoDon't retry the same call. Tell the user which scope or access is likely missing.
not_foundNoFix the tool name or the arguments first.
rate_limitedYesWait at least retry_after_seconds, then retry.
internal_errorYesRetry with exponential backoff and a cap on attempts.

Every operation is a read, so retrying a call never changes data.

Next steps

Was this page helpful?

Need help? Contact support