Skip to Content
Pesa VoucherDeveloper Documentation

Vouchers

Create, validate and redeem digital vouchers


Vouchers API

Simple, secure, and instant voucher system.

Live Base URL
https://payments.pesavoucher.com/api/v1

Sandbox Base URL (for testing)
https://sandbox.payments.pesavoucher.com/api/v1


Voucher Flows – How to use as a Merchant

DirectionVoucher Created ByRedeemed OnAPI You Call
Customer → You (Deposit)Customer (on pesavoucher.com)Your website/app/validate_voucher + /redeem_voucher
You → Customer (Withdrawal)You (merchant)pesavoucher.comOnly /create_voucher

Key Points:

  • Customers can paste vouchers on your site (for deposits)
  • You can send vouchers to customers (for payouts)

Authentication

All API requests require authentication using API credentials in request headers:

X-API-KEY: your_api_key_here
X-API-SECRET: your_api_secret_here

1. Create Voucher (Merchant → Customer)

Generate a voucher that your users can redeem on the PesaVoucher platform (e.g. withdrawal, refund, bonus).

Endpoint

POST /create_voucher

Headers

Content-Type: application/json
X-API-KEY: your_api_key
X-API-SECRET: your_api_secret

Request Body

{
"email": "customer@example.com",
"amount": 750.00,
"unique_id": "7373737",
"currency": "KES",
"callback_url": "https://yoursite.com/webhook/voucher-status",
"message": "Your withdrawal request has been approved!"
}

Field Descriptions:

FieldTypeRequiredDescription
emailstringYesCustomer's email address (must be registered on PesaVoucher)
amountfloatYesVoucher amount (min: 50.00, max: 150,000.00 KES)
currencystringYesCurrency code (currently only "KES" supported)
unique_idstringNoYour internal reference/transaction ID
callback_urlstringNoURL to receive async status updates
messagestringNoPersonal message to include in the voucher email

Success Response

{
"success": true,
"voucher_code": "NLV-53SKM7C0HNDSAZAM",
"currency": "KES",
"amount": 750.00,
"transaction_id": "463G4HDIF3",
"unique_id": "7373737"
}

Error Response

{
"success": false,
"error": "User not found"
}

Common Error Messages:

  • "Missing required fields: email, amount, currency"
  • "Minimum voucher amount is KES 50"
  • "Maximum voucher amount is KES 150000"
  • "Currency must be KES"
  • "User not found"
  • "Insufficient merchant balance"

What Happens Next:

  • The voucher is instantly created and credited to the user's wallet
  • A branded email with the voucher PDF is sent to the customer
  • The voucher can be redeemed on pesavoucher.com
  • If callback_url was provided, you'll receive status updates

2. Validate Voucher

Check if a voucher is valid before redeeming it. This is a read-only operation that doesn't modify any data.

Endpoint

POST /validate_voucher

Headers

Content-Type: application/json
X-API-KEY: your_api_key
X-API-SECRET: your_api_secret

Request Body

{
"voucher_code": "NLV-DTUMJQ6ILG9WNISE"
}

Valid & Ready Response

{
"success": true,
"valid": true,
"voucher": {
"code": "NLV-DTUMJQ6ILG9WNISE",
"amount": 750.00,
"currency": "KES",
"status": "active",
"is_active": true,
"recipient": {
"name": "Jane Doe",
"email": "customer@example.com"
}
}
}

Invalid Response Examples

Already Redeemed:

{
"success": true,
"valid": false,
"validation_errors": ["Voucher already redeemed on 2025-11-20 10:30:00"]
}

Not Found or Deleted:

{
"success": true,
"valid": false,
"validation_errors": ["Voucher not found or has been deleted"]
}

Platform-Only Voucher:

{
"success": true,
"valid": false,
"validation_errors": ["Voucher is only redeemable at PesaVoucher platform"]
}

Validation Error Types:

  • "Voucher not found or has been deleted"
  • "Voucher is not active"
  • "Voucher already redeemed on [date]"
  • "Voucher is only redeemable at PesaVoucher platform, not at merchant locations"
  • "Voucher does not belong to your merchant account"

3. Redeem Voucher (Final Step – Instant Credit)

This is the core action that marks the voucher as used and credits your merchant account.

Endpoint

POST /redeem_voucher

Headers

Content-Type: application/json
X-API-KEY: your_api_key
X-API-SECRET: your_api_secret

Request Body

{
"voucher_code": "NLV-DTUMJQ6ILG9WNISE",
"currency": "KES",
"callback_url": "https://yoursite.com/webhook/redemption",
"note": "November cashout",
"redeemed_by": "user_8871"
}

Field Descriptions:

FieldTypeRequiredDescription
voucher_codestringYesThe voucher code to redeem
currencystringYesCurrency code (must be "KES")
callback_urlstringNoURL to receive async redemption status
notestringNoInternal note for your records
redeemed_bystringNoStaff/cashier name or your internal user ID

Success Response

{
"success": true,
"message": "Voucher redeemed successfully",
"redemption": {
"voucher_code": "NLV-DTUMJQ6ILG9WNISE",
"amount": 750.00,
"currency": "KES",
"redeemed_at": "2025-11-21 14:22:10",
"redeemed_by": "user_8871",
"customer": {
"name": "Jane Doe",
"email": "customer@example.com"
}
}
}

Error Response

{
"success": false,
"error": "Voucher has already been redeemed on 2025-11-20 10:30:00"
}

Common Error Messages:

  • "Missing required field: voucher_code or currency"
  • "Currency must be KES"
  • "Voucher not found or does not belong to your merchant account"
  • "Voucher has been deleted"
  • "Voucher is not active"
  • "Voucher is only redeemable at PesaVoucher platform, not at merchant locations"
  • "Voucher has already been redeemed on [date]"
  • "Insufficient wallet balance"

What Happens:

  1. The voucher is marked as redeemed
  2. The amount is deducted from the customer's wallet
  3. Your merchant account is credited
  4. The customer receives an email notification
  5. If callback_url was provided, you'll receive a confirmation callback

Callbacks (Webhooks)

Both /create_voucher and /redeem_voucher endpoints support optional callback URLs for asynchronous notifications.

How Callbacks Work

When you provide a callback_url in your request, PesaVoucher will send an HTTP POST request to that URL with the operation status.

Callback Request Format

Headers:

Content-Type: application/json
X-Callback-Type: STK-Push

Create Voucher Callback

Success Payload:

{
"success": true,
"message": "Voucher created successfully",
"voucher_code": "NLV-53SKM7C0HNDSAZAM",
"amount": 750.00,
"transaction_id": "463G4HDIF3",
"unique_id": "7373737",
"currency": "KES",
"timestamp": "2025-11-26 14:30:45"
}

Failure Payload:

{
"success": false,
"message": "Failed to create voucher",
"voucher_code": null,
"amount": 750.00,
"transaction_id": "463G4HDIF3",
"unique_id": "7373737",
"currency": "KES",
"timestamp": "2025-11-26 14:30:45"
}

Redeem Voucher Callback

Success Payload:

{
"voucher_code": "NLV-DTUMJQ6ILG9WNISE",
"amount": 750.00,
"redeemed_at": "2025-11-26 14:35:20",
"redeemed_by": "user_8871",
"customer": {
"name": "Jane Doe",
"email": "customer@example.com"
},
"currency": "KES",
"timestamp": "2025-11-26 14:35:20"
}

Failure Payload:

{
"success": false,
"message": "Failed to redeem voucher",
"voucher_code": "NLV-DTUMJQ6ILG9WNISE",
"unique_id": null,
"currency": "KES",
"timestamp": "2025-11-26 14:35:20"
}

Callback Implementation Best Practices

  1. Always respond with HTTP 200 OK - Even if you encounter an error processing the callback
  2. Verify the callback - Check that the voucher_code or unique_id matches your records
  3. Be idempotent - Handle duplicate callbacks gracefully (same voucher_code may be sent multiple times)
  4. Timeout handling - PesaVoucher waits 10 seconds for your response
  5. Security - Validate the callback is coming from PesaVoucher's IP addresses
  6. Use HTTPS - Always use HTTPS URLs for your callback endpoints

Example Callback Handler (PHP)

<?php
// callback-handler.php
$payload = json_decode(file_get_contents('php://input'), true);
if (!$payload) {
http_response_code(400);
exit('Invalid payload');
}
// Log the callback
error_log("Received callback: " . json_encode($payload));
// Verify and process based on type
if (isset($payload['voucher_code'])) {
$voucherCode = $payload['voucher_code'];
$success = $payload['success'] ?? false;
if ($success) {
// Update your database
// Send notifications
// Update user balance
} else {
// Handle failure
// Alert admin
}
}
// Always respond with 200 OK
http_response_code(200);
echo json_encode(['received' => true]);

UI/UX Guidelines (Example Design Flow)

Implement a user-friendly interface for voucher redemption:

┌──────────────────────────────────────┐
│ Redeem Your Voucher │
├──────────────────────────────────────┤
│ Paste your voucher code below: │
│ │
│ [ NLV-___________________ ] │
│ │
│ [ Redeem → ] │
└──────────────────────────────────────┘

Recommended Flow:

  1. Single input field - Keep it simple
  2. Real-time validation - Call /validate_voucher on blur/paste
  3. Amount preview - Show voucher amount when valid
  4. Conditional button - Only enable "Redeem" when valid: true
  5. Success screen - Clear confirmation: "✓ KES 750 added to your account"
  6. Error handling - Show friendly error messages from validation

Testing in Sandbox

Use the sandbox environment for testing without affecting real data:

Sandbox URL:
https://sandbox.payments.pesavoucher.com/api/v1

Testing Features:

  • All vouchers created start with TEST-NLV-...
  • No actual emails sent (check logs instead)
  • Redemption works instantly
  • All endpoints return realistic test data
  • Separate test credentials provided

Test Scenarios to Cover:

  1. Create voucher → validate → redeem (happy path)
  2. Attempt to redeem twice (should fail)
  3. Validate non-existent voucher
  4. Create voucher with insufficient balance
  5. Test callback URL handling

Best Security Practices

  1. Always validate first - Call /validate_voucher before showing redemption UI
  2. Check ownership - Ensure voucher belongs to your merchant account
  3. Enable redemption conditionally - Only when "valid": true
  4. Secure storage - Never store voucher codes in localStorage plain text
  5. Idempotency - Handle duplicate redemption attempts gracefully
  6. HTTPS only - Always use secure connections
  7. Rate limiting - Implement rate limits on your redemption endpoint
  8. Audit logs - Keep detailed logs of all voucher operations
  9. Callback verification - Validate callbacks are from PesaVoucher
  10. Error handling - Show user-friendly messages, log technical details

Error Handling

All endpoints follow a consistent error response format:

{
"success": false,
"error": "Human-readable error message"
}

HTTP Status Codes:

  • 200 - Success or validation response
  • 400 - Bad request (invalid input)
  • 401 - Authentication failed
  • 403 - Forbidden (voucher doesn't belong to merchant)
  • 404 - Resource not found
  • 500 - Internal server error

Recommended Client-Side Handling:

try {
const response = await fetch('/api/v1/redeem_voucher', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-KEY': apiKey,
'X-API-SECRET': apiSecret
},
body: JSON.stringify(payload)
});
const data = await response.json();
if (data.success) {
// Handle success
showSuccess(`KES ${data.redemption.amount} credited!`);
} else {
// Handle error
showError(data.error);
}
} catch (error) {
// Network or parsing error
showError('Unable to process request. Please try again.');
}

Support

For API support or to request merchant credentials:

  • Email: support@pesavoucher.com
  • Documentation: https://docs.pesavoucher.com
  • Status Page: https://status.pesavoucher.com

Changelog

Version 1.0 (Current)

  • Initial API release
  • Support for KES currency
  • Create, validate, and redeem voucher endpoints
  • Callback/webhook support
  • Sandbox environment