Errors, diagnostics and reliability
How to read the errors of the Cash Server API, what to do in each case, and how to build an integration that does not duplicate tax documents.
1. Where Each Error Appears#
Errors are returned in two places, and they represent different classes of issues:
| Where | Class | Example |
|---|---|---|
| In the registration response (HTTP 4xx) | Request rejected: authorization, receipt schema, TIN mismatch, duplicate | 10, 11, 12, 32, 33 |
In the document result (report, document already accepted) |
Failed to print receipt: POS offline, POS rejection | 2001, 2002, type: "timeout" with code 1, driver errors |
The first class is resolved in the integration code. The second — on the POS and hardware side.
The service does return codes 2001, 2002 and 2003: 2001 — no POS became available for the receipt within 300 s (all offline or busy), 2002 — the POS cannot issue this kind of receipt, 2003 — the receipt TIN does not match the group TIN (answered right at registration, HTTP 400). Each case is covered below.
2. Request Errors#
10 · 11 · 12 — Authorization#
| Code | Cause | Solution |
|---|---|---|
| 10 | Token not passed | Header Token: <token> or ?token= |
| 11 | Token expired (valid for 24 hours) or unknown | Get a new one via getToken |
| 12 | Invalid login or password | Check group credentials |
| 20 | Token issued for another group | Check group_code in path |
| 21 | Group does not support this protocol version | Check v5 / v4 in path |
Best practice: cache the token for 23 hours and refresh it upon error 11, rather than on a schedule.
32 — Receipt Validation#
The most common error at the start of integration. The text always specifies the exact field, for example:
{ "error": { "code": 32, "type": "system",
"text": "items[0].measure is required (v5, tag 2108)" } }
Common causes:
| Error text | What is wrong |
|---|---|
receipt.client: at least one of email|phone is required |
Nowhere to send the electronic receipt |
receipt.company.inn: 10 or 12 digits expected |
TIN contains spaces, hyphens, or is invalid |
items[N].payment_object is required (v5) |
Calculation subject attribute not passed |
items[N].measure is required (v5, tag 2108) |
Unit of measurement is a string instead of a code |
items[N].measurement_unit is not supported in v5 |
v4 and v5 mixed in a single receipt |
receipt.total (…) does not equal the sum of items (…) |
Discount deducted from total, but not from items |
payment sum (…) does not equal receipt.total (…) |
Rounding discrepancy in payment |
items[N].supplier_info with valid inn is required when agent_info is present |
Agent item without supplier details |
receipt.company.inn (…) does not match the group INN (…) |
Receipt TIN does not match the one registered to the group's POS fiscal drive |
Check the receipt structure against the attributes reference guide — it lists what is required in v5 and what is in v4.
The last row — regarding TIN — is processed before queueing: a receipt with another company's TIN is rejected immediately (HTTP 400, code 32), the document is not created, and the external_id is not consumed. Check the TIN against the POS registration card and the details specified when creating the cash server.
33 — Duplicate external_id#
This is not an integration error, but a standard response to a retry. The response body contains the uuid of the first document:
{ "uuid": "47b30214-…", "status": "wait",
"error": { "code": 33, "text": "a document with this external_id has already been accepted in this group" } }
The correct action: take the uuid and request a report for it. This only becomes an error if you accidentally reused the external_id for another transaction.
30 · 34 — Working with report#
- 30 — unknown
uuid: typo, another group, or document older than 60 days (archive). - 34 — document has not been processed yet. Returned with HTTP 200 and
status: wait; simply continue waiting.
429 — Rate Limit Exceeded#
Registration is limited to 10 requests per second per group; polling is limited to 1 request per second for each POS in the group. Retry with a delay; for polling, a reasonable interval is 2–3 seconds, or better yet, subscribe to callback_url.
3. Errors in report: document accepted, but not printed#
Code 2001 (type: "timeout") — 300 seconds waiting for POS#
The document remained in the queue for 5 minutes and did not get an online POS from the group: the POS PC is turned off, there is no internet connection, the bridge is not running — or all POS devices in the group are busy with other documents longer than the allotted time. Error text: "queue: no available POS was found in the group within 300 s (all POS devices are offline or busy)".
Distinct from it is code 1 with the same type: "timeout": a POS did TAKE the receipt but never reported the result within 300 s (it hung, or the link dropped mid-print). Unlike 2001, the document may have reached the fiscal drive — check the last receipt on the POS itself before repeating the payment.
What to do:
- Check that the POS PC is turned on and the bridge is running (bridge status page on the PC itself); connection status for each POS is also visible in the admin panel — "POS API" section;
- Check the PC's internet connection;
- If the PC and bridge are fine, but timeouts keep occurring during peak hours — add a second POS to the group, including a backup one: the queue processes documents in order of arrival;
- Retry the settlement with a new
external_id— the old document has already been finalized asfail.
POS driver errors#
Everything returned directly by the POS comes with its native text: "out of paper", "POS blocked", "unfinished receipt open", "fiscal memory full", "shift exceeded 24 hours — generate a Z-report" (see Shift over 24 hours). Breakdown of common codes — ATOL Errors and SHTRIH-M Errors.
This also includes receipt incompatibility with the POS model — such a rejection arrives with code 2002 and the driver text:
- The POS cannot handle an electronic receipt without printing — this is a mandatory feature for online settlements (currently reliably supported by ATOL cash registers);
- The receipt contains track & trace tagging, but the POS lacks FFD 1.2 support;
- Extended customer attributes or industry-specific requisites that the model does not support.
What to do: check the POS model and the FFD version; if necessary, add a suitable device to the group. The queue does not select a POS based on its "capabilities" — the document is dispatched to any online POS in the group, so keep devices with identical capabilities within the same group.
4. Protection against a double receipt#
A double tax document for a single payment is the worst possible mistake in a fiscal integration: it has to be reversed with a correction receipt and explained to the FTS. Three lines of defence work against it in the service:
external_idat the intake. A repeat within the group returns the originaluuid(error 33) and never creates a second document.- The operation key all the way to the cash register. The bridge receives a key built from the group and
external_idand keeps an operation journal on disk. A repeat returns the first result — even if the cash register PC managed to reboot in between. - An honest refusal on an unknown outcome. If the connection dropped exactly at the moment the receipt was being closed (the document may or may not have reached the fiscal drive), a repeat of that operation is rejected with a demand to verify the last document on the cash register. A second receipt is never registered blindly.
What is required from your side:
- one settlement — one
external_id, stable across retries (order-10421, say, rather than a random UUID per attempt); - never change the
external_id"so that it goes through": if a document was not registered, first find out why; - an idempotent callback handler: the same notification may arrive more than once.
5. What to do if the cash register is offline#
The cash register PC is off or has no Internet — the receipt will not be registered: the cash register is physically yours, and the cloud cannot stand in for it. The service behaves as follows:
- the document waits in the queue for up to 300 seconds;
- if the cash register appears within that time, the receipt is registered normally;
- if not, the document moves to
failwith thetimeouttype.
Recommendations for stores that take orders around the clock:
- Keep the cash register PC on (turn off power saving and sleep);
- Add a second cash register to the group as a backup;
- Keep a queue of unsent receipts in your own system and repeat them with a new
external_idonce the cash register is back online — bearing in mind that by law the receipt must be generated no later than the next business day; - Set up monitoring: a
failwithtimeoutis an incident a human should learn about.
6. Checklist before going live#
- the KKT is registered with the "payments on the Internet" attribute, and tag 1187 carries the website address;
- the TIN in
receipt.company.innmatches the TIN the fiscal drive is registered to; - the taxation system in the receipt matches your actual taxation system;
-
external_idis deterministic and survives retries; - response 33 is handled (take the
uuidfrom the response, do not treat it as a failure); - both polling and
callback_urlare implemented — the latter does not replace the former; - a payment is recognized as fiscalized only on
status: done; - the FD, FPD, fiscal drive number and KKT registration number are saved with the order;
-
failandtimeoutreach monitoring, not just the log; - the behaviour with the cash register PC switched off has been tested;
- for marked goods, the code is verified before the receipt is sent;
- the VAT rates have been checked on the cash register's actual firmware (especially 22% and the derived rates).
7. Where to look during incident investigation#
| Question | Where to find the answer |
|---|---|
| What exactly we sent | Your request log + external_id |
| What the service responded | report by uuid (stored for at least 32 days) |
| Did it reach the POS | device_code in report — code of the POS to which the document was sent |
| What the POS reported | error field in report; receipt log and the latest error — in the “POS API” section |
| Is the receipt in the FN | FD number from payload + OFD dashboard |
| Was there a duplicate | Error 33 in your logs and a matching uuid |
The
errorfield is always an object{error_id, code, text, type}, including on a driver failure: the POS text arrives from the bridge as a plain string, and the service wraps it into an object, assigning the code (2002— the POS cannot issue this kind of receipt,1— any other rejection) andtype: "driver". Theerror_idof one and the same failure does not change between polls — quote it when contacting support.
If the receipt has been issued, but your system did not learn about it (missed the callback and did not poll), the document still exists: find it by external_id via report and save the remaining details — there is no need to issue it again.
Next: API reference · receipt details · store scenarios.