> For the complete documentation index, see [llms.txt](https://docs.payr.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.payr.com/error-handling.md).

# Error Handling

This page covers error handling for both API endpoints and SDK integration.

***

### API Error Handling

When calling Payr API endpoints (Onboarding, Authentication, Payment Session), you may receive the following HTTP status codes and error responses.

#### Common HTTP Status Codes

| Status | Meaning      | What to Check                                                              |
| ------ | ------------ | -------------------------------------------------------------------------- |
| 400    | Bad Request  | Validation errors in request body — check required fields and data formats |
| 401    | Unauthorized | API token is invalid, expired, or missing                                  |
| 403    | Forbidden    | Insufficient permissions or resource access denied                         |
| 404    | Not Found    | Resource does not exist or session has expired                             |

#### Error Response Formats

**Authentication errors:**

```json
{ "detail": "Invalid token." }
```

```json
{ "detail": "Authentication credentials were not provided." }
```

**Validation errors** (field-level):

```json
{
  "email": ["This field is required."],
  "user_id": ["This field is required."],
  "tenant": ["This field is required."]
}
```

**Nested validation errors** (within tenant/installment arrays):

```json
{
  "tenant": [
    { "frequency": ["\"weekly\" is not a valid choice."] }
  ]
}
```

**Processing errors:**

```json
{ "error": "Failed to download agreement document from provided URL" }
```

***

### SDK Error Handling

When using the Payr JavaScript SDK, errors are returned through the `onError` callback function configured in `PAYR.init()`.

#### SDK Error Codes

| Code               | Description                                                               |
| ------------------ | ------------------------------------------------------------------------- |
| `INIT_FAILED`      | SDK initialization failed (e.g., invalid config, container not found)     |
| `VALIDATION_ERROR` | Invalid payment request or missing required data (e.g., amount, currency) |
| `WORLDPAY_ERROR`   | Card processing error from WorldPay (e.g., invalid CVC, card declined)    |
| `NETWORK_ERROR`    | Network failure during API calls to Payr backend                          |
| `PAYMENT_FAILED`   | Payment declined or failed by the payment gateway                         |
| `USER_CANCELLED`   | User closed a 3DS, APM, or wallet verification overlay                    |

#### Example: SDK Error Handling

```javascript
PAYR.init({
  apiBaseUrl: 'https://api.mypayr.co.uk',
  authToken: token,
  container: '#payr-payment-form',
  onError: function(error) {
    console.error('Payment failed:', error);
    
    // Handle different error types
    switch (error.code) {
      case 'VALIDATION_ERROR':
        alert('Please check your payment details');
        break;
        
      case 'PAYMENT_FAILED':
        alert('Payment was declined. Please try another card.');
        break;
        
      case 'WORLDPAY_ERROR':
        alert('Card processing error: ' + error.message);
        break;
        
      case 'NETWORK_ERROR':
        alert('Network error. Please check your connection and try again.');
        break;
        
      case 'USER_CANCELLED':
        // User closed verification - don't show as hard error
        console.log('Payment verification was cancelled by user');
        break;
        
      case 'INIT_FAILED':
        alert('Failed to initialize payment form. Please refresh the page.');
        break;
        
      default:
        alert('An unexpected error occurred. Please try again.');
    }
  }
});
```

#### Error Object Structure

SDK errors are returned as objects with the following properties:

```javascript
{
  code: string,      // Error code (see table above)
  message: string,   // Human-readable error message
  details?: any      // Optional additional error details
}
```

#### Best Practices

1. **Always implement `onError`** - Don't rely on default browser error handling
2. **Show user-friendly messages** - Don't expose technical error details to end users
3. **Log errors for debugging** - Use `console.error()` or your logging service
4. **Handle `USER_CANCELLED` gracefully** - This isn't necessarily an error; the user may simply need to retry
5. **Provide retry options** - Allow users to attempt payment again after errors
6. **Test error scenarios** - Use sandbox environment to test different error conditions

***

### When to Use Each Error Handling Approach

* **API Error Handling** - Use when calling backend API endpoints directly from your server
* **SDK Error Handling** - Use when implementing the JavaScript SDK in your frontend

Both approaches work together: your backend handles API errors when creating sessions or onboarding users, while your frontend handles SDK errors during the payment process.
