Every error has the same shape:
"code": "no_active_bank_account",
"message": "Link a bank account before creating payment requests.",
"request_id": "req_01JD7QF0X2C4M8R6T1Y3W5Z7NB"
code is a stable contract – build your logic on it.
message is for humans and may change – don’t compare strings.
request_id – include it when contacting support so Hensa finds the exact request.
| Code | HTTP | Meaning |
|---|
validation_error | 400 | Invalid request data – see message. |
unauthorized | 401 | Missing or invalid API key. |
forbidden | 403 | The key lacks permission for this action. |
test_mode_only | 403 | Only available with hk_test_ keys. |
not_found | 404 | Not found (or not owned by this key's store). |
idempotency_conflict | 409 | Same Idempotency-Key with a different body. |
already_reconciled | 409 | The transaction is already reconciled. |
no_active_bank_account | 422 | The store has no active bank account. |
merchant_name_required | 422 | The store has no name yet – set it in the Dashboard before creating QR codes (live mode only). |
plan_limit | 422 | The current plan's limit is reached. |
url_not_https | 422 | Webhook URLs must use HTTPS. |
url_private_address | 422 | The URL resolves to a private address – not allowed. |
delivery_too_old | 422 | Only events from the last 30 days can be redelivered. |
rate_limited | 429 | Too many requests – wait for the Retry-After header. |
internal_error | 500 | Hensa-side error – retry later (safe with Idempotency-Key). |
| HTTP |
Retry? |
400, 401, 403, 404, 422 |
No – fix the request |
409 idempotency_conflict |
Only if the first request is still in progress; not if the body differs |
429 |
Yes – wait for the Retry-After header |
5xx, network error, timeout |
Yes – with the same Idempotency-Key, exponential backoff |