STATIRADeveloper documentation
Get API keys

Statira API

Build payments
that settle perfectly.

Use Statira's REST API to create hosted payment sessions, accept cards, bank transfers and USSD, and confirm every transaction from your server.

REST APIJSONHTTPS only
01 · AUTHENTICATION

Keep secret keys on your server

Every gateway request requires the public and secret keys created in your Statira Business dashboard. Send them using X-Public-Key and X-Secret-Key. Never expose the secret key in browser or mobile code.

Security ruleCall the Statira API from your backend. Your frontend should only receive the hosted checkout URL returned by your backend.
E-COMMERCE CONNECTIONS

Connect your store securely

  1. Sign in to the merchant dashboard for TEST or LIVE. Open Settings → Create API key and choose the permissions your store needs.
  2. For wallet transfers, select wallet.payout and wallet.view. Configure the calling server’s IP whitelist on the key.
  3. Your store starts hosted login with URL-encoded site_url and redirect_url. The merchant signs in and selects the API key to connect.
  4. Exchange the returned zijelapay_connect_code from your server at POST /api/v1/ecommerce/connect/exchange. The code expires after five minutes and is single-use.
  5. Store data.opaqueKey securely and send it as X-Ecommerce-Key to e-commerce endpoints. It inherits the selected key’s permissions, IP restrictions, and environment.

An e-commerce key is separate from a public/secret-key pair or partner onboarding credentials. It must never be embedded in browser code.

Download the full key-generation and integration guide

E-COMMERCE CHECKOUT

Create a checkout with your e-commerce key

Your server sends its zec_... key as X-Ecommerce-Key. The underlying API key needs payment.create and payment.verify. Keep the key on your server.

POST/api/v1/ecommerce/payments/intents
curl --request POST \
  --url 'https://api.paywithstatira.com/api/v1/ecommerce/payments/intents' \
  --header "X-Ecommerce-Key: $STATIRA_ECOMMERCE_KEY" \
  --header 'Content-Type: application/json' \
  --data '{
    "merchantReference": "ORDER-1001",
    "amountMinor": 250000,
    "currencyCode": "NGN",
    "customerEmail": "customer@example.com",
    "customerName": "Jane Doe",
    "description": "Payment for order ORDER-1001",
    "callbackUrl": "https://shop.example.com/payment/callback"
  }'

250000 represents ₦2,500.00. Save your order reference, data.id, and data.reference, then redirect the customer to the exact data.hostedCheckoutUrl returned. Sessions default to 60 minutes; sessionDurationMinutes can override this within 5–1440 minutes. Inspect data.amountQuotes for the fees and final charge.

Optional feeBearer accepts CUSTOMER or MERCHANT; omitting it uses configured fee handling. For testing, use https://api.dev.paywithstatira.com with a TEST connection key.

Verify the transaction before fulfilment

The HTTPS callbackUrl receives the browser return with reference, status, and your merchantReference when provided. Verify the reference from your server; browser parameters alone are not proof of payment.

GET/api/v1/ecommerce/payments/verify/{reference}
curl --request GET \
  --url 'https://api.paywithstatira.com/api/v1/ecommerce/payments/verify/TXN_REPLACE_WITH_TRANSACTION_REFERENCE' \
  --header "X-Ecommerce-Key: $STATIRA_ECOMMERCE_KEY"

Use the TXN_... transaction reference, not the ALT_... intent reference, intent UUID, or order reference. Read data.transaction.status, data.transaction.internalReference, data.transaction.merchantReference, and data.transaction.capturedAmountMinor. Confirm SUCCESS and reconcile the order and expected charge before fulfilment. Process each order once.

A validated payment webhook can also confirm payment when the customer closes the browser. The callback URL is not a webhook endpoint.

Download the e-commerce keys and checkout guide

PARTNER INTEGRATIONS

Onboard and track your merchants

Use X-Partner-Id and X-Partner-Key with credentials issued by Statira for your environment. Partner keys manage your linked merchants; they do not authorize wallet spending.

  1. Call POST /api/v1/partners/merchants with a stable externalUserId, owner details, and business details. Save data.merchant.id.
  2. If the owner already has a Statira merchant, use /api/v1/partners/merchants/link-requests and complete owner OTP consent. A different business under the same owner email needs resolution with Statira.
  3. Upload the CAC certificate and representative identity to /api/v1/partners/merchants/{externalUserId}/kyc/documents. Both must be approved; proof of business address is optional for now.
  4. Complete the KYC profile and required related parties, check the KYC case for missing requirements, then submit it for review.
  5. Configure an email and signed webhook at PUT /api/v1/partners/notifications to receive merchant.approved. Use the event’s external user ID to update your seller.

Download the partner onboarding API guide · Approval webhook and email contract

02 · ENVIRONMENTS

Test first, then go live

Testhttps://api.dev.paywithstatira.comUse TEST-mode API keys
Livehttps://api.paywithstatira.comUse LIVE-mode API keys

Amounts are integers in the currency's smallest unit. For NGN, 250000 represents ₦2,500.00.

FEE QUOTES

Show the fee before confirmation

Quote the base amount before creating a payment or payout. Use CARD, BANK_TRANSFER, USSD, or PAYOUT as the rail, and a positive integer amountMinor.

POST/api/v1/gateway/fees/quote
curl --request POST \
  --url https://api.paywithstatira.com/api/v1/gateway/fees/quote \
  --header 'Content-Type: application/json' \
  --header 'X-Public-Key: pk_live_your_key' \
  --header 'X-Secret-Key: sk_live_your_key' \
  --data '{"rail":"BANK_TRANSFER","amountMinor":50000}'
RESPONSEIllustrative fee; merchant pricing varies
{
  "success": true,
  "message": "Fee quote calculated",
  "data": { "totalFeeAmountMinor": 500 },
  "meta": {},
  "correlationId": "example-correlation-id"
}

Collection quotes require payment.create; payout quotes require wallet.payout. Use environment-matched keys. E-commerce integrations send the same body to /api/v1/ecommerce/fees/quote with X-Ecommerce-Key.

  • The response contains only totalFeeAmountMinor. It does not create a transaction, reserve funds, or guarantee a price.
  • For a ₦500 order and a ₦5 quote, CUSTOMER pays ₦505 before provider charges; MERCHANT collects ₦500 and receives ₦495. Set feeBearer on the intent, not the quote request.
  • Intent amountQuotes give the rail breakdown. After generating payment instructions, display expectedAmountMinor as the final transfer amount; a provider may add a processing charge.
  • A payout quote gives the total fee you will pay. A ₦1,000 payout with a ₦30 fee needs ₦1,030 in the wallet; the beneficiary receives ₦1,000.
  • Requote when the amount or rail changes. Example fees are not a fixed tariff.
03 · CREATE A PAYMENT

Create a hosted checkout session

Create an intent from your server. Use a unique Idempotency-Key for each order so network retries cannot create duplicate payments.

POST/api/v1/gateway/payments/intents
curl --request POST \
  --url https://api.paywithstatira.com/api/v1/gateway/payments/intents \
  --header 'Content-Type: application/json' \
  --header 'X-Public-Key: pk_live_your_key' \
  --header 'X-Secret-Key: sk_live_your_key' \
  --header 'Idempotency-Key: order_84392' \
  --data '{
    "merchantReference": "order_84392",
    "amountMinor": 250000,
    "currencyCode": "NGN",
    "customerEmail": "customer@example.com",
    "customerName": "Ada Okafor",
    "description": "Order #84392",
    "feeBearer": "CUSTOMER",
    "callbackUrl": "https://yourapp.com/payments/complete"
  }'

The response includes reference, checkoutSessionToken, amountQuotes, hostedCheckoutUrl, status and expiresAt. Redirect your customer to hostedCheckoutUrl for the recommended integration.

An intent is not a bank accountCreating an intent prepares the checkout. A temporary bank account is generated only after bank transfer is initiated on that checkout.
04 · GENERATE A BANK ACCOUNT

Build a custom bank-transfer interface

Most merchants should use hostedCheckoutUrl. If you are building your own checkout UI, your backend takes the intent reference and initiates BANK_TRANSFER using the same public and secret API keys. The intent must belong to that merchant and key environment.

POST/api/v1/gateway/payments/intents/{intentReference}/pay
curl --request POST \
  --url https://api.paywithstatira.com/api/v1/gateway/payments/intents/ALT_1789416000000/pay \
  --header 'Content-Type: application/json' \
  --header 'X-Public-Key: pk_live_your_key' \
  --header 'X-Secret-Key: sk_live_your_key' \
  --data '{
    "customerName": "Ada Okafor",
    "customerEmail": "customer@example.com",
    "paymentMethod": "BANK_TRANSFER",
    "metadata": {
      "orderId": "order_84392"
    }
  }'

The response creates a transaction and returns its internalReference. Parse nextActionDataJson once to read accountNumber, accountName, bankName, expectedAmountMinor, providerFeeAmountMinor, currencyCode, expiresAt and instructions.

Display the authoritative amountAsk the customer to transfer exactly expectedAmountMinor. Do not display the original base amount or calculate provider charges locally.
  • Keep internalReference for authenticated verification.
  • Do not generate multiple accounts by repeatedly submitting the same checkout.
  • Wait for the signed webhook or verify from the backend; a customer saying they paid is not proof of payment.
05 · FEE HANDLING

Choose who pays per checkout

Set feeBearer to CUSTOMER or MERCHANT when creating the intent. Omit it only when you want the merchant's configured default for the selected rail.

  • CUSTOMER: customer pays the base amount plus the Statira fee; the merchant receives the base amount.
  • MERCHANT: customer pays the base amount; the Statira fee is deducted from the merchant wallet credit.
  • feeAmountMinor in each quote is the Statira fee. totalAmountMinor is the pre-provider customer total.
  • After account generation, expectedAmountMinor is the final amount because the provider may add its own processing charge.
06 · VERIFY A PAYMENT

Confirm before delivering value

Always verify a transaction from your backend using its TXN_ internal transaction reference. The ALT_ intent reference is for payment initiation and returns 404 on verification. Do not rely only on the customer's browser redirect.

GET/api/v1/gateway/payments/verify/{reference}
curl --request GET \
  --url https://api.paywithstatira.com/api/v1/gateway/payments/verify/TXN_ABC123 \
  --header 'X-Public-Key: pk_live_your_key' \
  --header 'X-Secret-Key: sk_live_your_key'

Read data.transaction.status from the response and verify the merchant reference and amounts before fulfilment. Only fulfil an order once its verified status is SUCCESS.

If a payment is PENDING, wait for an update or verify it again using the same transaction reference. Do not generate a replacement account simply because notification is delayed. If the customer has paid but the status remains pending, contact support with the transaction reference and response correlation ID.

For a custom bank-transfer or USSD checkout, an “I have paid” button can call POST /api/v1/public/checkout/status/{transactionReference}/confirm with no body to request an immediate check. It checks the existing payment and may still return PENDING. Hosted checkout handles this action; authenticated verification remains required before fulfilment.

07 · WEBHOOKS

Receive payment updates

Add an HTTPS webhook endpoint to an API key in Statira Business. Statira delivers payment.updated when a transaction changes. Verify the signature and durably accept the event before returning HTTP 2xx; heavier work can run asynchronously. Failed deliveries are retried up to three attempts.

EVENTpayment.updated
{
  "event": "payment.updated",
  "reference": "TXN_ABC123",
  "merchantReference": "order_84392",
  "status": "SUCCESS",
  "mode": "LIVE",
  "amountMinor": 250500,
  "baseAmountMinor": 250000,
  "feeBearer": "CUSTOMER",
  "feeAmountMinor": 500,
  "netAmountMinor": 250000,
  "currencyCode": "NGN",
  "paymentMethod": "BANK_TRANSFER",
  "providerCode": "EMBEDLY",
  "providerReference": "provider-reference",
  "failureCode": null,
  "failureMessage": null
}

Collection statuses are CREATED, PENDING, PROCESSING, SUCCESS, FAILED, CANCELLED, EXPIRED, and REFUNDED. Only SUCCESS authorizes fulfilment.

EVENTpayout.updated
{
  "event": "payout.updated",
  "reference": "PAYOUT_1789416000000",
  "status": "SUCCESS",
  "mode": "LIVE",
  "amountMinor": 100000,
  "feeAmountMinor": 500,
  "netAmountMinor": 100000,
  "currencyCode": "NGN",
  "providerCode": "FLUTTERWAVE",
  "providerReference": "provider-payout-reference",
  "failureCode": null,
  "failureMessage": null
}

Payout statuses are PENDING, SUCCESS, and FAILED. The wallet debit is amountMinor + feeAmountMinor; amountMinor is sent to the beneficiary.

EVENTwallet.funded
{
  "event": "wallet.funded",
  "reference": "FUND_033511da032646d2a42f30d8f869b9b1",
  "providerReference": "provider-transaction-reference",
  "status": "SUCCESS",
  "mode": "LIVE",
  "amountMinor": 100000,
  "currencyCode": "NGN",
  "balanceAfterMinor": 350000
}

wallet.funded is sent only when a bank transfer has credited your Statira wallet. balanceAfterMinor is the balance immediately after the credit.

  • Verify X-Zijelapay-Signature as hex HMAC-SHA256 over the exact raw body using the endpoint secret.
  • Collection and payout scopes have separate URLs and signing secrets.
  • Handle repeated deliveries idempotently. An earlier PENDING event must not suppress a later SUCCESS for the same reference. Deduplicate fulfilment by transaction reference and process status changes.
  • Fetch collections from the authenticated verify endpoint before fulfilling an order.
PAYOUT BENEFICIARIES

Verify the account before transferring

With bank.verify, first call GET /api/v1/gateway/payouts/banks?countryCode=NG&currencyCode=NGN. Use a bank code returned by that directory; do not assume codes from another provider are interchangeable.

POST/api/v1/gateway/payouts/accounts/verify
curl --request POST \
  --url https://api.paywithstatira.com/api/v1/gateway/payouts/accounts/verify \
  --header 'Content-Type: application/json' \
  --header 'X-Public-Key: pk_live_your_key' \
  --header 'X-Secret-Key: sk_live_your_key' \
  --data '{"bankCode":"000013","accountNumber":"0123456789"}'

The response data contains bankCode, accountNumber, accountName, countryCode, currencyCode, and verified. Show the verified account name for confirmation, then use those details for the payout.

E-commerce equivalents are GET /api/v1/ecommerce/payouts/banks and POST /api/v1/ecommerce/payouts/accounts/verify, authenticated with X-Ecommerce-Key.

08 · CREATE A PAYOUT

Transfer from a merchant wallet

Use a key matching the server environment with the wallet.payout permission: TEST on dev and LIVE on production. Every payout requires a unique Idempotency-Key; repeating the same key safely returns the original payout.

POST/api/v1/gateway/payouts
curl --request POST \
  --url https://api.paywithstatira.com/api/v1/gateway/payouts \
  --header 'Content-Type: application/json' \
  --header 'X-Public-Key: pk_live_your_key' \
  --header 'X-Secret-Key: sk_live_your_key' \
  --header 'Idempotency-Key: payout_order_84392' \
  --data '{
    "destinationBankCode": "000013",
    "destinationBankName": "GTBank",
    "destinationAccountName": "Ada Okafor",
    "destinationAccountNumber": "0123456789",
    "amountMinor": 250000,
    "narration": "Vendor settlement"
  }'

Quote PAYOUT first and ensure the available wallet balance covers amountMinor + totalFeeAmountMinor. The payout response reports the actual total fee in feeAmountMinor. Both amountMinor and netAmountMinor are the beneficiary amount.

Statira prefixes narration with your business name, for example Amina Stores/Vendor settlement. Send only the descriptive part. Blank narration uses Payout.

Server-side onlyPayout credentials must never be embedded in browser or mobile applications. IP-whitelist the servers permitted to initiate transfers.
PAYOUT STATUS & RECOVERY

Recover a timeout without a second transfer

Read GET /api/v1/gateway/payouts/{payoutReference} using the PAYOUT_ reference. If the create request timed out before you received a reference, look up its original idempotency key:

GET/api/v1/gateway/payouts/by-idempotency-key/{idempotencyKey}
curl --request GET \
  --url https://api.paywithstatira.com/api/v1/gateway/payouts/by-idempotency-key/payout_order_84392 \
  --header 'X-Public-Key: pk_live_your_key' \
  --header 'X-Secret-Key: sk_live_your_key'

These routes require wallet.payout and return only payouts belonging to the authenticated merchant. E-commerce callers use /api/v1/ecommerce/payouts/... with X-Ecommerce-Key. URL-encode the key in a lookup path.

  • 404 means no matching payout has been persisted. If the first request may still be running, wait and repeat the lookup.
  • Retry the same logical request with the same key. A new key can create another transfer.
  • While a payout is PENDING, wait for a webhook or check its status again. Do not submit a replacement transfer.
  • SUCCESS settles the hold; FAILED releases the reserved amount and fees. Process payout.updated and refresh the wallet balance after resolution.
09 · WALLET BALANCE

Read the authoritative Statira balance

Use either authentication method from your backend. The wallet-transfer release also returns walletId, equal to id, for saving in your application. The response includes availableBalanceMinor, pendingBalanceMinor, totalCreditedMinor, and totalDebitedMinor.

GET/api/v1/gateway/wallet
curl --request GET \
  --url https://api.paywithstatira.com/api/v1/gateway/wallet \
  --header 'X-Public-Key: pk_live_your_key' \
  --header 'X-Secret-Key: sk_live_your_key'
GET/api/v1/ecommerce/wallet
curl --request GET \
  --url https://api.paywithstatira.com/api/v1/ecommerce/wallet \
  --header 'X-Ecommerce-Key: zec_your_key'

E-commerce connections use the same payout request body through their own authenticated endpoint:

POST/api/v1/ecommerce/payouts
curl --request POST \
  --url https://api.paywithstatira.com/api/v1/ecommerce/payouts \
  --header 'Content-Type: application/json' \
  --header 'X-Ecommerce-Key: zec_your_key' \
  --header 'Idempotency-Key: payout_order_84392' \
  --data '{
    "destinationBankCode": "000013",
    "destinationBankName": "GTBank",
    "destinationAccountName": "Ada Okafor",
    "destinationAccountNumber": "0123456789",
    "amountMinor": 250000,
    "narration": "Vendor settlement"
  }'
WALLET-TO-WALLET TRANSFERS

Send funds to another Statira merchant

Dashboard and APISend free wallet transfers from the merchant dashboard or integrate these endpoints from your server.

Transfers are free, immediate on success, and available through the dashboard or your server-side application. Both merchants must be active and approved, and both wallets must use the same currency.

Save data.walletId from GET /api/v1/gateway/wallet with the merchant and environment. The existing data.id remains the same identifier. A Statira wallet ID is different from a bank account number.

GET/api/v1/gateway/wallet/transfers/recipient/{walletId}

Returns walletId, businessName and currencyCode. Requires wallet.payout.

POST/api/v1/gateway/wallet/transfers

Requires wallet.payout and Idempotency-Key. Supply recipientWalletId, amountMinor and optional narration (maximum 140 characters).

GET/api/v1/gateway/wallet/transfers/{reference}

Requires wallet.view. Only the sending or receiving merchant can retrieve a receipt.

Authenticate with both X-Public-Key and X-Secret-Key from an IP-whitelisted server. These gateway routes do not accept an e-commerce connection key or dashboard bearer token.

POST BODY/api/v1/gateway/wallet/transfers
{
  "recipientWalletId": "33333333-3333-4333-8333-333333333333",
  "amountMinor": 50000,
  "narration": "Invoice 123"
}

For NGN, 50000 means ₦500.00. Confirm the recipient name before sending. HTTP 200 returns a SUCCESS receipt containing reference, senderWalletId, recipientWalletId, amountMinor, currencyCode and narration inside data.

  • Persist the request and Idempotency-Key before sending. After a timeout, retry the identical request with the same key.
  • The same key returns the original receipt. Changed details return HTTP 409.
  • Self-transfers, insufficient funds, and mismatched currencies are rejected.
  • No wallet-transfer webhook or automatic reversal is provided in this version. Confirm using the response or verification endpoint.
E-commerce keys also supportedUse X-Ecommerce-Key with /api/v1/ecommerce/wallet/transfers, /recipient/{walletId}, and /{reference}. Payloads, permissions, and idempotency rules are identical to the gateway routes.

Download the developer integration guide · Download the OpenAPI contract for Postman

10 · API REFERENCE

Core gateway endpoints

POST/api/v1/gateway/fees/quote

Quote collection or payout fees before confirmation.

POST/api/v1/ecommerce/fees/quote

Quote fees using an e-commerce key.

GET/api/v1/gateway/payouts/banks

List supported beneficiary bank codes.

POST/api/v1/gateway/payouts/accounts/verify

Verify the beneficiary account name.

GET/api/v1/gateway/payouts/{payoutReference}

Read payout status.

GET/api/v1/gateway/payouts/by-idempotency-key/{idempotencyKey}

Recover a payout reference after a timeout.

POST/api/v1/gateway/payments/intents

Create a payment intent and hosted checkout session.

POST/api/v1/gateway/payments/intents/{intentReference}/pay

Authenticate and initiate a rail to generate bank-transfer instructions.

GET/api/v1/gateway/payments/verify/{reference}

Retrieve the latest verified transaction state.

POST/api/v1/gateway/payouts

Transfer funds from the authenticated merchant wallet.

GET/api/v1/gateway/wallet

Read wallet balances using public and secret keys.

POST/api/v1/ecommerce/payments/intents

Create hosted checkout using an e-commerce key.

GET/api/v1/ecommerce/payments/verify/{reference}

Verify a checkout transaction using its TXN reference.

GET/api/v1/ecommerce/wallet

Read wallet balances using an e-commerce key.

POST/api/v1/ecommerce/payouts

Create a payout using an e-commerce key.

Bank directory lookup and account verification require bank.verify for both gateway and e-commerce keys. This permission cannot send payouts or wallet transfers. All existing merchant API keys receive verification access once during rollout; for a verification-only integration, grant bank.verify and remove wallet.payout. Gateway permissions are assigned per key: payment.create, payment.verify, wallet.view, and wallet.payout. Use TEST keys to test your integration and LIVE keys to accept real payments.

11 · ERRORS

Handle errors predictably

400Invalid request
401Invalid credentials
403Permission or IP denied
404Resource not found
409Conflicting request
5xxRetry safely

Log the response's correlation identifier when contacting support. Retry temporary failures with exponential backoff and reuse the same idempotency key.

Developer support

Need help with an integration?

Tell us what you're building and include the request correlation ID where available.

support@zijela.com