Developers · Documentation

NunuaPay API documentation

Base URL: https://pay.nunuanow.com/v1. A versioned REST API with scoped API keys, idempotent payment creation, server-side verification and signed outbound webhooks.

Authentication

  • Dashboard / management endpoints use a Bearer JWT from /v1/auth/login or /v1/auth/register.
  • Integration endpoints use a scoped API key: Authorization: Bearer nup_test_<lookup>_<secret> or nup_live_….
  • Some read endpoints accept either credential.

Every API key carries scopes, an environment (test or live), optional branchRestrictions and methodRestrictions. The secret is returned once at creation or rotation and can never be retrieved again.

Businesses, branches and identifiers

A Business ID identifies your tenant. A Branch ID identifies a location inside exactly one business. Provider credentials are configured once per business and inherited by branches; method availability can be overridden per branch.

A branch-scoped API key includes the branch in branchRestrictions and must always send that branchId; the API rejects a missing or different branch.

Create a payment intent

curl -X POST https://pay.nunuanow.com/v1/payment-intents \\
  -H "Authorization: Bearer nup_live_<lookup>_<secret>" \\
  -H "Idempotency-Key: order-1001" \\
  -H "Content-Type: application/json" \\
  -d '{
    "businessId": "<businessId>",
    "branchId": "<branchId>",
    "method": "card",
    "amount": 100,
    "currency": "KES",
    "email": "customer@example.com",
    "merchantRef": "ORDER-1001"
  }'

amount is an integer in minor units (whole shillings for KES). An optional provider pins routing when several providers offer the same method — still constrained to the key’s business, environment and configured routing.

Verify status

Never trust the browser return. POST /v1/payment-intents/:id/verify re-checks the transaction with the provider server-side. Only a succeeded status means the customer paid.

Idempotency

Payment and refund creation require an Idempotency-Key header ([A-Za-z0-9_\-:.]{8,128}). Repeating a key with an identical request returns the original resource; reusing it with a different body returns 409 idempotency_conflict.

Endpoints

Businesses & branches

  • GET /v1/businesses, POST /v1/businesses, GET|PATCH /v1/businesses/:id
  • GET|POST /v1/businesses/:id/branches, GET|PATCH /v1/businesses/:id/branches/:branchId
  • GET /v1/businesses/:id/branches/:branchId/api-setup — identifiers, callback URLs, eligible methods
  • GET|POST /v1/businesses/:id/members

Providers & methods

  • GET|POST /v1/businesses/:id/providers, POST /v1/providers/:accountId/test
  • GET|POST /v1/businesses/:id/payment-method-configs
  • GET /v1/payment-methods?businessId=&branchId=&currency=

Payment lifecycle

  • POST /v1/payment-intents, GET /v1/payment-intents, GET /v1/payment-intents/:id
  • GET /v1/payment-intents/:id/attempts
  • POST /v1/payment-intents/:id/cancel, POST /v1/payment-intents/:id/verify

Refunds

  • POST /v1/refunds, GET /v1/refunds, GET /v1/refunds/:id — where the provider supports refunds.

Webhooks

  • POST|GET /v1/webhook-endpoints, PATCH|DELETE /v1/webhook-endpoints/:id, POST /v1/webhook-endpoints/:id/test

Reports & reconciliation

  • GET /v1/transactions, GET /v1/transactions/export
  • GET /v1/reports/summary, GET /v1/reconciliation, POST /v1/reconciliation/run

Payment statuses

created, requires_action, processing, pending, succeeded, failed, cancelled, expired. Treat only succeeded as paid.

Error codes

Auth
unauthenticated, invalid_api_key, api_key_revoked, api_key_expired, api_key_scope_denied
Request
validation_error, invalid_amount, unsupported_currency, invalid_idempotency_key, idempotency_conflict
Resource
not_found, conflict, invalid_state
Provider
provider_not_configured, provider_disabled, provider_unavailable, method_not_available, provider_error, provider_timeout
Lifecycle
payment_already_succeeded, payment_already_terminal, refund_exceeds_available, refund_not_supported
Security
invalid_signature, replay_detected, ssrf_blocked
System
rate_limited, internal

All errors share the envelope { "error": { "code", "message" } }.

Money

Amounts are integer minor units (KES shillings; USD/EUR/GBP cents). The API never uses floating point for money.

Test versus live

Test keys operate against provider test environments; live keys move real money. A live payment intent cannot be created with a test key. Use test credentials and provider sandboxes to run the full flow before going live.

Next steps