API Documentation

Integrate VerPay into your application to verify Ethiopian payments.

Introduction

VerPay is an open-source verification engine for Ethiopian fintech. It lets businesses and developers programmatically verify customer payments by sending a receipt reference number (or an image of the receipt) to the API. The engine checks the transaction directly with the bank and returns a JSON response confirming whether the payment is real or fake.

Getting Started

1. Database Setup (Supabase)

  1. Create a new project at Supabase.
  2. Navigate to the SQL Editor in your Supabase dashboard.
  3. Copy the contents of supabase/migrations/001_init.sql and run it. This creates the api_keys and usage_logs tables, plus the increment_api_key_usage RPC function.
  4. Go to Project Settings > API to find your URL and Service Role Key.

2. Local Setup

git clone https://github.com/robiabebe/verpay.git
cd verpay
npm install
cp .env.example .env

Edit the .env file with your actual keys:

SUPABASE_URL=https://your-project-id.supabase.co
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key
ADMIN_KEY=your-secure-admin-password
MISTRAL_API_KEY=your-mistral-ai-key
# TELEBIRR_PROXY_URL=http://your-ethiopian-proxy.com:8080
PORT=3001

3. Generate an API Key

All verification endpoints require an API key passed in the x-api-key header. Generate one using your admin key:

curl -X POST http://localhost:3001/admin/api-keys \
  -H "x-admin-key: your-secure-admin-password" \
  -H "Content-Type: application/json" \
  -d '{"owner": "My Production App"}'

Response:

{
  "message": "API Key generated successfully. Save this key, it will not be shown again.",
  "apiKey": "verpay_live_a1b2c3d4e5f6...",
  "owner": "My Production App"
}

Authentication

All verification endpoints (/verify-cbe, /verify-telebirr, /verify-image) require an API key passed via the x-api-key HTTP header. Admin endpoints require the x-admin-key header.

curl -X POST http://localhost:3001/verify-cbe \
  -H "x-api-key: verpay_live_YOUR_GENERATED_KEY" \
  -H "Content-Type: application/json" \
  -d '{"reference": "v2-hfHCxz6TmMYrTUfWldzb"}'

CBE Verification

Verify a Commercial Bank of Ethiopia receipt by its reference number. Uses the modern CBE JSON API (Mbreceipt) for fast, direct lookups.

POST /verify-cbe
Reference Format: Starts with v2- followed by an alphanumeric string (e.g., v2-hfHCxz6TmMYrTUfWldzb).
Request Body:
{
  "reference": "v2-hfHCxz6TmMYrTUfWldzb"
}

Success Response 200

{
  "success": true,
  "provider": "cbe",
  "data": {
    "payerName": "John Doe",
    "payerAccount": "1000123456789",
    "receiverName": "Jane Smith",
    "receiverAccount": "9876543210",
    "amount": "ETB 1500",
    "date": "6/4/2026, 11:46:00 AM",
    "reference": "v2-hfHCxz6TmMYrTUfWldzb",
    "description": "CBE Mobile Transfer"
  }
}

Error Response 400

{
  "success": false,
  "provider": "cbe",
  "error": "Transaction not found or invalid reference"
}

Telebirr Verification

Verify an Ethio Telecom Telebirr receipt. This endpoint scrapes the official Telebirr receipt page and extracts all transaction details. Requires an Ethiopian IP or proxy for deployments outside Ethiopia.

POST /verify-telebirr
Reference Format: Exactly 10 uppercase alphanumeric characters (e.g., AG3HF92K10).
Request Body:
{
  "reference": "AG3HF92K10"
}

Success Response 200

{
  "success": true,
  "provider": "telebirr",
  "data": {
    "payerName": "John Doe",
    "payerNumber": "+251911234567",
    "receiverName": "Jane Smith",
    "receiverAccount": "1234567890",
    "bankName": "CBE",
    "status": "SUCCESS",
    "receiptNumber": "AG3HF92K10",
    "date": "2026-06-04",
    "amount": "1500",
    "serviceFee": "15",
    "vat": "2.25",
    "total": "1517.25"
  }
}

Error Response 400

{
  "success": false,
  "provider": "telebirr",
  "error": "Receipt not found or invalid format"
}

AI Image Verification

Upload a screenshot of a receipt instead of typing a reference number. The system first attempts to extract a QR code for 100% accuracy (CBE receipts), then falls back to Mistral AI OCR. Extracted data is automatically cross-verified with the bank API.

POST /verify-image
Request Body:
{
  "image": "base64_encoded_string_here..."
}
Notes: Pass the raw Base64 string (without the data:image/jpeg;base64, prefix). The API handles both formats.

Success Response 200

{
  "success": true,
  "provider": "cbe",
  "data": {
    "provider": "cbe",
    "reference": "v2-hfHCxz6TmMYrTUfWldzb",
    "amount": "1500",
    "date": "2026-06-04",
    "payerName": "John Doe",
    "receiverName": "Jane Smith",
    "payerAccount": "1000123456789",
    "receiverAccount": "9876543210",
    "description": "CBE Mobile Transfer",
    "isAutoVerified": true
  }
}

The isAutoVerified: true field confirms the OCR-extracted data was cross-checked with the real bank API and matched. If verification fails, the response includes ocrData with what was extracted from the image so you can debug.

Error Response 400

{
  "success": false,
  "provider": "cbe",
  "error": "Official verification failed: Transaction not found",
  "ocrData": {
    "provider": "cbe",
    "reference": "v2-hfHCxz6TmMYrTUfWldzb",
    "amount": "1500",
    "payerName": "John Doe",
    "receiverName": "Jane Smith"
  }
}

Admin Endpoints

Use the admin endpoints to generate and manage API keys. Pass your ADMIN_KEY via the x-admin-key header.

POST
/admin/api-keys

Generate a new API key. The raw key is returned only once.

curl -X POST http://localhost:3001/admin/api-keys \
  -H "x-admin-key: your-secure-admin-password" \
  -H "Content-Type: application/json" \
  -d '{"owner": "My Production App"}'
GET
/admin/api-keys

List all API keys with usage stats.

curl -X GET http://localhost:3001/admin/api-keys \
  -H "x-admin-key: your-secure-admin-password"

Vercel Deployment

This project is configured for serverless deployment on Vercel out of the box.

  1. Install the Vercel CLI: npm i -g vercel
  2. Run vercel and link your project.
  3. Add your environment variables using vercel env add.
  4. Deploy to production: vercel --prod

Troubleshooting

  • 1 Telebirr Proxy Errors

    Telebirr blocks non-Ethiopian IPs. If developing locally, comment out TELEBIRR_PROXY_URL in .env. If deploying outside Ethiopia, you will need a working residential Ethiopian proxy.

  • 2 Mistral API Errors

    Ensure your Mistral account is active and the MISTRAL_API_KEY is set. Pass a clean Base64 string (without the data:image/jpeg;base64, prefix) if calling the API directly.