BillOS v1
Console llms.txt OpenAPI

Errors

Every failure is a JSON body with the matching HTTP status:

{
  "error": "payments 30000 != total 35400",
  "reason": "payments_mismatch",
  "hint": "Make the sum of payments[].amount equal the total including VAT, in agorot. With priceMode gross the total is the sum of quantity x unitPriceExVat as you sent them.",
  "param": "payments",
  "doc_url": "https://docs.billos.co.il/errors#payments_mismatch",
  "retryable": false,
  "request_id": "5b0c7a52-6f0e-4c0e-9d0e-2f7f1f0a9a11"
}
FieldMeaning
errorWhat went wrong, in one sentence. For people and logs; do not branch on it.
reasonThe stable machine code. Branch on this.
hintWhat to change so the call succeeds.
paramThe request field the refusal is about, when there is one (lines, payments, party.taxId).
doc_urlThis page, at the reason.
retryabletrue when sending the same request again can succeed (after Retry-After when the response carries one). false means change something first.
request_idThe id in the X-Request-Id header. Quote it to support.

A create that fails with a retryable reason is safe to send again only with the same Idempotency-Key.

To learn whether a draft would issue without issuing it, call POST /businesses/:bid/documents/:id/validate: it runs every check issuing runs and takes no number.

reasonHTTPRetryableMeaning
unauthorized401noNo credential, or one we do not recognise: a missing, mistyped, revoked or expired key or token.
forbidden403noThe credential is real but may not do this: a missing scope, an address outside the key's allowlist, a route that belongs to an API key and was called with a session or a Connect token, a sandbox-only route called with a live key, or a business that is paused.
not_found404noNo such resource under this credential. A business another key owns answers exactly like one that does not exist.
validation400noThe request is malformed or misses a field. The message says which; param names the field when there is one.
doc_type_not_allowed400noThis dealer type may not issue this document type: an exempt dealer (patur) issues receipts and proformas, never a tax invoice.
payments_mismatch400noOn a receipt-bearing document the payments must add up to exactly the document total (net of withholding).
not_draft409noThe document or expense is already issued or recorded, and an issued record is immutable.
conflict409noThe request collides with existing state: a duplicate unique value, or a race another request won.
pdf_pending409yesThe document is issued but its PDF has not finished rendering.
allocation_required422noThe invoice is over the allocation-number threshold for an identified business buyer, the business requires a number, and none could be obtained.
fx_rate_required422noA foreign-currency document needs an exchange rate and the Bank of Israel published none for its date.
approval_required403noThe business account is not open for permanent records: pending approval, or suspended.
authorization_denied403noThe person who was asked to approve a sandbox key declined.
upgrade_required402noThe business is on a free plan and reached what that plan includes (its documents for the month, for example).
limit_reached429noA per-business ceiling was reached: the monthly document or expense ceiling, or a pending account's daily draft cap.
business_limit403noThis API client already holds as many open businesses as its owner allowed (5 unless changed).
payment_required402noOpening a live business needs a card on file, and an unpaid month blocks new businesses until it is paid.
rate_limited429yesToo many requests in the window.
quota_exceeded429noThe daily OCR quota is used up.
too_large413noThe request body is over the size limit (JSON 2MB, a receipt image 5MB, an imported file 8MB).
unconfigured503noThis server is missing configuration the request needs (for example, no sandbox database).
provider502yesAn internal dependency failed (rendering, signing, storage). Transient.
internal500noAn unexpected server error.

unauthorized

HTTP 401. No credential, or one we do not recognise: a missing, mistyped, revoked or expired key or token.

What to do: Send the key in the X-Api-Key header (or as Authorization: Bearer bk_...). No key yet? POST https://api.billos.co.il/v1/sandboxes with no credentials starts a request for a sandbox key that a person approves in the console.

forbidden

HTTP 403. The credential is real but may not do this: a missing scope, an address outside the key's allowlist, a route that belongs to an API key and was called with a session or a Connect token, a sandbox-only route called with a live key, or a business that is paused.

What to do: The message names what is missing. A scope has a read half and a write half; GET /keys shows what this key holds.

not_found

HTTP 404. No such resource under this credential. A business another key owns answers exactly like one that does not exist.

What to do: Check the id and the mode: a bk_test_ key sees only sandbox data and a bk_live_ key only live data (the X-BillOS-Mode response header says which answered). GET /businesses lists the ids this key holds.

validation

HTTP 400. The request is malformed or misses a field. The message says which; param names the field when there is one.

What to do: Fix the field the message names and send again. Amounts are integer agorot, dates are YYYY-MM-DD, docType is the numeric code (300, 305, 320, 330, 400).

doc_type_not_allowed

HTTP 400. This dealer type may not issue this document type: an exempt dealer (patur) issues receipts and proformas, never a tax invoice.

What to do: For a patur business use docType 400 (receipt) or 300 (proforma). GET /businesses/:bid returns dealerType.

payments_mismatch

HTTP 400. On a receipt-bearing document the payments must add up to exactly the document total (net of withholding).

What to do: Make the sum of payments[].amount equal the total including VAT, in agorot. With priceMode gross the total is the sum of quantity x unitPriceExVat as you sent them.

not_draft

HTTP 409. The document or expense is already issued or recorded, and an issued record is immutable.

What to do: Do not edit or delete it. Correct an issued document with POST /businesses/:bid/documents/:id/credit-note, and a recorded expense with its correction route.

conflict

HTTP 409. The request collides with existing state: a duplicate unique value, or a race another request won.

What to do: Read the resource again and decide from its current state. Retrying a create with the same Idempotency-Key returns the row that already exists.

pdf_pending

HTTP 409. The document is issued but its PDF has not finished rendering.

What to do: Wait a second or two and ask again, or subscribe to the document.pdf_ready webhook.

allocation_required

HTTP 422. The invoice is over the allocation-number threshold for an identified business buyer, the business requires a number, and none could be obtained.

What to do: The business owner connects the Israel Tax Authority once in the BillOS console; after that the number is requested automatically at issue. See the Documents guide, "Allocation numbers".

fx_rate_required

HTTP 422. A foreign-currency document needs an exchange rate and the Bank of Israel published none for its date.

What to do: Pass fxRate (ILS per 1 unit of the currency). GET /businesses/:bid/fx-rate?currency=USD&date=YYYY-MM-DD shows what would be used.

approval_required

HTTP 403. The business account is not open for permanent records: pending approval, or suspended.

What to do: Drafts still work. Nothing in the request is wrong: the account owner contacts BillOS support. A sandbox business is never pending.

authorization_denied

HTTP 403. The person who was asked to approve a sandbox key declined.

What to do: Do not ask again by yourself. Tell the person the request was declined and let them decide whether to start a new one (POST /sandboxes).

upgrade_required

HTTP 402. The business is on a free plan and reached what that plan includes (its documents for the month, for example).

What to do: The way forward is a paid plan for the business; sending again will not help until it has one or the month turns over.

limit_reached

HTTP 429. A per-business ceiling was reached: the monthly document or expense ceiling, or a pending account's daily draft cap.

What to do: Sending again will not help until the period turns over or BillOS raises the ceiling.

business_limit

HTTP 403. This API client already holds as many open businesses as its owner allowed (5 unless changed).

What to do: Close a business you no longer use (POST /businesses/:bid/deactivate), or raise the limit in the console under שימוש וחיוב. Every open business is billed for the month.

payment_required

HTTP 402. Opening a live business needs a card on file, and an unpaid month blocks new businesses until it is paid.

What to do: Add or replace the card in the console under שימוש וחיוב. Existing businesses keep working; only opening a new one waits.

rate_limited

HTTP 429. Too many requests in the window.

What to do: Wait the number of seconds in the Retry-After header, then send the same request. X-RateLimit-Remaining on every response says how much is left.

quota_exceeded

HTTP 429. The daily OCR quota is used up.

What to do: It resets at midnight Asia/Jerusalem. Create the expense with its fields typed instead of scanned.

too_large

HTTP 413. The request body is over the size limit (JSON 2MB, a receipt image 5MB, an imported file 8MB).

What to do: Send a smaller body: downscale the image, or split the request.

unconfigured

HTTP 503. This server is missing configuration the request needs (for example, no sandbox database).

What to do: Nothing in the request is wrong. Report it to BillOS support with the request_id.

provider

HTTP 502. An internal dependency failed (rendering, signing, storage). Transient.

What to do: Send the same request again with the same Idempotency-Key: a retry can never create a second record.

internal

HTTP 500. An unexpected server error.

What to do: Report it to BillOS support with the request_id. If you retry a create, keep the same Idempotency-Key.