Skip to main content

Error Response Format

All error responses follow this format:
{
  "success": false,
  "error": "Error message describing what went wrong"
}
The HTTP status code indicates the error category.

HTTP Status Codes

CodeMeaningDescription
200OKRequest succeeded
400Bad RequestInvalid request parameters
401UnauthorizedInvalid or missing API key
404Not FoundResource doesn’t exist
429Too Many RequestsRate limit exceeded
500Internal Server ErrorSomething went wrong on our end

400 Bad Request Errors

Invalid Amount

{
  "success": false,
  "error": "Amount must be at least 50 cents"
}
Cause: Payment amount is below the $0.50 minimum Solution:
// Ensure amount is at least 50 cents
const amount = Math.max(50, requestedAmount);

Invalid Currency

{
  "success": false,
  "error": "Currency must be 'usd'"
}
Cause: Unsupported currency code Solution:
// Only USD is supported
const payment = await createPayment({
  amount: 10000,
  currency: 'usd' // Must be 'usd'
});

Missing Return URL

{
  "success": false,
  "error": "Return URL is required"
}
Cause: No return_url provided in payment creation Solution:
const payment = await createPayment({
  amount: 10000,
  currency: 'usd',
  return_url: 'https://yoursite.com/success' // Required
});

Invalid Return URL

{
  "success": false,
  "error": "Return URL must be a valid HTTPS URL"
}
Cause: Return URL is not a valid HTTPS URL Solution:
// Must be valid HTTPS URL
return_url: 'https://yoursite.com/success' // Good
return_url: 'http://yoursite.com/success'  // Bad - not HTTPS
return_url: 'not-a-url'                     // Bad - invalid format

Invalid Metadata

{
  "success": false,
  "error": "Metadata cannot exceed 50 keys"
}
Cause: Too many keys in metadata object Solution:
// Keep metadata under 50 keys
metadata: {
  order_id: '1234',
  user_id: '5678',
  product: 'premium'
  // ... up to 50 keys total
}

Missing Required Fields

{
  "success": false,
  "error": "Missing required field: amount"
}
Cause: Required parameter not provided Solution:
// Ensure all required fields are present
const payment = await createPayment({
  amount: 10000,      // Required
  currency: 'usd',    // Required
  return_url: '...'   // Required
});

401 Unauthorized Errors

Invalid API Key

{
  "success": false,
  "error": "Invalid API key"
}
Causes:
  • API key doesn’t exist
  • API key format is incorrect
  • API key was deleted
  • Shop is inactive
Solutions:
  1. Check API key format:
// Correct format
c2c_live_[64 character hex string]

// Example
c2c_live_a1b2c3d4e5f6...
  1. Verify API key in dashboard:
Visit: https://card2crypto.cc/dashboard/shops
Check your API key under shop settings
  1. Ensure proper authentication header:
headers: {
  'Authorization': 'Bearer c2c_live_your_key' // Include 'Bearer '
}

Missing API Key

{
  "success": false,
  "error": "API key required"
}
Cause: No Authorization header provided Solution:
// Always include Authorization header
const response = await fetch('https://card2crypto.cc/api/v1/payments', {
  headers: {
    'Authorization': `Bearer ${apiKey}` // Required
  }
});

Shop Inactive

{
  "success": false,
  "error": "Shop is inactive"
}
Cause: Your shop has been deactivated Solution: Contact support or check dashboard for shop status

404 Not Found Errors

Payment Not Found

{
  "success": false,
  "error": "Payment not found"
}
Causes:
  • Payment ID is incorrect
  • Payment belongs to different shop
  • Payment was deleted (rare)
Solutions:
  1. Verify payment ID format:
// Correct format
pay_[alphanumeric string]

// Example
pay_abc123xyz789
  1. Ensure payment exists:
try {
  const payment = await getPayment(paymentId);
} catch (error) {
  if (error.message === 'Payment not found') {
    console.log('Invalid payment ID');
  }
}

429 Rate Limit Errors

Rate Limit Exceeded

{
  "success": false,
  "error": "Rate limit exceeded. Try again in 30 seconds."
}
Cause: Too many requests in short time period Limit: 100 requests per minute per API key Solutions:
  1. Implement exponential backoff:
async function apiRequestWithRetry(url, options, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    const response = await fetch(url, options);

    if (response.status === 429) {
      // Wait exponentially longer each retry
      const delay = Math.pow(2, i) * 1000;
      await new Promise(resolve => setTimeout(resolve, delay));
      continue;
    }

    return response;
  }

  throw new Error('Max retries exceeded');
}
  1. Implement request queuing:
class RateLimiter {
  constructor(maxRequests = 100, timeWindow = 60000) {
    this.maxRequests = maxRequests;
    this.timeWindow = timeWindow;
    this.requests = [];
  }

  async throttle() {
    const now = Date.now();
    this.requests = this.requests.filter(time => now - time < this.timeWindow);

    if (this.requests.length >= this.maxRequests) {
      const oldestRequest = this.requests[0];
      const waitTime = this.timeWindow - (now - oldestRequest);
      await new Promise(resolve => setTimeout(resolve, waitTime));
    }

    this.requests.push(now);
  }
}

const limiter = new RateLimiter();

async function createPayment(data) {
  await limiter.throttle();
  return fetch('https://card2crypto.cc/api/v1/payments', {...});
}
  1. Cache responses:
const cache = new Map();

async function getPayment(paymentId) {
  if (cache.has(paymentId)) {
    return cache.get(paymentId);
  }

  const payment = await fetchPayment(paymentId);
  cache.set(paymentId, payment);
  return payment;
}

500 Internal Server Error

Server Error

{
  "success": false,
  "error": "An unexpected error occurred"
}
Cause: Something went wrong on Card2Crypto’s servers Solutions:
  1. Retry the request:
async function apiRequestWithRetry(url, options) {
  const maxRetries = 3;

  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await fetch(url, options);

      if (response.status >= 500) {
        // Server error - retry
        await new Promise(resolve => setTimeout(resolve, 2000));
        continue;
      }

      return response;
    } catch (error) {
      if (i === maxRetries - 1) throw error;
      await new Promise(resolve => setTimeout(resolve, 2000));
    }
  }
}
  1. Log the error and contact support if it persists

Network Errors

Connection Timeout

Cause: Request took too long to connect Solution:
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 10000); // 10s timeout

try {
  const response = await fetch(url, {
    signal: controller.signal
  });
} catch (error) {
  if (error.name === 'AbortError') {
    console.error('Request timed out');
  }
} finally {
  clearTimeout(timeout);
}

Network Failure

Cause: No internet connection or DNS failure Solution:
try {
  const response = await fetch(url);
} catch (error) {
  if (error.message.includes('fetch')) {
    console.error('Network error - check internet connection');
  }
}

Error Handling Best Practices

1. Implement Proper Error Handling

async function createPayment(data) {
  try {
    const response = await fetch('https://card2crypto.cc/api/v1/payments', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${apiKey}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(data)
    });

    const result = await response.json();

    if (!response.ok) {
      throw new Error(result.error || 'Payment creation failed');
    }

    return result.data;

  } catch (error) {
    // Log error
    console.error('Payment creation error:', error.message);

    // Handle specific errors
    if (error.message.includes('Rate limit')) {
      // Wait and retry
    } else if (error.message.includes('Invalid API key')) {
      // Alert developer
    }

    throw error;
  }
}

2. Provide User-Friendly Error Messages

async function handlePayment(amount) {
  try {
    const payment = await createPayment({ amount, ... });
    return { success: true, payment };

  } catch (error) {
    // Log technical error
    console.error(error);

    // Return user-friendly message
    let userMessage = 'Payment failed. Please try again.';

    if (error.message.includes('Amount must be at least')) {
      userMessage = 'Minimum payment amount is $0.50';
    } else if (error.message.includes('Rate limit')) {
      userMessage = 'Too many requests. Please wait a moment.';
    }

    return { success: false, error: userMessage };
  }
}

3. Log All Errors

function logError(error, context) {
  console.error({
    timestamp: new Date().toISOString(),
    error: error.message,
    stack: error.stack,
    context: context
  });

  // Send to monitoring service
  // monitoring.track('api_error', { ... });
}

try {
  await createPayment(data);
} catch (error) {
  logError(error, { action: 'create_payment', data });
  throw error;
}

4. Implement Retry Logic

async function retryableRequest(fn, maxRetries = 3) {
  const retryableStatuses = [429, 500, 502, 503, 504];

  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      const shouldRetry = retryableStatuses.includes(error.statusCode);
      const isLastAttempt = i === maxRetries - 1;

      if (!shouldRetry || isLastAttempt) {
        throw error;
      }

      // Exponential backoff
      const delay = Math.pow(2, i) * 1000;
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }
}

// Usage
const payment = await retryableRequest(() => createPayment(data));

Debugging Errors

Enable Debug Logging

const DEBUG = process.env.DEBUG === 'true';

async function createPayment(data) {
  if (DEBUG) {
    console.log('Creating payment:', data);
  }

  const response = await fetch(url, options);

  if (DEBUG) {
    console.log('Response status:', response.status);
    console.log('Response body:', await response.clone().text());
  }

  // ... handle response
}

Inspect API Responses

# Use cURL to debug API calls
curl -v -X POST https://card2crypto.cc/api/v1/payments \
  -H "Authorization: Bearer c2c_live_..." \
  -H "Content-Type: application/json" \
  -d '{"amount": 10000, "currency": "usd", "return_url": "https://test.com"}'

Common Mistakes

1. Exposing API Keys

// BAD - Never expose API key in frontend
<script>
  const apiKey = 'c2c_live_...'; // Visible to everyone!
</script>

// GOOD - Keep API key on server
// server.js
const apiKey = process.env.CARD2CRYPTO_API_KEY;

2. Not Handling Errors

// BAD - No error handling
const payment = await createPayment(data);
redirect(payment.checkout_url);

// GOOD - Proper error handling
try {
  const payment = await createPayment(data);
  redirect(payment.checkout_url);
} catch (error) {
  showError('Payment creation failed');
}

3. Ignoring Rate Limits

// BAD - Can hit rate limits
for (let i = 0; i < 200; i++) {
  await createPayment(data);
}

// GOOD - Implement rate limiting
const limiter = new RateLimiter();
for (let i = 0; i < 200; i++) {
  await limiter.throttle();
  await createPayment(data);
}

Next Steps

I