API reference / Settlement
Settlement API
Live settlement, payout, supplier, callback, reconciliation, tracking, and retry endpoints for PayAssure.
PayAssure
Developer Dashboard
API reference / Settlement
Live settlement, payout, supplier, callback, reconciliation, tracking, and retry endpoints for PayAssure.
Settlement credentials are separate and are not interchangeable.
| Credential | Source | Header / use |
|---|---|---|
| User access JWT | /auth/login or /auth/refresh | Authorization Bearer; platform identity |
| Retailer settlement session | /settlement/authenticate token | x-settlement-session; retailer initiation for 1 hour |
| Supplier session | /supplier/authenticate sessionToken | x-supplier-session; supplier lookup |
| Internal gateway token | PAYMENT_GATEWAY_API_TOKEN, then SETTLEMENT_API_TOKEN, then INTERNAL_GATEWAY_TOKEN | Authorization Bearer; internal confirmation |
| Internal signature secret | PAYMENT_GATEWAY_SIGNATURE_SECRET, then SETTLEMENT_SIGNATURE_SECRET, then PAYASSURE_INTERNAL_SECRET | Creates x-payassure-signature |
| B2B gateway token | B2B_GATEWAY_API_TOKEN, then PAYMENT_GATEWAY_API_TOKEN, then SETTLEMENT_API_TOKEN | Server-to-gateway only; not client-facing |
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.
The supplier session also expires after 3600 seconds and is sent only to GET /supplier/settlements.
{
"statusCode": 400,
"message": ["totalAmount must not be less than 0.01"],
"error": "Bad Request",
"path": "/settlement/initiate-settlement"
}{
"statusCode": 401,
"message": "Invalid or expired one-time token",
"error": "INVALID_TOKEN"
}{
"statusCode": 400,
"message": "Validation failed",
"error": "VALIDATION_ERROR",
"errors": [{ "field": "suppliers[0].supplierMerchantId", "message": "Supplier was not found in PayAssure" }]
}| Status | Meaning |
|---|---|
| INITIATED | Request accepted; payment may be pending or retryable gateway failure held. |
| PENDING_PROCESSING | Payment callback or confirmation accepted; allocation is beginning. |
| PROCESSING | Ledger allocation or payout processing is underway. |
| PROCESSING_COMPLETE | Processing stage completed where used downstream. |
| AWAITING_RECONCILIATION | Waiting for bank or financial reconciliation. |
| COMPLETED | Settlement reconciled and completed. |
| PROCESSING_FAILED / FAILED | Downstream processing failed or failed permanently. |
/settlement/authenticateVerifies the API key and API secret for an active retailer integration. The platform JWT email must match the onboarding participant that owns the integration.
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": true,
"token": "session_1725900000000_0123456789abcdef",
"expiresIn": 3600,
"tokenType": "Bearer",
"business": { "id": "participant-123", "businessName": "Fresh Store Ltd", "participantType": "RETAILER", "status": "ACTIVE" }
}/settlement/initiate-settlementCreates 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.
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": 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 }]
}/settlement/payment-callbackReceives 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.
{
"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": 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" }] }
}/settlement/payment-confirmationConfirms 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.
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": 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": []
}/settlement/internal/settlements/payment-confirmationLegacy route alias for /settlement/payment-confirmation. It uses the same gateway bearer token, HMAC signature, timestamp, payload, idempotency, response, and error behavior.
Use the request and signature contract documented for endpoint 4.Returns the same payment confirmation response documented for endpoint 4./settlement/payouts/dispatchDispatches 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.
{
"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": 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" }
}/settlement/payouts/callbackProvider 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.
{
"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": 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" }
}/settlement/payouts/callback/:callbackIdentifierEquivalent payout callback route using the callbackIdentifier generated in the payout request. This is the preferred lookup path.
Path parameter: callbackIdentifier = callback identifier from the payout request.
Use the flat callback body documented for endpoint 7.Returns the same payout callback response documented for endpoint 7./settlement/payouts/callback/:callbackIdentifier/callbacks/mpesaEquivalent payout callback route that transforms the provider M-Pesa Result payload into the internal flat callback fields.
Path parameter: callbackIdentifier
{
"Result": {
"ResultCode": 0,
"ResultDesc": "The service request is processed successfully.",
"TransactionID": "UHHRY0DHFK",
"OriginatorConversationID": "oc-123",
"ConversationID": "c-123"
}
}Returns the same payout callback response documented for endpoint 7. ResultCode 0 becomes SUCCESS; any other result code becomes FAILED./supplier/settlementsReturns settlement summaries allocated to the supplier identified by the supplier session token.
x-supplier-session: <sessionToken_from_supplier_authenticate>{
"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" }]
}/settlement/track/:settlementIdReturns 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.
Authorization: Bearer <user_access_token>
Content-Type: application/json
Path parameter: settlementIdThe service also supports retailer, supplier, and payassure views when called internally.
{
"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": [] }
}/settlement/transactions/:transactionIdReturns a settlement transaction. Requires a platform user JWT.
Authorization: Bearer <user_access_token>
Content-Type: application/json
Path parameter: transactionIdIf 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": 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 }
}/settlement/reconcileMarks an existing settlement as completed and stores bank reconciliation data. Requires a platform user JWT.
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": true,
"settlement": { "settlementId": "clxsettlement123", "status": "COMPLETED", "reconciliationStatus": "VERIFIED", "reconciliationDetails": { "bankReference": "BANK_REF_001", "reconcileAt": "2026-09-10T10:00:00.000Z" } }
}/settlement/healthPublic health check. Returns 200 when the controller is running.
No authentication or request body.{
"status": "ok"
}/settlement/scenarios/runRuns a Swagger/manual testing scenario. Requires a platform user JWT and is not intended for production business traffic.
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 | realAn intentionally rejected scenario can still return status passed because the expected rejection occurred. Omitted fields receive defaults.
{
"status": "passed",
"scenario": "happy-path",
"message": "Happy-path settlement scenario completed successfully.",
"details": { "credentialMode": "fake", "settlementId": "clxsettlement123", "merchantTransactionReference": "TXN-SCENARIO-001", "token": "session_..." }
}/settlement/payouts/retry-status/:settlementIdReturns retry statistics for a settlement. No authentication guard is currently attached; protect this route externally.
Path parameter: settlementIdWhen no payout records exist, the current implementation returns zero-valued statistics and does not independently verify that the settlement exists.
{
"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"
}/settlement/payouts/pending-retriesReturns payout attempts that are waiting for another retry. No authentication guard is currently attached.
No authentication or request body.{
"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"
}/settlement/payouts/manual-retry/:settlementIdRetries failed or retrying payouts for a settlement. No authentication guard is currently attached and the request body is ignored.
Path parameter: settlementId
Request body: ignored{
"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 }/supplier/authenticateAuthenticates a supplier integration with a platform JWT, API key, and API secret. The integration must belong to an ACTIVE supplier.
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": true,
"sessionToken": "session_1725900000000_0123456789abcdef",
"expiresIn": 3600,
"tokenType": "Bearer",
"business": { "id": "supplier-participant-123", "businessName": "Supplier Ltd", "participantType": "SUPPLIER", "status": "ACTIVE" }
}/supplier/settlementsReturns settlement summaries allocated to the supplier identified by the supplier session token.
x-supplier-session: <sessionToken_from_supplier_authenticate>{
"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" }]
}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.
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.