Payzo Docs

Creating Payments

Learn how to create payment links and accept payments from customers

Overview

To accept a payment, you'll create a payment via the API, which returns a checkout_url. Redirect your customer to this URL to complete the payment.

Endpoint

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

Request Parameters

ParameterTypeRequiredDescription
amountintegerYesAmount in cents (e.g., 1000 = $10.00). Minimum: 50 ($0.50)
currencystringNoCurrency code. Default: "usd"
success_urlstringYesURL to redirect customer after successful payment
cancel_urlstringNoURL to redirect customer if they cancel
customer_emailstringNoCustomer's email address
customer_namestringNoCustomer's name
descriptionstringNoPayment description (internal use)
metadataobjectNoCustom key-value data to attach to payment

Response

Success (201 Created)

{
  "id": "pay_abc123def456",
  "status": "pending",
  "amount": 5000,
  "currency": "usd",
  "checkout_url": "https://payzo.cc/checkout/my-shop/pay_abc123def456",
  "created_at": "2025-01-12T10:30:00.000Z"
}
FieldDescription
idUnique payment identifier
statusPayment status: pending, completed, failed, expired
amountAmount in cents
currencyCurrency code
checkout_urlURL to redirect your customer to
created_atISO 8601 timestamp

Complete Example

Node.js / Express

const express = require('express');
const app = express();
 
app.post('/create-payment', async (req, res) => {
  try {
    // Create payment with Payzo
    const response = await fetch('https://payzo.cc/api/v1/payments', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${process.env.PAYZO_API_KEY}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        amount: 5000, // $50.00
        currency: 'usd',
        success_url: 'https://yoursite.com/payment/success',
        cancel_url: 'https://yoursite.com/payment/cancel',
        customer_email: req.body.email,
        customer_name: req.body.name,
        metadata: {
          order_id: req.body.orderId,
          user_id: req.body.userId,
          product: req.body.product
        }
      })
    });
 
    if (!response.ok) {
      const error = await response.json();
      return res.status(400).json({ error: error.error });
    }
 
    const payment = await response.json();
 
    // Save payment ID to your database
    await db.orders.update({
      id: req.body.orderId,
      payzo_payment_id: payment.id,
      status: 'pending_payment'
    });
 
    // Redirect customer to checkout
    res.json({ checkout_url: payment.checkout_url });
 
  } catch (error) {
    console.error('Payment creation error:', error);
    res.status(500).json({ error: 'Failed to create payment' });
  }
});

Python / Flask

from flask import Flask, request, jsonify
import requests
import os
 
app = Flask(__name__)
 
@app.route('/create-payment', methods=['POST'])
def create_payment():
    try:
        # Create payment with Payzo
        response = requests.post(
            'https://payzo.cc/api/v1/payments',
            headers={
                'Authorization': f'Bearer {os.getenv("PAYZO_API_KEY")}',
                'Content-Type': 'application/json'
            },
            json={
                'amount': 5000,  # $50.00
                'currency': 'usd',
                'success_url': 'https://yoursite.com/payment/success',
                'cancel_url': 'https://yoursite.com/payment/cancel',
                'customer_email': request.json.get('email'),
                'customer_name': request.json.get('name'),
                'metadata': {
                    'order_id': request.json.get('order_id'),
                    'user_id': request.json.get('user_id'),
                    'product': request.json.get('product')
                }
            }
        )
 
        if not response.ok:
            error = response.json()
            return jsonify({'error': error.get('error')}), 400
 
        payment = response.json()
 
        # Save payment ID to your database
        # db.orders.update(...)
 
        # Return checkout URL to frontend
        return jsonify({'checkout_url': payment['checkout_url']})
 
    except Exception as e:
        print(f'Payment creation error: {e}')
        return jsonify({'error': 'Failed to create payment'}), 500

PHP

<?php
 
function createPayment($amount, $email, $orderId) {
    $apiKey = getenv('PAYZO_API_KEY');
 
    $data = [
        'amount' => 5000,  // $50.00
        'currency' => 'usd',
        'success_url' => 'https://yoursite.com/payment/success',
        'cancel_url' => 'https://yoursite.com/payment/cancel',
        'customer_email' => $email,
        'metadata' => [
            'order_id' => $orderId
        ]
    ];
 
    $ch = curl_init('https://payzo.cc/api/v1/payments');
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json'
    ]);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
 
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
 
    if ($httpCode !== 201) {
        $error = json_decode($response, true);
        throw new Exception($error['error']);
    }
 
    $payment = json_decode($response, true);
 
    // Save to database
    // updateOrder($orderId, $payment['id']);
 
    return $payment['checkout_url'];
}
 
// Usage
try {
    $checkoutUrl = createPayment(5000, 'customer@example.com', 'order_123');
    header('Location: ' . $checkoutUrl);
    exit;
} catch (Exception $e) {
    echo 'Error: ' . $e->getMessage();
}

Metadata Usage

Use metadata to store custom information:

metadata: {
  order_id: 'ORD-12345',
  user_id: 'user_789',
  product_name: 'Premium Plan',
  quantity: 1,
  discount_code: 'SAVE20'
}

This data will be:

  • Returned in webhook notifications
  • Visible in your dashboard
  • Included when retrieving payment details

Error Handling

Common Errors

Amount Too Small

{
  "error": "Amount must be at least 50 cents"
}

Solution: Ensure amount is ≥ 50 (cents).

Missing Success URL

{
  "error": "success_url is required"
}

Solution: Always include success_url.

Invalid API Key

{
  "error": "Invalid API key"
}

Solution: Check your API key in the Authorization header.

Payment Flow

Here's how the complete payment process works:

1. Customer → Your Site
   Customer clicks "Buy Now" button

2. Your Site → Payzo API
   POST /api/v1/payments (create payment)

3. Payzo API → Your Site
   Returns checkout_url

4. Your Site → Customer
   Redirects customer to checkout_url

5. Customer → Payzo Checkout
   Customer enters payment details (card info)

6. Payzo → Payment Processor
   Securely processes card payment

7. Payment Processor → Payzo
   Payment succeeded

8. Payzo → Your Webhook
   POST payment.completed event

9. Payzo → Customer
   Redirects to your success_url

10. Your Webhook → Your System
    Fulfills order (e.g., deliver game items)

Best Practices

1. Always Store Payment IDs

// Save payment ID to your database before redirecting
await db.orders.create({
  id: orderId,
  payzo_payment_id: payment.id,
  amount: payment.amount,
  status: 'pending'
});
 
// Then redirect
res.redirect(payment.checkout_url);

2. Use Webhooks, Not Polling

//  Bad: Don't poll for status
setInterval(async () => {
  const status = await checkPaymentStatus(paymentId);
}, 5000);
 
//  Good: Use webhooks
app.post('/webhook', (req, res) => {
  const { event, payment } = req.body;
  if (event === 'payment.completed') {
    completeOrder(payment.metadata.order_id);
  }
});

3. Validate Amounts

// Always validate on your server
const amount = Math.round(req.body.amount);
if (amount < 50) {
  return res.status(400).json({ error: 'Minimum $0.50' });
}

Next Steps