Endpoint
Retrieves the current status and details of a payment by its ID.
Request
Header | Required | Description |
---|
Authorization | Yes | Bearer token with your API key |
Path Parameters
Parameter | Type | Required | Description |
---|
id | string | Yes | The 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
Field | Type | Description |
---|
id | string | Unique payment identifier |
amount | integer | Payment amount in cents |
currency | string | Currency code (always "usd" ) |
status | string | Payment status: pending , completed , failed , or refunded |
checkout_url | string | URL where customer can complete payment |
customer_email | string | null | Customer’s email (if provided) |
customer_name | string | null | Customer’s name (if provided) |
metadata | object | Custom data attached to payment |
created_at | string | ISO 8601 timestamp when payment was created |
completed_at | string | null | ISO 8601 timestamp when payment was completed (null for pending/failed) |
Payment Statuses
Status | Description |
---|
pending | Payment created but not yet completed. Customer needs to complete checkout. |
completed | Payment successfully processed. Seller balance has been credited. |
failed | Payment failed or was declined by the card processor. |
refunded | Payment 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.