mode_mismatch
HTTP 403 type: authorization_error param: device_id{ "error": { "type": "authorization_error", "code": "mode_mismatch", "message": "This is a test key (fh_test_…) but company AWAIT 8 J.D.O.O. is in live mode. Test keys can never reach production tax endpoints.", "param": "device_id", "upstream": null, "doc_url": "https://docs.fiskhub.com/errors/mode_mismatch" }}What happened
The API key’s mode does not match the target company’s mode. An fh_test_ key was used against a
company in live mode, or an fh_live_ key against a company in test mode.
Nothing was fiscalized.
Should you retry?
Not with the same key. Either the key or the company is wrong for what you intended.
The fix
Work out which side is wrong.
If you meant to fiscalize for real, use the live key:
curl -sS https://api.fiskhub.com/v1/invoices \ -H "Authorization: Bearer $FISKHUB_LIVE_KEY" …If you meant to test, target a company in test mode. Check which one you hit:
curl -sS "https://api.fiskhub.com/v1/companies" \ -H "Authorization: Bearer $FISKHUB_API_KEY"Each company’s mode is in the response.
If the company is in the wrong mode — a company that has finished testing and should be live — promote it, which requires a valid certificate:
curl -sS -X PATCH \ "https://api.fiskhub.com/v1/companies/3a5f2b18-7c4d-4e91-9a2b-6d8e0f1c3a57" \ -H "Authorization: Bearer $FISKHUB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "mode": "live" }'Why the boundary is hard
fh_test_… | fh_live_… | |
|---|---|---|
| Endpoint | cistest.apis-it.hr | cis.porezna-uprava.hr |
| Certificates | Demo | Real |
| JIRs | Real-looking, no legal effect | Real fiscal records |
There is deliberately no request parameter that switches modes. Swapping the key is the only way.
That is what makes this error valuable. A parameter could be defaulted wrongly in one deployment
and file a load-test’s worth of fake sales with the Croatian Tax Administration — or leave a
production fleet quietly writing to TEST, producing receipts with no legal standing that nobody
notices until an audit. A 403 at the boundary is the cheapest possible version of both
problems.
In your own configuration
Keep the two keys in separate variables, not one that changes meaning by environment:
FISKHUB_TEST_KEY=fh_test_…FISKHUB_LIVE_KEY=fh_live_…A single FISKHUB_API_KEY whose value depends on the deployment is exactly the ambiguity this
error exists to catch — and it catches it at the API, after the deployment has already shipped.