Essentials

Error Handling

Handle API errors gracefully and implement proper error recovery

Understanding how to handle errors properly ensures a robust integration with the DVPay API. This guide covers error response formats, common error codes, and best practices for error recovery.

Error Response Format

All DVPay API errors follow a consistent JSON structure:

{
  "error": {
    "code": "insufficient_funds",
    "message": "The merchant account has insufficient funds to process this payout",
    "details": {
      "available_balance": 50.00,
      "required_amount": 100.00
    },
    "request_id": "req_abc123xyz",
    "timestamp": 1696435200
  }
}
code
string required
Machine-readable error code for programmatic handling
message
string required
Human-readable error description
details
object
Additional context about the error (varies by error type)
request_id
string required
Unique identifier for the request (use this when contacting support)
timestamp
number required
Unix timestamp when the error occurred

HTTP Status Codes

DVPay API uses standard HTTP status codes:

Status CodeMeaningCommon Causes
400Bad RequestInvalid request parameters, malformed JSON
401UnauthorizedMissing or invalid API credentials
403ForbiddenValid credentials but insufficient permissions
404Not FoundResource (order, transaction) doesn't exist
409ConflictDuplicate order ID, conflicting operation
422Unprocessable EntityValid JSON but business logic validation failed
429Too Many RequestsRate limit exceeded
500Internal Server ErrorServer-side issue (safe to retry)
503Service UnavailableTemporary maintenance or overload

Common Error Codes

Authentication Errors

Validation Errors

Business Logic Errors

Rate Limiting

Error Handling Best Practices

1. Implement Retry Logic

Retry transient errors with exponential backoff:

func retryableRequest(fn func() error, maxRetries int) error {
    retryableErrors := map[int]bool{
        429: true, // Rate limit
        500: true, // Internal server error
        503: true, // Service unavailable
    }

    for attempt := 0; attempt < maxRetries; attempt++ {
        err := fn()
        if err == nil {
            return nil
        }

        // Check if error is retryable
        if httpErr, ok := err.(*HTTPError); ok {
            if retryableErrors[httpErr.StatusCode] {
                backoff := time.Duration(math.Pow(2, float64(attempt))) * time.Second
                time.Sleep(backoff)
                continue
            }
        }

        return err // Non-retryable error
    }

    return errors.New("max retries exceeded")
}

2. Log Errors with Context

Always log errors with request IDs for debugging:

function logError(error, context) {
  console.error({
    timestamp: new Date().toISOString(),
    request_id: error.request_id,
    error_code: error.code,
    message: error.message,
    context: context,
    details: error.details
  });
}

// Usage
try {
  await createOrder(orderData);
} catch (error) {
  logError(error, {
    action: 'create_order',
    order_id: orderData.order_id
  });
}

3. Handle Errors Gracefully

Provide user-friendly error messages:

func handleAPIError(err error) string {
    apiErr, ok := err.(*APIError)
    if !ok {
        return "An unexpected error occurred. Please try again."
    }

    switch apiErr.Code {
    case "insufficient_funds":
        return "Unable to process payment. Please contact support."
    case "invalid_amount":
        return "Invalid payment amount. Please check and try again."
    case "rate_limit_exceeded":
        return "Too many requests. Please wait a moment and try again."
    default:
        return apiErr.Message
    }
}

4. Monitor Error Rates

Track error rates and set up alerts:

const errorMetrics = {
  total: 0,
  by_code: {},
  by_status: {}
};

function trackError(error) {
  errorMetrics.total++;
  errorMetrics.by_code[error.code] = (errorMetrics.by_code[error.code] || 0) + 1;
  errorMetrics.by_status[error.status] = (errorMetrics.by_status[error.status] || 0) + 1;

  // Alert if error rate exceeds threshold
  if (errorMetrics.total > 100) {
    sendAlert('High error rate detected', errorMetrics);
  }
}

Idempotency

Prevent duplicate operations by using idempotency keys:

POST /api/v1/payment-gateway/order/create
X-Idempotency-Key: unique-key-123

DVPay stores the result of the first request and returns the same response for subsequent requests with the same idempotency key within 24 hours.

import "github.com/google/uuid"

func createOrderWithIdempotency(payload OrderRequest) (*OrderResponse, error) {
    idempotencyKey := uuid.New().String()

    req.Header.Set("X-Idempotency-Key", idempotencyKey)

    // Safe to retry - same idempotency key returns same result
    return callAPI(req)
}

Troubleshooting Checklist

Verify API Credentials

  • Check X-App-Id and X-Api-Key are correct
  • Ensure credentials are from production (not sandbox)

Check Request Format

  • Validate JSON syntax
  • Ensure all required fields are present
  • Verify data types match API specification

Review Timestamp

  • Use current server time (±5 minutes tolerance)
  • Format as Unix timestamp in seconds

Test Connectivity

  • Ensure your server can reach https://merchant.dv.vai247.pro
  • Check firewall rules and SSL certificate validation

Inspect Response

  • Log full error response including request_id
  • Check HTTP status code and error code
  • Review error details for specific guidance

Getting Help

If you encounter persistent errors:

  1. Check Status Page: Visit status.dvpay.com for service status
  2. Review Logs: Include request_id from error responses
  3. Contact Support: Email support@dvpay.com with:
    • Request ID
    • Timestamp of the error
    • Full error response
    • Steps to reproduce
Include the request_id from error responses when contacting support for faster resolution.

Next Steps

Testing & Sandbox

Test your integration without real transactions

Security Best Practices

Secure your API integration properly