Skip to content

Payments API

Endpoints

Method Path Scope Description
POST /v1/payments payments:write Create a payment
GET /v1/payments payments:read List & filter transactions
GET /v1/payments/{id} payments:read Get payment status
POST /v1/payments/{id}/capture payments:write Capture PayPal order
POST /v1/payments/mpesa/check-status/{code} payments:read Check M-Pesa transaction
POST /v1/payments/mpesa/reconcile payments:write Pull missed M-Pesa transactions
POST /v1/payments/mpesa/register-pull payments:write Register for Pull API
POST /v1/payments/cards payments:write Save a card
GET /v1/payments/cards payments:read List saved cards
DELETE /v1/payments/cards/{id} payments:write Delete a saved card

Response Envelope

All responses follow this format:

{
  "success": true,
  "data": { ... },
  "meta": { "page": 1, "page_size": 50, "total": 120 }
}

Payment Object

{
  "id": "a1b2c3d4-...",
  "merchant_id": "m1m2m3-...",
  "amount": "50.00",
  "currency": "USD",
  "provider": "stripe",
  "status": "completed",
  "provider_ref": "pi_3abc...",
  "idempotency_key": "order-123",
  "created_at": "2025-01-01T12:00:00Z"
}

Payment Statuses

stateDiagram-v2
    [*] --> pending: Payment created
    pending --> completed: Provider confirms success
    pending --> failed: Provider declines / error
    completed --> refunded: Stripe/PayPal refund
    completed --> reversed: M-Pesa reversal
    failed --> [*]
    refunded --> [*]
    reversed --> [*]

List & Filter Transactions

GET /v1/payments
X-API-Key: sk_live_...

Transactions are automatically scoped to the authenticated merchant.

Query Parameters

Param Type Example Description
status string completed Filter by status: pending, completed, failed, reversed, refunded
provider string mpesa Filter by provider: stripe, mpesa, paypal
currency string KES Filter by 3-letter ISO currency code
min_amount decimal 100 Minimum transaction amount (inclusive)
max_amount decimal 5000 Maximum transaction amount (inclusive)
since datetime 2025-01-01T00:00:00Z Transactions created after this date (ISO 8601)
until datetime 2025-01-31T23:59:59Z Transactions created before this date (ISO 8601)
search string NEF61H8J60 Search by M-Pesa receipt number or idempotency key
page int 1 Page number (default: 1)
page_size int 50 Items per page (default: 50, max: 100)

Examples

All completed M-Pesa payments this month

GET /v1/payments?status=completed&provider=mpesa&since=2025-06-01T00:00:00Z

High-value failed transactions

GET /v1/payments?status=failed&min_amount=10000

Search by M-Pesa receipt number

GET /v1/payments?search=NEF61H8J60

Stripe payments between $50 and $500

GET /v1/payments?provider=stripe&min_amount=50&max_amount=500&currency=USD

Response

{
  "success": true,
  "data": [
    {
      "id": "a1b2c3d4-...",
      "merchant_id": "m1m2m3-...",
      "amount": "500.00",
      "currency": "KES",
      "provider": "mpesa",
      "status": "completed",
      "provider_ref": "NEF61H8J60",
      "idempotency_key": "order-456",
      "created_at": "2025-06-15T10:30:00Z"
    },
    {
      "id": "e5f6g7h8-...",
      "merchant_id": "m1m2m3-...",
      "amount": "1200.00",
      "currency": "KES",
      "provider": "mpesa",
      "status": "completed",
      "provider_ref": "QKJ82BXRT5",
      "idempotency_key": "order-789",
      "created_at": "2025-06-14T08:15:00Z"
    }
  ],
  "meta": {
    "page": 1,
    "page_size": 50,
    "total": 127
  }
}

Empty Result

{
  "success": true,
  "data": [],
  "meta": {
    "page": 1,
    "page_size": 50,
    "total": 0
  }
}

Idempotency

The Idempotency-Key header is required on POST /v1/payments. If the same key is sent twice:

  • Same merchant → returns the original payment (no duplicate charge)
  • Different merchant → returns 409 CONFLICT

Error Codes

Code HTTP When
VALIDATION_ERROR 422 Missing fields, invalid provider, or credentials not configured
CONFLICT 409 Duplicate idempotency key, or payment in wrong status for operation
NOT_FOUND 404 Payment ID not found or doesn't belong to merchant