Documentation Index
Fetch the complete documentation index at: https://docs.paybridgenp.com/llms.txt
Use this file to discover all available pages before exploring further.
All errors return a single nested envelope. The flat {error, code} shape used in earlier docs has been replaced — see the migration note below if you have older code.
{
"error": {
"message": "Invalid API key. Verify the key in your dashboard at https://dashboard.paybridgenp.com.",
"type": "authentication_error",
"code": "api_key_invalid",
"request_id": "req_2Je91NlWKuXkdXUJOK9gaHNW"
}
}
Fields
| Field | Type | Description |
|---|
error.message | string | Human-readable explanation. Safe to surface in logs; safe to show developers. Not always safe to show end users. |
error.type | string (enum) | Broad category - SDKs use this to instantiate typed exceptions. See error types. |
error.code | string | Specific, stable identifier for programmatic branching. See error codes. |
error.request_id | string | Same value as the X-Request-Id response header. Quote in support requests for fastest triage. |
error.suspension | object | Present only on code: "account_suspended" - includes suspended_at and reason. |
error.pause | object | Present only on code: "token_paused" - includes paused_at and reason. |
Error types
Use error.type to route an error to the right handler. Each type maps to a typed exception class in the SDKs.
| Type | Status range | Meaning |
|---|
authentication_error | 401 | Auth credentials missing or invalid |
account_error | 403, 423 | Credentials valid but the account or token is not in good standing |
permission_error | 403 | Action not permitted (missing scope, wrong key type, plan gate) |
invalid_request_error | 400, 404, 409, 422 | Request was malformed, references something that does not exist, or violates business rules |
idempotency_error | 409 | Concurrent request with same Idempotency-Key |
rate_limit_error | 429 | Rate-limit window exhausted - back off and retry |
api_error | 500-599 | Server-side failure - safe to retry |
HTTP status codes
| Status | Typical type | Notes |
|---|
400 | invalid_request_error | Validation failure |
401 | authentication_error | Missing or invalid API key |
403 | permission_error or account_error | Permission gate or suspended account |
404 | invalid_request_error | Resource not found or not visible to your project |
409 | invalid_request_error or idempotency_error | State conflict, or Idempotency-Key collision |
422 | invalid_request_error | Request is valid but the action cannot be performed |
423 | account_error | MCP token paused for anomalous activity |
429 | rate_limit_error | See Retry-After, X-RateLimit-Remaining, X-RateLimit-Reset headers |
500 | api_error | Server-side failure - safe to retry with backoff |
Error codes
Authentication
| Code | Status | Description |
|---|
api_key_missing | 401 | No Authorization header, or empty key portion |
api_key_invalid | 401 | Key not recognised - typo, deleted project, or wrong environment |
api_key_revoked | 401 | Key was explicitly revoked from the dashboard |
api_key_expired | 401 | Key passed its expiration timestamp |
api_key_must_be_secret | 403 | Endpoint requires sk_...; a publishable pk_... was sent |
account_suspended | 403 | Merchant account suspended - see error.suspension |
token_paused | 423 | MCP token paused due to anomalous activity - see error.pause |
forbidden | 403 | Key doesn’t have permission for this action |
wrong_mode | 403 | Sandbox key used on a live resource or vice versa |
Resources
| Code | Status | Description |
|---|
not_found | 404 | Resource not found or not visible to your project |
already_exists | 409 | Resource with that identifier already exists |
invalid_state | 409 | Resource is in a state that doesn’t allow this action |
idempotency_conflict | 409 | Concurrent request with same Idempotency-Key is still in flight |
Billing
| Code | Status | Description |
|---|
subscription_not_active | 422 | Subscription is not in an active state |
trial_already_ended | 409 | Trial has already ended and cannot be modified |
coupon_inactive | 422 | Coupon has been deactivated |
promotion_code_invalid | 422 | Promotion code is invalid or expired |
plan_not_found | 404 | Plan does not exist or has been deactivated |
Validation + rate limiting
| Code | Status | Description |
|---|
invalid_request_error | 400 | Generic validation failure - read error.message for the specific issue |
rate_limited | 429 | Public-API rate-limit window exhausted |
The account_suspended error
When your account is suspended, every API request returns 403 account_suspended - including read-only endpoints. Hosted checkout pages and payment links also stop working.
{
"error": {
"message": "This merchant account has been suspended. Contact support@paybridgenp.com to resolve.",
"type": "account_error",
"code": "account_suspended",
"request_id": "req_...",
"suspension": {
"suspended_at": "2026-04-20T10:00:00.000Z",
"reason": "Violation of terms of service"
}
}
}
Contact support@paybridgenp.com to appeal or resolve the suspension.
Handling errors in code
import PayBridge, { AuthenticationError, RateLimitError, InvalidRequestError } from "@paybridge-np/sdk";
const client = new PayBridge({ apiKey: process.env.PAYBRIDGE_API_KEY });
try {
const payment = await client.payments.get("pay_abc123");
} catch (err) {
if (err instanceof AuthenticationError) {
// Re-prompt for credentials
} else if (err instanceof RateLimitError) {
// Back off and retry after err.retryAfter seconds
} else if (err instanceof InvalidRequestError) {
// Bad input - log err.code and err.message
} else {
throw err;
}
}
Migrating from the flat envelope
If you have integration code written before the new envelope, here is the upgrade path. The change is breaking - upgrade your SDK and any direct error parsing in lockstep.
Old shape
{
"error": "Invalid API key",
"code": "unauthorized"
}
New shape
{
"error": {
"message": "Invalid API key",
"type": "authentication_error",
"code": "api_key_invalid",
"request_id": "req_..."
}
}
What changed
error is now an object instead of a string. Reading response.error directly will give you [object Object] instead of the message.
- Read
response.error.message for the human-readable string, response.error.type for the broad category, response.error.code for the specific identifier.
code: "unauthorized" was generic - it has been split into api_key_missing, api_key_invalid, api_key_revoked, api_key_expired so you can branch by failure mode.
- Suspension fields previously at the top level (
suspended_at, suspended_reason) are now nested under error.suspension.
- All errors now include
error.request_id matching the X-Request-Id response header. Quote it in support requests.
SDK versions
The TypeScript, PHP, and Python SDKs handle this transparently when you upgrade:
| Language | Pre-envelope | Post-envelope |
|---|
TypeScript (@paybridge-np/sdk) | < 3.0.0 | >= 3.0.0 |
PHP (paybridge-np/sdk) | < 3.0.0 | >= 3.0.0 |
Python (paybridge-np) | < 1.0.0 | >= 1.0.0 |