Skip to main content
GET
/
api
/
v1
/
payments
/
:id
Retrieve Payment
curl --request GET \
  --url https://card2crypto.cc/api/v1/payments/:id

Endpoint

GET /api/v1/payments/:id
Retrieves the current status and details of a payment by its ID.

Request

Headers

HeaderRequiredDescription
AuthorizationYesBearer token with your API key

Path Parameters

ParameterTypeRequiredDescription
idstringYesThe payment ID (e.g., pay_abc123)

Example Request

curl https://card2crypto.cc/api/v1/payments/pay_abc123xyz789 \
  -H "Authorization: Bearer c2c_live_your_api_key"

Response

Success Response (200 OK)

Pending Payment

{
  "success": true,
  "data": {
    "id": "pay_abc123xyz789",
    "amount": 10000,
    "currency": "usd",
    "status": "pending",
    "checkout_url": "https://card2crypto.cc/checkout/pay_abc123xyz789",
    "customer_email": "customer@example.com",
    "customer_name": "John Doe",
    "metadata": {
      "order_id": "1234",
      "product": "Premium Plan"
    },
    "created_at": "2025-10-16T12:00:00Z",
    "completed_at": null
  }
}

Completed Payment

{
  "success": true,
  "data": {
    "id": "pay_abc123xyz789",
    "amount": 10000,
    "currency": "usd",
    "status": "completed",
    "checkout_url": "https://card2crypto.cc/checkout/pay_abc123xyz789",
    "customer_email": "customer@example.com",
    "customer_name": "John Doe",
    "metadata": {
      "order_id": "1234",
      "product": "Premium Plan"
    },
    "created_at": "2025-10-16T12:00:00Z",
    "completed_at": "2025-10-16T12:01:30Z"
  }
}

Failed Payment

{
  "success": true,
  "data": {
    "id": "pay_abc123xyz789",
    "amount": 10000,
    "currency": "usd",
    "status": "failed",
    "checkout_url": "https://card2crypto.cc/checkout/pay_abc123xyz789",
    "customer_email": "customer@example.com",
    "customer_name": "John Doe",
    "metadata": {
      "order_id": "1234",
      "product": "Premium Plan"
    },
    "created_at": "2025-10-16T12:00:00Z",
    "completed_at": null
  }
}

Refunded Payment

{
  "success": true,
  "data": {
    "id": "pay_abc123xyz789",
    "amount": 10000,
    "currency": "usd",
    "status": "refunded",
    "checkout_url": "https://card2crypto.cc/checkout/pay_abc123xyz789",
    "customer_email": "customer@example.com",
    "customer_name": "John Doe",
    "metadata": {
      "order_id": "1234",
      "product": "Premium Plan"
    },
    "created_at": "2025-10-16T12:00:00Z",
    "completed_at": "2025-10-16T12:01:30Z"
  }
}

Response Fields

FieldTypeDescription
idstringUnique payment identifier
amountintegerPayment amount in cents
currencystringCurrency code (always "usd")
statusstringPayment status: pending, completed, failed, or refunded
checkout_urlstringURL where customer can complete payment
customer_emailstring | nullCustomer’s email (if provided)
customer_namestring | nullCustomer’s name (if provided)
metadataobjectCustom data attached to payment
created_atstringISO 8601 timestamp when payment was created
completed_atstring | nullISO 8601 timestamp when payment was completed (null for pending/failed)

Payment Statuses

StatusDescription
pendingPayment created but not yet completed. Customer needs to complete checkout.
completedPayment successfully processed. Seller balance has been credited.
failedPayment failed or was declined by the card processor.
refundedPayment was completed but has been refunded by an admin.

Error Responses

401 Unauthorized

Invalid or missing API key:
{
  "success": false,
  "error": "Invalid API key"
}

404 Not Found

Payment doesn’t exist or doesn’t belong to your shop:
{
  "success": false,
  "error": "Payment not found"
}
Possible causes:
  • Payment ID is incorrect
  • Payment belongs to a different shop
  • Payment was deleted (rare)

429 Too Many Requests

Rate limit exceeded:
{
  "success": false,
  "error": "Rate limit exceeded. Try again in 30 seconds."
}

Use Cases

1. Verify Payment After Return URL

When customer returns to your site after payment:
// Customer redirected to: https://yoursite.com/success?payment_id=pay_abc123

app.get('/success', async (req, res) => {
  const paymentId = req.query.payment_id;

  // Retrieve payment to verify status
  const response = await fetch(
    `https://card2crypto.cc/api/v1/payments/${paymentId}`,
    {
      headers: {
        'Authorization': `Bearer ${process.env.CARD2CRYPTO_API_KEY}`
      }
    }
  );

  const payment = await response.json();

  if (payment.data.status === 'completed') {
    // Payment successful - grant access
    res.send('Payment successful! Thank you for your purchase.');
  } else if (payment.data.status === 'pending') {
    // Still processing
    res.send('Payment is being processed...');
  } else {
    // Failed
    res.send('Payment failed. Please try again.');
  }
});

2. Check Payment Status in Webhook

Verify payment details when webhook is received:
app.post('/webhooks/card2crypto', async (req, res) => {
  // Return 200 immediately
  res.status(200).send('OK');

  // Process webhook asynchronously
  const { payment } = req.body;

  // Optional: Retrieve payment to double-check status
  const response = await fetch(
    `https://card2crypto.cc/api/v1/payments/${payment.id}`,
    {
      headers: {
        'Authorization': `Bearer ${process.env.CARD2CRYPTO_API_KEY}`
      }
    }
  );

  const verifiedPayment = await response.json();

  if (verifiedPayment.data.status === 'completed') {
    // Process payment
    await fulfillOrder(verifiedPayment.data.metadata.order_id);
  }
});

3. Poll Payment Status

For synchronous payment verification (not recommended - use webhooks instead):
async function waitForPayment(paymentId, maxWaitSeconds = 300) {
  const startTime = Date.now();

  while ((Date.now() - startTime) / 1000 < maxWaitSeconds) {
    const response = await fetch(
      `https://card2crypto.cc/api/v1/payments/${paymentId}`,
      {
        headers: {
          'Authorization': `Bearer ${process.env.CARD2CRYPTO_API_KEY}`
        }
      }
    );

    const payment = await response.json();

    if (payment.data.status === 'completed') {
      return { success: true, payment: payment.data };
    } else if (payment.data.status === 'failed') {
      return { success: false, payment: payment.data };
    }

    // Wait 5 seconds before next check
    await new Promise(resolve => setTimeout(resolve, 5000));
  }

  return { success: false, error: 'Timeout waiting for payment' };
}
Polling is inefficient and can hit rate limits. Use webhooks for real-time notifications instead.

Implementation Examples

Node.js / Express

const express = require('express');
const fetch = require('node-fetch');

const app = express();
const API_KEY = process.env.CARD2CRYPTO_API_KEY;

app.get('/payment/:id', async (req, res) => {
  try {
    const response = await fetch(
      `https://card2crypto.cc/api/v1/payments/${req.params.id}`,
      {
        headers: {
          'Authorization': `Bearer ${API_KEY}`
        }
      }
    );

    const payment = await response.json();

    if (payment.success) {
      res.json(payment.data);
    } else {
      res.status(404).json({ error: payment.error });
    }

  } catch (error) {
    console.error('Failed to retrieve payment:', error);
    res.status(500).json({ error: 'Failed to retrieve payment' });
  }
});

PHP

<?php

function getPayment($paymentId) {
    $apiKey = getenv('CARD2CRYPTO_API_KEY');

    $ch = curl_init('https://card2crypto.cc/api/v1/payments/' . $paymentId);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'Authorization: Bearer ' . $apiKey
    ]);

    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    $result = json_decode($response, true);

    if ($httpCode === 200 && $result['success']) {
        return $result['data'];
    } else {
        throw new Exception($result['error'] ?? 'Payment not found');
    }
}

// Usage
try {
    $payment = getPayment('pay_abc123');

    if ($payment['status'] === 'completed') {
        echo 'Payment successful!';
    } else {
        echo 'Payment status: ' . $payment['status'];
    }
} catch (Exception $e) {
    echo 'Error: ' . $e->getMessage();
}

Python / Flask

import os
import requests
from flask import Flask, jsonify

app = Flask(__name__)
API_KEY = os.getenv('CARD2CRYPTO_API_KEY')

@app.route('/payment/<payment_id>')
def get_payment(payment_id):
    try:
        response = requests.get(
            f'https://card2crypto.cc/api/v1/payments/{payment_id}',
            headers={
                'Authorization': f'Bearer {API_KEY}'
            }
        )

        payment = response.json()

        if payment['success']:
            return jsonify(payment['data'])
        else:
            return jsonify({'error': payment['error']}), 404

    except Exception as e:
        return jsonify({'error': str(e)}), 500

Best Practices

1. Use Webhooks Instead of Polling

Webhooks provide instant notifications when payment status changes:
// Bad - Polling
async function checkPayment(paymentId) {
  setInterval(async () => {
    const payment = await getPayment(paymentId);
    if (payment.status === 'completed') {
      fulfillOrder();
    }
  }, 5000); // Check every 5 seconds - inefficient!
}

// Good - Webhook
app.post('/webhooks/card2crypto', (req, res) => {
  if (req.body.event === 'payment.completed') {
    fulfillOrder(req.body.payment.metadata.order_id);
  }
  res.send('OK');
});

2. Verify Payment Belongs to Your Shop

The API only returns payments for your shop, but double-check in production:
const payment = await getPayment(paymentId);

if (payment.metadata.order_id !== expectedOrderId) {
  throw new Error('Payment does not match order');
}

3. Handle All Statuses

Don’t assume payments are always completed:
switch (payment.status) {
  case 'completed':
    await fulfillOrder();
    break;
  case 'pending':
    await sendReminderEmail();
    break;
  case 'failed':
    await logFailedPayment();
    break;
  case 'refunded':
    await revokeAccess();
    break;
  default:
    console.error('Unknown payment status:', payment.status);
}

4. Cache Payment Data

Reduce API calls by caching payment data:
const cache = new Map();

async function getPayment(paymentId) {
  // Check cache first
  if (cache.has(paymentId)) {
    const cached = cache.get(paymentId);
    // Only cache completed/failed/refunded (final states)
    if (['completed', 'failed', 'refunded'].includes(cached.status)) {
      return cached;
    }
  }

  // Fetch from API
  const payment = await fetchPayment(paymentId);

  // Cache if in final state
  if (['completed', 'failed', 'refunded'].includes(payment.status)) {
    cache.set(paymentId, payment);
  }

  return payment;
}

Testing

Test payment retrieval with real payment IDs from your shop. See Testing Guide for details.
I