Skip to content

Search is only available in production builds. Try building and previewing the site to test it out locally.

Errors

Every failure the API returns is one shape:

{
"error": {
"type": "quota_exceeded",
"message": "Monthly document quota reached: 200 of 200 documents used this month. The cap resets on 2026-08-01. Email sales@easting.ai to raise it.",
"documents_used": 200,
"monthly_cap": 200,
"resets_on": "2026-08-01"
}
}

Switch on error.type; it is stable. error.message is written to be shown to a person verbatim, which is what the QGIS plugin does. Extra fields ride inside the error object where a type has numbers worth acting on: a 402 carries documents_used and resets_on, a 429 carries its limit. Anything protocol-shaped stays in the protocol: back-off time is a Retry-After header, never a JSON field.

400: the request was understood and refused

Section titled “400: the request was understood and refused”

All five are on POST /v1/signup, the free-tier door.

type when it fires what to do
invalid_email The address does not parse as an email. Fix the address.
terms_not_accepted accepted_terms was not true. Accept the Terms of Service and Privacy Policy, then resend.
disposable_email The domain is a known disposable-mail provider. Use an address you can receive mail at; the key and invite go there.
undeliverable_domain The domain accepts no mail, so the invitation would bounce. Check the spelling.
already_granted This address already used its free documents. Sign in at app.easting.ai, or buy a plan or a pack.

401: fix the credential, retrying will not help

Section titled “401: fix the credential, retrying will not help”
type when it fires what to do
invalid_api_key The bearer token is missing, malformed, or matches no key. Paste the current key from your account page.
revoked_api_key The key existed and was revoked, including by a rotation. Use the successor key, or contact sales@easting.ai.
invalid_token A portal session token (not a key) failed verification. Sign in again.

The family that matters most, because each type calls for different client behavior. All carry the numbers (documents_used plus the relevant cap) so a client can display the state rather than guess it.

quota_exceeded: the account’s cap is reached, counting work already in flight. On a subscription past its overage ceiling the message names the ceiling and resets_on; the ceiling exists to catch runaway usage, so reaching it is a conversation (add seats in the billing portal, or email sales) rather than a wall. Nothing was submitted and nothing was billed. Do not retry until the reset or the raise.

pack_exhausted: a document pack’s credits are spent. Credits never expire, and neither did these: they did their job. Buy another pack (a new key arrives instantly) or subscribe for monthly volume; the response carries the checkout path.

trial_exhausted: the trial’s 3 documents are used. The subscription starts automatically on trial_ends_on and unlocks the full quota; manage or cancel at easting.ai/account. Waiting is a valid strategy here; buying is not required.

free_tier_exhausted: the free documents are used. This is the free tier’s only conversion moment, so the response carries both paths: a $10 seat (50 documents a month) and a $30 pack (10 that never expire), as subscribe and pack checkout paths.

checkout_incomplete: the claim page was reached with a Stripe Checkout session that never completed. Finish the checkout; if you were charged anyway, email support@easting.ai.

type when it fires what to do
upload_not_yours An upload id that could not be one of this key’s (wrong shape, or a path escape). Request a fresh slot from POST /v1/uploads.
not_permitted A staff-only endpoint, called without the staff group. Nothing; the endpoint is for Easting staff.

Ownership failures elsewhere deliberately answer 404, so an id can never confirm that somebody else’s resource exists.

type when it fires what to do
no_such_job GET /v1/extracts/{job} with an id this key never submitted. Check the id; an unknown id and someone else’s look identical.
no_such_batch A batch id this key never submitted. Same.
no_such_upload The staged document is gone. Ids work exactly once and expire unused. Stage the document again.
no_such_key A key prefix that does not exist on this account, e.g. in GET /v1/usage?prefix=. List your keys; prefixes outside the account are invisible by design.
no_subscription A billing-portal route on a key billed by arrangement or by pack. Email sales@easting.ai; there is no self-serve portal for it.

409: the request conflicts with current state

Section titled “409: the request conflicts with current state”
type when it fires what to do
batch_not_ended Results asked for while the batch runs. Carries batch_status. Poll GET /v1/batches/{id} until status is ended.
rotate_failed The key was already revoked or replaced when the rotation ran. List keys and use the current one.
too_many_keys The account’s key ceiling: ten live keys, or one on a free account. Revoke one first, or (free) rotate instead of minting.
no_entitlement The account has no active plan to extract against or issue a key against. Subscribe or buy a document pack first.
type when it fires what to do
result_expired An async job’s result is past its retention window. Nothing to fetch: results live seven days after a fetch, thirty without one. Re-extract if you still need it.
results_expired A batch’s results, same windows. Same.
type when it fires what to do
document_too_large One document over its ceiling: 4.5 MB direct, 32 MB staged, PDF size after image conversion. Stage it through POST /v1/uploads, split it, or rescan lower. The message names both sizes.
batch_too_large A multipart batch whose documents total over the 4.5 MB request ceiling. Stage the documents and submit the ids, which share no ceiling.

The largest family, grouped by which route raises it.

Document intake (/v1/extract, /v1/extracts, /v1/batches):

type when it fires what to do
empty_document The body (or the staged object) was empty. Send PDF, TIFF, PNG, or JPEG bytes.
unsupported_format The magic bytes match none of the four accepted formats. Convert to one of them; filenames are not consulted.
conversion_failed A TIFF/PNG/JPEG that could not be read as an image, or has no pages. If it opens in a viewer, re-export it and try again.
missing_file A multipart body with no file/files part, or a batch with no staged ids. Name the form field the message asks for.
not_multipart A batch body that is neither multipart nor a JSON uploads list. Use one of the two documented batch bodies.
too_many_documents More than 50 documents in one batch. Split it across several batches.
invalid_json A batch JSON body that did not parse. Send {"uploads": [...]}.
missing_upload_id An empty X-Upload-Id. Pass the id POST /v1/uploads returned.

Post-back routes (/v1/certificate, /v1/dxf, /v1/geopackage, /v1/locate, /v1/corrections). See artifacts for the signature rules, including why re-serializing the JSON breaks them:

type when it fires what to do
attestation_missing The posted body carries no signature. Re-run the extraction to get a signed response, then post that.
attestation_mismatch The signature does not match the bytes, edited or re-serialized. Post the response exactly as the API returned it.
attestation_unavailable This server holds no signing key and cannot verify anything. Contact support@easting.ai; this one is ours.
nothing_to_draw No tract carries computed geometry (DXF, GeoPackage). Nothing; the burden and reference fields are in the JSON.
nothing_to_certify No tracts and no document verdict (certificate). Nothing; there is nothing to certify, honestly.
no_extraction The body carries no extraction object. Post a whole extraction response back.
nothing_to_do A corrections call with no corrections and no tracts to adjust. Send at least one of either.
unknown_source A locate source the service does not know. Use plss_corner.
source_unavailable A locate source that is named but not built yet. Use plss_corner.
no_such_tract A correction or adjustment names a tract index the extraction lacks. Indexes are zero-based over extraction.tracts.
no_such_call A correction names a course the tract lacks. Same, over the tract’s calls.
unknown_field A correction targets a field that is not correctable. The message lists the correctable fields.
bad_correction A correction value that does not parse (a bearing that is not a bearing, a distance that is not a number). Fix the value.
stale_correction The correction’s before disagrees with what the extraction now holds. Re-read the extraction and correct against what it actually says.
not_adjustable An adjustment on a tract with no traversable geometry. Nothing; there is no misclosure to distribute.

Checkout parameters (/billing/checkout):

type when it fires what to do
unknown_tier A tier slug that does not exist. The message lists the self-serve tiers.
unknown_pack A pack slug that does not exist. pack-10 is the only pack.
invalid_quantity Pack quantity outside 1–25. For more, email sales@easting.ai.
invalid_seats Seats outside 1–100. Same.

429: back off, and the header says how long

Section titled “429: back off, and the header says how long”

All three carry Retry-After.

type when it fires Retry-After what to do
rate_limited Over the per-minute request limit (120, or 10 free). 60 Wait between polls rather than spin.
too_many_in_flight Over the concurrent-extraction limit (25, or 2 free), batch items included. 30 Collect results, or send volume through POST /v1/batches, which has no concurrency limit.
free_tier_busy The free tier’s daily signup caps (global or per network) are spent. 3600 Try again tomorrow, or start with a document pack.

The two rate limits are documented on the authentication page.

Retrying later is reasonable for all four; nothing was billed on a failed extraction.

type when it fires
extraction_failed The model call failed. The message is the actual reason.
batch_submit_failed The batch could not be handed upstream.
checkout_failed Stripe did not return a checkout URL.
portal_failed Stripe did not return a portal URL.

Each names a capability the deployment lacks rather than a transient fault, so retrying the same server changes nothing.

type when it fires
server_misconfigured Extraction itself is unconfigured. Contact support@easting.ai.
staging_unavailable No staging bucket; large documents cannot be sent here.
async_unavailable No async worker; use POST /v1/extract or POST /v1/batches.
billing_unavailable Self-serve billing is not configured. Email sales@easting.ai.
identity_unavailable Accounts are not configured. The API-key path is unaffected.
free_tier_closed Free signups are switched off. Carries no reopening date, because there is none to promise.

These exist, use the same envelope, and belong to surfaces an API client does not call: invalid_admin_token, not_staff (the operator’s console), not_signed_in, unknown_key, account_unavailable (the legacy /account pages), invalid_webhook, invalid_signature (the Stripe webhook receiver), and no_job, no_document (worker plumbing). Meeting one means a request went somewhere it should not have.