Settlr|API Reference

API Reference

The Settlr API lets you create payment links, request withdrawals, and receive real-time webhook events when transactions complete.

Authentication

All API requests must include your secret key in the Authorization header. Keep your secret key on the server — never expose it in client-side code or browsers.

Authorization: Bearer sk_live_YOUR_SECRET_KEY
Your secret key is shown once when generated. If you lose it, revoke it and generate a new one from your dashboard settings.

Create a payment link

POSThttps://payments.afriversedao.org/api/payment-links

Creates a new pending payment and returns a hosted checkout URL to redirect your customer to.

POST https://payments.afriversedao.org/api/payment-links
Authorization: Bearer sk_live_...
Content-Type: application/json

{
  "email": "customer@example.com",
  "amount": 25000,
  "redirectTo": "https://yourapp.com/order/complete"
}

Request body

emailrequiredstringThe customer's email address. They'll receive a confirmation when payment is detected.
amountrequiredintegerAmount in Naira (NGN). Must be a whole number — no decimals. E.g. 25000 for ₦25,000.
redirectTorequiredstringURL to redirect the customer to after their payment is confirmed.

Response

{
  "id": "clx4f2g0000abc123",
  "url": "https://payments.afriversedao.org/pay/clx4f2g0000abc123",
  "reference": "PAY-1A2B3C4D",
  "amount": 25000,
  "email": "customer@example.com"
}

Redirect your customer to url. They will see the exact transfer amount and bank account details. Store reference against your order — you'll receive it back in the webhook.

Payment lifecycle

A payment moves through the following statuses. Your webhook fires on approved and declined.

pending

Payment created. Waiting for customer to transfer.

approved

Transfer detected and confirmed. Webhook fires with charge.success.

declined

Payment was manually declined by the gateway. Webhook fires with charge.failed.

abandoned

No transfer received within 30 minutes. No webhook is sent.

Virtual accounts

Programmatically create a dedicated bank account (powered by Flutterwave) tied to a specific amount and expiry. Show the returned account number to your customer — when they transfer the exact amount, the account is funded and your charge.success webhook fires.

POSThttps://payments.afriversedao.org/api/virtual-accounts

Creates a dedicated virtual account for a single collection.

POST https://payments.afriversedao.org/api/virtual-accounts
Authorization: Bearer sk_live_...
Content-Type: application/json

{
  "amount": 25000,
  "email": "customer@example.com",
  "expirySeconds": 900
}

Request body

amountrequiredintegerAmount in Naira (NGN). Whole number, between 100 and 10,000,000. The customer must transfer this exact amount.
emailstringOptional. The customer's email — attached to the Flutterwave customer and used for the confirmation email. Defaults to a Settlr placeholder when omitted.
expirySecondsintegerOptional. Account lifetime in seconds (60–31,536,000). Defaults to 900 (15 minutes).
bankCodestringOptional. Partner bank for the account — WEMA (035) or Sterling (232). Defaults to the platform's configured bank.

Response

{
  "id": "clx9v1a0000va0001",
  "reference": "va3f9c2a1b8d4e6f0...",
  "provider": "flutterwave",
  "amount": 25000,
  "currency": "NGN",
  "status": "pending",
  "accountNumber": "7824822527",
  "bankName": "WEMA BANK",
  "email": "customer@example.com",
  "expiresAt": "2026-06-16T13:54:21.546Z",
  "paidAt": null,
  "createdAt": "2026-06-16T13:39:21.546Z"
}

Display accountNumber and bankName to your customer. Store reference against your order — you'll receive it back in the charge.success webhook when the account is funded.

Retrieve a virtual account

GEThttps://payments.afriversedao.org/api/virtual-accounts/:id

Fetch a single virtual account's current status.

GEThttps://payments.afriversedao.org/api/virtual-accounts

List your most recent virtual accounts.

An account is pending until funded (paid), or becomes expired if the expiry elapses with no transfer.

Verify a transaction

Confirm the status of a single transaction server-side before fulfilling an order. Look it up by your payment reference or by the Settlr transaction id — pass exactly one. Only transactions belonging to your account are returned.

GEThttps://payments.afriversedao.org/api/transactions/verify

Fetch one transaction by reference or id and check whether it's been paid.

GET https://payments.afriversedao.org/api/transactions/verify?reference=PAY-1A2B3C4D
Authorization: Bearer sk_live_...

# or by transaction id
GET https://payments.afriversedao.org/api/transactions/verify?id=clx4f2g0000abc123
Authorization: Bearer sk_live_...

Query parameters

referencestringYour payment reference (the value returned when the link was created). Required if id is omitted.
idstringThe Settlr transaction id. Required if reference is omitted.

Response

{
  "verified": true,
  "transaction": {
    "id": "clx4f2g0000abc123",
    "reference": "PAY-1A2B3C4D",
    "email": "customer@example.com",
    "amount": 25000,
    "currency": "NGN",
    "status": "approved",
    "source": "manual",
    "providerTxId": null,
    "expiresAt": "2026-06-16T13:54:21.546Z",
    "settledAt": null,
    "createdAt": "2026-06-16T13:39:21.546Z",
    "updatedAt": "2026-06-16T13:41:02.118Z"
  }
}

verified is true only when status is approved. Always verify server-side before fulfilling — don't rely on the browser redirect alone. Returns 404 if no matching transaction exists for your account.

Query transactions

List your transactions, newest first. Filter by customer email, status, reference, or a created-at date range, and page through results with limit and offset.

GEThttps://payments.afriversedao.org/api/transactions

List and filter your transactions.

GET https://payments.afriversedao.org/api/transactions?email=customer@example.com&status=approved&limit=50
Authorization: Bearer sk_live_...

Query parameters

emailstringFilter by the customer's email address (case-insensitive, exact match).
statusstringFilter by status: pending, awaiting_review, approved, declined, or abandoned.
referencestringFilter by a specific payment reference.
fromstringOnly transactions created on or after this ISO 8601 date/time.
tostringOnly transactions created on or before this ISO 8601 date/time.
limitintegerNumber of results to return (1–200). Defaults to 50.
offsetintegerNumber of results to skip, for pagination. Defaults to 0.

Response

{
  "data": [
    {
      "id": "clx4f2g0000abc123",
      "reference": "PAY-1A2B3C4D",
      "email": "customer@example.com",
      "amount": 25000,
      "currency": "NGN",
      "status": "approved",
      "source": "manual",
      "providerTxId": null,
      "expiresAt": "2026-06-16T13:54:21.546Z",
      "settledAt": null,
      "createdAt": "2026-06-16T13:39:21.546Z",
      "updatedAt": "2026-06-16T13:41:02.118Z"
    }
  ],
  "pagination": {
    "total": 134,
    "limit": 50,
    "offset": 0,
    "hasMore": true
  }
}

Use pagination.hasMore to decide whether to fetch the next page by increasing offset by your limit.

Banks & account lookup

List Nigerian banks and verify a bank account's name before saving it (e.g. to collect and confirm a payout account in your own UI). Both endpoints use your secret API key.

List banks

GEThttps://payments.afriversedao.org/api/banks

Returns the list of supported Nigerian banks with their codes.

GET https://payments.afriversedao.org/api/banks
Authorization: Bearer sk_live_...

Response

{
  "banks": [
    { "code": "044", "name": "Access Bank" },
    { "code": "035", "name": "Wema Bank" },
    { "code": "100004", "name": "OPay" }
  ]
}

Verify an account number

POSThttps://payments.afriversedao.org/api/banks/resolve

Resolves an account number + bank code to the registered account name (name enquiry).

POST https://payments.afriversedao.org/api/banks/resolve
Authorization: Bearer sk_live_...
Content-Type: application/json

{
  "accountNumber": "0123456789",
  "bankCode": "035"
}

Request body

accountNumberrequiredstringThe 10-digit NUBAN account number to verify.
bankCoderequiredstringThe bank's code from GET /api/banks (e.g. 035 for Wema).

Response

{
  "accountName": "JOHN ADEYEMI",
  "accountNumber": "0123456789",
  "bankCode": "035"
}

A 422 is returned when the account can't be verified — check the number and bank code and try again. This endpoint is rate-limited to 20 requests per minute.

Create a withdrawal

POSThttps://payments.afriversedao.org/api/withdrawal

Requests a payout to a bank account. The withdrawal is queued for processing and you'll receive a webhook when it's sent or declined.

POST https://payments.afriversedao.org/api/withdrawal
Authorization: Bearer sk_live_...
Content-Type: application/json

{
  "email": "customer@example.com",
  "accountName": "John Doe",
  "accountNumber": "0123456789",
  "bank": "GTBank",
  "amount": 15000,
  "transactionId": "your-unique-tx-id-001"
}

Request body

emailrequiredstringRecipient's email address. They'll be notified when the withdrawal is processed.
accountNamerequiredstringExact name on the bank account.
accountNumberrequiredstring10-digit NUBAN account number.
bankrequiredstringBank name. E.g. GTBank, Access Bank, OPay.
amountrequiredintegerAmount in Naira to withdraw.
transactionIdrequiredstringYour unique identifier for this withdrawal. Used for idempotency — submitting the same ID twice returns the original.

Response

{
  "id": "clx4g1h0000xyz789",
  "status": "requested",
  "amount": 15000,
  "bank": "GTBank",
  "accountNumber": "0123456789"
}

Webhooks

Settlr sends a signed POST request to your webhook URL when a payment or withdrawal status changes. Configure your webhook URLs and secrets in the dashboard settings.

Payment webhook — charge.success

{
  "event": "charge.success",
  "data": {
    "reference": "PAY-1A2B3C4D"
  }
}

Virtual account fundings fire the same charge.success event, with extra fields — match on reference:

{
  "event": "charge.success",
  "data": {
    "reference": "va3f9c2a1b8d4e6f0...",
    "amount": 25000,
    "accountNumber": "7824822527",
    "provider": "flutterwave",
    "providerTxId": "chg_Hq4oBRTJ4r"
  }
}

Withdrawal webhook

{
  "transactionId": "your-unique-tx-id-001",
  "amount": 15000,
  "status": "sent"   // or "declined"
}

Verifying signatures

Every webhook request includes a signature header. Always verify it before processing the event.

Payment webhook — header: x-nexgen-signature

import { createHmac } from "crypto";

function verifyPaymentWebhook(rawBody: string, signature: string, secret: string) {
  const expected = createHmac("sha512", secret)
    .update(rawBody)
    .digest("hex");
  return signature === expected;
}

Withdrawal webhook — header: x-nexgen-withdrawal-signature

import { createHmac } from "crypto";

function verifyWithdrawalWebhook(rawBody: string, signature: string, secret: string) {
  const expected = createHmac("sha512", secret)
    .update(rawBody)
    .digest("hex");
  return signature === expected;
}
Always verify signatures. Never credit a user or fulfill an order based on a webhook that hasn't been verified. Treat all webhooks as idempotent — the same event may be delivered more than once.

Responding to webhooks

Return a 200 status as quickly as possible. Do your processing asynchronously — if your endpoint takes too long or returns a non-2xx status, delivery may be retried.

Errors

All errors return a JSON object with an error field describing the problem.

StatusMeaning
400Bad request — a required field is missing or malformed.
401Unauthorized — your API key is missing or invalid.
403Forbidden — your key doesn't have permission for this action.
404Not found — the requested resource doesn't exist.
409Conflict — a resource with this ID already exists (e.g. duplicate transactionId).
429Rate limited — slow down and retry after a short delay.
500Server error — something went wrong on our end. Contact support if it persists.
// Example error response
{
  "error": "amount is required and must be a positive integer"
}