Skip to main content

Error Handling

The ChainPal API uses conventional HTTP status codes to indicate the success or failure of requests. All error responses follow a consistent JSON structure.

HTTP Status Codes

CodeStatusDescription
200OKRequest succeeded
400Bad RequestInvalid request parameters or validation error
401UnauthorizedMissing or invalid API key
403ForbiddenValid API key but access denied (e.g., IP not whitelisted)
404Not FoundRequested resource doesn’t exist
429Too Many RequestsRate limit exceeded
500Internal Server ErrorServer-side error

Error Response Format

All error responses use this structure:
{
  "success": false,
  "message": "Descriptive error message",
  "data": null
}
FieldTypeDescription
successbooleanAlways false for errors
messagestringHuman-readable error description
datanullAlways null for errors

Common Errors

Authentication Errors (401)

Missing API Key
{
  "success": false,
  "message": "api key not provided, use the format 'Bearer <api key>'",
  "data": null
}
Invalid API Key
{
  "success": false,
  "message": "api key is invalid, use the format 'Bearer <api key>'",
  "data": null
}
Wrong Key Type
{
  "success": false,
  "message": "endpoint requires a secret key",
  "data": null
}

Authorization Errors (403)

IP Not Whitelisted
{
  "success": false,
  "message": "access denied",
  "data": null
}

Validation Errors (400)

Missing Required Field
{
  "success": false,
  "message": "Key: 'InitializePaymentDTO.Amount' Error:Field validation for 'Amount' failed on the 'required' tag",
  "data": null
}
Invalid Email
{
  "success": false,
  "message": "Key: 'InitializePaymentDTO.CustomerEmail' Error:Field validation for 'CustomerEmail' failed on the 'email' tag",
  "data": null
}
Amount Below Minimum
{
  "success": false,
  "message": "amount must be at least 1000.00 NGN",
  "data": null
}
Amount Above Maximum
{
  "success": false,
  "message": "amount cannot exceed 1000000.00 NGN",
  "data": null
}
Duplicate Reference
{
  "success": false,
  "message": "the reference you provided is already in use, please try again with a different reference",
  "data": null
}
Invalid Reference Format
{
  "success": false,
  "message": "Key: 'InitializePaymentDTO.Reference' Error:Field validation for 'Reference' failed on the 'alphanum' tag",
  "data": null
}
Unsupported Token/Network
{
  "success": false,
  "message": "pair not supported",
  "data": null
}
Webhook Secret Required
{
  "success": false,
  "message": "You must generate a webhook signing secret before configuring webhook URLs",
  "data": null
}

Not Found Errors (404)

Payment Not Found
{
  "success": false,
  "message": "payment not found",
  "data": null
}
Invalid Payment ID Format
{
  "success": false,
  "message": "invalid payment ID format",
  "data": null
}

Rate Limit Errors (429)

Too Many Requests
{
  "success": false,
  "message": "too many requests",
  "data": null
}

Server Errors (500)

Generic Server Error
{
  "success": false,
  "message": "something went wrong, please try again",
  "data": null
}

Handling Errors

Best Practices

  1. Check the success field first
    const response = await fetch('/api/v1/payments', { ... });
    const data = await response.json();
    
    if (!data.success) {
      console.error('API Error:', data.message);
      // Handle error
      return;
    }
    
    // Process successful response
    
  2. Handle specific status codes
    if (response.status === 401) {
      // Re-authenticate or check API key
    } else if (response.status === 429) {
      // Wait and retry with exponential backoff
    } else if (response.status >= 500) {
      // Server error, retry later
    }
    
  3. Implement retry logic for transient errors
    async function fetchWithRetry(url, options, maxRetries = 3) {
      for (let i = 0; i < maxRetries; i++) {
        const response = await fetch(url, options);
    
        if (response.status === 429 || response.status >= 500) {
          const delay = Math.pow(2, i) * 1000; // Exponential backoff
          await new Promise((resolve) => setTimeout(resolve, delay));
          continue;
        }
    
        return response;
      }
      throw new Error("Max retries exceeded");
    }
    
  4. Log errors for debugging
    if (!data.success) {
      console.error({
        endpoint: "/api/v1/payments",
        status: response.status,
        message: data.message,
        requestId: response.headers.get("x-request-id"),
        timestamp: new Date().toISOString(),
      });
    }
    

Validation Rules

Amount Field

  • Must be a positive number
  • Must meet minimum and maximum limits for the currency
  • See Types & Enums for limits

Reference Field

  • Optional (auto-generated if not provided)
  • 12-16 alphanumeric characters
  • Must be unique per merchant

Email Field

  • Must be a valid email format

URL Fields (callbackURL, failureURL)

  • Must be valid URLs
  • Must use HTTPS protocol

Token/Network

  • Must be a supported combination for your country
  • See Types & Enums