CanPay BNPL v1
Merchant API Documentation
Classic View
CanPay BNPL

Merchant API Documentation

Connect your business to CanPay's secure payment ecosystem for effortless customer transactions.

REST API HTTPS Only JSON

Integrate CanPay BNPL flexible payment checkout into your application with our comprehensive RESTful API. Accept payments from our customers with enterprise-grade security.

Production Ready
This API documentation covers production-ready endpoints with complete integration examples for multiple platforms.
Fast Integration

Get started in minutes with our simple REST API

Secure Payments

High-grade security with HMAC signature verification

Multi-Platform

Works with any programming language or framework

Authentication

Merchant API uses API keys to authenticate requests. You can obtain your credentials from your merchant portal account.

Environment-Aware API Integration

Merchant API supports both sandbox (testing) and production environments. Always test in sandbox first before going live.

Environment Configuration
Sandbox Mode

Use for: Development, testing, integration

X-Environment: sandbox

Credentials: Use test_* prefixed API keys

Production Mode

Use for: Live payments, real money

X-Environment: production

Credentials: Use production API keys (no prefix)

Required Credentials

Credential Header Description Location
Merchant ID X-Merchant-Key Your unique merchant identifier Merchant Dashboard > Account > Configuration
API Key X-API-Key API authentication key Merchant Dashboard > Account > Configuration
Client Secret - Used for webhook signature verification Merchant Dashboard > Account > Configuration
Production API Key X-API-Key Production API key (no prefix) Merchant Dashboard > Account > Configuration > Production Mode
Production Merchant ID X-Merchant-Key Production merchant identifier (no prefix) Merchant Dashboard > Account > Configuration > Production Mode
Security Notice Never expose your Client Secret in client-side code. Store all credentials securely on your server.

Quick Start

Get up and running with Merchant API in just a few steps:

Step 1: Get Credentials
  1. Login to your portal dashboard account via https://portal.canpaybnpl.com
  2. Navigate to Dashboard → Account → Configuration
  3. Copy your Merchant ID, API Key, and Client Secret
Step 2: Make Request
  1. Set required headers with your credentials
  2. POST to /api/v1/initiate-payment
  3. Redirect user to returned payment URL
Test API Now

Try Merchant API endpoints directly in your browser

Initiate Payment

Create a new payment request and get a secure checkout URL for your customer. This endpoint works in both sandbox and production environments based on your X-Environment header.

POST /api/v1/initiate-payment

Request Headers

Header Value Required Description
Content-Type application/json Request content type
X-Environment sandbox | production API environment mode
X-Merchant-Key {merchant_key} Your Merchant ID (sandbox: test_ prefix, production: no prefix)
X-API-Key {api_key} Your API Key (sandbox: test_ prefix, production: no prefix)

Request Parameters

Parameter Type Required Description
payment_amount number Payment amount (minimum 100.00)
currency_code string 3-letter currency code (GHC, GHS)
ref_trx string Your unique transaction reference
description string Payment description
callback_url string Redirect URL

Code Examples

Environment Configuration: Replace {environment} with sandbox or production, and use corresponding credentials - test_ prefix for sandbox, no prefix for production.
curl -X POST "https://pay.canpaybnpl.com/api/v1/initiate-payment" \
  -H "Content-Type: application/json" \
  -H "X-Environment: {environment}" \
  -H "X-Merchant-Key: {merchant_key}" \
  -H "X-API-Key: {api_key}" \
  -d '{"payment_amount": 250.00, "currency_code": "GHC", "ref_trx": "ORDER_12345", "description": "Premium Subscription", "callback_url": "https://yoursite.com/payment/callback_url"}'
<?php

use App\Enums\EnvironmentMode;
use Illuminate\Support\Facades\Http;

class PaymentInitiator
{
    private $environment;
    private $merchantKey;
    private $apiKey;
    private $baseUrl = 'https://pay.canpaybnpl.com/api/v1';

    public function __construct(EnvironmentMode $environment, $merchantKey, $apiKey)
    {
        $this->environment = $environment;
        $this->merchantKey = $merchantKey;
        $this->apiKey = $apiKey;
    }

    // Factory methods for easy configuration
    public static function sandbox($testMerchantKey, $testApiKey): self
    {
        return new self(EnvironmentMode::SANDBOX, $testMerchantKey, $testApiKey);
    }

    public static function production($merchantKey, $apiKey): self
    {
        return new self(EnvironmentMode::PRODUCTION, $merchantKey, $apiKey);
    }

    public function initiatePayment($paymentData)
    {
        try {
            $response = Http::withHeaders([
                'Content-Type' => 'application/json',
                'X-Environment' => $this->environment->value,
                'X-Merchant-Key' => $this->merchantKey,
                'X-API-Key' => $this->apiKey,
            ])->post("{$this->baseUrl}/initiate-payment", $paymentData);

            if ($response->successful()) {
                $data = $response->json();
                
                if ($data['success']) {
                    return ['success' => true, 'data' => $data];
                }
                
                return ['success' => false, 'status' => $data['status'], 'message' => $data['message'] ?? 'Payment initiation failed'];
            }

            return ['success' => false, 'error' => 'API request failed'];
        } catch (Exception $e) {
            return ['success' => false, 'error' => $e->getMessage()];
        }
    }
}

// Usage: Choose appropriate factory method based on your environment
$initiator = PaymentInitiator::sandbox('test_merchant_key', 'test_api_key'); // For testing
// $initiator = PaymentInitiator::production('merchant_key', 'api_key'); // For production

$paymentData = [
    'payment_amount' => 250.00,
    'currency_code' => 'GHS',
    'ref_trx' => 'ORDER_12345',
    'description' => 'Premium Subscription',
    'callback_url' => 'https://yoursite.com/payment/callback_url',
];

$result = $initiator->initiatePayment($paymentData);
const axios = require('axios');

const EnvironmentMode = {
    SANDBOX: 'sandbox',
    PRODUCTION: 'production'
};

class PaymentInitiator {
    constructor(environment, merchantKey, apiKey) {
        this.environment = environment;
        this.merchantKey = merchantKey;
        this.apiKey = apiKey;
        this.baseUrl = 'https://pay.canpaybnpl.com/api/v1';
    }

    // Factory methods
    static sandbox(testMerchantKey, testApiKey) {
        return new PaymentInitiator(EnvironmentMode.SANDBOX, testMerchantKey, testApiKey);
    }

    static production(merchantKey, apiKey) {
        return new PaymentInitiator(EnvironmentMode.PRODUCTION, merchantKey, apiKey);
    }

    async initiatePayment(paymentData) {
        try {
            const response = await axios.post(`${this.baseUrl}/initiate-payment`, paymentData, {
                headers: {
                    'Content-Type': 'application/json',
                    'X-Environment': this.environment,
                    'X-Merchant-Key': this.merchantKey,
                    'X-API-Key': this.apiKey
                }
            });

            const data = response.data;

            if (data.success) {
                return { success: true, data };
            }

            return { 
                success: false, 
                status: data.status, 
                message: data.message || 'Payment initiation failed' 
            };

        } catch (error) {
            if (error.response) {
                return { 
                    success: false, 
                    error: error.response.data.error || 'API request failed' 
                };
            }
            return { success: false, error: error.message };
        }
    }
}

// Usage: Choose appropriate factory method based on your environment
const initiator = PaymentInitiator.sandbox('test_merchant_key', 'test_api_key'); // For testing
// const initiator = PaymentInitiator.production('merchant_key', 'api_key'); // For production

const paymentData = {
    payment_amount: 250.00,
    currency_code: 'GHC',
    ref_trx: 'ORDER_12345',
    description: 'Premium Subscription',
    callback_url: 'https://yoursite.com/payment/callback_url',
};

initiator.initiatePayment(paymentData)
    .then(result => console.log(result))
    .catch(error => console.error(error));
import requests
import logging
from enum import Enum

class EnvironmentMode(Enum):
    SANDBOX = 'sandbox'
    PRODUCTION = 'production'

class PaymentInitiator:
    def __init__(self, environment, merchant_key, api_key):
        self.environment = environment
        self.merchant_key = merchant_key
        self.api_key = api_key
        self.base_url = 'https://pay.canpaybnpl.com/api/v1'

    @classmethod
    def sandbox(cls, test_merchant_key, test_api_key):
        return cls(EnvironmentMode.SANDBOX, test_merchant_key, test_api_key)

    @classmethod
    def production(cls, merchant_key, api_key):
        return cls(EnvironmentMode.PRODUCTION, merchant_key, api_key)

    def initiate_payment(self, payment_data):
        try:
            headers = {
                'Content-Type': 'application/json',
                'X-Environment': self.environment.value,
                'X-Merchant-Key': self.merchant_key,
                'X-API-Key': self.api_key
            }

            response = requests.post(
                f"{self.base_url}/initiate-payment",
                headers=headers,
                json=payment_data,
                timeout=30
            )

            if response.status_code == 200:
                data = response.json()
                
                if data['success']:
                    return {'success': True, 'data': data}
                
                return {
                    'success': False, 
                    'status': data['status'], 
                    'message': data.get('message', 'Payment initiation failed')
                }

            return {'success': False, 'error': f'HTTP {response.status_code}'}

        except requests.RequestException as e:
            return {'success': False, 'error': str(e)}

# Usage: Choose appropriate factory method based on your environment
initiator = PaymentInitiator.sandbox('test_merchant_key', 'test_api_key')  # For testing
# initiator = PaymentInitiator.production('merchant_key', 'api_key')  # For production

payment_data = {
    'payment_amount': 250.00,
    'currency_code': 'GHC',
    'ref_trx': 'ORDER_12345',
    'description': 'Premium Subscription',
    'callback_url': 'https://yoursite.com/payment/callback_url'
}

result = initiator.initiate_payment(payment_data)
print(result)

Success Response

200 OK Success
{
    "payment_url": "https://pay.canpaybnpl.com/api/v1/payment/checkout?expires=1753724376&token=AmQvJdGIdGUVJUUMayJZZreBv2UcTyIHclk9Ps1s1pZhLpVlIqIBVPqGTRKQ3NUSehyM3qRUIf69IhLbNfJ1JqiMxlxNrnn22lNz1N01hZQn65r5VZnvhWmQPxQO8UX6rE4yfRUvT6bHdqLj7UDJhRPYRFSgCsG1b86sxSdKTZNOVJdWV5z8L6a5pNMZ2KlpG5e7bYa&signature=e9q7ea91456dcc167e7d498ea486f923570821957be8881566186655950f364",
    "info": {
        "ref_trx": "TXNT4AQFESTAG4F",
        "description": "Order #1234",
        "callback_url": "https://merchant.com/callback_url",
        "merchant_id": 1,
        "merchant_name": "Xanthus Wiggins", 
        "amount": 200,
        "currency_code": "GHC",
        "environment": "production",
        "is_sandbox": false
    }
}

Error Response

400 Bad Request Error
{
  "success": false,
  "message": "Validation failed",
  "errors": {
    "payment_amount": ["The payment amount field is required."],
    "currency_code": ["The currency code field is required."]
  }
}
Next Step After successful payment initiation, redirect your customer to the payment_url to complete the payment.

Verify Payment

Verify the status of a payment using the transaction ID returned from the payment initiation.

GET /api/v1/verify-payment/{trxId}

Request Headers

Header Value Required Description
Accept application/json Request content type
X-Environment sandbox | production API environment mode
X-Merchant-Key {merchant_key} Your Merchant ID (sandbox: test_ prefix, production: no prefix)
X-API-Key {api_key} Your API Key (sandbox: test_ prefix, production: no prefix)

Path Parameters

Parameter Type Required Description
trxId string Merchant transaction ID (e.g., TXNQ5V8K2L9N3XM1)

Code Examples

Environment Configuration: Replace {environment} with sandbox or production, and use corresponding credentials - test_ prefix for sandbox, no prefix for production.
curl -X GET "https://pay.canpaybnpl.com/api/v1/verify-payment/TXNQ5V8K2L9N3XM1" \
  -H "Accept: application/json" \
  -H "X-Environment: {environment}" \
  -H "X-Merchant-Key: {merchant_key}" \
  -H "X-API-Key: {api_key}"
<?php

use App\Enums\EnvironmentMode;
use Illuminate\Support\Facades\Http;

class PaymentVerifier
{
    private $environment;
    private $merchantKey;
    private $apiKey;
    private $baseUrl = 'https://pay.canpaybnpl.com/api/v1';

    public function __construct(EnvironmentMode $environment, $merchantKey, $apiKey)
    {
        $this->environment = $environment;
        $this->merchantKey = $merchantKey;
        $this->apiKey = $apiKey;
    }

    // Factory methods for easy configuration
    public static function sandbox($testMerchantKey, $testApiKey): self
    {
        return new self(EnvironmentMode::SANDBOX, $testMerchantKey, $testApiKey);
    }

    public static function production($merchantKey, $apiKey): self
    {
        return new self(EnvironmentMode::PRODUCTION, $merchantKey, $apiKey);
    }

    public function verifyPayment($trxId)
    {
        try {
            $response = Http::withHeaders([
                'Accept' => 'application/json',
                'X-Environment' => $this->environment->value,
                'X-Merchant-Key' => $this->merchantKey,
                'X-API-Key' => $this->apiKey,
            ])->get("{$this->baseUrl}/verify-payment/{$trxId}");

            if ($response->successful()) {
                $data = $response->json();
                
                if ($data['status'] === 'success') {
                    // Payment completed successfully
                    $this->fulfillOrder($data);
                    return ['success' => true, 'data' => $data];
                }
                
                return ['success' => false, 'status' => $data['status'], 'message' => $data['message'] ?? 'Payment not completed'];
            }

            return ['success' => false, 'error' => 'API request failed'];
        } catch (Exception $e) {
            return ['success' => false, 'error' => $e->getMessage()];
        }
    }

    private function fulfillOrder($paymentData)
    {
        // Your order fulfillment logic here
        logger('Payment verified successfully', $paymentData);
    }
}

// Usage: Choose appropriate factory method based on your environment
$verifier = PaymentVerifier::sandbox('test_merchant_key', 'test_api_key'); // For testing
// $verifier = PaymentVerifier::production('merchant_key', 'api_key'); // For production

$result = $verifier->verifyPayment('TXNQ5V8K2L9N3XM1');
const axios = require('axios');

const EnvironmentMode = {
    SANDBOX: 'sandbox',
    PRODUCTION: 'production'
};

class PaymentVerifier {
    constructor(environment, merchantKey, apiKey) {
        this.environment = environment;
        this.merchantKey = merchantKey;
        this.apiKey = apiKey;
        this.baseUrl = 'https://pay.canpaybnpl.com/api/v1';
    }

    // Factory methods
    static sandbox(testMerchantKey, testApiKey) {
        return new PaymentVerifier(EnvironmentMode.SANDBOX, testMerchantKey, testApiKey);
    }

    static production(merchantKey, apiKey) {
        return new PaymentVerifier(EnvironmentMode.PRODUCTION, merchantKey, apiKey);
    }

    async verifyPayment(trxId) {
        try {
            const response = await axios.get(`${this.baseUrl}/verify-payment/${trxId}`, {
                headers: {
                    'Accept': 'application/json',
                    'X-Environment': this.environment,
                    'X-Merchant-Key': this.merchantKey,
                    'X-API-Key': this.apiKey
                }
            });

            const data = response.data;

            if (data.status === 'success') {
                // Payment completed successfully
                await this.fulfillOrder(data);
                return { success: true, data };
            }

            return { 
                success: false, 
                status: data.status, 
                message: data.message || 'Payment not completed' 
            };

        } catch (error) {
            if (error.response) {
                return { 
                    success: false, 
                    error: error.response.data.error || 'API request failed' 
                };
            }
            return { success: false, error: error.message };
        }
    }

    async fulfillOrder(paymentData) {
        // Your order fulfillment logic here
        console.log('Payment verified successfully:', paymentData);
    }
}

// Usage: Choose appropriate factory method based on your environment
const verifier = PaymentVerifier.sandbox('test_merchant_key', 'test_api_key'); // For testing
// const verifier = PaymentVerifier.production('merchant_key', 'api_key'); // For production

verifier.verifyPayment('TXNQ5V8K2L9N3XM1')
    .then(result => console.log(result))
    .catch(error => console.error(error));
import requests
import logging
from enum import Enum

class EnvironmentMode(Enum):
    SANDBOX = 'sandbox'
    PRODUCTION = 'production'

class PaymentVerifier:
    def __init__(self, environment, merchant_key, api_key):
        self.environment = environment
        self.merchant_key = merchant_key
        self.api_key = api_key
        self.base_url = 'https://pay.canpaybnpl.com/api/v1'

    @classmethod
    def sandbox(cls, test_merchant_key, test_api_key):
        return cls(EnvironmentMode.SANDBOX, test_merchant_key, test_api_key)

    @classmethod
    def production(cls, merchant_key, api_key):
        return cls(EnvironmentMode.PRODUCTION, merchant_key, api_key)

    def verify_payment(self, trx_id):
        try:
            headers = {
                'Accept': 'application/json',
                'X-Environment': self.environment.value,
                'X-Merchant-Key': self.merchant_key,
                'X-API-Key': self.api_key
            }

            response = requests.get(
                f"{self.base_url}/verify-payment/{trx_id}",
                headers=headers,
                timeout=30
            )

            if response.status_code == 200:
                data = response.json()
                
                if data['status'] == 'success':
                    # Payment completed successfully
                    self.fulfill_order(data)
                    return {'success': True, 'data': data}
                
                return {
                    'success': False, 
                    'status': data['status'], 
                    'message': data.get('message', 'Payment not completed')
                }

            return {'success': False, 'error': f'HTTP {response.status_code}'}

        except requests.RequestException as e:
            return {'success': False, 'error': str(e)}

    def fulfill_order(self, payment_data):
        """Your order fulfillment logic here"""
        logging.info(f"Payment verified successfully: {payment_data}")

# Usage: Choose appropriate factory method based on your environment
verifier = PaymentVerifier.sandbox('test_merchant_key', 'test_api_key')  # For testing
# verifier = PaymentVerifier.production('merchant_key', 'api_key')  # For production

result = verifier.verify_payment('TXNQ5V8K2L9N3XM1')
print(result)

Success Response

200 OK Success
{
    "status": "success",
    "trx_id": "TXNQ5V8K2L9N3XM1",
    "amount": 237.5,
    "fee": 12.5,
    "currency": "GHC",
    "net_amount": 237.5,
    "customer": {
        "name": "John Doe",
        "email": "john@example.com"
    },
    "description": "Premium Subscription Payment",
    "created_at": "2024-01-15T10:30:00.000000Z",
    "updated_at": "2024-01-15T10:35:45.000000Z"
}

Failed/Canceled Transaction Response

{
    "status": "failed",
    "trx_id": "TXNQ5V8K2L9N3XM1",
    "message": "Payment failed or canceled."
}

Pending Transaction Response

{
    "status": "pending",
    "trx_id": "TXNQ5V8K2L9N3XM1",
    "message": "Payment is still pending."
}

Payment Status Values

Status Description Action Required
pending Payment is still processing Wait until transaction completes
completed Payment was successful Fulfill order/service
failed Payment failed Handle failed payment
cancelled Payment was cancelled by user Handle cancellation
expired Payment session expired Create new payment
Rate Limiting This endpoint is rate-limited to 60 requests per minute per merchant.

Integration Examples

Complete integration examples for popular platforms and frameworks.

Environment Configuration: Replace {environment} with sandbox or production, and use corresponding credentials - test_ prefix for sandbox, no prefix for production in your configuration files.
<?php
// Laravel Integration Service
namespace App\Services;

use Illuminate\Support\Facades\Http;
use Exception;

class CanPayService
{
    private string $baseUrl;
    private string $merchantKey;
    private string $apiKey;
    private string $environment;

    public function __construct()
    {
        $this->baseUrl = config('canpaybnpl.base_url');
        $this->merchantKey = config('canpaybnpl.merchant_key');
        $this->apiKey = config('canpaybnpl.api_key');
        $this->environment = config('canpaybnpl.environment'); // 'sandbox' or 'production'
    }

    public function initiatePayment(array $paymentData): array
    {
        try {
            $response = Http::withHeaders([
                'Content-Type' => 'application/json',
                'X-Environment' => $this->environment,
                'X-Merchant-Key' => $this->merchantKey,
                'X-API-Key' => $this->apiKey,
            ])->post("{$this->baseUrl}/api/v1/initiate-payment", $paymentData);

            if ($response->successful()) {
                return $response->json();
            }

            throw new Exception('Payment initiation failed');
        } catch (Exception $e) {
            throw new Exception('CanPayBNPL API Error: ' . $e->getMessage());
        }
    }

    public function verifyPayment(string $transactionId): array
    {
        try {
            $response = Http::withHeaders([
                'Accept' => 'application/json',
                'X-Environment' => $this->environment,
                'X-Merchant-Key' => $this->merchantKey,
                'X-API-Key' => $this->apiKey,
            ])->get("{$this->baseUrl}/api/v1/verify-payment/{$transactionId}");

            if ($response->successful()) {
                return $response->json();
            }

            throw new Exception('Payment verification failed');
        } catch (Exception $e) {
            throw new Exception('CanPayBNPL API Error: ' . $e->getMessage());
        }
    }
}

// Configuration (config/canpaybnpl.php)
return [
    'base_url' => env('CANPAYBNPL_BASE_URL', 'https://pay.canpaybnpl.com'),
    'environment' => env('CANPAYBNPL_ENVIRONMENT', 'sandbox'), // sandbox or production
    'merchant_key' => env('CANPAYBNPL_MERCHANT_KEY'), // Use appropriate prefix
    'api_key' => env('CANPAYBNPL_API_KEY'), // Use appropriate prefix
];

// Usage in Controller
class PaymentController extends Controller
{
    public function initiatePayment(Request $request, CanPayService $canpaybnpl)
    {
        $paymentData = [
            'payment_amount' => $request->amount,
            'currency_code' => 'GHC',
            'ref_trx' => 'ORDER_' . time(),
            'description' => $request->description,
            'callback_url' => route('payment.callback_url'),
        ];

        try {
            $result = $canpaybnpl->initiatePayment($paymentData);
            return redirect($result['payment_url']);
        } catch (Exception $e) {
            return back()->withErrors(['error' => $e->getMessage()]);
        }
    }
}
// Node.js Integration Service
const axios = require('axios');

class CanPayService {
    constructor() {
        this.baseUrl = process.env.CANPAYBNPL_BASE_URL || 'https://pay.canpaybnpl.com';
        this.environment = process.env.CANPAYBNPL_ENVIRONMENT || 'sandbox'; // sandbox or production
        this.merchantKey = process.env.CANPAYBNPL_MERCHANT_KEY; // Use appropriate prefix
        this.apiKey = process.env.CANPAYBNPL_API_KEY; // Use appropriate prefix
    }

    async initiatePayment(paymentData) {
        try {
            const response = await axios.post(`${this.baseUrl}/api/v1/initiate-payment`, paymentData, {
                headers: {
                    'Content-Type': 'application/json',
                    'X-Environment': this.environment,
                    'X-Merchant-Key': this.merchantKey,
                    'X-API-Key': this.apiKey
                }
            });

            return response.data;
        } catch (error) {
            throw new Error(`CanPay BNPL API Error: ${error.message}`);
        }
    }

    async verifyPayment(transactionId) {
        try {
            const response = await axios.get(`${this.baseUrl}/api/v1/verify-payment/${transactionId}`, {
                headers: {
                    'Accept': 'application/json',
                    'X-Environment': this.environment,
                    'X-Merchant-Key': this.merchantKey,
                    'X-API-Key': this.apiKey
                }
            });

            return response.data;
        } catch (error) {
            throw new Error(`CanPay BNPL API Error: ${error.message}`);
        }
    }
}

// Express.js Route Example
const express = require('express');
const app = express();
const canpaybnpl = new CanPayService();

app.post('/initiate-payment', async (req, res) => {
    const paymentData = {
        payment_amount: req.body.amount,
        currency_code: 'GHC',
        ref_trx: `ORDER_${Date.now()}`,
        description: req.body.description,
        callback_url: `${req.protocol}://${req.get('host')}/payment/callback_url`,
    };

    try {
        const result = await canpaybnpl.initiatePayment(paymentData);
        res.redirect(result.payment_url);
    } catch (error) {
        res.status(500).json({ error: error.message });
    }
});

module.exports = CanPayService;
# Python/Django Integration Service
import os
import requests
from django.conf import settings

class CanPayService:
    def __init__(self):
        self.base_url = getattr(settings, 'CANPAYBNPL_BASE_URL', 'https://pay.canpaybnpl.com')
        self.environment = getattr(settings, 'CANPAYBNPL_ENVIRONMENT', 'sandbox')  # sandbox or production
        self.merchant_key = getattr(settings, 'CANPAYBNPL_MERCHANT_KEY')  # Use appropriate prefix
        self.api_key = getattr(settings, 'CANPAYBNPL_API_KEY')  # Use appropriate prefix

    def initiate_payment(self, payment_data):
        try:
            headers = {
                'Content-Type': 'application/json',
                'X-Environment': self.environment,
                'X-Merchant-Key': self.merchant_key,
                'X-API-Key': self.api_key
            }

            response = requests.post(
                f"{self.base_url}/api/v1/initiate-payment",
                headers=headers,
                json=payment_data,
                timeout=30
            )

            response.raise_for_status()
            return response.json()

        except requests.RequestException as e:
            raise Exception(f'CanPay BNPL API Error: {str(e)}')

    def verify_payment(self, transaction_id):
        try:
            headers = {
                'Accept': 'application/json',
                'X-Environment': self.environment,
                'X-Merchant-Key': self.merchant_key,
                'X-API-Key': self.api_key
            }

            response = requests.get(
                f"{self.base_url}/api/v1/verify-payment/{transaction_id}",
                headers=headers,
                timeout=30
            )

            response.raise_for_status()
            return response.json()

        except requests.RequestException as e:
            raise Exception(f'CanPay BNPL API Error: {str(e)}')

# Django Settings Configuration
CANPAYBNPL_BASE_URL = 'https://pay.canpaybnpl.com'
CANPAYBNPL_ENVIRONMENT = 'sandbox'  # Change to 'production' for live
CANPAYBNPL_MERCHANT_KEY = os.environ.get('CANPAYBNPL_MERCHANT_KEY')  # Use appropriate prefix
CANPAYBNPL_API_KEY = os.environ.get('CANPAYBNPL_API_KEY')  # Use appropriate prefix

# Django View Example
from django.shortcuts import redirect
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
import json

canpaybnpl = CanPayService()

@csrf_exempt
def initiate_payment(request):
    if request.method == 'POST':
        data = json.loads(request.body)
        
        payment_data = {
            'payment_amount': data['amount'],
            'currency_code': 'GHS',
            'ref_trx': f'ORDER_{int(time.time())}',
            'description': data['description'],
            'callback_url': request.build_absolute_uri('/payment/callback_url/'),
        }

        try:
            result = canpaybnpl.initiate_payment(payment_data)
            return redirect(result['payment_url'])
        except Exception as e:
            return JsonResponse({'error': str(e)}, status=500)
# Environment Variables Setup
export CANPAYBNPL_ENVIRONMENT="sandbox"  # or "production"
export CANPAYBNPL_MERCHANT_KEY="test_merchant_your_key"  # or "merchant_your_key" for production
export CANPAYBNPL_API_KEY="test_your_api_key"  # or "your_api_key" for production

# Initiate Payment
curl -X POST "https://pay.canpaybnpl.com/api/v1/initiate-payment" \
  -H "Content-Type: application/json" \
  -H "X-Environment: $CANPAYBNPL_ENVIRONMENT" \
  -H "X-Merchant-Key: $CANPAYBNPL_MERCHANT_KEY" \
  -H "X-API-Key: $CANPAYBNPL_API_KEY" \
  -d '{
    "payment_amount": 250.00,
    "currency_code": "GHC",
    "ref_trx": "ORDER_12345",
    "description": "Premium Subscription",
    "callback_url": "https://yoursite.com/payment/callback_url"
  }'

# Verify Payment
curl -X GET "https://pay.canpaybnpl.com/api/v1/verify-payment/TXNQ5V8K2L9N3XM1" \
  -H "Accept: application/json" \
  -H "X-Environment: $CANPAYBNPL_ENVIRONMENT" \
  -H "X-Merchant-Key: $CANPAYBNPL_MERCHANT_KEY" \
  -H "X-API-Key: $CANPAYBNPL_API_KEY"

# Environment-specific credential examples:
# Sandbox: test_merchant_xxxxx, test_api_key_xxxxx
# Production: merchant_xxxxx, api_key_xxxxx

WooCommerce Integration

Complete integration guide for CanPay BNPL payment gateway with WooCommerce. Follow best practices for secure and reliable payment processing.

WooCommerce Integration

Seamlessly integrate CanPay BNPL payment gateway with your WooCommerce store for secure, fast transactions.

5 Minutes Setup
99.9% Uptime
24/7 Support
Quick Download

Ready-to-use WooCommerce payment gateway plugin for CanPay BNPL.

Plugin Size: 2 KB
Version: 1.0
Requirements
  • WordPress 5.0+
  • WooCommerce 4.0+
  • PHP 7.4+
  • SSL Certificate
  • CanPay Merchant Account
Fully Compatible

Key Features

Everything you need for seamless payment processing

Secure Payments

End-to-end encryption with PCI DSS compliance

Mobile Optimized

Responsive design for all devices and screen sizes

Installation Guide

Follow these simple steps to get started with CanPay BNPL WooCommerce integration

1
Download Plugin

Download the CanPay BNPL WooCommerce plugin ZIP file from the Quick Download section above.

2
Upload to WordPress

Go to your WordPress admin panel → PluginsAdd NewUpload Plugin and select the downloaded ZIP file.

3
Activate Plugin

After successful upload, click Activate Plugin to enable CanPay BNPL payment gateway in your WooCommerce store.

4
Configure Settings

Navigate to WooCommerceSettingsPaymentsCanPay BNPL and enter your API credentials.

5
Test Integration

Enable Test/Sandbox Mode first and process a test/sandbox transaction to ensure everything works correctly before going live/production.

Configuration Details

Essential settings for optimal performance

API Credentials

Obtain your Merchant ID, API Key from CanPay merchant account configuration section

Required
SSL Certificate

Ensure your site has a valid SSL certificate for secure transactions

Required

Pre-Launch Checklist

Ensure everything is ready before going live

Production Readiness
Need Help?

Our technical team is here to assist you with integration and troubleshooting.

Checkout Assets

CanPay provides a set of ready-made, pre-designed checkout button images — complete with branding, colours, and text already built in. Download the variant that fits your design and drop it into your storefront, cart page, or payment flow as a clickable button. No custom styling needed.

CanPay Media & Asset Library

Browse, preview, and download all official checkout button images from the public asset library. No API key required.

Open Asset Library

Checkout Button Variants

Each image is a fully-designed button. Use it as-is — wrap it in an <a> or <button> tag to make it interactive.

Checkout with CanPay BNPL

Checkout with CanPay BNPL

WEBP · 17 KB

Download
Pay with CanPay BNPL

Pay with CanPay BNPL

WEBP · 14.7 KB

Download
Checkout with CanPay BNPL White Background

Checkout with CanPay BNPL White Background

WEBP · 16.2 KB

Download
Pay with CanPay BNPL White Background

Pay with CanPay BNPL White Background

WEBP · 14.2 KB

Download
Pay with CanPay BNPL Yellow Text

Pay with CanPay BNPL Yellow Text

WEBP · 15 KB

Download
Checkout With CanPay BNPL Yellow Text

Checkout With CanPay BNPL Yellow Text

WEBP · 16.9 KB

Download

Logo Assets

Standalone CanPay logos for use in headers, receipts, and email templates.

CanPay BNPL Logo

CanPay BNPL Logo

PNG · 48.4 KB

Download
CanPay BNPL Logo White

CanPay BNPL Logo White

PNG · 40.6 KB

Download

Download Endpoints

All endpoints below are public — no authentication header is required.
Method Endpoint Description
GET /media-assets Browse the full asset library in-browser
GET /media-assets/download/{id} Download a single asset by its numeric ID
GET /media-assets/category/{folder}/download Download a full category as a ZIP file (checkout, logos)

Integration Examples

Download the assets first from the library above, then host them on your own server or CDN. Reference them with your own URL in your integration.
<!-- Step 1: Download your preferred variant from the asset library      -->
<!-- Step 2: Upload to your server or CDN                                -->
<!-- Step 3: Reference with your own URL as shown below                  -->

<!-- "Checkout with CanPay" button -->
<a href="#" onclick="initiateCanPayCheckout(); return false;">
  <img
    src="/assets/canpay/checkout-with-canpay.webp"
    alt="Checkout with CanPay BNPL"
    height="48"
    loading="lazy"
  >
</a>

<!-- "Pay with CanPay" button (white background variant) -->
<a href="#" onclick="initiateCanPayCheckout(); return false;">
  <img
    src="/assets/canpay/white-pay-with-canpay.webp"
    alt="Pay with CanPay BNPL"
    height="48"
    loading="lazy"
  >
</a>

<!-- Best practice: choose the variant that fits your page background   -->
<!-- Dark backgrounds  → use the dark or yellow-text variants           -->
<!-- Light backgrounds → use the white-background variants              -->
// CanPayButton.jsx
// Download your preferred asset variant and host it alongside your app.

const CHECKOUT_BUTTONS = {
  'checkout-dark':   '/assets/canpay/checkout-with-canpay.webp',
  'pay-dark':        '/assets/canpay/pay-with-canpay.webp',
  'checkout-white':  '/assets/canpay/white-checkout-with-canpay.webp',
  'pay-white':       '/assets/canpay/white-pay-with-canpay.webp',
  'pay-yellow':      '/assets/canpay/yellow-pay-with-canpay.webp',
  'checkout-yellow': '/assets/canpay/yellow-checkout-with-canpay.webp',
};

export function CanPayButton({ variant = 'checkout-dark', onClick, height = 48 }) {
  const src = CHECKOUT_BUTTONS[variant] ?? CHECKOUT_BUTTONS['checkout-dark'];

  return (
    <button
      type="button"
      onClick={onClick}
      style= background: 'none', border: 'none', padding: 0, cursor: 'pointer'
    >
      <img src={src} alt="Checkout with CanPay BNPL" height={height} loading="lazy" />
    </button>
  );
}

// Usage in your checkout page
import { CanPayButton } from './CanPayButton';

function CheckoutPage() {
  const handleCanPay = () => initiateCanPayPayment({ amount, ref });

  return (
    <div className="payment-actions">
      <CanPayButton variant="checkout-dark" onClick={handleCanPay} />
    </div>
  );
}
<?php
// config/canpaybnpl.php
// After downloading assets, place them in your public directory
// and reference them via your application's asset helper.

return [
    'checkout_buttons' => [
        'checkout_dark'   => 'assets/canpay/checkout-with-canpay.webp',
        'pay_dark'        => 'assets/canpay/pay-with-canpay.webp',
        'checkout_white'  => 'assets/canpay/white-checkout-with-canpay.webp',
        'pay_white'       => 'assets/canpay/white-pay-with-canpay.webp',
        'pay_yellow'      => 'assets/canpay/yellow-pay-with-canpay.webp',
        'checkout_yellow' => 'assets/canpay/yellow-checkout-with-canpay.webp',
    ],
];


// In your Blade template:

// <a href="https://pay.canpaybnpl.com/payment/checkout">
//   <img
//     src="https://pay.canpaybnpl.com/"
//     alt="Checkout with CanPay BNPL"
//     height="48"
//   >
// </a>


// Choose the variant that suits your page:
// Dark page background   → checkout_dark / pay_dark
// Light page background  → checkout_white / pay_white
// Coloured CTA area      → checkout_yellow / pay_yellow
// CanPayButton.vue
// Place downloaded assets in /public/assets/canpay/ and reference as shown.

<template>
  <button type="button" class="canpay-btn" @click="$emit('click')">
    <img :src="src" :alt="alt" :height="height" loading="lazy" />
  </button>
</template>

<script setup>
const VARIANTS = {
  'checkout-dark':   '/assets/canpay/checkout-with-canpay.webp',
  'pay-dark':        '/assets/canpay/pay-with-canpay.webp',
  'checkout-white':  '/assets/canpay/white-checkout-with-canpay.webp',
  'pay-white':       '/assets/canpay/white-pay-with-canpay.webp',
  'pay-yellow':      '/assets/canpay/yellow-pay-with-canpay.webp',
  'checkout-yellow': '/assets/canpay/yellow-checkout-with-canpay.webp',
};

const props = defineProps({
  variant: { type: String, default: 'checkout-dark' },
  height:  { type: Number, default: 48 },
  alt:     { type: String, default: 'Checkout with CanPay BNPL' },
});

const src = computed(() => VARIANTS[props.variant] ?? VARIANTS['checkout-dark']);
</script>

<style scoped>
.canpay-btn {
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  display: inline-flex;
}
</style>

<!-- Usage -->
<CanPayButton variant="checkout-white" @click="initiateCheckout" />

Usage Rules

Allowed
  • Use as a clickable button in your checkout, cart, or product page
  • Scale proportionally (keep aspect ratio — do not stretch)
  • Choose the variant that best fits your background colour
  • Self-host on your own server or CDN
  • Include in transactional emails and push notifications
Not Allowed
  • Alter, recolour, crop, or overlay any part of the image
  • Use on backgrounds that make the button illegible
  • Imply CanPay endorses your product beyond BNPL payment acceptance
  • Redistribute the image files as standalone downloads to third parties
  • Use in non-merchant or personal projects without written approval
Need a custom size or format? Contact canpaybnpl@gmail.com with your merchant ID and the required specification.

Interactive API Testing

Test Merchant API endpoints directly from this documentation. Use the demo credentials below for sandbox testing.

Demo Payment Information SANDBOX MODE

Use these demo credentials to test all payment methods in sandbox environment:

Testing Guidelines
  • Environment Header: Always include X-ENVIRONMENT: sandbox in your API requests
  • Sandbox Behavior: All transactions auto authenticated as merchant user account without real money processing
  • Transaction Status: Sandbox transactions are marked with "SANDBOX_TRANSACTION" in remarks
  • IPN Notifications: Webhook notifications work normally in sandbox mode
Environment Setup: Use sandbox for testing and production for live transactions. Only sandbox credentials use test_ prefix, production credentials have no prefix.
API Testing Console
Authentication Headers
Sandbox: test_*, Production: no prefix
Sandbox: test_*, Production: no prefix
Request Parameters
Currency code must be uppercase (e.g. GHC, GHS). You must use the currency that matches your merchant shop setup.
Sandbox Environment

Base URL: https://pay.canpaybnpl.com

Environment Header: X-Environment: sandbox

Credentials: Use test_ prefixed keys

Purpose: Safe testing without real money

Production Environment

Base URL: https://pay.canpaybnpl.com

Environment Header: X-Environment: production

Credentials: No prefix for production keys

Purpose: Live transactions with real money

Error Codes

Merchant API uses conventional HTTP response codes to indicate the success or failure of API requests.

HTTP Status Codes

Code Status Description
200 OK Request succeeded
400 Bad Request Invalid request parameters
401 Unauthorized Invalid or missing API credentials
403 Forbidden Insufficient permissions
404 Not Found Resource not found
429 Too Many Requests Rate limit exceeded
500 Internal Server Error Server error occurred

API Error Codes

Error Code Description Solution
INVALID_CREDENTIALS Invalid API credentials provided Check your Merchant ID and API Key
INVALID_AMOUNT Payment amount is invalid Check minimum and maximum amount limits
INVALID_CURRENCY Unsupported currency code Use a supported currency code (GHS, GHC)
DUPLICATE_REFERENCE Transaction reference already exists Use a unique transaction reference
EXPIRED_SESSION Payment session has expired Create a new payment request
MERCHANT_SUSPENDED Merchant account is suspended Contact CanPay BNPL support

Error Response Format

{
  "success": false,
  "message": "Validation failed",
  "error_code": "INVALID_AMOUNT",
  "errors": {
    "payment_amount": [
      "The payment amount must be at least 1.00"
    ]
  },
  "timestamp": "2024-01-20T10:30:00Z"
}
Error Handling Always check the success field in API responses and handle errors appropriately in your application.

Support

Get help with your CanPay BNPL Merchant API integration from our support team and developer resources.

Technical Support

For API integration help:

  • Email: canpaybnpl@gmail.com
  • Response Time: 24–48 hours
  • Hours: Monday–Friday, 9:00AM – 6:00PM GMT

Include your Merchant ID and detailed error descriptions for faster resolution.

Contact Support