Errors The error response envelope, the full catalogue of error codes, and how they map to HTTP status codes.
When a request fails, ShadhinPay returns a consistent error envelope with a stable,
machine-readable errorType. Branch on errorType in your code — never on the
human-readable message, which may change.
{
"status" : "error" ,
"errorType" : "VALIDATION_ERROR" ,
"message" : "Invalid payment request" ,
"data" : {
"amount" : "Amount must be between 10.00 and 200000.00" ,
"callbackUrl" : "Invalid URL format"
}
}
On validation errors, data maps each offending field to a message. For other
errors data may be null or carry extra context (e.g. unlockAt for a locked
account).
HTTP When Typical errorType 400Malformed or invalid request VALIDATION_ERROR, MISSING_REQUIRED_FIELD, INVALID_FORMAT, INVALID_AMOUNT401Authentication failed AUTHENTICATION_ERROR, INVALID_API_KEY, SESSION_EXPIRED403Authenticated but not allowed AUTHORIZATION_ERROR, MFA_REQUIRED404Resource doesn't exist RESOURCE_NOT_FOUND409Conflict with current state DUPLICATE_RESOURCE, INVALID_STATUS_TRANSITION, IDEMPOTENCY_CONFLICT422Request valid but breaks a rule BUSINESS_RULE_VIOLATION, REFUND_NOT_ALLOWED, PAYMENT_EXPIRED, VENDOR_UNAVAILABLE423Account locked ACCOUNT_LOCKED429Rate limit exceeded RATE_LIMIT_EXCEEDED500Server error INTERNAL_SERVER_ERROR, DATABASE_ERROR502Provider returned an error VENDOR_ERROR, MFS_ADAPTER_FAILURE503Provider/service unavailable EXTERNAL_SERVICE_ERROR, VENDOR_TIMEOUT
errorTypeMeaning AUTHENTICATION_ERRORCredentials couldn't be verified AUTHORIZATION_ERRORNot permitted to perform this action INVALID_API_KEYMissing, wrong, revoked, or mismatched API key SESSION_EXPIREDSession/token no longer valid (dashboard) MFA_REQUIREDA fresh two-factor check is required OTP_INVALIDWrong one-time code OTP_EXPIREDOne-time code expired OTP_ATTEMPTS_EXCEEDEDToo many wrong codes for this reference ACCOUNT_LOCKEDLocked after repeated failures; data.unlockAt shows when it lifts
errorTypeMeaning VALIDATION_ERROROne or more fields failed validation MISSING_REQUIRED_FIELDA required field was absent INVALID_FORMATA field's format was wrong INVALID_AMOUNTAmount out of range or otherwise invalid
errorTypeMeaning RESOURCE_NOT_FOUNDThe referenced resource doesn't exist DUPLICATE_RESOURCEA resource with this identity already exists INVALID_STATUS_TRANSITIONThe action isn't valid for the resource's current state BUSINESS_RULE_VIOLATIONThe request breaks a business rule IDEMPOTENCY_CONFLICTIdempotency key reused with a different body — see Idempotency
errorTypeMeaning PAYMENT_EXPIREDThe payment's checkout window has lapsed PAYMENT_ALREADY_COMPLETEDThe payment is already settled REFUND_NOT_ALLOWEDThe payment can't be refunded (state or amount) INSUFFICIENT_FUNDSNot enough funds for the operation VENDOR_ERRORThe provider returned an error VENDOR_TIMEOUTThe provider didn't respond in time VENDOR_UNAVAILABLEThe provider is currently unavailable MFS_ADAPTER_FAILUREThe provider integration failed WEBHOOK_DELIVERY_FAILEDA webhook couldn't be delivered
errorTypeMeaning QUOTA_EXCEEDEDFree tier used up — informational; the payment still succeeds as billable INSUFFICIENT_BALANCENot enough settled balance (e.g. for a payout) RATE_LIMIT_EXCEEDEDToo many requests; honour Retry-After INTERNAL_SERVER_ERRORUnexpected server error DATABASE_ERRORStorage-layer error EXTERNAL_SERVICE_ERRORA dependency was unavailable
4xx errors are about your request — fix the input; retrying unchanged won't
help (except 429, which you should retry after Retry-After).
5xx errors and VENDOR_TIMEOUT are transient — retry with backoff, reusing
the same idempotency key so you don't
double-charge.
New errorType values can be added over time. Treat unknown codes as a generic
failure rather than crashing.