Bank statements (beta)
Upload a bank statement and get its transactions as JSON, CSV, Excel, QuickBooks or Quicken files. Create, upload, then poll: three calls and one download.
How does the FastOCR bank statement API work?
Create a statement to get a presigned upload URL, upload the PDF or image to it, then poll the statement. The first poll after the upload starts extraction. When the status is completed, the response carries a download link for each format: JSON, CSV, Excel (XLSX), QuickBooks QBO, QuickBooks CSV, QFX and OFX. The API is in beta, like the web converter. It uses the same bank statement pages as the website, and your first 50 pages are free.
Docs menu
On this page
Quickstart
Install the Python SDK, or use Node.js or plain HTTP. Choose a language in any code block. Every example reads the API key from FASTOCR_API_KEY. Get an API key first.
pip install fastocr-sdkfrom fastocr_sdk import FastOCR
# Reads the key from the FASTOCR_API_KEY environment variable.
with FastOCR() as client:
job = client.extract_statement("statement.pdf")
client.bank_statements.save(job.id, "statement.xlsx", "xlsx")
print(job.status, job.pages_billed, job.needs_review)// Node.js 18+, no dependencies. Save as statement.mjs and run: node statement.mjs
import { readFile, writeFile } from 'node:fs/promises';
import { randomUUID } from 'node:crypto';
const BASE = 'https://api.fastocr.org';
const auth = { Authorization: `Bearer ${process.env.FASTOCR_API_KEY}` };
async function api(path, init = {}) {
const response = await fetch(BASE + path, { ...init, headers: { ...auth, ...init.headers } });
const body = await response.json();
if (!response.ok) throw new Error(`${response.status} ${body.error?.code ?? body.message}`);
return body;
}
const pdf = await readFile('statement.pdf');
// 1. Create a statement
const created = await api('/v1/bank-statements', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Idempotency-Key': randomUUID() },
body: JSON.stringify({ filename: 'statement.pdf' }),
});
// 2. Upload the file to the presigned URL
const upload = await fetch(created.upload_url, {
method: 'PUT',
headers: { 'Content-Type': 'application/pdf' },
body: pdf,
});
if (!upload.ok) throw new Error(`Upload failed: ${upload.status}`);
// 3. Poll until the status is completed or failed. The first poll after the upload starts extraction.
let statement;
do {
statement = await api(`/v1/bank-statements/${created.id}`);
if (!['completed', 'failed'].includes(statement.status)) await new Promise((resolve) => setTimeout(resolve, 3000));
} while (!['completed', 'failed'].includes(statement.status));
if (statement.status === 'failed') throw new Error(statement.error.code);
// Download the Excel file from the link in the completed statement
await writeFile('statement.xlsx', Buffer.from(await (await fetch(statement.outputs.xlsx.url)).arrayBuffer()));
console.log(statement.status, statement.pages_billed, statement.needs_review);export FASTOCR_API_KEY="your_api_key"
# 1. Create a statement
RESPONSE=$(curl -sS --fail-with-body -X POST https://api.fastocr.org/v1/bank-statements \
-H "Authorization: Bearer $FASTOCR_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"filename":"statement.pdf"}')
STATEMENT_ID=$(echo "$RESPONSE" | jq -r .id)
UPLOAD_URL=$(echo "$RESPONSE" | jq -r .upload_url)
# 2. Upload the file to the presigned URL
curl -sS --fail-with-body -X PUT "$UPLOAD_URL" \
-H "Content-Type: application/pdf" \
--data-binary @statement.pdf
# 3. Poll until the status is completed or failed. The first poll after the upload starts extraction.
while true; do
BODY=$(curl -sS --fail-with-body https://api.fastocr.org/v1/bank-statements/$STATEMENT_ID \
-H "Authorization: Bearer $FASTOCR_API_KEY") || exit 1
STATUS=$(echo "$BODY" | jq -r .status)
case "$STATUS" in completed|failed) break;; esac
sleep 3
done
[ "$STATUS" = "completed" ] || { echo "$BODY" | jq .error; exit 1; }
# Download the Excel file from the link in the completed statement
curl -sS --fail-with-body "$(echo "$BODY" | jq -r .outputs.xlsx.url)" -o statement.xlsxextract_statement creates the statement, uploads the file, waits for the result and returns it. The SDK always sends size_bytes. save downloads one format.
size_bytes, POST /start and GET /output, is unchanged. See Start and output.Authentication
Send your API key as Bearer <key> in the Authorization header. Create keys in the developer console. One key works for Document OCR and bank statements.
curl https://api.fastocr.org/v1/bank-statements \
-H "Authorization: Bearer $FASTOCR_API_KEY"A missing, unknown or revoked key returns a gateway error before the request reaches the API. See Errors.
POST/v1/bank-statements
Create a statement and get a presigned upload URL.
Required headers
Idempotency-Key: a unique value for each statement, up to 255 characters. Repeat a request with the same key and body to get the same statement back. A replay after the upload URL expired returns a fresh URL. A different body with the same key returns 409 idempotency_key_conflict.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
| Fieldfilename | Typestring | RequiredYes | DescriptionUp to 255 characters. The extension sets the upload Content-Type: .pdf, .png, .jpg, .jpeg or .webp. |
| Fieldsize_bytes | Typeinteger | RequiredNo | DescriptionExact size of the file in bytes. If you send it, the API checks the uploaded file against it. If you leave it out, the API checks the real size when extraction starts. |
| Fieldexternal_id | Typestring | RequiredNo | DescriptionYour own reference, up to 256 characters. The API returns it on every read. |
statement = client.bank_statements.create("statement.pdf", size_bytes=1_048_576, external_id="ACME-2026-10")
print(statement.id, statement.upload_url)const created = await api('/v1/bank-statements', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Idempotency-Key': randomUUID() },
body: JSON.stringify({ filename: 'statement.pdf', external_id: 'ACME-2026-10' }),
});curl -sS -X POST https://api.fastocr.org/v1/bank-statements \
-H "Authorization: Bearer $FASTOCR_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"filename":"statement.pdf","external_id":"ACME-2026-10"}'Response
{
"id": "stmt_9f2c4e1a7b3d",
"status": "awaiting_upload",
"upload_url": "https://...s3.amazonaws.com/...",
"expires_at": "2026-11-05T13:00:00.123456+00:00"
}{
"error": {
"type": "invalid_request",
"code": "unsupported_file_type",
"message": "Bank statements must be PDF, PNG, JPG, JPEG, or WebP files",
"request_id": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef"
}
}Send the file with PUT to upload_url before expires_at (one hour). Set Content-Type to application/pdf, image/png, image/jpeg or image/webp to match the extension. The URL is signed for that type.
GET/v1/bank-statements/{id}
Get one statement. This is the call you poll. When the status is awaiting_upload and the file has arrived, the call starts extraction, and the response already shows processing. A call never returns an error for a bad upload: the statement becomes failed with a code instead, so a polling loop always ends.
| Field | Type | Required | Description |
|---|---|---|---|
| Fieldid | Typestring | RequiredYes | DescriptionThe statement id from the create response. |
statement = client.bank_statements.get(statement_id)
print(statement.status)const statement = await api(`/v1/bank-statements/${created.id}`);curl -sS https://api.fastocr.org/v1/bank-statements/$STATEMENT_ID \
-H "Authorization: Bearer $FASTOCR_API_KEY"{
"id": "stmt_9f2c4e1a7b3d",
"status": "completed",
"external_id": "ACME-2026-10",
"pages_billed": 3,
"pages_total": 3,
"has_transactions": true,
"needs_review": false,
"coverage": "complete",
"outputs": {
"json": { "available": true, "url": "https://...", "expires_at": "2026-11-05T14:00:00.123456+00:00" },
"csv": { "available": true, "url": "https://...", "expires_at": "2026-11-05T14:00:00.123456+00:00" },
"xlsx": { "available": true, "url": "https://...", "expires_at": "2026-11-05T14:00:00.123456+00:00" },
"qbo": {
"available": true,
"accounts": [1],
"files": [{ "account": 1, "url": "https://...", "expires_at": "2026-11-05T14:00:00.123456+00:00" }]
}
}
}{
"id": "stmt_9f2c4e1a7b3d",
"status": "failed",
"pages_billed": 0,
"error": {
"type": "insufficient_credits",
"code": "buy_pages",
"message": "You're out of bank statement pages. Add a bank statement pack to process this file."
}
}Response fields
pages_billedandpages_total: pages charged and pages in the file. A failed or refunded statement bills 0.needs_reviewandcoverage(complete,unconfirmedorpartial) are present on a completed statement;has_transactionsis always present. The JSON file carries the detail. See JSON schema 3.outputs.<format>.urlandexpires_at: a download link, valid for one hour. CallGETagain for fresh links.- Accounting formats list their
accounts(numbers from 1) and one link per account infiles: [{ account, url, expires_at }]. error: on a failed statement, withtype,codeandmessage. See Errors.
GET/v1/bank-statements
List statements, newest first, in the bank_statements array. Pass next_cursor as cursor until it is null. The list shows outputs.<format>.available but no download links: get one statement for links.
| Field | Type | Required | Description |
|---|---|---|---|
| Fieldlimit | Typeinteger | RequiredNo | Description1 to 100. Default 20. |
| Fieldcursor | Typestring | RequiredNo | DescriptionThe next_cursor of the previous page. A cursor expires after 24 hours. |
| Fieldstatus | Typestring | RequiredNo | DescriptionOne of awaiting_upload, queued, processing, completed, failed. |
| Fieldupdated_since | Typestring | RequiredNo | DescriptionOnly statements whose status changed at or after this ISO 8601 time. Percent-encode a + offset. |
page = client.bank_statements.list(status="completed")
for statement in page.bank_statements:
print(statement.id, statement.pages_billed)
print(page.next_cursor)curl -sS "https://api.fastocr.org/v1/bank-statements?limit=20&status=completed" \
-H "Authorization: Bearer $FASTOCR_API_KEY"DELETE/v1/bank-statements/{id}
Delete a statement and its files. The API returns 202 with {"status":"deleting"} and removes the files in the background. A statement in processing returns 409 statement_processing.
client.bank_statements.delete(statement_id)curl -sS -X DELETE https://api.fastocr.org/v1/bank-statements/$STATEMENT_ID \
-H "Authorization: Bearer $FASTOCR_API_KEY"Start and output (optional)
Two calls from the original flow stay available. New code does not need them.
POST /v1/bank-statements/{id}/start
Starts extraction without a poll. Use it to retry a statement that failed with buy_pages after you buy a pack: a GET never restarts that statement. It returns 202. When the account is at its concurrency limit it returns 429 concurrency_limit with Retry-After. If you sent size_bytes at create, a different uploaded size returns 400 size_mismatch.
GET /v1/bank-statements/{id}/output
Returns { format, url, expires_at, pages_billed, pages_total } for one format of a completed statement. It is the only way to ask for schema=3 or include=source.
| Field | Type | Required | Description |
|---|---|---|---|
| Fieldformat | Typestring | RequiredYes | DescriptionOne of json, csv, xlsx, qbo, quickbooks_csv, qfx, ofx. |
| Fieldaccount | Typeinteger | RequiredNo | DescriptionThe 1-based account for an accounting format. Required when the statement has several accounts. |
| Fieldschema | Typestring | RequiredNo | Description3 returns the schema 3 JSON document. |
| Fieldinclude | Typestring | RequiredNo | Descriptionsource adds the as-read source text to format=json. |
Output formats
| format | File | Notes |
|---|---|---|
| formatjson | FileSchema 3 JSON | NotesAccounts, summaries, transactions and review signals. See JSON schema 3. |
| formatcsv | FileCSV | NotesOne file for all accounts. UTF-8 with a BOM, dot decimals, ISO dates, rows oldest first. |
| formatxlsx | FileExcel | NotesOne sheet per account with the CSV columns, plus a Summary sheet. |
| formatqbo | FileQuickBooks Web Connect | NotesOne file per account. |
| formatquickbooks_csv | FileQuickBooks Online CSV | NotesThe 3-column import CSV. One file per account. |
| formatqfx | FileQuicken | NotesOne file per account. |
| formatofx | FileOFX 1.0.2 | NotesFor Xero, Wave and other tools. One file per account. |
The accounting formats hold one account each. For a statement with one account, GET /output needs no account; with several, leave it out and the API returns 400 account_required.
client.bank_statements.save(statement_id, "statement.qbo", "qbo", account=1)
data = client.bank_statements.json(statement_id)# Accounting formats: add the account when the statement has several
curl -sS --fail-with-body "$(echo "$BODY" | jq -r '.outputs.qbo.files[0].url')" -o statement.qboFields and columns are never renamed, removed or reordered. The API may add JSON fields and trailing CSV and Excel columns, so ignore what you do not know.
JSON schema 3
format=json returns one document with a list of accounts, each with its own transactions. Money fields are decimal strings, such as "2500.00". Parse them with a decimal type, not a float. amount is unsigned and direction gives the sign.
{
"schema_version": "3",
"status": "completed",
"needs_review": true,
"coverage": { "state": "complete", "issues": [] },
"document": { "bank": "Example Bank", "pages": [{ "page": 1, "status": "read" }] },
"accounts": [
{
"account_number": "12345678",
"holder": "Jane Smith",
"type": "deposit",
"currency": "USD",
"period": { "start": "2025-06-01", "end": "2025-06-30" },
"summary": {
"opening_balance": "5000.00",
"opening_balance_printed": true,
"closing_balance": "7412.50",
"closing_balance_printed": true,
"total_in": "2500.00",
"total_out": "87.50",
"rows": 2,
"rows_verified": 1,
"ties_out": true
},
"issues": [],
"transactions": [
{
"id": "txn_3f9a1c2b7d8e4a5f60b1c2d3",
"date": "2025-06-02",
"date_printed": "02/06/2025",
"description": "Direct Deposit - Payroll",
"reference": "PAY-2025-06",
"amount": "2500.00",
"direction": "in",
"balance": "7500.00",
"page": 1,
"status": "verified",
"reasons": []
}
]
}
]
}Document
| Field | Type | Description |
|---|---|---|
| Fieldschema_version | Typestring | Description"3". |
| Fieldstatus | Typestring | Descriptioncompleted or no_transactions. |
| Fieldneeds_review | Typeboolean | DescriptionA workflow signal, not a guarantee. false only when no check found an issue in any account. It is true when coverage.state is partial. Read coverage to learn whether anything is missing. |
| Fieldcoverage | Typeobject | Description{ state, issues }. state is complete, unconfirmed or partial. Each issue is { page, type, state, detail }. Treat only complete as nothing known to be missing. Absent on old results. |
| Fielddocument | Typeobject | Description{ bank, pages }. pages is [{ page, status }] with read, blank, no_transactions, unsupported_script, unreadable, empty, rows_empty, rows_failed or ungrounded. |
| Fieldaccounts | Typearray | DescriptionOne object per detected account. |
Account
| Field | Type | Description |
|---|---|---|
| Fieldaccount_number | Typestring? | DescriptionAs printed, or null. |
| Fieldholder | Typestring? | DescriptionAccount holder name. |
| Fieldtype | Typestring | Descriptiondeposit, credit_card, loan or other. |
| Fieldcurrency | Typestring? | DescriptionISO 4217 code. |
| Fieldperiod | Typeobject | Description{ start, end } as ISO dates, or null. |
| Fieldsummary | Typeobject | Descriptionopening_balance, opening_balance_printed, closing_balance, closing_balance_printed, total_in, total_out, rows, rows_verified and ties_out. Money is a decimal string. ties_out is null when an endpoint is missing or a row direction is unclear. |
| Fieldissues | Typearray | DescriptionItems shaped { type, page, detail } that need review, such as unverified_rows or does_not_tie_out. |
| Fieldtransactions | Typearray | DescriptionOldest first. |
Transaction
| Field | Type | Description |
|---|---|---|
| Fieldid | Typestring | DescriptionUnique in the document and identical across the JSON, CSV and Excel of one statement. |
| Fielddate | Typestring? | DescriptionISO 8601 date. null when the year is not proven. The API never guesses a year. |
| Fielddate_printed | Typestring | DescriptionThe date as printed. |
| Fielddescription | Typestring | DescriptionNarration. Empty, never null. |
| Fieldreference | Typestring? | DescriptionReference or cheque number. |
| Fieldamount | Typestring? | DescriptionUnsigned decimal string. |
| Fielddirection | Typein | out | null | Descriptionnull when the statement does not show which way the amount goes. |
| Fieldbalance | Typestring? | DescriptionRunning balance as printed. Negative when the statement prints it with a minus, brackets or a debit mark. |
| Fieldpage | Typeinteger | DescriptionPage number, from 1. |
| Fieldstatus | Typestring | Descriptionverified: the balance chain and source checks passed. check: a check failed, so compare the row with the source. unchecked: nothing could check the row, for example the statement prints no running balances. |
| Fieldreasons | Typestring[] | DescriptionAt least one code on every row that is not verified, such as chain_break, direction_unknown or date_unproven. Ignore codes you do not know. |
Verification is a review aid, not a guarantee. Apply your own controls before you automate on verified rows.
Statuses
| Status | Meaning | Final |
|---|---|---|
| Statusawaiting_upload | MeaningThe statement exists and the file has not arrived. | FinalNo |
| Statusqueued | MeaningThe file arrived and the account is at its concurrency limit. The response carries Retry-After. Keep polling: a later GET starts it. | FinalNo |
| Statusprocessing | MeaningExtraction is running. | FinalNo |
| Statuscompleted | MeaningThe result is ready, including a statement with no transactions (has_transactions is false). outputs carries the download links. | FinalYes |
| Statusfailed | MeaningExtraction failed. error has the type, code and message. | FinalYes |
Poll every few seconds until the status is final. A statement that waits for a slot shows queued and starts on a later poll.
Pages and limits
- The API uses the same bank statement pages as the website. Your first 50 pages are free, once per account. Then buy a Bank Statement Pack. A pack bought on the website works for the API, and the reverse.
GET /v1/balanceshowsstatement_pages_remaining. - Each page counts. A statement has up to 100 pages. A refused or failed statement is not charged.
- Files: PDF up to 50 MiB, and PNG, JPG, JPEG or WebP images up to 20 MiB. Scanned statements may need more review. Loan statements are refused and not charged.
- Concurrency, the same rule as Document OCR: 2 statements at once; 10 with a document contract or 10,000+ pages bought. Statements and documents are counted separately.
Errors
A request error returns { "error": { type, code, message, request_id } } with an HTTP status. A statement that fails during extraction is a 200 with status failed and an error object.
Failure codes
| Code | Type | When | Retryable |
|---|---|---|---|
| Codebuy_pages | Typeinsufficient_credits | WhenThe account has no bank statement pages left. | RetryableNo. Buy a Bank Statement Pack. Then call POST /start again on the same statement. |
| Codeunreadable_statement | Typeinvalid_request | WhenThe API could not read the statement. Nothing is charged. | RetryableNo |
| Codenot_a_bank_statement | Typeinvalid_request | WhenThe file is not a bank account statement. Nothing is charged. | RetryableNo |
| Codeunsupported_statement_type | Typeinvalid_request | WhenThe file is a loan statement, or a scanned card statement. | RetryableNo |
| Codescan_limit_reached | Typerate_limit | WhenToo many scans or photos from this account could not be read today. Upload the PDF from online banking, or try again tomorrow. | RetryableNo |
| Codeinvalid_upload | Typeinvalid_request | WhenThe uploaded file is over the size limit for its type, or its size does not match size_bytes. Create a new statement and upload the file again. | RetryableNo |
| Codestatement_pages_unavailable | Typeprocessing_error | WhenThe API could not reserve pages right now. Nothing is charged. | RetryableYes |
| Codepassword_protected | Typeinvalid_request | WhenThe file has a password. | RetryableNo |
| Codeunreadable_document | Typeinvalid_request | WhenThe API could not read the PDF. | RetryableNo |
| Codeno_text_detected | Typeinvalid_request | WhenThe API found no readable text in the file. | RetryableNo |
| Codecorrupted_file | Typeinvalid_request | WhenThe file has damage, or the API does not support it. | RetryableNo |
| Codeimage_too_large | Typeinvalid_request | WhenThe image is too large or has too many pixels to read. Upload a smaller copy. | RetryableNo |
| Codetoo_many_pages | Typeinvalid_request | WhenThe file has more pages than one document may hold. | RetryableNo |
| Codeempty_file | Typeinvalid_request | WhenThe file has no pages. | RetryableNo |
| Codetimeout | Typeprocessing_error | WhenProcessing took too long. | RetryableYes |
| Codeout_of_memory | Typeprocessing_error | WhenProcessing used all available memory. | RetryableYes |
| Codeprocessing_failed | Typeprocessing_error | WhenAny other failure. | RetryableYes |
Request error codes
| HTTP | Code | Type | When |
|---|---|---|---|
| HTTP400 | Codemissing_idempotency_key | Typeinvalid_request | WhenA create request has no Idempotency-Key header. |
| HTTP400 | Codeinvalid_idempotency_key | Typeinvalid_request | WhenThe Idempotency-Key header is longer than 255 characters. |
| HTTP400 | Codeinvalid_filename | Typeinvalid_request | Whenfilename is missing, is not a string, or is longer than 255 characters. |
| HTTP400 | Codeunsupported_file_type | Typeinvalid_request | Whenfilename does not end in .pdf, .png, .jpg, .jpeg or .webp. |
| HTTP400 | Codeinvalid_size_bytes | Typeinvalid_request | Whensize_bytes is sent and is not a positive integer. |
| HTTP400 | Codefile_too_large | Typeinvalid_request | Whensize_bytes is more than the PDF or image limit. |
| HTTP400 | Codeinvalid_external_id | Typeinvalid_request | Whenexternal_id is not a string of at most 256 characters. |
| HTTP400 | Codeupload_not_found | Typeinvalid_request | WhenA POST /start request came before the file upload. |
| HTTP400 | Codesize_mismatch | Typeinvalid_request | WhenA POST /start request found an uploaded file whose size differs from the size_bytes sent at create. A GET makes the statement fail with invalid_upload instead. |
| HTTP400 | Codeinvalid_format | Typeinvalid_request | Whenformat is not one of the output formats. |
| HTTP400 | Codeinvalid_account | Typeinvalid_request | Whenaccount is not a positive integer, or it is sent with a format that is not an accounting format. |
| HTTP400 | Codeaccount_required | Typeinvalid_request | WhenThe statement has several accounts and an accounting format request has no account. |
| HTTP400 | Codeinvalid_schema | Typeinvalid_request | Whenschema is not 3. |
| HTTP400 | Codeinvalid_include | Typeinvalid_request | Wheninclude is not source, or it is sent with a format other than json. |
| HTTP400 | Codeinvalid_limit | Typeinvalid_request | Whenlimit is not an integer from 1 to 100. |
| HTTP400 | Codeinvalid_status | Typeinvalid_request | Whenstatus is not a public statement status. |
| HTTP400 | Codeinvalid_cursor | Typeinvalid_request | Whencursor has the wrong format, or it is more than 24 hours old. |
| HTTP404 | Codestatement_not_found | Typenot_found | WhenThis account has no such statement. |
| HTTP404 | Codeoutput_not_found | Typenot_found | WhenThe statement has no file in the requested format. |
| HTTP409 | Codeidempotency_key_conflict | Typeconflict | WhenA request used the key before with a different body. |
| HTTP409 | Codestatement_not_startable | Typeconflict | WhenThe statement is completed, or failed with a code other than buy_pages. |
| HTTP409 | Codestatement_not_ready | Typeconflict | WhenA client requested GET /output before the statement completed. |
| HTTP409 | Codestatement_processing | Typeconflict | WhenA client sent DELETE for a statement that is in flight. |
| HTTP429 | Codeconcurrency_limit | Typerate_limit | WhenToo many statements are in flight on POST /start. Wait the Retry-After seconds, then call it again. A GET shows queued instead of this error. |
Gateway error codes
| HTTP | Code | Type | When |
|---|---|---|---|
| HTTP401 | Codeunauthorized | Typegateway_error | WhenThe request has no Authorization header. |
| HTTP403 | Codeaccess_denied | Typegateway_error | WhenThe API key is unknown, malformed, or revoked. |
| HTTP429 | Codethrottled | Typegateway_error | WhenThe request is above the per-key or per-address rate limit on /v1, or the shared throttle of the API gateway. A per-key or per-address 429 has message only and a Retry-After header. Wait, then retry. |
| HTTP403 | Codemissing_authentication_token | Typegateway_error | WhenThe route does not exist and the request has no Authorization header. With a Bearer API key, the same request returns 403 gateway_error. |
| HTTPOther | Codegateway_error | Typegateway_error | WhenAny other gateway condition. Use the HTTP status and message. |