Error Handling

Effective error handling is crucial for building robust integrations with the Localpayment API. Understanding the different error types and their corresponding codes will help you diagnose issues promptly and implement appropriate solutions.

Localpayment provides comprehensive error handling through standardized HTTP status codes and detailed error responses. This guide explains how to effectively handle errors in your integration to build resilient and user-friendly applications.

Overview

Proper error handling is crucial for creating reliable payment integrations. Localpayment uses a consistent error structure across all API endpoints to help you quickly identify and resolve issues.

HTTP Response Codes

Localpayment utilizes standard HTTP status codes to indicate the success or failure of API requests:​

HTTP CodeStatusDescription
200OKThe request was successful and the response contains the requested data.
201CreatedThe resource was successfully created (e.g., new payment initiated).
400Bad RequestThe request was malformed, contained invalid parameters, or missing required fields.
401UnauthorizedAuthentication failed, invalid credentials, or access token missing/expired.
403ForbiddenThe request is understood but has been refused due to insufficient permissions.
404Not FoundThe requested resource could not be found (e.g., invalid endpoint or transaction ID).
409ConflictThe request conflicts with the current state of the resource (e.g., duplicate transaction).
429Too Many RequestsRate limit exceeded. Too many requests made in a given time frame.
500Internal Server ErrorAn unexpected error occurred on Localpayment's servers.

Error Response Structure

When an error occurs, Localpayment returns a JSON object with detailed error information:

{
  "status": {
    "code": "300",
    "description": "REJECTED",
    "detail": "Invalid param + [paymentMethod] + [Is mandatory]"
  },
  "errors": [
    {
      "code": "300",
      "description": "REJECTED",
      "detail": "Invalid param + [paymentMethod] + [Is mandatory]"
    }
  ]
}

Error Response Fields

FieldTypeDescriptionExample
status.codestringLocalpayment-specific status code300
status.descriptionstringBrief error descriptionREJECTED
status.detailstringDetailed error messageInvalid param [paymentMethod]
errors[]arrayArray of specific error objectsSee below
errors[].codestringLocalpayment-specific error code300

Common Error Scenarios

Authentication Errors

{
  "detail": "Given token not valid for any token type",
  "code": "token_not_valid",
  "messages": [
    {
      "token_class": "AccessToken",
      "token_type": "access",
      "message": "Token is invalid or expired"
    }
  ]
}
🔑

Solution: Check your API credentials and ensure your access token is valid. Use the token refresh endpoint if needed.

Validation Errors

{
  "externalId": "46014bdc-c3a7-1b15-8dcf-c7050c1c8199",
  "internalId": "caa4e9aa-f634-497c-ba75-7f88b005ca62",
  "status": {
    "code": "801",
    "description": "REJECTED",
    "detail": "Params error"
  },
  "errors": [
    {
      "code": "300",
      "detail": "Invalid param + [paymentMethod] + doesn´t exists for MEX"
    },
    {
      "code": "300",
      "detail": "Invalid param + [payer.bank.account.[number, type | alias]] + must not be null"
    },
    {
      "code": "300",
      "detail": "Invalid param + [payer.document.type] + is invalid for country MEX"
    },
    {
      "code": "300",
      "detail": "Invalid param + [payer.document] + is invalid for payer type"
    },
    {
      "code": "701",
      "detail": "IncorrectAccountNumber"
    }
  ]
}
📝

Solution: Review the errors array for specific field validation issues. Check API documentation for required fields and format specifications.

Business Logic Errors

{
  "externalId": "8c0b537a-e907-4d87-93db-5dab9807e093",
  "internalId": "dddfde6c-b61c-4b0e-8916-d88886133c4d",
  "status": {
    "code": "701",
    "description": "REJECTED"
  },
  "errors": [
    {
      "code": "701",
      "detail": "Invalid bank account number. Account number verification failed."
    }
  ]
}
💳

Solution: These errors require business-level resolution. Check account balances, transaction limits, or contact support for specific restrictions.


Best Practices for Error Handling

1. Implement Comprehensive Logging

function handleApiError(error, context) {
  const logEntry = {
    timestamp: new Date().toISOString(),
    context: context,
    errorCode: error.status?.code,
    errorDescription: error.status?.description,
    errorDetail: error.status?.detail,
    externalId: error.externalId,
    httpStatus: error.httpStatus
  };
  
  console.error('Localpayment API Error:', logEntry);
  // Send to your monitoring system
  sendToMonitoring(logEntry);
}

2. User-Friendly Error Messages

Create a mapping from technical error codes to user-friendly messages:

const errorMessages = {
  '300': 'Please check your information and try again.',
  '701': 'Your payment was declined. Please use a different payment method.',
  '702': 'Payment authorization expired. Please try again.',
  '703': 'Temporary system issue. Please try again in a few minutes.',
  'default': 'An unexpected error occurred. Please contact support.'
};

function getUserMessage(errorCode) {
  return errorMessages[errorCode] || errorMessages['default'];
}

3. Retry Mechanism with Exponential Backoff

async function makeRequestWithRetry(apiCall, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await apiCall();
    } catch (error) {
      // Only retry on certain errors
      if (!isRetryableError(error)) {
        throw error;
      }
      
      if (attempt === maxRetries) {
        throw error;
      }
      
      // Exponential backoff
      const delay = Math.pow(2, attempt) * 1000;
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }
}

function isRetryableError(error) {
  const retryableCodes = ['500', '502', '503', '504', '800'];
  return retryableCodes.includes(error.status?.code);
}

4. Circuit Breaker Pattern

Implement a circuit breaker to prevent cascading failures:

class CircuitBreaker {
  constructor(failureThreshold = 5, resetTimeout = 60000) {
    this.failureThreshold = failureThreshold;
    this.resetTimeout = resetTimeout;
    this.failureCount = 0;
    this.lastFailureTime = null;
    this.state = 'CLOSED';
  }
  
  async call(apiFunction) {
    if (this.state === 'OPEN') {
      if (Date.now() - this.lastFailureTime > this.resetTimeout) {
        this.state = 'HALF_OPEN';
      } else {
        throw new Error('Circuit breaker is OPEN');
      }
    }
    
    try {
      const result = await apiFunction();
      this.onSuccess();
      return result;
    } catch (error) {
      this.onFailure();
      throw error;
    }
  }
  
  onSuccess() {
    this.failureCount = 0;
    this.state = 'CLOSED';
  }
  
  onFailure() {
    this.failureCount++;
    this.lastFailureTime = Date.now();
    
    if (this.failureCount >= this.failureThreshold) {
      this.state = 'OPEN';
    }
  }
}

Next Steps

💡

Pro Tip: Implement structured logging from day one. Include correlation IDs, error codes, and context information to make debugging much easier when issues occur in production.