# Error Handling

Easypay uses standard HTTP response status codes to indicate the success or failure of API requests.

## HTTP Status Codes

The API uses three main ranges of status codes:

- **2xx Success**: Your request was successful
- **4xx Client Error**: There was an error with the information you provided
- **5xx Server Error**: An error occurred on Easypay's servers (rare)


## Common Status Codes

| Status Code | Meaning | What to Do |
|  --- | --- | --- |
| `200 OK` | Request successful | Process the response |
| `201 Created` | Resource created successfully | Process the newly created resource |
| `204 No Content` | Request successful, no content to return | Continue normally |
| `400 Bad Request` | Invalid request parameters | Check your request payload |
| `403 Forbidden` | Authentication failed | Verify your credentials |
| `404 Not Found` | Resource doesn't exist | Check the resource ID |
| `409 Conflict` | Request conflicts with current state | Review the conflict details |
| `429 Too Many Requests` | Rate limit exceeded | Slow down your requests |
| `500 Internal Server Error` | Server error | Retry or contact support |
| `502 Bad Gateway` | Temporary server issue | Retry the request |
| `503 Service Unavailable` | Service temporarily unavailable | Retry the request |


## Error Response Format

When an error occurs, the API returns a JSON response with error details:


```json
{
  "status": "error",
  "message": "Error description",
  "code": "ERROR_CODE",
  "doc_url": "https://docs.easypay.pt/errors/ERROR_CODE"
}
```

## Error Types

### Authentication Error (403)

**Possible Causes**:

- Missing or invalid `AccountId` or `ApiKey` headers
- Account has been blocked
- Insufficient permissions for the requested action


**Example**:


```json
{
  "status": "error",
  "message": "Authentication Error: Invalid AccountId or ApiKey",
  "code": "AUTHENTICATION_ERROR"
}
```

**Resolution**: Verify your credentials and ensure your account is active.

### Invalid Content Type Error (415)

**Cause**: You provided an invalid or unsupported `Content-Type` header.

**Example**:


```json
{
  "status": "error",
  "message": "Invalid Content Type Error: Unsupported content type",
  "code": "INVALID_CONTENT_TYPE"
}
```

**Resolution**: Set the `Content-Type` header to `application/json`.

### Invalid JSON Error (400)

**Cause**: The request body contains malformed JSON.

**Example**:


```json
{
  "status": "error",
  "message": "Invalid JSON Error: Unexpected token",
  "code": "INVALID_JSON"
}
```

**Resolution**: Validate your JSON payload before sending the request.

### Invalid Params Error (400)

**Cause**: Required parameters are missing or invalid.

**Example**:


```json
{
  "status": "error",
  "message": "Invalid Params Error: Field 'value' is required",
  "code": "INVALID_PARAMS",
  "doc_url": "https://docs.easypay.pt/errors/INVALID_PARAMS"
}
```

**Resolution**: Review the error message and ensure all required parameters are provided with valid values.

### Internal Error (500)

**Cause**: An unexpected error occurred on Easypay's servers.

**Example**:


```json
{
  "status": "error",
  "message": "Internal Error: An unexpected error occurred",
  "code": "INTERNAL_ERROR"
}
```

**Resolution**: Retry the request. If the problem persists, contact support.

## Retry Logic

Some errors are safe to retry, while others are not. The API includes an `X-Easypay-Should-Retry` header to help you decide:


```
X-Easypay-Should-Retry: true
```

### When to Retry

**Safe to Retry** (when `X-Easypay-Should-Retry: true` or for these status codes):

- `409 Conflict` - May indicate the original request is still in transit
- `429 Too Many Requests` - Wait and retry
- `502 Bad Gateway` - Temporary server issue
- `503 Service Unavailable` - Service temporarily down


**Do NOT Retry**:

- `400 Bad Request` - Fix your request first
- `403 Forbidden` - Fix authentication first
- `404 Not Found` - Resource doesn't exist
- `422 Unprocessable Entity` - Fix validation errors first


### Retry Strategy

If the `X-Easypay-Should-Retry` header is not present, use this strategy:

1. **No response received**: Retry the request
2. **Status code 409, 429, 502, or 503**: Retry the request
3. **Status code 500** on non-POST requests: Retry the request
4. **Status code 500** on POST requests: Do NOT retry (may duplicate resources)
5. **All other errors**: Do NOT retry


### Example Retry Implementation


```javascript
async function retryableRequest(url, options, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await fetch(url, options);

      // Check if we should retry
      const shouldRetry = response.headers.get('X-Easypay-Should-Retry');
      if (shouldRetry === 'true' || [409, 429, 502, 503].includes(response.status)) {
        if (i < maxRetries - 1) {
          await sleep(Math.pow(2, i) * 1000); // Exponential backoff
          continue;
        }
      }

      return response;
    } catch (error) {
      if (i < maxRetries - 1) {
        await sleep(Math.pow(2, i) * 1000);
        continue;
      }
      throw error;
    }
  }
}
```

## Best Practices

1. **Always Check Status Codes**: Don't assume requests succeed
2. **Log Errors**: Keep detailed logs of errors for debugging
3. **Handle Errors Gracefully**: Provide meaningful feedback to users
4. **Use Idempotency**: Use idempotency keys for safe retries (see [Idempotency](/docs/idempotency))
5. **Implement Exponential Backoff**: When retrying, increase wait time between attempts
6. **Monitor Error Rates**: Track error rates to identify issues early
7. **Respect Rate Limits**: Implement rate limiting to avoid 429 errors


## Next Steps

- [Idempotency](/docs/idempotency) - Learn about safe retries with idempotency keys
- [Authentication](/docs/authentication) - Fix authentication errors
- [Quick Start](/docs/quickstart) - Make your first successful API call