Skip to main content

API overview

JSON over HTTPS. One base URL, one bearer header, one error shape.

https://api-833252724876.us-central1.run.app

These pages are generated from the contract the API publishes at build time, so they describe the deployment that is running right now. Download it.

Credentials​

Authorization: Bearer jean_live_...
Content-Type: application/json

Two kinds of bearer token are accepted, and each page says which it needs.

  • An API key: jean_live_…, created in the dashboard, for everything your code does: submitting evals, reading jobs, checking usage.
  • A session token: issued to a signed-in browser, for the things a human does: creating and revoking keys, inviting people, claiming a domain, accepting terms. An API key is refused on these, so a leaked key cannot mint itself a successor or change who has access.

Keys are scoped to one organization. Nothing belonging to another organization is reachable with yours, and a resource you may not see returns 404 rather than admitting it exists.

Requests​

Every response carries X-Request-Id. Keep it; it is the fastest way for us to find what happened, and it appears inside the error body too.

Send an Idempotency-Key when you submit an eval. Repeating the same key returns the original job instead of queueing a second one, which makes a retry after a timeout safe.

List endpoints take limit and a cursor: GET /v1/jobs returns next_before; pass it back as before for the next page. Its absence means you have reached the end.

Jobs​

Anything that takes real work returns 202 and a job rather than blocking your request. Poll GET /v1/jobs/{job_id}: queued → running → succeeded | failed, or cancelled if you cancel it first. A succeeded job carries a typed result; a failed one carries an error with a code and a message. Every job also has a trace once it has run.

Poll every couple of seconds. An eval job is given fifteen minutes before it is considered stuck, and is retried up to three times.

Errors​

Every non-2xx response, validation failures included, has the same body:

{
"error": {
"code": "quota_exceeded",
"message": "this submission would bring eval_items to 21000 this month; the free plan allows 20000.",
"request_id": "req_z9x8c7v6b5n4m3l2",
"details": {"limit": "eval_items_per_month", "max": 20000, "resets_at": "2026-02-01T00:00:00Z"}
}
}

code is from a closed set, so it is safe to branch on. message is for a human and may change. details is present when there is something specific to say.

CodeStatusWhat to do
invalid_request400Fix the request.
validation_failed422A field is missing or the wrong type; details says which.
payload_too_large413Over 5 MB inline. Use an upload and input_ref.
unauthenticated401No credential was supplied.
invalid_token401The key or session token is not valid.
key_revoked401This key was revoked. Create another.
forbidden403Valid credential, not allowed to do this.
session_required403This route needs a signed-in session, not an API key.
org_required403The credential resolves to no organization.
not_found404No such resource in your organization.
conflict409It already exists.
invalid_state409Not a legal transition, such as cancelling a finished job.
quota_exceeded429A plan limit. details names it and when it resets.
rate_limited429Too many requests this minute. Honour Retry-After.
internal500Ours. Retry with the same idempotency key, and quote request_id.
unavailable503Retry with backoff.

Rate limits​

Counted per organization, per minute: 60 requests on free, 300 on dev, 1,000 on team. Every response tells you where you stand.

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 41
X-RateLimit-Reset: 1768470000
Retry-After: 18

Retry-After appears on 429. Honour it rather than retrying immediately; repeated failed authentication is throttled separately and more harshly.

Versions​

The contract is versioned in info.version, and info.x-git-sha names the exact build serving it. Additions (a new endpoint, a new optional field) happen without a version change; anything that could break a client does not happen silently.