LIBPAY Merchant API

Integrate LIBPAY payment gateway into your application with our comprehensive RESTful API. Accept payments from wallets, cards, and multiple payment methods 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

Bank-grade security with HMAC signature verification

Multi-Platform

Works with any programming language or framework

Authentication

LIBPAY API uses API keys to authenticate requests. You can obtain your credentials from your merchant dashboard.

Environment-Aware API Integration

LIBPAY 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 Dashboard → Merchant → CONFIG
API Key X-API-Key API authentication key Dashboard → Merchant → CONFIG
Client Secret - Used for webhook signature verification Dashboard → Merchant → CONFIG
Production API Key X-API-Key Production API key (no prefix) Merchant Dashboard > API Config > Production Mode
Production Merchant Key X-Merchant-Key Production merchant identifier (no prefix) Merchant Dashboard > API Config > 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 LIBPAY API in just a few steps:

Step 1: Get Credentials
  1. Login to your LIBPAY dashboard
  2. Navigate to Merchant → CONFIG
  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 LIBPAY 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 1.00)
currency_code string 3-letter currency code (USD, EUR, etc.)
ref_trx string Your unique transaction reference
description string Payment description
success_redirect string Success redirect URL
failure_url string Failure redirect URL
cancel_redirect string Cancel redirect URL
ipn_url string Webhook notification URL (same URL for both environments)

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://app.libpay.app/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": "USD", "ref_trx": "ORDER_12345", "description": "Premium Subscription", "success_redirect": "https://yoursite.com/payment/success", "failure_url": "https://yoursite.com/payment/failed", "cancel_redirect": "https://yoursite.com/payment/cancelled", "ipn_url": "https://yoursite.com/api/webhooks/LIBPAY"}'
<?php

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

class LIBPAYPaymentInitiator
{
    private $environment;
    private $merchantKey;
    private $apiKey;
    private $baseUrl = 'https://app.libpay.app/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 = LIBPAYPaymentInitiator::sandbox('test_merchant_key', 'test_api_key'); // For testing
// $initiator = LIBPAYPaymentInitiator::production('merchant_key', 'api_key'); // For production

$paymentData = [
    'payment_amount' => 250.00,
    'currency_code' => 'USD',
    'ref_trx' => 'ORDER_12345',
    'description' => 'Premium Subscription',
    'success_redirect' => 'https://yoursite.com/payment/success',
    'failure_url' => 'https://yoursite.com/payment/failed',
    'cancel_redirect' => 'https://yoursite.com/payment/cancelled',
    'ipn_url' => 'https://yoursite.com/api/webhooks/LIBPAY',
];

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

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

class LIBPAYPaymentInitiator {
    constructor(environment, merchantKey, apiKey) {
        this.environment = environment;
        this.merchantKey = merchantKey;
        this.apiKey = apiKey;
        this.baseUrl = 'https://app.libpay.app/api/v1';
    }

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

    static production(merchantKey, apiKey) {
        return new LIBPAYPaymentInitiator(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 = LIBPAYPaymentInitiator.sandbox('test_merchant_key', 'test_api_key'); // For testing
// const initiator = LIBPAYPaymentInitiator.production('merchant_key', 'api_key'); // For production

const paymentData = {
    payment_amount: 250.00,
    currency_code: 'USD',
    ref_trx: 'ORDER_12345',
    description: 'Premium Subscription',
    success_redirect: 'https://yoursite.com/payment/success',
    failure_url: 'https://yoursite.com/payment/failed',
    cancel_redirect: 'https://yoursite.com/payment/cancelled',
    ipn_url: 'https://yoursite.com/api/webhooks/LIBPAY',
};

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 LIBPAYPaymentInitiator:
    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://app.libpay.app/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 = LIBPAYPaymentInitiator.sandbox('test_merchant_key', 'test_api_key')  # For testing
# initiator = LIBPAYPaymentInitiator.production('merchant_key', 'api_key')  # For production

payment_data = {
    'payment_amount': 250.00,
    'currency_code': 'USD',
    'ref_trx': 'ORDER_12345',
    'description': 'Premium Subscription',
    'success_redirect': 'https://yoursite.com/payment/success',
    'failure_url': 'https://yoursite.com/payment/failed',
    'cancel_redirect': 'https://yoursite.com/payment/cancelled',
    'ipn_url': 'https://yoursite.com/api/webhooks/LIBPAY',
}

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

Success Response

200 OK Success
{
    "payment_url": "https://LIBPAY.test/payment/checkout?expires=1753724376&token=AmQvJdGIdGUVJUUMayJZZreBv2UcTyIHclk9Ps1s1pZhLpVlIqIBVPqGTRKQ3NUSehyM3qRUIf69IhLbNfJ1JqiMxlxNrnn22lNz1N01hZQn65r5VZnvhWmQPxQO8UX6rE4yfRUvT6bHdqLj7UDJhRPYRFSgCsG1b86sxSdKTZNOVJdWV5z8L6a5pNMZ2KlpG5e7bYa&signature=e9q7ea91456dcc167e7d498ea486f923570821957be8881566186655950f364",
    "info": {
        "ref_trx": "TXNT4AQFESTAG4F",
        "description": "Order #1234",
        "ipn_url": "https://webhook.site/5711b7d5-917a-4d94-bbb3-c28f4a37bea5",
        "cancel_redirect": "https://merchant.com/cancel",
        "success_redirect": "https://merchant.com/success",
        "merchant_id": 1,
        "merchant_name": "LIBPAY", 
        "amount": 200,
        "currency_code": "USD",
        "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 LIBPAY 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 LIBPAY 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://app.libpay.app/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 LIBPAYPaymentVerifier
{
    private $environment;
    private $merchantKey;
    private $apiKey;
    private $baseUrl = 'https://app.libpay.app/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 = LIBPAYPaymentVerifier::sandbox('test_merchant_key', 'test_api_key'); // For testing
// $verifier = LIBPAYPaymentVerifier::production('merchant_key', 'api_key'); // For production

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

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

class LIBPAYPaymentVerifier {
    constructor(environment, merchantKey, apiKey) {
        this.environment = environment;
        this.merchantKey = merchantKey;
        this.apiKey = apiKey;
        this.baseUrl = 'https://app.libpay.app/api/v1';
    }

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

    static production(merchantKey, apiKey) {
        return new LIBPAYPaymentVerifier(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 = LIBPAYPaymentVerifier.sandbox('test_merchant_key', 'test_api_key'); // For testing
// const verifier = LIBPAYPaymentVerifier.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 LIBPAYPaymentVerifier:
    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://app.libpay.app/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 = LIBPAYPaymentVerifier.sandbox('test_merchant_key', 'test_api_key')  # For testing
# verifier = LIBPAYPaymentVerifier.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": "USD",
    "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 for webhook notification
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.

Webhooks (IPN)

LIBPAY sends real-time notifications to your specified IPN URL when payment status changes. This ensures you're immediately notified of payment completions, failures, and other status updates. Webhooks work identically in both sandbox and production environments.

Environment-Aware Webhooks

Use the same webhook URL for both sandbox and production. LIBPAY will include environment context in webhook payloads to help you differentiate between test and live transactions.

Reliable Delivery LIBPAY implements retry logic for failed webhook deliveries. We'll retry up to 5 times with exponential backoff.

Webhook Headers

Header Description Example
Content-Type Always application/json application/json
X-Signature HMAC-SHA256 signature for verification a8b9c2d1e5f3...

Webhook Payload

All webhook payloads include environment information to help you differentiate between sandbox and production transactions:

Environment Context: environment field will be sandbox for test transactions or production for live transactions. Transaction IDs are prefixed accordingly (SANDBOX_ or PRODUCTION_).
{
    "data": {
        "ref_trx": "TXNT4AQFESTAG4F",
        "description": "Order #1234",
        "ipn_url": "https://webhook.site/5711b7d5-917a-4d94-bbb3-c28f4a37bea5",
        "cancel_redirect": "https://merchant.com/cancel",
        "success_redirect": "https://merchant.com/success",
        "customer_name": "John Doe",
        "customer_email": "john@example.com",
        "merchant_name": "Xanthus Wiggins",
        "amount": 200,
        "currency_code": "USD",
        "environment": "production",
        "is_sandbox": false
    },
    "message": "Payment Completed",
    "status": "completed",
    "timestamp": 1705747245
}

Signature Verification

Always verify webhook signatures to ensure authenticity and prevent unauthorized requests. Use your API secret (environment-specific) to verify signatures:

Environment-Specific Secrets: Use test_webhook_secret for sandbox and webhook_secret for production environments.
<?php
// Laravel Webhook Handler
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use App\Enums\EnvironmentMode;

class LIBPAYWebhookController extends Controller
{
    public function handle(Request $request)
    {
        // Get webhook headers
        $environment = $request->header('X-Environment', 'production');
        $signature = $request->header('X-Signature');
        $webhookId = $request->header('X-Webhook-ID');
        
        // Get appropriate secret based on environment
        $secret = $this->getSecretForEnvironment($environment);
        
        // Verify signature
        if (!$this->verifySignature($request->getContent(), $signature, $secret)) {
            Log::warning('LIBPAY webhook signature verification failed', [
                'webhook_id' => $webhookId,
                'environment' => $environment
            ]);
            
            return response()->json(['error' => 'Invalid signature'], 401);
        }
        
        $payload = $request->json()->all();
        
        // Handle based on environment
        if ($environment === EnvironmentMode::SANDBOX->value) {
            return $this->handleSandboxWebhook($payload);
        } else {
            return $this->handleProductionWebhook($payload);
        }
    }
    
    private function getSecretForEnvironment(string $environment): string
    {
        // Return test secret for sandbox, live secret for production
        return $environment === 'sandbox' 
            ? config('libpay.test_webhook_secret')
            : config('libpay.webhook_secret');
    }
    
    private function verifySignature(string $payload, string $signature, string $secret): bool
    {
        $expectedSignature = hash_hmac('sha256', $payload, $secret);
        return hash_equals($expectedSignature, $signature);
    }
    
    private function handleSandboxWebhook(array $payload): JsonResponse
    {
        Log::info('Processing sandbox webhook', $payload);
        
        // Your sandbox-specific logic here
        // Don't fulfill orders, don't send emails to real customers, etc.
        
        return response()->json(['status' => 'sandbox_processed']);
    }
    
    private function handleProductionWebhook(array $payload): JsonResponse
    {
        Log::info('Processing production webhook', $payload);
        
        // Your production logic here
        // Fulfill orders, send confirmation emails, etc.
        
        return response()->json(['status' => 'processed']);
    }
}
const crypto = require('crypto');
const express = require('express');

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

// Webhook handler
app.post('/api/webhooks/libpay', async (req, res) => {
    const environment = req.headers['x-environment'] || 'production';
    const signature = req.headers['x-signature'];
    const webhookId = req.headers['x-webhook-id'];
    
    // Get appropriate secret based on environment
    const secret = getSecretForEnvironment(environment);
    
    // Verify signature
    if (!verifySignature(JSON.stringify(req.body), signature, secret)) {
        console.warn('LIBPAY webhook signature verification failed', {
            webhook_id: webhookId,
            environment: environment
        });
        
        return res.status(401).json({ error: 'Invalid signature' });
    }
    
    const payload = req.body;
    
    try {
        // Handle based on environment
        if (environment === EnvironmentMode.SANDBOX) {
            await handleSandboxWebhook(payload);
        } else {
            await handleProductionWebhook(payload);
        }
        
        res.json({ status: 'processed' });
    } catch (error) {
        console.error('Webhook processing error:', error);
        res.status(500).json({ error: 'Processing failed' });
    }
});

function getSecretForEnvironment(environment) {
    // Return test secret for sandbox, live secret for production
    return environment === 'sandbox' 
        ? process.env.LIBPAY_TEST_WEBHOOK_SECRET
        : process.env.LIBPAY_WEBHOOK_SECRET;
}

function verifySignature(payload, signature, secret) {
    if (!signature) {
        return false;
    }
    
    const expectedSignature = 'sha256=' + crypto
        .createHmac('sha256', secret)
        .update(payload)
        .digest('hex');
    
    return crypto.timingSafeEqual(
        Buffer.from(expectedSignature),
        Buffer.from(signature)
    );
}

async function handleSandboxWebhook(payload) {
    console.log('Processing sandbox webhook:', payload);
    
    // Your sandbox-specific logic here
    // Don't fulfill orders, don't send emails to real customers, etc.
}

async function handleProductionWebhook(payload) {
    console.log('Processing production webhook:', payload);
    
    // Your production logic here
    // Fulfill orders, send confirmation emails, etc.
}
import hmac
import hashlib
import json
import logging
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_http_methods

logger = logging.getLogger(__name__)

ENVIRONMENT_MODE = {
    'SANDBOX': 'sandbox',
    'PRODUCTION': 'production'
}

@csrf_exempt
@require_http_methods(["POST"])
def libpay_webhook(request):
    environment = request.headers.get('X-Environment', 'production')
    signature = request.headers.get('X-Signature', '')
    webhook_id = request.headers.get('X-Webhook-ID')
    
    // Get appropriate secret based on environment
    secret = get_secret_for_environment(environment)
    
    // Verify signature
    if not verify_signature(request.body, signature, secret):
        logger.warning('LIBPAY webhook signature verification failed', extra={
            'webhook_id': webhook_id,
            'environment': environment
        })
        
        return JsonResponse({'error': 'Invalid signature'}, status=401)
    
    try:
        payload = json.loads(request.body)
        
        // Handle based on environment
        if environment == ENVIRONMENT_MODE['SANDBOX']:
            handle_sandbox_webhook(payload)
        else:
            handle_production_webhook(payload)
        
        return JsonResponse({'status': 'processed'})
    
    except Exception as e:
        logger.error(f'Webhook processing error:{str(e)}')
        return JsonResponse({'error': 'Processing failed'}, status=500)

def get_secret_for_environment(environment):
    from django.conf import settings
    
    // Return test secret for sandbox, live secret for production
    return (settings.LIBPAY_TEST_WEBHOOK_SECRET 
            if environment == 'sandbox' 
            else settings.LIBPAY_WEBHOOK_SECRET)

def verify_signature(payload, signature, secret):
    if not signature:
        return False
    
    expected_signature = 'sha256=' + hmac.new(
        secret.encode('utf-8'),
        payload,
        hashlib.sha256
    ).hexdigest()
    
    return hmac.compare_digest(expected_signature, signature)

def handle_sandbox_webhook(payload):
    logger.info('Processing sandbox webhook', extra=payload)
    
    // Your sandbox-specific logic here
    // Don't fulfill orders, don't send emails to real customers, etc.

def handle_production_webhook(payload):
    logger.info('Processing production webhook', extra=payload)
    
    // Your production logic here
    // Fulfill orders, send confirmation emails, etc.

Environment-Specific Best Practices

Sandbox Webhooks
  • Use for testing webhook integration
  • No real money transactions
  • Don't fulfill actual orders
  • Don't send emails to real customers
  • Use test webhook secret for verification
Production Webhooks
  • Process real customer orders
  • Send confirmation emails
  • Update inventory systems
  • Trigger fulfillment processes
  • Use production webhook secret for verification

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 LIBPAYService
{
    private string $baseUrl;
    private string $merchantKey;
    private string $apiKey;
    private string $environment;

    public function __construct()
    {
        $this->baseUrl = config('libpay.base_url');
        $this->merchantKey = config('libpay.merchant_key');
        $this->apiKey = config('libpay.api_key');
        $this->environment = config('libpay.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('LIBPAY API Error: Payment initiation failed');
        } catch (Exception $e) {
            throw new Exception('LIBPAY 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('LIBPAY API Error: Payment verification failed');
        } catch (Exception $e) {
            throw new Exception('LIBPAY API Error: ' . $e->getMessage());
        }
    }
}

// Configuration (config/libpay.php)
return [
    'base_url' => env('LIBPAY_BASE_URL', 'https://app.libpay.app'),
    'environment' => env('LIBPAY_ENVIRONMENT', 'sandbox'), // sandbox or production
    'merchant_key' => env('LIBPAY_MERCHANT_KEY'), // Use appropriate prefix
    'api_key' => env('LIBPAY_API_KEY'), // Use appropriate prefix
];

// Usage in Controller
class PaymentController extends Controller
{
    public function initiatePayment(Request $request, LIBPAYService $libpay)
    {
        $paymentData = [
            'payment_amount' => $request->amount,
            'currency_code' => 'USD',
            'ref_trx' => 'ORDER_' . time(),
            'description' => $request->description,
            'success_redirect' => route('payment.success'),
            'failure_url' => route('payment.failed'),
            'cancel_redirect' => route('payment.cancelled'),
            'ipn_url' => route('webhooks.libpay'),
        ];

        try {
            $result = $libpay->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 LIBPAYService {
    constructor() {
        this.baseUrl = process.env.LIBPAY_BASE_URL || 'https://app.libpay.app';
        this.environment = process.env.LIBPAY_ENVIRONMENT || 'sandbox'; // sandbox or production
        this.merchantKey = process.env.LIBPAY_MERCHANT_KEY; // Use appropriate prefix
        this.apiKey = process.env.LIBPAY_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(`LIBPAY 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(`LIBPAY API Error: ${error.message}`);
        }
    }
}

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

app.post('/initiate-payment', async (req, res) => {
    const paymentData = {
        payment_amount: req.body.amount,
        currency_code: 'USD',
        ref_trx: `ORDER_${Date.now()}`,
        description: req.body.description,
        success_redirect: `${req.protocol}://${req.get('host')}/payment/success`,
        failure_url: `${req.protocol}://${req.get('host')}/payment/failed`,
        cancel_redirect: `${req.protocol}://${req.get('host')}/payment/cancelled`,
        ipn_url: `${req.protocol}://${req.get('host')}/webhooks/libpay`,
    };

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

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

class LIBPAYService:
    def __init__(self):
        self.base_url = getattr(settings, 'LIBPAY_BASE_URL', 'https://app.libpay.app')
        self.environment = getattr(settings, 'LIBPAY_ENVIRONMENT', 'sandbox')  # sandbox or production
        self.merchant_key = getattr(settings, 'LIBPAY_MERCHANT_KEY')  # Use appropriate prefix
        self.api_key = getattr(settings, 'LIBPAY_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'LIBPAY 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'LIBPAY API Error: {str(e)}')

# Django Settings Configuration
LIBPAY_BASE_URL = 'https://app.libpay.app'
LIBPAY_ENVIRONMENT = 'sandbox'  # Change to 'production' for live
LIBPAY_MERCHANT_KEY = os.environ.get('LIBPAY_MERCHANT_KEY')  # Use appropriate prefix
LIBPAY_API_KEY = os.environ.get('LIBPAY_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

libpay = LIBPAYService()

@csrf_exempt
def initiate_payment(request):
    if request.method == 'POST':
        data = json.loads(request.body)
        
        payment_data = {
            'payment_amount': data['amount'],
            'currency_code': 'USD',
            'ref_trx': f'ORDER_{int(time.time())}',
            'description': data['description'],
            'success_redirect': request.build_absolute_uri('/payment/success/'),
            'failure_url': request.build_absolute_uri('/payment/failed/'),
            'cancel_redirect': request.build_absolute_uri('/payment/cancelled/'),
            'ipn_url': request.build_absolute_uri('/webhooks/libpay/'),
        }

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

# Initiate Payment
curl -X POST "https://app.libpay.app/api/v1/initiate-payment" \
  -H "Content-Type: application/json" \
  -H "X-Environment: $LIBPAY_ENVIRONMENT" \
  -H "X-Merchant-Key: $LIBPAY_MERCHANT_KEY" \
  -H "X-API-Key: $LIBPAY_API_KEY" \
  -d '{
    "payment_amount": 250.00,
    "currency_code": "USD",
    "ref_trx": "ORDER_12345",
    "description": "Premium Subscription",
    "success_redirect": "https://yoursite.com/payment/success",
    "failure_url": "https://yoursite.com/payment/failed",
    "cancel_redirect": "https://yoursite.com/payment/cancelled",
    "ipn_url": "https://yoursite.com/api/webhooks/libpay"
  }'

# Verify Payment
curl -X GET "https://app.libpay.app/api/v1/verify-payment/TXNQ5V8K2L9N3XM1" \
  -H "Accept: application/json" \
  -H "X-Environment: $LIBPAY_ENVIRONMENT" \
  -H "X-Merchant-Key: $LIBPAY_MERCHANT_KEY" \
  -H "X-API-Key: $LIBPAY_API_KEY"

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

WooCommerce Integration

Advanced LIBPAY payment gateway with modern WooCommerce Blocks support, dynamic branding, and enterprise-grade security features.

Advanced WooCommerce Integration

Production-ready payment gateway with WooCommerce Blocks (Gutenberg) support, dynamic branding, and secure webhook processing.

3 Minutes Setup
99.9% Uptime
24/7 Webhook Support
Latest Plugin Download

Enterprise-grade WooCommerce payment gateway with modern Blocks support and dynamic branding.

Plugin Size: 45.2 KB
Version: 2.8.0
Last Updated: Sep 02, 2025
System Requirements
  • WordPress 5.8+
  • WooCommerce 6.0+
  • PHP 8.1+ (8.2+ Recommended)
  • SSL Certificate (Required)
  • LIBPAY Merchant Account
  • WooCommerce Blocks Support
Production Ready

Advanced Features

Enterprise-grade payment processing with modern architecture

WooCommerce Blocks

Full Gutenberg checkout compatibility with React-based UI

Dynamic Branding

Auto-fetch logo, colors, and branding from LIBPAY API

Secure Webhooks

HMAC-SHA256 signature verification for payment callbacks

Compact Mobile UI

Space-efficient, responsive design for all devices

Advanced Security

Multi-header authentication with environment isolation

Test/Live Mode

Seamless sandbox testing with production deployment

Quick Installation Guide

Get started with LIBPAY WooCommerce integration in minutes

1
Download Latest Plugin

Download LIBPAY WooCommerce Gateway v2.8.0 from the download section above. This includes all latest features and security updates.

2
Install via WordPress Admin

Navigate to Plugins → Add New → Upload Plugin and select the downloaded ZIP file. The plugin will auto-extract and install.

3
Activate & Configure

Activate the plugin and go to WooCommerce → Settings → Payments → LIBPAY. Enter your API credentials and webhook secret.

4
Test Integration

Enable Test Mode, process a sandbox transaction to verify Blocks checkout, webhook delivery, and order completion.

5
Go Live

Disable test mode, ensure production API keys are configured, and start accepting real payments with full webhook processing.

API Configuration

Essential API settings for secure payment processing

API Base URL

https://app.libpay.app

Auto-configured
Merchant ID & API Key

Your unique merchant credentials from LIBPAY dashboard

Required
Webhook Secret

HMAC-SHA256 signature verification for secure callbacks

Recommended
Authentication Headers

Required headers for all LIBPAY API requests:

X-Environment: sandbox|production
X-Merchant-Key: your_merchant_id
X-API-Key: your_api_key
Content-Type: application/json

Webhook Configuration

Real-time payment status updates and order processing

Webhook Endpoint
https://yoursite.com/wc-api/libpay_webhook

Configure this URL in your LIBPAY merchant dashboard for automatic order updates.

Supported Events
  • Payment Success
  • Payment Failed
  • Payment Cancelled
  • Payment Pending
  • Refund Processed
  • Payment Timeout

WooCommerce Blocks Integration

Modern Gutenberg checkout with React-based payment UI

Responsive Design

Compact, mobile-optimized payment interface that adapts to any screen size.

Dynamic Branding

Automatically fetches and displays your LIBPAY branding and logos.

Security Indicators

Clear SSL and security badges to build customer trust during checkout.

Test Mode Support

Clear sandbox indicators for testing without affecting live transactions.

Production Deployment Checklist

Ensure everything is configured correctly before going live

Technical Requirements
API Configuration
Final Verification

Troubleshooting

Common issues and solutions for LIBPAY WooCommerce integration

Payment method not showing in checkout

Solutions:

  • Verify plugin is activated and enabled in WooCommerce → Settings → Payments
  • Clear browser cache and WooCommerce cache
  • Check if API credentials are correctly configured
  • Ensure SSL certificate is properly installed
401 Unauthorized API errors

Solutions:

  • Verify Merchant ID and API Key are correct
  • Ensure environment (sandbox/production) matches your credentials
  • Check that all required headers are being sent
  • Contact LIBPAY support to verify account status
Orders not updating after payment

Solutions:

  • Verify webhook URL is configured in LIBPAY dashboard
  • Check webhook secret key matches plugin configuration
  • Review WordPress error logs for webhook processing errors
  • Test webhook delivery using LIBPAY dashboard tools
Technical Support

Need assistance with LIBPAY WooCommerce integration? Our technical team provides comprehensive support.

Support Hours: 24/7 for critical issues

Interactive API Testing

Test LIBPAY 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:

Demo Wallet
Wallet ID: 123456789 Password: demo123
Auto-approved in sandbox
Demo Voucher
Voucher Code: TESTVOUCHER
Instant redemption
Gateway Payment
Behavior: Auto Success
No external redirection
Testing Guidelines
  • Environment Header: Always include X-ENVIRONMENT: sandbox in your API requests
  • Demo Credentials: Use the provided demo wallet/voucher codes for testing payment flows
  • Sandbox Behavior: All payments auto-complete successfully 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. USD, EUR, BDT). You must use the currency that matches your merchant shop setup.
Sandbox Environment

Base URL: https://app.libpay.app

Environment Header: X-Environment: sandbox

Credentials: Use test_ prefixed keys

Purpose: Safe testing without real money

Production Environment

Base URL: https://app.libpay.app

Environment Header: X-Environment: production

Credentials: No prefix for production keys

Purpose: Live transactions with real money

Error Codes

LIBPAY 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
INSUFFICIENT_FUNDS Customer has insufficient funds Customer needs to add funds to their wallet
PAYMENT_DECLINED Payment was declined by payment processor Customer should try a different payment method
INVALID_AMOUNT Payment amount is invalid Check minimum and maximum amount limits
INVALID_CURRENCY Unsupported currency code Use a supported currency code (USD, EUR, etc.)
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 LIBPAY 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 LIBPAY integration from our support team and developer resources.

Technical Support

For API integration help:

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

Contact Support