Errors
Lidya wraps every error response in a stable envelope:
{
"error": {
"code": "validation_failed",
"message": "amount must be a positive integer",
"requestId": "req_01HYP…",
"details": { "issues": [ /* ... */ ] }
}
}code is the part you switch on. message is for humans and may change without notice. Always log requestId so support can find the trace.
Reference
| Code | HTTP | When | Action |
|---|---|---|---|
missing_api_key | 401 | No X-API-Key header. | Send the header. |
invalid_api_key | 401 | Key not found, revoked, or signature mismatch. | Verify the key. Check it isn't a sk_live_ key on a sk_test_ endpoint. |
api_key_expired | 401 | Key passed expiresAt. | Issue a new key. |
unauthorized | 401 | Generic auth failure. | Check headers and key validity. |
forbidden | 403 | Auth ok but you can't do this. | Check scopes and IP allowlist. |
organization_frozen | 403 | Organization is paused. | Contact info@lidya.money. |
not_found | 404 | Resource doesn't exist (or isn't yours). | Verify the id. |
validation_failed | 400 | Request body didn't pass schema. details.issues[] enumerates problems. | Fix the body. |
idempotency_key_reuse | 409 | Same key, different body, within 24h. | Use a fresh key for the new request. |
duplicate_request | 409 | Generic conflict (often duplicate merchantReference). | Either use the existing resource or pick a new ref. |
duplicate_merchant_reference | 409 | This merchantReference already exists for your org. | Re-use the existing charge id, or pick a new ref. |
insufficient_balance | 400 | Payout > available. | Wait for funds to settle, or reduce amount. |
wallet_not_configured | 400 | Crypto payout with no destination wallet. | Add a wallet via POST /v1/wallets. |
invalid_wallet_address | 400 | Wallet address fails network validation. | Re-check address. |
amount_below_minimum | 400 | Payout amount below acquirer minimum. | Increase amount or batch. |
payouts_unavailable | 503 | Crypto payouts not enabled for this merchant yet. | Email info@lidya.money to enable. |
too_many_requests | 429 | Rate limit exceeded. Retry-After header is set. | Back off then retry. |
provider_unavailable | 502 | Acquirer is down. We've already retried internally. | Retry with the same idempotency key after 30s. |
internal_error | 500 | Bug on our side. | Email info@lidya.money with requestId. |
Internal errors
If you ever see unauthorized for a key you know is valid, that's almost certainly the wrong mode (test vs live). The second most common cause is using a sk_live_ key against api.lidya.money while the merchant is still in kycStatus = REVIEWING. Live traffic is gated until KYC is APPROVED.