Payzo Docs

Retrieving Payments

Query payment status and retrieve payment details via API

Overview

Retrieve payment information from Payzo to check status, view details, or list all payments for your shop.

Recommended: Use webhooks instead of polling for real-time updates.

Get Single Payment

Retrieve details for a specific payment by ID.

Endpoint

GET https://payzo.cc/api/v1/payments/{payment_id}

Parameters

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

Example Request

curl https://payzo.cc/api/v1/payments/pay_abc123def456 \
  -H "Authorization: Bearer YOUR_API_KEY"

Example Response

{
  "id": "pay_abc123def456",
  "status": "completed",
  "amount": 5000,
  "currency": "usd",
  "customer_email": "customer@example.com",
  "customer_name": "John Doe",
  "metadata": {
    "order_id": "ORD-12345",
    "product": "Premium Plan"
  },
  "created_at": "2025-01-12T10:30:00.000Z",
  "completed_at": "2025-01-12T10:30:15.000Z"
}

Node.js Example

async function getPayment(paymentId) {
  const response = await fetch(
    `https://payzo.cc/api/v1/payments/${paymentId}`,
    {
      headers: {
        'Authorization': `Bearer ${process.env.PAYZO_API_KEY}`
      }
    }
  );
 
  if (!response.ok) {
    throw new Error(`Failed to get payment: ${response.statusText}`);
  }
 
  return await response.json();
}
 
// Usage
const payment = await getPayment('pay_abc123def456');
console.log('Payment status:', payment.status);

List All Payments

Retrieve a list of all payments for your shop with pagination and filtering.

Endpoint

GET https://payzo.cc/api/v1/payments

Query Parameters

ParameterTypeRequiredDescription
limitintegerNoNumber of payments to return (max: 100, default: 10)
offsetintegerNoNumber of payments to skip (default: 0)
statusstringNoFilter by status: pending, completed, failed, expired

Example Request

# Get 20 completed payments
curl "https://payzo.cc/api/v1/payments?limit=20&status=completed" \
  -H "Authorization: Bearer YOUR_API_KEY"

Example Response

{
  "data": [
    {
      "id": "pay_abc123",
      "status": "completed",
      "amount": 5000,
      "currency": "usd",
      "customer_email": "customer1@example.com",
      "metadata": {"order_id": "ORD-001"},
      "created_at": "2025-01-12T10:30:00.000Z",
      "completed_at": "2025-01-12T10:30:15.000Z"
    },
    {
      "id": "pay_def456",
      "status": "completed",
      "amount": 2500,
      "currency": "usd",
      "customer_email": "customer2@example.com",
      "metadata": {"order_id": "ORD-002"},
      "created_at": "2025-01-12T09:15:00.000Z",
      "completed_at": "2025-01-12T09:15:10.000Z"
    }
  ],
  "has_more": true,
  "total": 145
}

Node.js Example

async function listPayments(options = {}) {
  const {
    limit = 10,
    offset = 0,
    status = null
  } = options;
 
  const params = new URLSearchParams({
    limit: limit.toString(),
    offset: offset.toString()
  });
 
  if (status) {
    params.append('status', status);
  }
 
  const response = await fetch(
    `https://payzo.cc/api/v1/payments?${params}`,
    {
      headers: {
        'Authorization': `Bearer ${process.env.PAYZO_API_KEY}`
      }
    }
  );
 
  if (!response.ok) {
    throw new Error(`Failed to list payments: ${response.statusText}`);
  }
 
  return await response.json();
}
 
// Usage: Get all completed payments
const { data, total, has_more } = await listPayments({
  limit: 50,
  status: 'completed'
});
 
console.log(`Found ${total} completed payments`);
data.forEach(payment => {
  console.log(`- ${payment.id}: $${payment.amount / 100}`);
});

Payment Status Values

StatusDescription
pendingPayment created, awaiting customer action
completedPayment successful, customer charged
failedPayment attempt failed
expiredPayment link expired without completion
refundedPayment was refunded by Payzo support

Pagination

Basic Pagination

// Get first page
const page1 = await listPayments({ limit: 20, offset: 0 });
 
// Get second page
const page2 = await listPayments({ limit: 20, offset: 20 });
 
// Get third page
const page3 = await listPayments({ limit: 20, offset: 40 });

Auto-Pagination

async function getAllPayments() {
  let allPayments = [];
  let offset = 0;
  const limit = 100; // Max per request
  let hasMore = true;
 
  while (hasMore) {
    const response = await listPayments({ limit, offset });
    allPayments = allPayments.concat(response.data);
    offset += limit;
    hasMore = response.has_more;
  }
 
  return allPayments;
}
 
// Get ALL payments (use carefully with large datasets)
const payments = await getAllPayments();
console.log(`Total payments: ${payments.length}`);

Filtering by Status

Get Only Completed Payments

const completed = await listPayments({
  status: 'completed',
  limit: 100
});
 
console.log('Completed payments:', completed.data.length);

Get Only Failed Payments

const failed = await listPayments({
  status: 'failed',
  limit: 50
});
 
failed.data.forEach(payment => {
  console.log(`Failed payment: ${payment.id} - ${payment.customer_email}`);
});

Get Only Pending Payments

const pending = await listPayments({
  status: 'pending',
  limit: 20
});
 
console.log('Pending payments:', pending.total);

Use Cases

Check Payment Status

async function checkOrderPaymentStatus(orderId) {
  // Get payment ID from your database
  const order = await db.orders.findOne({ id: orderId });
 
  if (!order.payzo_payment_id) {
    return { status: 'not_started' };
  }
 
  // Query Payzo API
  const payment = await getPayment(order.payzo_payment_id);
 
  return {
    status: payment.status,
    amount: payment.amount,
    completed_at: payment.completed_at
  };
}

Generate Payment Report

async function generatePaymentReport(startDate, endDate) {
  const allPayments = await getAllPayments();
 
  // Filter by date range
  const filtered = allPayments.filter(payment => {
    const date = new Date(payment.created_at);
    return date >= startDate && date <= endDate;
  });
 
  // Calculate statistics
  const completed = filtered.filter(p => p.status === 'completed');
  const totalRevenue = completed.reduce((sum, p) => sum + p.amount, 0);
 
  return {
    total_payments: filtered.length,
    completed_payments: completed.length,
    failed_payments: filtered.filter(p => p.status === 'failed').length,
    total_revenue: totalRevenue / 100, // Convert cents to dollars
    average_payment: totalRevenue / completed.length / 100
  };
}
 
// Generate report for last 30 days
const endDate = new Date();
const startDate = new Date();
startDate.setDate(startDate.getDate() - 30);
 
const report = await generatePaymentReport(startDate, endDate);
console.log('Payment Report:', report);

Reconciliation

async function reconcilePayments() {
  // Get all completed payments from Payzo
  const { data: c2cPayments } = await listPayments({
    status: 'completed',
    limit: 100
  });
 
  // Get all orders from your database
  const dbOrders = await db.orders.find({
    status: 'paid'
  });
 
  // Find mismatches
  const mismatches = [];
 
  for (const payment of c2cPayments) {
    const order = dbOrders.find(o =>
      o.payzo_payment_id === payment.id
    );
 
    if (!order) {
      mismatches.push({
        payment_id: payment.id,
        issue: 'Payment in Payzo but not in database'
      });
    } else if (order.amount !== payment.amount / 100) {
      mismatches.push({
        payment_id: payment.id,
        issue: 'Amount mismatch',
        c2c_amount: payment.amount / 100,
        db_amount: order.amount
      });
    }
  }
 
  return mismatches;
}

Best Practices

1. Use Webhooks, Not Polling

//  Bad: Polling every 5 seconds
setInterval(async () => {
  const payment = await getPayment(paymentId);
  if (payment.status === 'completed') {
    completeOrder(orderId);
  }
}, 5000);
 
//  Good: Use webhooks
app.post('/webhook', (req, res) => {
  const { event, payment } = req.body;
  if (event === 'payment.completed') {
    completeOrder(payment.metadata.order_id);
  }
});

2. Cache Results

const cache = new Map();
 
async function getPaymentCached(paymentId) {
  // Check cache first
  if (cache.has(paymentId)) {
    return cache.get(paymentId);
  }
 
  // Fetch from API
  const payment = await getPayment(paymentId);
 
  // Cache for 5 minutes (only if completed or failed)
  if (['completed', 'failed', 'refunded'].includes(payment.status)) {
    cache.set(paymentId, payment);
    setTimeout(() => cache.delete(paymentId), 5 * 60 * 1000);
  }
 
  return payment;
}

3. Handle Errors

async function getPaymentSafe(paymentId) {
  try {
    return await getPayment(paymentId);
  } catch (error) {
    if (error.status === 404) {
      console.error('Payment not found:', paymentId);
      return null;
    }
 
    if (error.status === 401) {
      console.error('Invalid API key');
      throw new Error('Authentication failed');
    }
 
    console.error('API error:', error);
    throw error;
  }
}

4. Implement Retry Logic

async function getPaymentWithRetry(paymentId, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await getPayment(paymentId);
    } catch (error) {
      if (attempt === maxRetries) throw error;
 
      const delay = Math.pow(2, attempt) * 1000; // 2s, 4s, 8s
      console.log(`Retry ${attempt}/${maxRetries} after ${delay}ms`);
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }
}

Error Responses

404 Not Found

{
  "error": "Payment not found"
}

Cause: Payment ID doesn't exist or belongs to different shop

401 Unauthorized

{
  "error": "Invalid API key"
}

Cause: Missing or incorrect API key

429 Too Many Requests

{
  "error": "Too many requests, please slow down"
}

Cause: Exceeded rate limit

Next Steps