Every error the UrbanPayX API can return, what causes it, and how to resolve it.
Error Reference
This page documents every error the UrbanPayX API can return, what causes it, and how to resolve it.
Error response formats
The API uses two error response formats depending on the context:
Standard format — used by most endpoints:
{
"detail": "Human-readable error message"
}Validation format — returned by FastAPI for request body schema violations (422):
{
"detail": [
{
"loc": ["body", "field_name"],
"msg": "description of what's wrong",
"type": "error type"
}
]
}The HTTP status code is always present in the response header. Use the status code to determine the error category, then read the detail field for specifics.
HTTP status codes at a glance
| Code | Meaning | When you'll see it |
|---|---|---|
400 | Bad Request | Business rule violation, invalid state transition, or configuration error |
401 | Unauthorized | Invalid/expired token, wrong credentials, or revoked session |
403 | Forbidden | Your role doesn't have permission, or a feature is disabled for your account |
404 | Not Found | Resource doesn't exist or doesn't belong to your client |
409 | Conflict | Idempotency key reuse with different payload, or resource state conflict |
422 | Validation Error | Request body doesn't match the expected schema |
429 | Too Many Requests | Rate limit exceeded — wait before retrying |
500 | Internal Server Error | Something went wrong on our side |
502 | Bad Gateway | Upstream service (email delivery) failed |
503 | Service Unavailable | A dependent service is down or not configured |
400 — Bad Request
These errors indicate your request is structurally valid but violates a business rule or attempts an impossible operation.
Authentication & accounts
| Error message | Cause | Fix |
|---|---|---|
Invalid API key or secret | API credentials are wrong | Double-check your api_key and api_secret. If you rotated keys, use the new ones. |
Invalid refresh token | Refresh token is malformed or expired | Re-authenticate with login or API key. Refresh tokens expire after 30 days. |
Current token is not a dashboard account token | Using an API token for a dashboard-only operation | Use email/password login instead of API key auth for this endpoint. |
New password must be different from current password | Password change uses the same password | Choose a different password. |
Current password is incorrect | Wrong current password during password change | Verify the current password. |
Refresh token does not belong to current access token | Mismatched token pair | Use the refresh token that was issued alongside your current access token. |
MFA configuration
| Error message | Cause | Fix |
|---|---|---|
Cannot enable TOTP before enrolling an authenticator app | Trying to enable TOTP without setup | Complete TOTP enrollment first via POST /auth/mfa/totp/enroll. |
When account MFA is enabled, at least one method must be enabled | Disabling the last MFA method while MFA is on | Either keep one method enabled, or disable MFA entirely. |
Account primary MFA method is totp but totp MFA is disabled | Setting primary to TOTP while TOTP is off | Enable TOTP first, then set it as primary. |
TOTP enrollment challenge is invalid or expired | Enrollment confirmation too late | Start a new enrollment with POST /auth/mfa/totp/enroll. |
Invalid authenticator code | Wrong TOTP code | Check the code in your authenticator app. Codes refresh every 30 seconds. |
Team accounts
| Error message | Cause | Fix |
|---|---|---|
Client account email already exists | Duplicate team member email | Use a different email address. |
Cannot delete the last active owner | Deleting the only OWNER account | Promote another account to OWNER first. |
Cannot deactivate or demote the last active owner | Removing the last OWNER role | Ensure another active OWNER exists before changing this account. |
Cannot delete the currently logged-in account | Self-deletion attempt | Log in as a different account to delete this one. |
OpCo (Operating Company)
| Error message | Cause | Fix |
|---|---|---|
Opco is in status and can no longer be edited | Editing a non-DRAFT OpCo | OpCos can only be edited in DRAFT status. Create a new one if needed. |
Opco status is not DRAFT. Only DRAFT opco can be submitted again | Submitting a non-DRAFT OpCo | Only OpCos in DRAFT status can be submitted. |
Opco cannot be bound to a project when rejected or deactivated | Linking a REJECTED/DEACTIVATED OpCo to a project | Use an ACTIVATED OpCo. If rejected, create and submit a new one. |
Target opco belongs to a different client | Referencing another client OpCo | Use an OpCo ID that belongs to your client. |
Opco_type cannot be null | Missing OpCo type in request | Specify opco_type as licensed_tpp_sole_trader or licensed_tpp_non_sole_trader_private. |
OpCo validation (by type)
| Error message | Cause | Fix |
|---|---|---|
Sole_trader is required for licensed_tpp_sole_trader | Missing sole trader details | Include the sole_trader object with fullName, address, and dateOfBirth. |
UBOs is required for licensed_tpp_non_sole_trader_private | Missing UBO details | Include the ubos array for non-sole-trader OpCos. |
Directors is required for licensed_tpp_non_sole_trader_private | Missing director details | Include the directors array. |
Signatories is required for licensed_tpp_non_sole_trader_private | Missing signatory details | Include the signatories array. |
Transactions & payments
| Error message | Cause | Fix |
|---|---|---|
Callback URL is not set | No callback URL configured | Set your callback_url via PUT /auth/client/settings before generating payment links. |
Transaction in terminal status cannot be refreshed | Refreshing a terminal transaction | Only pending and processing transactions can be refreshed. |
Transaction has no upstream payment id, cannot refresh | Transaction was not fully created | The payment provider did not return a payment ID. Contact support. |
X-Idempotency-Key must not be empty | Empty idempotency header | Provide a non-empty value for the X-Idempotency-Key header. |
Opco does not have a valid Sub-TPP ID | OpCo not fully set up | Submit the OpCo and wait for activation before creating transactions. |
Webhooks
| Error message | Cause | Fix |
|---|---|---|
Webhook_url is required when webhook is enabled | Enabling webhooks without a URL | Set webhook_url before enabling webhook delivery. |
Webhook_url is required before sending a test event | Testing without a webhook URL | Configure your webhook_url first. |
Event_types must contain at least one event | Empty event types array | Include at least one event type (e.g., payment.status_changed). |
Invalid JSON payload | Malformed request body | Ensure your request body is valid JSON. |
Support tickets
| Error message | Cause | Fix |
|---|---|---|
Closed tickets cannot receive new client replies | Replying to a closed ticket | Open a new ticket if you need further assistance. |
Closed tickets must be reopened before replying | Same as above | Create a new ticket instead. |
Only resolved tickets can be closed by the client | Closing a non-resolved ticket | Wait for the ticket to be marked as resolved, then close it. |
401 — Unauthorized
These errors mean authentication failed. Your token is missing, expired, revoked, or the credentials are wrong.
| Error message | Cause | Fix |
|---|---|---|
Could not validate credentials | Token is missing, malformed, or expired | Include a valid Authorization: Bearer <token> header. If expired, refresh it. |
Token has been revoked | The token was explicitly revoked (logout) | Re-authenticate to get a new token. |
Incorrect email or password | Wrong login credentials | Check email and password. After 5 failed attempts, you will be locked out for 5 minutes. |
Invalid API key or secret | Wrong API credentials | Verify your API key and secret. If you rotated them, use the new ones. |
Client is not active | Account is deactivated | Contact support to reactivate your account. |
Client account is not active | Team member account is deactivated | Ask an OWNER to reactivate your account. |
Invalid OTP challenge payload | Expired or wrong MFA challenge token | Request a new challenge and complete verification promptly. |
All 401 responses include a WWW-Authenticate: Bearer header.
403 — Forbidden
You are authenticated, but your role does not have permission for this action, or a feature is disabled.
| Error message | Cause | Fix |
|---|---|---|
Insufficient permissions for this action | Your role cannot perform this operation | Check the Roles and Permissions matrix. API key tokens have the operations role. |
This action requires a dashboard account token | Using API key auth for a dashboard-only operation | Authenticate via email/password login instead. |
Payment link generation is disabled for this client | Feature gated for your account | Contact support to enable payment link generation. |
KYC link generation is disabled for this client | Feature gated for your account | Contact support to enable KYC link generation. |
Project is frozen by admin | Project has been frozen | Contact support to understand why the project was frozen. |
Production access is disabled for this client | Your account is not yet enabled for the production environment | Use the sandbox environment, or contact support to enable production access. |
Client is not activated yet. Please verify email first | Email verification not complete | Complete the email verification step from registration. |
Client registration is not allowed, please contact support | Self-registration is disabled | Contact the UrbanPayX team to get an account provisioned. |
404 — Not Found
The resource does not exist, or it belongs to a different client (the API intentionally does not distinguish between these for security).
| Error message | Cause | Fix |
|---|---|---|
Opco not found | Invalid OpCo ID | Verify the OpCo ID. List your OpCos with GET /opcos. |
Project not found | Invalid project ID | Verify the project ID. List your projects with GET /projects. |
Transaction not found | Invalid transaction ID | Verify the transaction ID. List transactions with GET /transactions. |
User not found | Invalid user ID | Verify the user ID. List users with GET /kyc/users. |
User not found, please create user and complete required verification first | Trying to generate a payment link for a non-existent user | Create the user via POST /kyc/users and verify them before generating a payment link. |
Account not found | Team account ID is invalid | List team accounts with GET /auth/team-accounts. |
Ticket not found | Support ticket ID is invalid | List tickets with GET /tickets. |
Invoice not found | Billing invoice ID is invalid | List invoices with GET /billing/invoices. |
409 — Conflict
The request conflicts with the current state of a resource.
| Error message | Cause | Fix |
|---|---|---|
Idempotency key already used with a different request payload | Same X-Idempotency-Key but different body | Use a new idempotency key for each distinct payment. |
Duplicated request with same idempotency key is still being processed | Concurrent request with the same key | Wait for the first request to complete, then retry. |
Transaction is already in terminal status and cannot start a new checkout | Re-initiating a completed transaction | Create a new transaction for a new payment. |
Project has dependent transactions | Deleting a project with transactions | Add cascade=true to the request, or resolve the transactions first. |
User has dependent transactions | Deleting a user with transactions | Add cascade=true to the request, or resolve the transactions first. |
422 — Validation Error
The request body does not match the expected schema. FastAPI auto-generates these from the Pydantic models.
{
"detail": [
{
"loc": ["body", "amount"],
"msg": "ensure this value is greater than 0",
"type": "value_error.number.not_gt"
}
]
}Common causes: missing required fields, wrong data types, invalid email format, amount less than or equal to zero, currency not exactly 3 characters. Read the loc field to identify which field failed, and msg for what went wrong.
429 — Too Many Requests
You have hit a rate limit. Wait before retrying.
| Error message | Cause | Fix |
|---|---|---|
Too many login attempts | 5+ failed login attempts | Wait the indicated time. Lockout is per-email, lasts 300 seconds. |
Please wait before refreshing this transaction again | Transaction refresh cooldown | Use webhooks instead of polling, or respect the cooldown. |
Tip: For transaction status, prefer webhooks over polling. Configure your webhook_url and listen for payment.status_changed events.
500 — Internal Server Error
Something went wrong on our side. These should be rare.
| Error message | Cause | Fix |
|---|---|---|
Failed to initiate payment | Payment provider communication failed | Retry after a brief wait. If persistent, contact support. |
Failed to create user, please retry | User creation failed unexpectedly | Retry the request. |
Failed to initialize user for KYC, please retry | KYC provider setup failed | Retry. If persistent, contact support. |
Failed to initiate KYC, please retry later | KYC provider is not responding | Wait and retry. |
If you consistently see 500 errors, please contact support with the request details (endpoint, payload, timestamp).
502 — Bad Gateway
An upstream service (typically email delivery) failed.
| Context | Fix |
|---|---|
| Team member creation or credential delivery | The team member was likely created, but the email was not delivered. Check the team accounts list and resend credentials manually if needed. |
503 — Service Unavailable
A required service is down or not configured.
| Error message | Cause | Fix |
|---|---|---|
Email delivery failed. Please retry later or contact support. | Email provider is unreachable | Retry after a brief wait. |
Common troubleshooting scenarios
I am getting 403 on Generate Payment Link
Your token has the developer role, which cannot generate payment links. Use an OWNER or OPERATIONS token. If you are using API key auth, this should not happen since API keys default to OPERATIONS.
OpCo must be ACTIVATED
Your OpCo is still in DRAFT or AWAITING_APPROVAL. Submit it with POST /opcos/{opco_id}/submit and wait for activation. In sandbox, this takes minutes.
User not found when generating a payment link
The user needs to exist and be verified before you can create a payment. Create the user with POST /kyc/users, initiate verification with POST /kyc/verify, and wait for kyc_status to reach approved.
Idempotency key already used with a different request payload
You are reusing an X-Idempotency-Key from a previous request but the body has changed (different amount, user, etc.). Generate a new unique key for each distinct payment intent.
Callback URL is not set
You need to configure a callback URL before generating payment links. This is where users get redirected after checkout. Set it with PUT /auth/client/settings.
Could not validate credentials on every request
Check that your Authorization header is formatted correctly: Bearer <token> (with a space, no quotes around the token). Access tokens expire after 2 hours (API key) or 30 minutes (dashboard login) — refresh or re-authenticate if expired.