TapPayAPI Documentation

TapPay Developer API

Accept NGNm stablecoin payments in your app. Create payment requests, receive webhook notifications, and initiate payouts to Nigerian bank accounts.

Getting Started

  1. Download TapPay from the App Store or Google Play
  2. Open Settings → Developer → Generate API Key
  3. Copy your API key and store it securely — it is shown only once
  4. Start making API calls to https://api.usetappay.app/v1

Authentication

All API requests require a Bearer token in the Authorization header.

Request Header
Authorization: Bearer tap_live_sk_xxxxxxxxxxxxxxxxxxxx

Two key types are available:

  • tap_live_sk_ — Production keys (Celo Mainnet)
  • tap_test_sk_ — Sandbox keys (Celo Sepolia testnet)

Endpoints

POST/v1/payment-requestsCreate a payment request
GET/v1/payment-requests/:idGet payment request status
GET/v1/payment-requestsList payment requests
GET/v1/transactionsList transactions
GET/v1/balanceGet wallet balance
POST/v1/payoutsInitiate bank payout
POST/v1/webhooksRegister webhook
GET/v1/webhooksList webhooks
DELETE/v1/webhooks?id=xxxDelete webhook

Create Payment Request

Creates a payment request (like an invoice) that can be paid via the TapPay app or web page.

POST /v1/payment-requests
curl -X POST https://api.usetappay.app/v1/payment-requests \
  -H "Authorization: Bearer tap_live_sk_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 5000,
    "currency": "NGNm",
    "reference": "INV-2026-001",
    "description": "School fees - Term 1",
    "expires_in": 3600
  }'
Response
{
  "id": "pr_a1b2c3d4e5f6...",
  "payment_url": "https://usetappay.app/pay/school_fees?ref=pr_a1b2c3d4e5f6...",
  "qr_url": "https://api.usetappay.app/v1/payment-requests/pr_a1b2.../qr",
  "amount": 5000,
  "currency": "NGNm",
  "reference": "INV-2026-001",
  "status": "pending",
  "expires_at": "2026-03-15T12:00:00.000Z"
}

Check Payment Status

GET /v1/payment-requests/:id
curl https://api.usetappay.app/v1/payment-requests/pr_a1b2c3d4e5f6 \
  -H "Authorization: Bearer tap_live_sk_xxx"
Response
{
  "id": "pr_a1b2c3d4e5f6...",
  "status": "completed",
  "paid_at": "2026-03-14T10:23:00Z",
  "paid_by": "@student_username",
  "tx_hash": "0x...",
  "amount": 5000,
  "currency": "NGNm"
}

Get Balance

GET /v1/balance
curl https://api.usetappay.app/v1/balance \
  -H "Authorization: Bearer tap_live_sk_xxx"
Response
{
  "balances": [
    { "currency": "NGNm", "balance": "45250.00", "fiat_symbol": "₦" },
    { "currency": "cUSD", "balance": "120.50", "fiat_symbol": "$" }
  ],
  "wallet_address": "0x...",
  "environment": "live"
}

List Transactions

GET /v1/transactions
curl "https://api.usetappay.app/v1/transactions?limit=20&type=received" \
  -H "Authorization: Bearer tap_live_sk_xxx"
Response
{
  "transactions": [
    {
      "id": "ref_abc123",
      "type": "received",
      "amount": "5000",
      "currency": "NGNm",
      "tx_hash": "0x...",
      "status": "completed",
      "created_at": "2026-03-14T10:23:00Z"
    }
  ],
  "total": 143,
  "has_more": true
}

Initiate Payout

Only available to verified merchants. Initiates a withdrawal to a Nigerian bank account.

POST /v1/payouts
curl -X POST https://api.usetappay.app/v1/payouts \
  -H "Authorization: Bearer tap_live_sk_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 10000,
    "bank_code": "044",
    "account_number": "0123456789",
    "reference": "PAYOUT-001"
  }'

Webhooks

Register webhook endpoints to receive real-time notifications when events occur. All webhook payloads are signed with HMAC-SHA256.

Available Events

  • payment.received — A payment was received
  • payment.sent — A payment was sent
  • payout.completed — A bank payout completed
  • payout.failed — A bank payout failed
  • deposit.confirmed — A Flutterwave deposit confirmed

Register a Webhook

POST /v1/webhooks
curl -X POST https://api.usetappay.app/v1/webhooks \
  -H "Authorization: Bearer tap_live_sk_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://yourapp.com/webhooks/tappay",
    "events": ["payment.received", "payout.completed"]
  }'
Response
{
  "id": "wh_xxx",
  "secret": "whsec_xxx",
  "url": "https://yourapp.com/webhooks/tappay",
  "events": ["payment.received", "payout.completed"]
}

Verifying Webhook Signatures

Every webhook request includes a TapPay-Signature header containing an HMAC-SHA256 signature of the request body using your webhook secret.

Verify Signature (Node.js)
const crypto = require('crypto');

function verifyWebhook(body, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(body)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

// In your webhook handler:
app.post('/webhooks/tappay', (req, res) => {
  const signature = req.headers['tappay-signature'];
  const isValid = verifyWebhook(
    JSON.stringify(req.body),
    signature,
    'whsec_xxx'
  );
  if (!isValid) return res.status(401).send('Invalid signature');

  const { event, data } = req.body;
  console.log('Event:', event, 'Data:', data);
  res.status(200).send('OK');
});

Webhooks are retried up to 3 times with exponential backoff (1 min, 5 min, 30 min). After 3 failures, the delivery is marked as failed. After 10 consecutive failures, the webhook endpoint is automatically deactivated.

JavaScript SDK

Install
npm install @tappay/sdk
Usage
import { TapPay } from '@tappay/sdk';

const tappay = new TapPay('tap_live_sk_xxx');

// Create a payment request
const request = await tappay.paymentRequests.create({
  amount: 5000,
  reference: 'INV-001',
  description: 'School fees',
});
console.log(request.payment_url);

// Check payment status
const status = await tappay.paymentRequests.get('pr_xxx');
console.log(status.status); // "pending" | "completed" | "expired"

// List transactions
const txns = await tappay.transactions.list({ limit: 20 });

// Get balance
const balance = await tappay.balance.get();

// Verify webhook signature
const isValid = TapPay.webhooks.verify(payload, signature, secret);

Sandbox

Use test keys (tap_test_sk_) to develop against the Celo Sepolia testnet. Test keys cannot move real funds.

  • Get testnet CELO from the Celo Sepolia faucet
  • Flutterwave sandbox bank: Test Bank, Account 0690000031
  • All API endpoints work identically in sandbox mode

Rate Limits

TierRequests/minRequests/day
Default6010,000
Verified Merchant300100,000
EnterpriseUnlimitedUnlimited

Rate limit info is included in every response via headers:

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 47
X-RateLimit-Reset: 1710432000