Skip to content
Try Free →

AskVault API error codes

Last updated: · 4 min read

Error response shape

Errors are JSON with a single field:

{ "detail": "Invalid or revoked API key." }

There is no machine-readable error code field, so branch on the HTTP status and treat detail as a human-readable message. Every response, successful or not, carries an X-Request-ID header. Log it. Unhandled server errors also repeat it in the body as request_id.

Status codes

StatusWhenWhat to do
401Missing, malformed, revoked or inactive API key. detail is "Missing or invalid API key. Use: Authorization: Bearer ak_xxx" or "Invalid or revoked API key."Check the Authorization: Bearer ak_... header. Do not retry.
402Your account is out of message credits, or the workspace's model is not available on your plan.Buy credits, upgrade, or change model. Do not retry until fixed.
403Your plan does not include API access: "'api' requires a higher plan."The API needs Starter or above.
404"Conversation not found." when you pass a conversation_id that does not belong to the workspace, or the key's workspace or owner no longer exists.Check the ID, or start a new conversation.
422The request body failed validation, for example a missing query or one over 4,000 characters: "Validation error: query: Field required".Fix the body. Do not retry unchanged.
429A key's rate limit was hit: "Per-minute rate limit exceeded (60/min). Try again shortly." or "Daily rate limit exceeded (1000/day). Try again later."Back off and retry. No Retry-After header is sent.
500Something failed on our side: "An internal error occurred. Please try again later." plus request_id.Retry with backoff; contact support if it persists.
502 / 503 / 504An upstream service or the network failed.Retry with backoff.

Retry strategy

import time, requests
from random import uniform
def ask(query: str, key: str, attempts: int = 5):
for attempt in range(attempts):
r = requests.post(
"https://api.askvault.co/v1/query",
headers={"Authorization": f"Bearer {key}"},
json={"query": query},
timeout=60,
)
if r.status_code == 200:
return r.json()
if r.status_code == 429 or r.status_code >= 500:
time.sleep(min(60, 2 ** attempt) + uniform(0, 1))
continue
raise Exception(f"{r.status_code}: {r.json().get('detail')} (request {r.headers.get('X-Request-ID')})")
raise Exception("Max attempts exceeded")

Rules of thumb:

  • 4xx other than 429: do not retry; the request needs changing.
  • 429: back off with increasing delays, up to a minute, then retry.
  • 5xx: exponential backoff with jitter, a handful of attempts at most.

What counts against your limits

  • A request that reaches AskVault reserves one unit of the key's daily limit. Server errors (5xx) and an unknown conversation_id (404) give it back. Other rejections, such as 402, 403 or 429, can still use the unit today; a change that refunds those is rolling out.
  • Message credits are only used when an answer is produced.

Debugging tips

  • Log X-Request-ID for every failed call.
  • Print detail; it names the field or limit involved.
  • Test the same question in the chat playground to separate content problems from integration problems.

Common pitfalls

Branching on an error code field. There isn't one. Use the HTTP status.

Retrying 422 in a loop. The body is invalid; retrying gives the same error.

Retrying 429 immediately. You will get another 429. Back off first.

FAQ

Is a retried request idempotent?

No. Each retry is a new question and can use a message credit if it produces an answer. There is no idempotency key on the query API.

Are 5xx errors charged?

No message credit is used when no answer is produced, and 5xx responses give back the daily-limit unit.

How do I reach support about an error?

Email [email protected] with the X-Request-ID value, the time and the detail message.

Was this page helpful?