DoxboxAPI v1 Base URL  https://app.doxbox.io Try it → עברית

Developer documentation

The Doxbox API

Read your account's invoices and receipts, fetch the original files, list suppliers, generate exports and upload new documents. JSON over HTTPS, one bearer token, no SDK required.

Your first call
curl https://app.doxbox.io/api/v1/documents \
  -H "Authorization: Bearer $DOXBOX_API_KEY"
Base URL
https://app.doxbox.io
Base path
/api/v1
Format
JSON, UTF-8
Auth
Bearer token

What you can do

Seven endpoints. Everything is read-only unless your key was created with write access.

Access: read by default. Uploading documents requires a write-enabled key.

Quickstart

  1. Create a key, as an account admin, go to Account settings → Connections → API keys → Create key. Copy it (shown once).
  2. Set it in your shell:
export DOXBOX_API_KEY="dbx_..."

Then make your first call:

Shell
curl https://app.doxbox.io/api/v1/documents \
  -H "Authorization: Bearer $DOXBOX_API_KEY"

Authentication

Every request except /health requires an API key sent as a Bearer token:

Authorization: Bearer dbx_<prefix>_<secret>
Shown once. The full key is displayed only at creation, Doxbox stores only a hash. If you lose it, revoke the key and create a new one.

Each key belongs to a single account and can only ever touch that account's data. Revoking a key takes effect immediately.

Scopes

A key carries one of two permission levels, chosen at creation. Keys are read-only unless you opt in to write; calling a write endpoint with a read-only key returns 403 API_KEY_FORBIDDEN.

ScopeGrants
readRead documents & suppliers, generate exports (default)
writeEverything in read, plus uploading documents

Conventions

Pagination

List endpoints use cursor pagination: ?limit= (1–100, default 25) and ?cursor= (the last item id from the previous page). Responses carry nextCursor, an id, or null on the last page.

Rate limiting

Requests are limited per key (default 120 / minute). Every response carries rate-limit headers; exceeding the limit returns 429 with a Retry-After header.

X-RateLimit-Limit: 120
X-RateLimit-Remaining: 118
X-RateLimit-Reset: 1785690000

Quotas

Uploads count against your plan's monthly document limit. When the limit is reached, POST /documents returns 403 PLAN_LIMIT_EXCEEDED and no documents in the batch are ingested, all-or-nothing, so you're never left with a partial upload.

Duplicate handling

Uploads are de-duplicated by file content. Re-uploading a file Doxbox already has does not create a second document, the response marks it "duplicate" and returns the existing id. Uploads are safe to retry.

Recipes

Three things people actually do with this API, end to end.

Page through every document

Keep passing nextCursor back as cursor until it comes back null. Nothing else terminates the loop.

Node
const base = "https://app.doxbox.io/api/v1";
const auth = { Authorization: `Bearer ${process.env.DOXBOX_API_KEY}` };

let cursor = null, all = [];
do {
  const url = new URL(base + "/documents");
  url.searchParams.set("limit", "100");
  if (cursor) url.searchParams.set("cursor", cursor);

  const res = await fetch(url, { headers: auth });
  if (res.status === 429) {                // respect the limiter
    await new Promise(r => setTimeout(r, (+res.headers.get("Retry-After") || 5) * 1000));
    continue;
  }
  const page = await res.json();
  all.push(...page.data);
  cursor = page.nextCursor;
} while (cursor);

Download the original file of every unpaid invoice

The file endpoint answers with a 302 to a short-lived signed URL, so follow redirects and stream the body straight to disk.

Python
import os, requests

base = "https://app.doxbox.io/api/v1"
auth = {"Authorization": f"Bearer {os.environ['DOXBOX_API_KEY']}"}

docs, cursor = [], None
while True:
    params = {"limit": 100, **({"cursor": cursor} if cursor else {})}
    page = requests.get(f"{base}/documents", headers=auth, params=params, timeout=30).json()
    docs += page["data"]
    cursor = page["nextCursor"]
    if not cursor: break

for d in docs:
    if d["documentType"] != "Invoice" or d["paymentStatus"] != "Unpaid":
        continue
    r = requests.get(f"{base}/documents/{d['id']}/file", headers=auth,
                     allow_redirects=True, timeout=60)
    r.raise_for_status()
    with open(f"{d['documentNumber'] or d['id']}.pdf", "wb") as f:
        f.write(r.content)
Filtering is client side. The list endpoint takes only limit and cursor. Anything else, by type, status or supplier, you filter yourself on the returned objects.

Build last month's file for the accountant

One call. The response carries a signed download URL that is good for about 12 hours.

Shell
curl -X POST https://app.doxbox.io/api/v1/exports \
  -H "Authorization: Bearer $DOXBOX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"exportType":"excel_monthly","filters":{"year":2026,"month":7}}'

Swap exportType for csv, pdf_merged or zip. To export a hand-picked set instead of a whole month, send "scope":"selected" with selectedDocumentIds.

Errors

Errors return a JSON body with a message and, where useful, a machine-readable code:

{ "message": "API key has expired", "code": "API_KEY_EXPIRED" }
HTTPcodeMeaning
400, Invalid request (bad parameters or body)
401API_KEY_MISSINGNo Authorization: Bearer header
401API_KEY_INVALIDUnknown key
401API_KEY_REVOKEDKey was revoked
401API_KEY_EXPIREDKey is past its expiry
403API_KEY_FORBIDDENKey lacks the required scope (e.g. write)
403PLAN_LIMIT_EXCEEDEDMonthly document quota reached
404, Not found, or not in your account
429RATE_LIMITEDRate limit exceeded (see Retry-After)

Field reference

Enumerated values you'll see in responses:

documentTypeInvoice · Receipt · CreditInvoice · Other
paymentStatusPaid · Unpaid
currencyILS · USD · EUR · GBP · JPY · AUD

Amount fields are numbers in the document's currency. Dates are ISO 8601 strings and may be null when Doxbox could not read them from the document.

GET/api/v1/health

Service health and version. No authentication.

200 OK
{ "status": "ok", "api": "v1" }
GET/api/v1/documents

List the account's documents, newest first. Cursor-paginated (limit, cursor).

Request
curl "https://app.doxbox.io/api/v1/documents?limit=2" \
  -H "Authorization: Bearer $DOXBOX_API_KEY"
200 OK
{
  "data": [
    {
      "id": 1042,
      "documentNumber": "INV-2026-118",
      "totalAmount": 1170.0,
      "currency": "ILS",
      "documentType": "Invoice",
      "paymentStatus": "Unpaid",
      "supplierName": "Acme Ltd"
    }
  ],
  "nextCursor": 1041
}
GET/api/v1/documents/{id}

A single document with full metadata and the ids of its image pages. A document that isn't in your account returns 404, no cross-account existence leak.

200 OK
{
  "id": 1042,
  "documentNumber": "INV-2026-118",
  "documentType": "Invoice",
  "netAmount": 1000.0,
  "vat": 170.0,
  "totalAmount": 1170.0,
  "currency": "ILS",
  "paymentStatus": "Unpaid",
  "supplier": { "id": 9, "name": "Acme Ltd", "crn": "514123456" },
  "images": [{ "id": 5001 }, { "id": 5002 }]
}
GET/api/v1/documents/{id}/file

Returns a 302 redirect to a fresh, short-lived signed URL for the document's file. The storage bucket stays private. Optional ?image=<id> selects a specific page (defaults to the first).

Request, follow the redirect and save
curl -L https://app.doxbox.io/api/v1/documents/1042/file \
  -H "Authorization: Bearer $DOXBOX_API_KEY" \
  -o invoice.pdf
POST/api/v1/documents requires write

Upload one or more documents. They run through the same pipeline as documents added in the app, OCR, supplier matching, and de-duplication, and appear in your account tagged as uploaded via the API. Send a multipart/form-data body with one or more files in the files field. Counts against your monthly quota; the batch is all-or-nothing.

Request
curl -X POST https://app.doxbox.io/api/v1/documents \
  -H "Authorization: Bearer $DOXBOX_API_KEY" \
  -F "files=@invoice-july.pdf" \
  -F "files=@receipt-123.pdf"
201 Created
{
  "results": [
    { "filename": "invoice-july.pdf", "documentId": 1055, "status": "created" },
    { "filename": "receipt-123.pdf",  "documentId": 980,  "status": "duplicate" }
  ],
  "summary": { "total": 2, "created": 1, "duplicate": 1, "failed": 0 }
}

Per-file status is created, duplicate, or failed (a failed file includes a reason and doesn't stop the rest of the batch).

GET/api/v1/suppliers

The account's suppliers (those with documents in the account), with per-supplier aggregates, sorted by total amount.

200 OK
{
  "data": [
    { "id": 8, "name": "Globex", "crn": "514000222", "documentCount": 12, "totalAmount": 18400.0 },
    { "id": 9, "name": "Acme Ltd", "crn": "514123456", "documentCount": 5, "totalAmount": 5850.0 }
  ]
}
POST/api/v1/exports

Generate an export file for a month's documents. Returns a signed download URL valid for about 12 hours. Exporting via the API never changes your documents.

FieldTypeNotes
exportTypestringexcel_monthly · csv · pdf_merged · zip
scopestringall_results (default) or selected
selectedDocumentIdsnumber[]required when scope is selected
filters.yearnumbere.g. 2026
filters.monthnumber112
Request
curl -X POST https://app.doxbox.io/api/v1/exports \
  -H "Authorization: Bearer $DOXBOX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "exportType": "excel_monthly", "filters": { "year": 2026, "month": 7 } }'
200 OK
{
  "fileName": "Acme_2026-07.xlsx",
  "fileUrl": "https://storage.googleapis.com/.../signed...",
  "totalDocuments": 17,
  "skippedFiles": 0,
  "provider": "server"
}

fileUrl is a temporary signed URL (~12h).

Versioning and support

Versioning

Every path is prefixed with the version, /api/v1. Additive changes, a new field on a response or a new optional parameter, can appear in v1 at any time, so parse responses leniently and ignore fields you do not recognise. Breaking changes ship under a new version and are announced in advance; v1 is not removed from under you.

Getting help

Questions about the API, a response you cannot explain, or an endpoint you need that is not here: inbox@doxbox.io.

It saves a round trip if you include the request you made with the key redacted, the full response body including the code, and the time it happened.

Email
inbox@doxbox.io
Try it live
Swagger UI
OpenAPI spec
openapi.json
Status
GET /api/v1/health
Doxbox API v1 · Keep your key secret, it grants access to your account's financial data. Grant write only when you need it. Questions: inbox@doxbox.io