PA

PayAssure

Developer Dashboard

What the tokens mean

Settlement credentials are separate and are not interchangeable.

CredentialSourceHeader / use
User access JWT/auth/login or /auth/refreshAuthorization Bearer; platform identity
Retailer settlement session/settlement/authenticate tokenx-settlement-session; retailer initiation for 1 hour
Supplier session/supplier/authenticate sessionTokenx-supplier-session; supplier lookup
Internal gateway tokenPAYMENT_GATEWAY_API_TOKEN, then SETTLEMENT_API_TOKEN, then INTERNAL_GATEWAY_TOKENAuthorization Bearer; internal confirmation
Internal signature secretPAYMENT_GATEWAY_SIGNATURE_SECRET, then SETTLEMENT_SIGNATURE_SECRET, then PAYASSURE_INTERNAL_SECRETCreates x-payassure-signature
B2B gateway tokenB2B_GATEWAY_API_TOKEN, then PAYMENT_GATEWAY_API_TOKEN, then SETTLEMENT_API_TOKENServer-to-gateway only; not client-facing

Retailer session

The session has the session_... format, expires after 3600 seconds by default, and has ACTIVE, REVOKED, or EXPIRED status. Active sessions can be reused for multiple initiation requests until expiry or revocation; each use updates lastUsedAt.

Supplier session

The supplier session also expires after 3600 seconds and is sent only to GET /supplier/settlements.

Recommended flow

  1. Create or complete retailer and supplier onboarding records.
  2. Verify payout destinations and generate API credentials.
  3. Log in to obtain a user accessToken.
  4. Authenticate the retailer to obtain a settlement session.
  5. Initiate the settlement with both user JWT and settlement session.
  6. Wait for a provider callback or send authenticated internal confirmation.
  7. Dispatch payouts, receive callbacks, track, retry, and reconcile.

Common errors and settlement statuses

Validation error

{
  "statusCode": 400,
  "message": ["totalAmount must not be less than 0.01"],
  "error": "Bad Request",
  "path": "/settlement/initiate-settlement"
}

Business error

{
  "statusCode": 401,
  "message": "Invalid or expired one-time token",
  "error": "INVALID_TOKEN"
}

Validation errors with field details

{
  "statusCode": 400,
  "message": "Validation failed",
  "error": "VALIDATION_ERROR",
  "errors": [{ "field": "suppliers[0].supplierMerchantId", "message": "Supplier was not found in PayAssure" }]
}
StatusMeaning
INITIATEDRequest accepted; payment may be pending or retryable gateway failure held.
PENDING_PROCESSINGPayment callback or confirmation accepted; allocation is beginning.
PROCESSINGLedger allocation or payout processing is underway.
PROCESSING_COMPLETEProcessing stage completed where used downstream.
AWAITING_RECONCILIATIONWaiting for bank or financial reconciliation.
COMPLETEDSettlement reconciled and completed.
PROCESSING_FAILED / FAILEDDownstream processing failed or failed permanently.
POST/settlement/authenticate

1. Authenticate a retailer integration

Verifies the API key and API secret for an active retailer integration. The platform JWT email must match the onboarding participant that owns the integration.

Request

Authorization: Bearer <user_access_token>
Content-Type: application/json

{
  "apiKey": "pk_live_abc123",
  "apiSecret": "sk_live_xyz789"
}

The returned session token is reused through its 3600-second lifetime and is sent in x-settlement-session, not Authorization. Current implementation requires participant status ACTIVE; older LIVE documentation is stale.

Success response

{
  "success": true,
  "token": "session_1725900000000_0123456789abcdef",
  "expiresIn": 3600,
  "tokenType": "Bearer",
  "business": { "id": "participant-123", "businessName": "Fresh Store Ltd", "participantType": "RETAILER", "status": "ACTIVE" }
}

Errors

  • 400 Bad Request: apiKey or apiSecret is missing or has the wrong type.
  • 401 Unauthorized: user JWT is missing or invalid; the JWT email does not own the integration (INVALID_TOKEN_FOR_API_KEYS); or the secret is wrong (INVALID_CREDENTIALS).
  • 403 Forbidden: participant is not ACTIVE (BUSINESS_NOT_ACTIVE).
  • 404 Not Found: no active integration matches the API key (BUSINESS_NOT_FOUND).
POST/settlement/initiate-settlement

2. Initiate a settlement

Creates a parent settlement and supplier child settlements, validates supplier eligibility and amount allocations, and starts customer payment processing. Requires both a user JWT and retailer settlement session.

Request

Authorization: Bearer <user_access_token>
x-settlement-session: <token_from_settlement_authenticate>
Content-Type: application/json

{
  "merchantId": "pay_retailer_001",
  "merchantTransactionReference": "TXN-20260910-000001",
  "totalAmount": 16500,
  "currency": "KES",
  "settlementMethod": "BANK_TRANSFER",
  "description": "Daily sales batch",
  "paymentMethod": { "type": "MPESA", "payerPhoneNumber": "254712345678", "provider": "Safaricom" },
  "callbackUrl": "https://merchant.example.com/payassure/callback",
  "transactionDate": "2026-09-10T17:30:15+03:00",
  "metadata": { "branchId": "BR-01", "terminalId": "POS-03" },
  "suppliers": [{
    "supplierMerchantId": "pay_supplier_001",
    "supplierTotalAmount": 15000,
    "retailerTotalAmount": 1200,
    "platformFee": 300,
    "items": [{ "itemId": "ITEM-001", "itemName": "Product A", "supplierAmount": 15000, "quantity": 5, "unitPrice": 3000, "description": "Product A sales" }]
  }]
}

Required: merchantTransactionReference, totalAmount greater than 0.01, currency KES/USD/TZS, non-empty settlementMethod, paymentMethod.type, transactionDate, and at least one supplier. MPESA requires payerPhoneNumber. The total is supplier amounts plus retailer amounts plus platform fees. Item supplierAmount values are summed and must agree with supplierTotalAmount within 0.01. Duplicate references for the same retailer normally return 200 with the existing settlement. Invalid supplier groups may be excluded when at least one eligible group remains, with excludedSuppliers in the response.

Success response

{
  "success": true,
  "settlement": { "settlementId": "clxsettlement123", "merchantId": "pay_retailer_001", "status": "INITIATED", "amount": 16500, "retailerAmount": 1200, "supplierAmount": 15000, "systemAmount": 300, "currency": "KES", "reference": "PASTL-20260910083000-EE8AE32E", "createdAt": "2026-09-10T08:30:00.000Z", "estimatedProcessingTime": "24-48 hours" },
  "message": "Settlement request received and queued for processing",
  "children": [{ "id": "clxchild123", "reference": "TXN-20260910-000001-pay_supplier_001-0", "supplier": { "amount": 15000 }, "retailer": { "amount": 1200 }, "systemAmount": 300, "amount": 16500 }]
}

Errors

  • 401 INVALID_TOKEN: session not found.
  • 401 TOKEN_EXPIRED: session expiry has passed.
  • 401 SESSION_INACTIVE: session is revoked or not ACTIVE.
  • 401 INVALID_SESSION: session integration or retailer context cannot be loaded.
  • 403 RETAILER_NOT_AUTHORIZED: session is not a retailer, or retailer is not ACTIVE/LIVE.
  • 400 VALIDATION_ERROR: general validation failure with an errors array.
  • 400 NO_ELIGIBLE_SUPPLIERS: every supplier group is invalid; includes invalidSuppliers.
  • 400: unsupported currency, missing payment method, invalid timestamp, no allocations, missing MPESA payerPhoneNumber, invalid supplier integration/payout destination, or allocation totals do not match.
  • 409 Conflict: documented for duplicates, but current handling normally returns the existing settlement with 200.
  • 500 INITIATION_FAILED: unexpected persistence or processing failure.
POST/settlement/payment-callback

3. Payment provider callback

Receives a provider callback and moves the linked settlement to PENDING_PROCESSING. No JWT guard is attached because this is called by the provider or callback adapter.

Request

{
  "merchantTransactionReference": "TXN-20260910-000001",
  "status": "SUCCESS",
  "provider": "M-PESA",
  "providerReference": "MPESA-12345",
  "amount": 16500,
  "currency": "KES",
  "metadata": { "checkoutRequestId": "ws_CO_123" }
}

merchantTransactionReference is required. Other fields are optional and status defaults to SUCCESS.

Success response

{
  "success": true,
  "status": "PENDING_PROCESSING",
  "message": "Payment callback received. The settlement is now moving into ledger allocation and payout processing.",
  "settlementId": "clxsettlement123",
  "nextStep": "Create ledger entries and split the customer funds into supplier, retailer, and platform allocations.",
  "allocationPlan": { "customerReceived": 16500, "allocations": [{ "party": "Supplier", "amount": 15000, "status": "PENDING" }, { "party": "Retailer", "amount": 1200, "status": "PENDING" }, { "party": "Platform", "amount": 300, "status": "PENDING" }] }
}

Errors

  • 400 Bad Request: missing or invalid callback payload.
  • 404 SETTLEMENT_NOT_FOUND: no settlement matches the merchant transaction reference.
POST/settlement/payment-confirmation

4. Internal payment confirmation

Confirms a customer payment from the internal payment gateway and advances the settlement into allocation and payout dispatch. The legacy /settlement/internal/settlements/payment-confirmation alias runs the same logic.

Request

Authorization: Bearer <PAYMENT_GATEWAY_API_TOKEN>
x-payassure-signature: <hmac_sha256_hex>
x-payassure-timestamp: <unix_seconds>
Content-Type: application/json

{
  "settlementId": "clxsettlement123",
  "paymentId": "payment-123",
  "status": "PAID",
  "provider": "MPESA",
  "paidAmount": 16500,
  "paidAt": "2026-09-10T08:45:00.000Z",
  "providerReference": { "checkoutRequestId": "ws_CO_123", "merchantRequestId": "ws_MR_123", "receiptNumber": "QAB123456" }
}

settlementId and status are required. Only PAID is accepted for a new confirmation. Existing PENDING_PROCESSING, PROCESSING, or COMPLETED confirmations are idempotent successes. Sign JSON.stringify({ paymentId, settlementId, status, provider, paidAmount, paidAt }) with HMAC-SHA256 using the internal signature secret. Timestamp is not signed but must be Unix seconds within 300 seconds of server time.

Success response

{
  "success": true,
  "status": "PENDING_PROCESSING",
  "message": "Payment confirmation accepted. The settlement is now processing B2B payout dispatch.",
  "settlementId": "clxsettlement123",
  "nextStep": "Dispatch B2B payouts to supplier and retailer and wait for payout callbacks.",
  "allocationPlan": {},
  "dispatchResults": []
}

Errors

  • 401 UNAUTHORIZED: missing/invalid bearer token, signature secret not configured, missing signature headers, invalid signature, or expired/invalid timestamp.
  • 400 INVALID_PAYMENT_STATUS: only PAID confirmations are accepted.
  • 400 Bad Request: DTO validation failure.
  • 404 SETTLEMENT_NOT_FOUND: settlement ID or fallback reference was not found.
POST/settlement/internal/settlements/payment-confirmation

5. Legacy internal payment confirmation alias

Legacy route alias for /settlement/payment-confirmation. It uses the same gateway bearer token, HMAC signature, timestamp, payload, idempotency, response, and error behavior.

Request

Use the request and signature contract documented for endpoint 4.

Success response

Returns the same payment confirmation response documented for endpoint 4.

Errors

  • The same 401, 400, and 404 errors as /settlement/payment-confirmation.
POST/settlement/payouts/dispatch

6. Dispatch a B2B payout

Dispatches a payout to a supplier or retailer after successful customer payment confirmation. No JWT or application-token guard is currently attached; protect it at the network or API gateway layer.

Request

{
  "merchantTransactionReference": "TXN-20260910-000001",
  "party": "SUPPLIER",
  "supplierMerchantId": "pay_supplier_001",
  "amount": 15000,
  "payoutReference": "PAYOUT-REF-1",
  "metadata": { "operator": "settlement-worker" }
}

party is SUPPLIER or RETAILER and defaults to SUPPLIER. Zero or omitted amount falls back to the matching allocation. MPESA uses B2C and needs a phone; BANK uses B2B and needs shortcode and accountName. Gateway statuses are SUBMITTED, FAILED, or COMPLETED with isDuplicate true for a completed duplicate.

Success response

{
  "success": true,
  "status": "SUBMITTED",
  "payoutReference": "TXN-20260910-000001-SUPPLIER-1725900000-a1b2c3",
  "gatewayResult": { "success": true, "statusCode": 200, "responseCode": "0", "responseDescription": "Accepted", "response": {} },
  "dispatchRecord": { "reference": "TXN-20260910-000001-SUPPLIER-1725900000-a1b2c3", "party": "SUPPLIER", "status": "SUBMITTED", "amount": 15000, "callbackIdentifier": "uuid-callback-id" }
}

Errors

  • 404 PAYMENT_NOT_CONFIRMED: no successful payment callback or confirmation.
  • 400 SUPPLIER_MERCHANT_ID_REQUIRED: supplier payout has no supplier merchant ID.
  • 400 RETAILER_PAYMENT_NOT_CONFIGURED or SUPPLIER_PAYMENT_NOT_CONFIGURED.
  • 404 SUPPLIER_PAYMENT_NOT_FOUND: supplier integration or participant cannot be found.
  • 400 BANK_PAYOUT_DETAILS_INCOMPLETE or MPESA_PAYOUT_DETAILS_INCOMPLETE.
  • 400 INVALID_PAYOUT_AMOUNT: amount and allocation are both zero or negative.
  • 404 SETTLEMENT_NOT_FOUND or RETAILER_NOT_FOUND.
POST/settlement/payouts/callback

7. B2B payout callback

Provider callback route for payout status updates. No JWT is required. The service can resolve the payout using callback identifiers, merchant references, provider references, or transaction IDs.

Request

{
  "merchantTransactionReference": "TXN-20260910-000001",
  "party": "SUPPLIER",
  "supplierMerchantId": "pay_supplier_001",
  "reference": "TXN-20260910-000001-SUPPLIER-1725900000-a1b2c3",
  "status": "SUCCESS",
  "providerReference": "GW-12345",
  "transactionId": "UHHRY0DHFK",
  "amount": 15000,
  "metadata": {}
}

Provider SUCCESS or PAID maps to payout status PAID; all other statuses become FAILED. A successful callback completes the idempotency record.

Success response

{
  "success": true,
  "status": "PROCESSING",
  "settlementId": "clxsettlement123",
  "payoutCallback": { "reference": "TXN-20260910-000001-SUPPLIER-1725900000-a1b2c3", "party": "SUPPLIER", "status": "PAID", "providerReference": "GW-12345", "amount": 15000, "processedAt": "2026-09-10T09:00:00.000Z" }
}

Errors

  • 400 Bad Request: invalid callback field types or unsupported party/status.
  • 404 SETTLEMENT_NOT_FOUND: payout callback reference cannot be resolved.
POST/settlement/payouts/callback/:callbackIdentifier

8. B2B payout callback by identifier

Equivalent payout callback route using the callbackIdentifier generated in the payout request. This is the preferred lookup path.

Request

Path parameter: callbackIdentifier = callback identifier from the payout request.

Use the flat callback body documented for endpoint 7.

Success response

Returns the same payout callback response documented for endpoint 7.

Errors

  • 400 Bad Request: invalid callback payload.
  • 404 SETTLEMENT_NOT_FOUND: callback identifier cannot be resolved.
POST/settlement/payouts/callback/:callbackIdentifier/callbacks/mpesa

9. Nested M-Pesa payout callback

Equivalent payout callback route that transforms the provider M-Pesa Result payload into the internal flat callback fields.

Request

Path parameter: callbackIdentifier

{
  "Result": {
    "ResultCode": 0,
    "ResultDesc": "The service request is processed successfully.",
    "TransactionID": "UHHRY0DHFK",
    "OriginatorConversationID": "oc-123",
    "ConversationID": "c-123"
  }
}

Success response

Returns the same payout callback response documented for endpoint 7. ResultCode 0 becomes SUCCESS; any other result code becomes FAILED.

Errors

  • 400 Bad Request: invalid provider callback payload.
  • 404 SETTLEMENT_NOT_FOUND: callback identifier or fallback reference cannot be resolved.

Supplier, tracking, and operations

GET/supplier/settlements

10. List supplier settlements

Returns settlement summaries allocated to the supplier identified by the supplier session token.

Request

x-supplier-session: <sessionToken_from_supplier_authenticate>

Success response

{
  "success": true,
  "count": 1,
  "data": [{ "reference": "TXN-20260910-000001-pay_supplier_001-0", "merchantTransactionReference": "MTXN-20260910083000-A1B2C3", "amount": 15000, "status": "INITIATED", "retailerMerchantId": "pay_retailer_001", "itemReference": "ITEM-001" }]
}

Errors

  • 401 INVALID_SUPPLIER_SESSION: missing, unknown, or invalid session context.
  • 401 SUPPLIER_SESSION_EXPIRED: session expiry has passed.
  • 403 NOT_A_SUPPLIER_SESSION: session belongs to a non-supplier integration.
GET/settlement/track/:settlementId

11. Track a settlement

Returns settlement status, amounts, timeline, customer payment, supplier allocations, and transactions. Requires a platform user JWT. HTTP callers receive the default retailer view because the controller view parameter is not decorated with @Query.

Request

Authorization: Bearer <user_access_token>
Content-Type: application/json

Path parameter: settlementId

The service also supports retailer, supplier, and payassure views when called internally.

Success response

{
  "success": true,
  "view": "retailer",
  "settlement": { "settlementId": "clxsettlement123", "reference": "PASTL-20260910083000-EE8AE32E", "merchantTransactionReference": "MTXN-20260910083000-A1B2C3", "status": "PROCESSING", "currency": "KES", "createdAt": "2026-09-10T08:30:00.000Z", "processedAt": null, "estimatedCompletionTime": "2026-09-12T08:30:00.000Z", "timeline": [{ "status": "INITIATED", "timestamp": "2026-09-10T08:30:00.000Z" }], "amounts": { "total": 16500, "supplier": 15000, "retailer": 1200, "platformFee": 300 }, "customerPayment": { "type": "MPESA" }, "suppliers": [], "transactions": [] }
}

Errors

  • 401 Unauthorized: invalid or missing user JWT.
  • 404 SETTLEMENT_NOT_FOUND: settlement ID does not exist.
GET/settlement/transactions/:transactionId

12. Get transaction details

Returns a settlement transaction. Requires a platform user JWT.

Request

Authorization: Bearer <user_access_token>
Content-Type: application/json

Path parameter: transactionId

If the repository cannot find the transaction, the current implementation returns a synthetic success with status UNKNOWN, amount 0, and description Synthetic fallback transaction rather than the documented 404.

Success response

{
  "success": true,
  "transaction": { "transactionId": "clxtransaction123", "settlementId": "clxsettlement123", "itemId": "ITEM-001", "type": "SALE", "amount": 15000, "currency": "KES", "status": "INITIATED", "description": "Product A sales", "createdAt": "2026-09-10T08:30:00.000Z", "completedAt": null }
}

Errors

  • 401 Unauthorized: invalid or missing user JWT.
POST/settlement/reconcile

13. Reconcile a settlement

Marks an existing settlement as completed and stores bank reconciliation data. Requires a platform user JWT.

Request

Authorization: Bearer <user_access_token>
Content-Type: application/json

{
  "settlementId": "clxsettlement123",
  "bankReference": "BANK_REF_001",
  "bankTransactionId": "BANK_TXN_987654",
  "notes": "Settlement completed successfully."
}

settlementId and bankReference are required. notes is accepted by the DTO but is not persisted by the current operation.

Success response

{
  "success": true,
  "settlement": { "settlementId": "clxsettlement123", "status": "COMPLETED", "reconciliationStatus": "VERIFIED", "reconciliationDetails": { "bankReference": "BANK_REF_001", "reconcileAt": "2026-09-10T10:00:00.000Z" } }
}

Errors

  • 400 Bad Request: required fields are missing or invalid.
  • 401 Unauthorized: invalid or missing user JWT.
  • 404 SETTLEMENT_NOT_FOUND: settlement does not exist.
GET/settlement/health

14. Settlement health

Public health check. Returns 200 when the controller is running.

Request

No authentication or request body.

Success response

{
  "status": "ok"
}
POST/settlement/scenarios/run

15. Run a documented scenario

Runs a Swagger/manual testing scenario. Requires a platform user JWT and is not intended for production business traffic.

Request

Authorization: Bearer <user_access_token>
Content-Type: application/json

{
  "scenario": "happy-path",
  "credentialMode": "fake",
  "apiKey": "pk_live_test123",
  "apiSecret": "sk_live_test123",
  "userEmail": "merchant@example.com",
  "merchantTransactionReference": "TXN-SCENARIO-001",
  "totalAmount": 7200,
  "currency": "KES",
  "settlementMethod": "BANK_TRANSFER",
  "paymentMethodType": "MPESA",
  "payerPhoneNumber": "254700000000",
  "supplierMerchantId": "SUP-1001",
  "itemId": "ITEM-001",
  "supplierAmount": 7200
}

scenario: happy-path | invalid-credentials | expired-session | invalid-payload
credentialMode: fake | real

An intentionally rejected scenario can still return status passed because the expected rejection occurred. Omitted fields receive defaults.

Success response

{
  "status": "passed",
  "scenario": "happy-path",
  "message": "Happy-path settlement scenario completed successfully.",
  "details": { "credentialMode": "fake", "settlementId": "clxsettlement123", "merchantTransactionReference": "TXN-SCENARIO-001", "token": "session_..." }
}

Errors

  • 400 Bad Request: scenario request validation failed.
GET/settlement/payouts/retry-status/:settlementId

16. Get payout retry status

Returns retry statistics for a settlement. No authentication guard is currently attached; protect this route externally.

Request

Path parameter: settlementId

When no payout records exist, the current implementation returns zero-valued statistics and does not independently verify that the settlement exists.

Success response

{
  "success": true,
  "settlementId": "clxsettlement123",
  "retryStatistics": { "totalPayouts": 2, "completed": 1, "submitted": 0, "pending": 0, "retrying": 1, "failed": 0, "totalAttempts": 3, "averageAttempts": 1.5 },
  "timestamp": "2026-09-10T10:00:00.000Z"
}
GET/settlement/payouts/pending-retries

17. List pending retries

Returns payout attempts that are waiting for another retry. No authentication guard is currently attached.

Request

No authentication or request body.

Success response

{
  "success": true,
  "count": 1,
  "pendingRetries": [{ "id": "payout-attempt-123", "payoutReference": "TXN-001-SUPPLIER-...", "settlementId": "clxsettlement123", "status": "RETRYING", "attemptCount": 2, "nextRetryAt": "2026-09-10T10:02:00.000Z", "failureReason": "Gateway timeout" }],
  "timestamp": "2026-09-10T10:00:00.000Z"
}
POST/settlement/payouts/manual-retry/:settlementId

18. Manually retry settlement payouts

Retries failed or retrying payouts for a settlement. No authentication guard is currently attached and the request body is ignored.

Request

Path parameter: settlementId

Request body: ignored

Success response

{
  "success": true,
  "settlementId": "clxsettlement123",
  "retryResult": { "message": "Manually retried 1 failed payouts", "count": 1, "results": [{ "payoutReference": "TXN-001-SUPPLIER-...", "status": "SUBMITTED", "success": true }] },
  "timestamp": "2026-09-10T10:00:00.000Z"
}

No retries:
{ "success": true, "message": "No failed payouts to retry", "count": 0 }

Errors

  • 404 SETTLEMENT_NOT_FOUND: settlement does not exist.
POST/supplier/authenticate

19. Authenticate a supplier

Authenticates a supplier integration with a platform JWT, API key, and API secret. The integration must belong to an ACTIVE supplier.

Request

Authorization: Bearer <user_access_token>
Content-Type: application/json

{
  "apiKey": "pk_live_supplier123",
  "apiSecret": "sk_live_supplier789"
}

Send sessionToken only in x-supplier-session to GET /supplier/settlements. It is not interchangeable with a user JWT or retailer settlement session.

Success response

{
  "success": true,
  "sessionToken": "session_1725900000000_0123456789abcdef",
  "expiresIn": 3600,
  "tokenType": "Bearer",
  "business": { "id": "supplier-participant-123", "businessName": "Supplier Ltd", "participantType": "SUPPLIER", "status": "ACTIVE" }
}

Errors

  • 401 INVALID_TOKEN_FOR_API_KEYS: JWT email does not own the integration.
  • 401 INVALID_CREDENTIALS: supplier API secret is incorrect.
  • 404 SUPPLIER_NOT_FOUND: no active integration matches the API key.
  • 403 NOT_A_SUPPLIER: integration belongs to a retailer.
  • 403 SUPPLIER_NOT_ACTIVE: supplier participant is not active.
GET/supplier/settlements

20. List supplier settlements

Returns settlement summaries allocated to the supplier identified by the supplier session token.

Request

x-supplier-session: <sessionToken_from_supplier_authenticate>

Success response

{
  "success": true,
  "count": 1,
  "data": [{ "reference": "TXN-20260910-000001-pay_supplier_001-0", "merchantTransactionReference": "MTXN-20260910083000-A1B2C3", "amount": 15000, "status": "INITIATED", "retailerMerchantId": "pay_retailer_001", "itemReference": "ITEM-001" }]
}

Errors

  • 401 INVALID_SUPPLIER_SESSION: missing, unknown, or invalid session context.
  • 401 SUPPLIER_SESSION_EXPIRED: session expiry has passed.
  • 403 NOT_A_SUPPLIER_SESSION: session belongs to a non-supplier integration.

Payout idempotency and retry semantics

Payout idempotency is generated from SHA256(settlementId + "::" + party + "::" + recipientMerchantId). One payout attempt exists per settlement, party, and recipient. Repeating dispatch does not create a second completed payout; a completed duplicate returns isDuplicate true and the original reference.

Retry policy

  • Maximum retries: 5
  • Initial delay: 60 seconds
  • Backoff multiplier: 2
  • Maximum delay: 3600 seconds
  • Jitter: approximately plus or minus 10 percent
  • Scheduler batch size: 10
  • Scheduler interval: 30 seconds

Payout attempt statuses

  • PENDING: attempt exists but submission has not completed.
  • SUBMITTED: gateway accepted the request.
  • COMPLETED: successful callback or completion mark received.
  • FAILED: permanently failed or not currently retryable.
  • RETRYING: scheduled or being prepared for another attempt.

Integration guidance

References and amounts

  • merchantTransactionReference: caller idempotency/business reference. The API-generated PayAssure reference is different; do not replace the caller reference.
  • Customer versus payout: paymentMethod describes how the customer pays. Supplier and retailer payout destinations come from verified onboarding records. Do not use customer payerPhoneNumber as a payout destination.
  • Supplier totals: use supplier-level totals or item allocations. When both are present they must agree; duplicate supplier groups are aggregated.

Payouts and callbacks

  • MPESA: B2C and verified phone number. BANK: B2B and verified shortcode plus accountName.
  • Keep the callback identifier from the payout request unchanged; the callback route with :callbackIdentifier is most reliable.
  • Only SUCCESS and PAID are successful payout callback statuses. PROCESSING or unknown statuses become failed results. M-Pesa ResultCode 0 maps to SUCCESS.
  • Amounts are numeric currency values. Dispatch rounds to whole numbers and forces values between 0 and 1 to 1.

Sensitive data

Never log or expose user JWTs, settlement or supplier session tokens, API secrets, internal gateway tokens, HMAC signature secrets, or payment provider credentials. Review production logging and route protection before exposing unauthenticated callback, payout, scenario, or retry routes publicly.