API Documentation

Complete integration guide for CheckoutPay Payment Gateway API. Build powerful payment solutions with our RESTful API.

Getting Started

1. Sign Up & Get Your API Key

Create an account and get your API key from the dashboard. Your API key is required for all authenticated requests.

Sign Up Now

2. Base URL

https://check-outnow.com/api/v1

3. Request Format

All API requests must:

  • Use HTTPS
  • Include X-API-Key header for authenticated endpoints
  • Send JSON data in request body (for POST/PUT requests)
  • Use Content-Type: application/json header

Authentication

All authenticated API requests require your API key in the request header.

X-API-Key: pk_your_api_key_here

Security: Keep your API key secure and never expose it in client-side code. Store it securely on your server.

API Endpoints

Payments

POST /payment-request

Create a new payment request. Returns account details for the customer to make payment.

Request Body

{
  "amount": 5000.00,
  "payer_name": "John Doe",
  "bank": "GTBank",
  "webhook_url": "https://yourwebsite.com/webhook/payment-status",
  "service": "Product Purchase",
  "transaction_id": "TXN-1234567890",
  "business_website_id": 1,
  "website_url": "https://yourwebsite.com"
}

Request Parameters

Parameter Type Required Description
amount decimal Yes Payment amount (minimum 0.01)
payer_name string Yes Customer's name (required to get account number)
name string Yes* Alternative to payer_name (either 'name' or 'payer_name' is required)
bank string No Customer's bank name
webhook_url string Yes URL to receive payment notifications (must be from approved website)
service string No Description of the service/product
transaction_id string No Your unique transaction ID (auto-generated if not provided)
business_website_id integer No ID of your approved website (for website-specific webhooks)
website_url string No Your website URL (for website identification)

Response (201 Created)

{
  "success": true,
  "message": "Payment request created successfully",
  "data": {
    "transaction_id": "TXN-1234567890",
    "amount": 5000.00,
    "payer_name": "John Doe",
    "account_number": "0123456789",
    "account_name": "Your Business Name",
    "bank_name": "GTBank",
    "status": "pending",
    "expires_at": "2024-01-15T12:00:00Z",
    "created_at": "2024-01-15T10:00:00Z",
    "charges": {
      "percentage": 50.00,
      "fixed": 50.00,
      "total": 100.00,
      "paid_by_customer": false,
      "amount_to_pay": 5000.00,
      "business_receives": 4900.00
    },
    "website": {
      "id": 1,
      "url": "https://yourwebsite.com"
    }
  }
}
GET /payment/{transactionId}

Retrieve payment details by transaction ID.

Response (200 OK)

{
  "success": true,
  "data": {
    "transaction_id": "TXN-1234567890",
    "amount": 5000.00,
    "payer_name": "John Doe",
    "bank": "GTBank",
    "account_number": "0123456789",
    "account_name": "Your Business Name",
    "bank_name": "GTBank",
    "status": "approved",
    "webhook_url": "https://yourwebsite.com/webhook/payment-status",
    "expires_at": "2024-01-15T12:00:00Z",
    "matched_at": "2024-01-15T10:30:00Z",
    "approved_at": "2024-01-15T10:35:00Z",
    "created_at": "2024-01-15T10:00:00Z",
    "updated_at": "2024-01-15T10:35:00Z",
    "charges": {
      "percentage": 50.00,
      "fixed": 50.00,
      "total": 100.00,
      "paid_by_customer": false,
      "business_receives": 4900.00
    },
    "website": {
      "id": 1,
      "url": "https://yourwebsite.com"
    }
  }
}
GET /payments

List all payments for your business with optional filters.

Query Parameters

Parameter Type Description
status string Filter by status: pending, approved, rejected
from_date date Filter payments from this date (YYYY-MM-DD)
to_date date Filter payments until this date (YYYY-MM-DD)
website_id integer Filter by website ID
per_page integer Number of results per page (default: 15)

Example Request

GET https://check-outnow.com/api/v1/payments?status=approved&from_date=2024-01-01&per_page=20
X-API-Key: pk_your_api_key_here

Webhooks

Overview

Webhooks allow you to receive real-time notifications when payment events occur. You can set webhook URLs at the business level or per-website level for more granular control.

Webhook Priority

Webhooks are sent in the following priority order:

  1. Website-specific webhook URL (if payment is associated with a website that has a webhook URL)
  2. Payment webhook URL (from the payment request)
  3. Business webhook URL (fallback)

Webhook Payload

When a payment is approved, you'll receive a POST request to your webhook URL with the following payload:

{
  "event": "payment.approved",
  "transaction_id": "TXN-1234567890",
  "status": "approved",
  "amount": 5000.00,
  "received_amount": 5000.00,
  "payer_name": "John Doe",
  "bank": "GTBank",
  "payer_account_number": "0123456789",
  "account_number": "0987654321",
  "account_details": {
    "account_name": "Your Business Name",
    "bank_name": "GTBank"
  },
  "is_mismatch": false,
  "mismatch_reason": null,
  "name_mismatch": false,
  "name_similarity_percent": 100,
  "matched_at": "2024-01-15T10:30:00Z",
  "approved_at": "2024-01-15T10:35:00Z",
  "created_at": "2024-01-15T10:00:00Z",
  "timestamp": "2024-01-15T10:35:00Z",
  "website": {
    "id": 1,
    "url": "https://yourwebsite.com"
  },
  "charges": {
    "percentage": 50.00,
    "fixed": 50.00,
    "total": 100.00,
    "paid_by_customer": false,
    "business_receives": 4900.00
  },
  "email": {
    "subject": "Credit Alert",
    "from": "noreply@gtbank.com",
    "date": "2024-01-15T10:30:00Z"
  }
}

Charges Mismatch Handling

Automatic Charges Mismatch Detection: Our system automatically detects when a customer pays the base amount without including charges.

If the following conditions are met, the payment will be automatically approved with a mismatch flag:

  • The payer name matches the expected name
  • The received amount is less than the requested amount
  • The difference equals the calculated charges (within ₦1 tolerance)

In this case, the webhook will include:

  • is_mismatch: true
  • received_amount - The actual amount received (base amount without charges)
  • mismatch_reason - Explanation of the mismatch
  • amount - The originally requested amount (includes charges)
{
  "event": "payment.approved",
  "transaction_id": "TXN-1234567890",
  "status": "approved",
  "amount": 2070.00,  // Requested amount (includes charges)
  "received_amount": 2000.00,  // Actual amount received (base amount)
  "is_mismatch": true,
  "mismatch_reason": "Customer paid base amount without charges. Expected: ₦2,070.00, Received: ₦2,000.00 (charges: ₦70.00)",
  "name_mismatch": false,
  "charges": {
    "percentage": 20.00,
    "fixed": 50.00,
    "total": 70.00,
    "paid_by_customer": false,
    "business_receives": 1930.00  // received_amount - charges
  },
  ...
}

Important: When handling charges mismatch, your business balance will be credited with the business_receives amount (received_amount minus charges), not the full requested amount. Always check is_mismatch and received_amount fields in your webhook handler to process payments correctly.

Webhook Security

Important: Always validate webhook requests on your server. Consider implementing:

  • IP whitelisting (if possible)
  • Request signature verification (coming soon)
  • Idempotency checks using transaction_id

Setting Webhook URLs

You can set webhook URLs in two ways:

  1. Per-Website: Set a webhook URL for each approved website in your dashboard. This allows different webhook endpoints for different websites.
  2. Business-Level: Set a default webhook URL in your business settings that will be used as a fallback.

Note: Webhook URLs must be from your approved website domains. Add and approve websites in your dashboard before using them.

Code Examples

PHP

$apiKey = 'pk_your_api_key_here';
$apiUrl = 'https://check-outnow.com/api/v1';

$data = [
    'amount' => 5000.00,
    'payer_name' => 'John Doe', // Required
    'bank' => 'GTBank',
    'webhook_url' => 'https://yourwebsite.com/webhook/payment-status',
    'service' => 'Product Purchase'
];

$ch = curl_init($apiUrl . '/payment-request');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    'X-API-Key: ' . $apiKey
]);

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

$result = json_decode($response, true);

if ($httpCode === 201 && $result['success']) {
    echo "Payment created: " . $result['data']['transaction_id'];
    echo "Account Number: " . $result['data']['account_number'];
} else {
    echo "Error: " . $result['message'];
}

JavaScript (Fetch API)

const apiKey = 'pk_your_api_key_here';
const apiUrl = 'https://check-outnow.com/api/v1';

const createPayment = async () => {
  const response = await fetch(`${apiUrl}/payment-request`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-API-Key': apiKey
    },
    body: JSON.stringify({
      amount: 5000.00,
      payer_name: 'John Doe',
      bank: 'GTBank',
      webhook_url: 'https://yourwebsite.com/webhook/payment-status',
      service: 'Product Purchase'
    })
  });

  const result = await response.json();

  if (result.success) {
    console.log('Payment created:', result.data.transaction_id);
    console.log('Account Number:', result.data.account_number);
  } else {
    console.error('Error:', result.message);
  }
};

createPayment();

Python

import requests
import json

api_key = 'pk_your_api_key_here'
api_url = 'https://check-outnow.com/api/v1'

data = {
    'amount': 5000.00,
    'payer_name': 'John Doe',  # Required
    'bank': 'GTBank',
    'webhook_url': 'https://yourwebsite.com/webhook/payment-status',
    'service': 'Product Purchase'
}

headers = {
    'Content-Type': 'application/json',
    'X-API-Key': api_key
}

response = requests.post(
    f'{api_url}/payment-request',
    headers=headers,
    data=json.dumps(data)
)

result = response.json()

if response.status_code == 201 and result['success']:
    print(f"Payment created: {result['data']['transaction_id']}")
    print(f"Account Number: {result['data']['account_number']}")
else:
    print(f"Error: {result['message']}")

Webhook Handler (PHP)

<?php
// webhook-handler.php

$payload = json_decode(file_get_contents('php://input'), true);

if ($payload['event'] === 'payment.approved') {
    $transactionId = $payload['transaction_id'];
    $amount = $payload['amount'];
    $status = $payload['status'];
    
    // Update your database
    // Mark order as paid, send confirmation email, etc.
    
    // Always return 200 OK to acknowledge receipt
    http_response_code(200);
    echo json_encode(['status' => 'received']);
} else {
    http_response_code(400);
    echo json_encode(['error' => 'Unknown event']);
}
?>

Error Handling

Error Response Format

All errors follow a consistent format:

{
  "success": false,
  "message": "Error description here"
}

HTTP Status Codes

Code Meaning
200 Success
201 Created (payment request created)
400 Bad Request (validation error)
401 Unauthorized (invalid or missing API key)
404 Not Found
500 Internal Server Error

Common Errors

Invalid API Key

Status: 401

{
  "success": false,
  "message": "Invalid API key"
}

Missing Payer Name

Status: 400

{
  "success": false,
  "message": "The payer name field is required. Please provide either \"name\" or \"payer_name\"."
}

Webhook URL Not Approved

Status: 400

{
  "success": false,
  "message": "Webhook URL must be from your approved website domain."
}

Insufficient Balance

Status: 400

{
  "success": false,
  "message": "Insufficient balance",
  "available_balance": 5000.00
}

Rate Limits

API rate limits are applied per API key. Current limits:

  • 100 requests per minute per API key
  • 1000 requests per hour per API key

If you exceed rate limits, you'll receive a 429 Too Many Requests response. Implement exponential backoff for retries.

Need Help?

Get support from our team or check out additional resources.