View as Markdown

#The envelope

{
  "error": "method_not_allowed",
  "message": "GET is not supported on this endpoint. Allowed: POST.",
  "request_id": "d22e3678-8a18-4aa3-ab86-bfd374080269",
  "documentation_url": "https://glassmkr.com/docs/api/errors#method_not_allowed",
  "retryable": false,
  "retry_after_seconds": null,
  "details": [{ "allowed_methods": ["POST"] }]
}
  • error is a stable machine code. It is the only field you should make decisions from. Codes are added over time; an unrecognised one should be treated by its HTTP status.
  • message is for humans and logs. The wording can change in any release.
  • request_id matches the X-Request-Id response header. Quote it when reporting a problem.
  • retryable says whether an identical retry could plausibly succeed. A client mistake is never retryable, because retrying it unchanged only burns quota.
  • retry_after_seconds is set when the server can say how long to wait. The Retry-After header carries the same value.
  • details is a list of structured extras, empty when there are none.

This holds for the whole namespace, including a 404 for an unknown path and a 405 for the wrong verb. Those two used to return the HTML app shell and untyped plain text respectively, which is exactly the shape an autonomous client cannot recover from.

#Deciding what to do

The envelope is designed so a client can decide without reading prose:

  • retryable: true and a retry_after_seconds: wait that long, then retry the same request.
  • retryable: true without a delay: retry with your own backoff.
  • retryable: false on a 401: get a different credential. The same one will fail identically.
  • retryable: false on a 403: stop. This credential is not permitted the operation, and repeating it will not change that.
  • retryable: false on a 400 or 422: fix the request from details before sending anything again.
  • retryable: false on a 409: re-read the current state before deciding, because yours is stale.

#Code reference

19 codes, 5 of them retryable. Each anchor here is what documentation_url points at.

CodeStatusRetryableMeaning
invalid_request400noThe request was malformed or a field failed validation. Read details, correct the request, do not retry unchanged.
unauthenticated401noNo credential was presented, or the one presented was not accepted. Obtain or refresh a credential; retrying the same one will fail identically.
payment_required402noThe account's billing state blocks this operation.
forbidden403noThe credential is valid but not permitted this operation, usually a scope or ownership boundary. Do not retry; a different credential is needed.
not_found404noThe addressed resource does not exist, or is not visible to this credential.
unknown_endpoint404noNo API route matches this path at all. Check /api/openapi.json for the routes this deployment serves.
method_not_allowed405noThe route exists but not for this HTTP verb. details carries allowed_methods, and the Allow header repeats it.
conflict409noThe operation conflicts with current state, for example a stale version or an operation already in progress. Re-read state before deciding.
gone410noThe resource existed and has been removed permanently.
payload_too_large413noThe request body exceeded the accepted size.
unsupported_media_type415noThe Content-Type is not accepted by this route.
unprocessable422noThe request parsed but could not be acted on as given.
rate_limited429yesToo many requests. Wait retry_after_seconds, or the Retry-After header, before retrying.
pro_required403noLegacy code from the retired Free/Pro split, kept because old clients may still branch on it. Nothing in the API is tier-gated as of August 2026.
internal_error500yesAn unexpected server fault. Safe to retry with backoff; report request_id if it persists.
upstream_error502yesA dependency failed. Retry with backoff.
unavailable503yesThe service is temporarily unable to handle the request. Retry with backoff.
upstream_timeout504yesA dependency did not answer in time. Retry with backoff.
request_failed4xxnoFallback for a 4xx status with no more specific code. Treat as non-retryable and read message.

#OAuth is deliberately different

The MCP authorization endpoints under /oauth/ return the shape RFC 6749 mandates, { error, error_description }, not the envelope above. An OAuth client is entitled to expect the standard shape, so those routes are excluded on purpose rather than by oversight.