{"openapi":"3.0.3","info":{"title":"Ziba Pay Developer API","description":"Ziba Pay payment gateway, mobile money, orders, and transaction processing REST API documentation.","version":"1.0.0","contact":{"name":"Ziba Pay Developer Support","url":"https://zibapay.com"}},"servers":[{"url":"https://payment-service-mh2d.onrender.com/api","description":"Test environment server host"}],"paths":{"/developer/gatewayConfigs":{"post":{"summary":"Create API keys","description":"Generate an API key and secret pair used to authenticate server-to-server requests for the MTN developer route. In Ziba Pay, API keys are managed and configured as gateway configs (gatewayConfigs).","tags":["API reference"],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Human-readable label for this API key pair (e.g., 'Production Webhook Server', 'Mobile App Checkout')."},"description":{"type":"string","description":"System, service, or environment using this key."}}},"example":{"name":"Production Store Checkout","description":"Server-to-server payment collections for online ecommerce store"}}}},"responses":{"201":{"description":"API key and secret generated successfully.","content":{"application/json":{"example":{"id":"gwcfg_9f8e7d6c5b4a","apiKey":"zp_live_9a8b7c6d5e4f3a2b1c0d","apiSecret":"zsec_817263544a3b2c1d0e9f8a7b6c5d4e","name":"Production Store Checkout","description":"Server-to-server payment collections for online ecommerce store","userId":"usr_clx982347102","createdAt":"2026-10-21T05:15:00.000Z"}}}},"400":{"description":"Bad request / validation failed"},"401":{"description":"Unauthorized"},"429":{"description":"Rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/developer/all":{"get":{"summary":"List API keys","description":"List all API key configs for the signed-in merchant.","tags":["API reference"],"parameters":[],"responses":{"200":{"description":"Array of API key configs without plaintext secrets.","content":{"application/json":{"example":[{"id":"gwcfg_9f8e7d6c5b4a","apiKey":"zp_live_9a8b7c6d5e4f3a2b1c0d","name":"Production Store Checkout","description":"Server-to-server payment collections for online ecommerce store","userId":"usr_clx982347102","createdAt":"2026-10-21T05:15:00.000Z"},{"id":"gwcfg_1a2b3c4d5e6f","apiKey":"zp_test_8b7a6c5d4e3f2a1b0c9d","name":"Staging Testing Server","description":"Automated integration test runner","userId":"usr_clx982347102","createdAt":"2026-10-20T12:00:00.000Z"}]}}},"400":{"description":"Bad request / validation failed"},"401":{"description":"Unauthorized"},"429":{"description":"Rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/developer/gatewayConfigs/:apiKey":{"get":{"summary":"Get API key","description":"Read one API key config. The key in the path must match x-api-key.","tags":["API reference"],"parameters":[{"name":"x-api-key","in":"header","required":true,"description":"Gateway API key created while signed in.","schema":{"type":"string"}},{"name":"x-api-secret","in":"header","required":true,"description":"Secret returned once when the gateway key is created.","schema":{"type":"string"}},{"name":"apiKey","in":"path","required":true,"description":"Public API key identifier matching the x-api-key header.","schema":{"type":"string"}}],"responses":{"200":{"description":"The API key config payload, without plaintext apiSecret.","content":{"application/json":{"example":{"id":"gwcfg_9f8e7d6c5b4a","apiKey":"zp_live_9a8b7c6d5e4f3a2b1c0d","name":"Production Store Checkout","description":"Server-to-server payment collections for online ecommerce store","userId":"usr_clx982347102"}}}},"400":{"description":"Bad request / validation failed"},"401":{"description":"Unauthorized"},"429":{"description":"Rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/developer/delete/:id":{"delete":{"summary":"Delete API key","description":"Delete an API key config owned by the signed-in merchant.","tags":["API reference"],"parameters":[{"name":"id","in":"path","required":true,"description":"API key config ID (id) from create or list.","schema":{"type":"string"}}],"responses":{"200":{"description":"API key config deleted and revoked.","content":{"application/json":{"example":{"id":"gwcfg_9f8e7d6c5b4a","apiKey":"zp_live_9a8b7c6d5e4f3a2b1c0d","name":"Production Store Checkout","message":"Gateway configuration deleted successfully"}}}},"400":{"description":"Bad request / validation failed"},"401":{"description":"Unauthorized"},"429":{"description":"Rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/payment/mtn-momo-pay":{"post":{"summary":"Collect with MTN","description":"Initiate an MTN Mobile Money collection. Documented samples use the production Bearer route.","tags":["API reference"],"parameters":[{"name":"Authorization","in":"header","required":true,"description":"Bearer <merchant_token>","schema":{"type":"string"}},{"name":"Content-Type","in":"header","required":true,"description":"application/json","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"amount":{"type":"number","description":"Must be greater than 0."},"currency":{"type":"string","description":"Exactly 3 letters. Sample market uses RWF."},"phoneNumber":{"type":"string","description":"8–15 digits, optional leading +. Paying customer MSISDN (does not need a Ziba account). Cannot be the merchant’s own number."},"description":{"type":"string","description":"Max 160 characters. Defaults to an empty string."},"idempotencyKey":{"type":"string","description":"8–128 characters. Repeating it returns the existing order."}}},"example":{"amount":1000,"currency":"RWF","phoneNumber":"+250788000000","description":"Illustrative order 1042","idempotencyKey":"order-1042-mtn"}}}},"responses":{"200":{"description":"Collection started successfully, or an idempotent replay.","content":{"application/json":{"example":{"_label":"Illustrative example","transactionReferenceId":"8f1c0b2e-4a7d-4c1e-9b55-0a1d2e3f4a5b","orderId":"ord_rw_sample_1042","status":"PENDING"}}}},"400":{"description":"Bad request / validation failed"},"401":{"description":"Unauthorized"},"429":{"description":"Rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/payment/mtn/status/:reference":{"get":{"summary":"MTN payment status","description":"Poll MTN and return the order status for a reference you own.","tags":["API reference"],"parameters":[{"name":"reference","in":"path","required":true,"description":"transactionReferenceId from the collect response.","schema":{"type":"string"}}],"responses":{"200":{"description":"Status payload.","content":{"application/json":{"example":{"transactionReferenceId":"8f1c0b2e-4a7d-4c1e-9b55-0a1d2e3f4a5b","orderId":"clxorderid","status":"COMPLETED","providerStatus":"COMPLETED","alreadyFinalized":true}}}},"400":{"description":"Bad request / validation failed"},"401":{"description":"Unauthorized"},"429":{"description":"Rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/payment/airtel-momo-pay":{"post":{"summary":"Collect with Airtel","description":"Start an Airtel Money collection with a merchant session.","tags":["API reference"],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"amount":{"type":"number or string","description":"Collection amount in the configured Airtel currency. The example server configuration uses RWF."},"number":{"type":"string","description":"Subscriber MSISDN phone number (e.g., '788000000')."},"reference":{"type":"string","description":"Your unique merchant order or transaction reference."}}},"example":{"amount":1500,"number":"788000000","reference":"order-1042"}}}},"responses":{"200":{"description":"Airtel response body.","content":{"application/json":{"example":{"data":{"transaction":{"id":"AIRTEL-TX-9812401","status":"In Progress"}},"status":{"code":"200","message":"Payment successfully initiated","success":true}}}}},"400":{"description":"Bad request / validation failed"},"401":{"description":"Unauthorized"},"429":{"description":"Rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/payment/zibapay/order/create":{"post":{"summary":"Create order","description":"Create a TransactPay order for the signed-in merchant.","tags":["API reference"],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"order.amount":{"type":"number","description":"Stored on the Ziba Pay order and sent to TransactPay."},"order.currency":{"type":"string","description":"3-letter currency sent to TransactPay. Examples use RWF to match the default configured mobile-money market. Illustrative example."},"order.description":{"type":"string","description":"Narrative description of order goods or service."},"order.reference":{"type":"string","description":"Ignored. The service assigns the unique order reference."},"redirectUrl":{"type":"string","description":"Sent to TransactPay as payment.RedirectUrl."}}},"example":{"order":{"amount":1000,"currency":"RWF","description":"Order 1042"},"redirectUrl":"https://merchant.example/return"}}}},"responses":{"201":{"description":"Order created successfully.","content":{"application/json":{"example":{"status":"success","data":{"orderId":"clx_ord_8f1c0b2e4a7d","reference":"clx_ord_8f1c0b2e4a7d","amount":1000,"currency":"RWF","description":"Order 1042","status":"PENDING","redirectUrl":"https://merchant.example/return","checkoutUrl":"https://checkout.transactpay.com/pay/clx_ord_8f1c0b2e4a7d"}}}}},"400":{"description":"Bad request / validation failed"},"401":{"description":"Unauthorized"},"429":{"description":"Rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/payment/zibapay/order/fee":{"post":{"summary":"Order fee","description":"Ask TransactPay for the fee on an amount.","tags":["API reference"],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"amount":{"type":"number","description":"Forwarded to TransactPay."},"currency":{"type":"string","description":"Currency code (e.g. RWF, NGN, GHS)."},"paymentoption":{"type":"string","description":"Payment channel: 'card' or 'bank'."}}},"example":{"amount":1000,"currency":"RWF","paymentoption":"card"}}}},"responses":{"200":{"description":"Fee calculated successfully.","content":{"application/json":{"example":{"status":"success","data":{"fee":15,"amount":1000,"total":1015,"currency":"RWF"}}}}},"400":{"description":"Bad request / validation failed"},"401":{"description":"Unauthorized"},"429":{"description":"Rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/payment/zibapay/card/:reference":{"post":{"summary":"Pay order with card","description":"Pay an existing order reference with card details.","tags":["API reference"],"parameters":[{"name":"reference","in":"path","required":true,"description":"transactionReferenceId from the collect response, or the order reference.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"card.cardnumber":{"type":"string","description":"Customer primary account number (PAN). Do not log."},"card.expirymonth":{"type":"string","description":"Two-digit expiration month (MM)."},"card.expiryyear":{"type":"string","description":"Two-digit or four-digit expiration year (YY or YYYY)."},"card.cvv":{"type":"string","description":"Three-digit or four-digit security code. Do not log."},"country":{"type":"string","description":"Two-letter customer country code (e.g., 'NG', 'GH')."},"paymentoption":{"type":"string","description":"Payment option identifier (e.g., 'card')."}}},"example":{"card":{"cardnumber":"4111111111111111","expirymonth":"12","expiryyear":"2028","cvv":"123"},"country":"NG","paymentoption":"card"}}}},"responses":{"200":{"description":"Card payment processed.","content":{"application/json":{"example":{"status":"COMPLETED","reference":"clx_ord_8f1c0b2e4a7d","transactionId":"tx_card_9921827361","amount":1000,"currency":"RWF","message":"Approved and charged successfully"}}}},"400":{"description":"Bad request / validation failed"},"401":{"description":"Unauthorized"},"429":{"description":"Rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/payment/zibapay/bank/:reference":{"post":{"summary":"Pay order with bank","description":"Pay an existing order reference by bank transfer.","tags":["API reference"],"parameters":[{"name":"reference","in":"path","required":true,"description":"transactionReferenceId from the collect response, or the order reference.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"paymentoption":{"type":"string","description":"Payment option identifier ('bank')."},"country":{"type":"string","description":"Customer country code (e.g. 'NG')."},"BankTransfer.bankcode":{"type":"string","description":"Selected bank code from /payment/zibapay/banks."}}},"example":{"paymentoption":"bank","country":"NG","BankTransfer":{"bankcode":"044"}}}}},"responses":{"200":{"description":"Virtual bank account generated.","content":{"application/json":{"example":{"status":"PENDING","reference":"clx_ord_8f1c0b2e4a7d","accountnumber":"9901827364","bankname":"Wema Bank / TransactPay","accountname":"Ziba Pay - Order 1042","amount":1000,"currency":"RWF","expiresAt":"2026-10-21T06:00:00.000Z"}}}},"400":{"description":"Bad request / validation failed"},"401":{"description":"Unauthorized"},"429":{"description":"Rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/payment/zibapay/order/status/:reference":{"post":{"summary":"Order status","description":"Read TransactPay status for an order reference.","tags":["API reference"],"parameters":[{"name":"reference","in":"path","required":true,"description":"transactionReferenceId from the collect response, or the order reference.","schema":{"type":"string"}}],"responses":{"200":{"description":"Provider status body.","content":{"application/json":{"example":{"orderId":"clx_ord_8f1c0b2e4a7d","status":"COMPLETED","amount":1000,"currency":"RWF","paymentMethod":"CARD","paidAt":"2026-10-21T05:04:12.000Z"}}}},"400":{"description":"Bad request / validation failed"},"401":{"description":"Unauthorized"},"429":{"description":"Rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/payment/zibapay/order/verify/:reference":{"post":{"summary":"Verify order","description":"Verify a TransactPay order reference.","tags":["API reference"],"parameters":[{"name":"reference","in":"path","required":true,"description":"transactionReferenceId from the collect response, or the order reference.","schema":{"type":"string"}}],"responses":{"200":{"description":"Provider verify confirmation.","content":{"application/json":{"example":{"verified":true,"orderId":"clx_ord_8f1c0b2e4a7d","status":"COMPLETED","amount":1000}}}},"400":{"description":"Bad request / validation failed"},"401":{"description":"Unauthorized"},"429":{"description":"Rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/payment/zibapay/order/save-card/:reference":{"post":{"summary":"Save card","description":"Ask TransactPay to save the card used for an order reference.","tags":["API reference"],"parameters":[{"name":"reference","in":"path","required":true,"description":"transactionReferenceId from the collect response, or the order reference.","schema":{"type":"string"}}],"responses":{"200":{"description":"Card saved and token generated.","content":{"application/json":{"example":{"cardToken":"tok_crd_98127394871263","last4":"1111","brand":"Visa","expirymonth":"12","expiryyear":"2028"}}}},"400":{"description":"Bad request / validation failed"},"401":{"description":"Unauthorized"},"429":{"description":"Rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/payment/zibapay/card/tokenize/:reference":{"get":{"summary":"Tokenize charge","description":"Charge a saved card token. The route is GET and still reads a JSON body.","tags":["API reference"],"parameters":[{"name":"reference","in":"path","required":true,"description":"transactionReferenceId from the collect response, or the order reference.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"customer.firstname":{"type":"string","description":"Customer first name."},"customer.lastname":{"type":"string","description":"Customer last name."},"customer.mobile":{"type":"string","description":"Customer mobile number."},"customer.country":{"type":"string","description":"Customer country code."},"customer.email":{"type":"string","description":"Must match a Ziba Pay user email or the service returns 404."},"order.amount":{"type":"number","description":"Stored on the created order."},"order.currency":{"type":"string","description":"Stored on the created order."},"order.description":{"type":"string","description":"Stored on the created order."},"order.reference":{"type":"string","description":"Stored as the order transaction id."},"redirectUrl":{"type":"string","description":"Sent as payment.RedirectUrl."},"cardToken":{"type":"string","description":"Sent as authorization.cardToken."}}},"example":{"customer":{"firstname":"Amina","lastname":"Owusu","mobile":"+250788000000","country":"GH","email":"amina@example.com"},"order":{"amount":500,"currency":"RWF","description":"Monthly SaaS Renewal","reference":"ord-token-1043"},"redirectUrl":"https://merchant.example/return","cardToken":"tok_crd_98127394871263"}}}},"responses":{"200":{"description":"Tokenized payment charged.","content":{"application/json":{"example":{"status":"COMPLETED","reference":"clx_ord_8f1c0b2e4a7d","transactionId":"tx_tok_8817263541","amount":500,"currency":"RWF"}}}},"400":{"description":"Bad request / validation failed"},"401":{"description":"Unauthorized"},"429":{"description":"Rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/payment/zibapay/order/refund/:reference":{"post":{"summary":"Refund order","description":"Refund a TransactPay order reference.","tags":["API reference"],"parameters":[{"name":"reference","in":"path","required":true,"description":"transactionReferenceId from the collect response, or the order reference.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"Reason":{"type":"string","description":"Forwarded to TransactPay. Capital R matches the controller."},"Amount":{"type":"number","description":"Forwarded to TransactPay. Capital A matches the controller."}}},"example":{"Reason":"Customer returned the item","Amount":1000}}}},"responses":{"200":{"description":"Refund executed successfully.","content":{"application/json":{"example":{"status":"COMPLETED","refundId":"ref_ord_7718293645","reference":"clx_ord_8f1c0b2e4a7d","amount":1000,"reason":"Customer returned the item","refundedAt":"2026-10-21T05:30:00.000Z"}}}},"400":{"description":"Bad request / validation failed"},"401":{"description":"Unauthorized"},"429":{"description":"Rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/payment/zibapay/orders/all":{"get":{"summary":"List orders","description":"List TransactPay orders for the signed-in merchant.","tags":["API reference"],"parameters":[],"responses":{"200":{"description":"Merchant orders list.","content":{"application/json":{"example":[{"orderId":"clx_ord_8f1c0b2e4a7d","amount":1000,"currency":"RWF","description":"Order 1042","status":"COMPLETED","createdAt":"2026-10-21T05:00:00.000Z"},{"orderId":"clx_ord_1a2b3c4d5e6f","amount":500,"currency":"RWF","description":"Order 1041","status":"PENDING","createdAt":"2026-10-21T04:30:00.000Z"}]}}},"400":{"description":"Bad request / validation failed"},"401":{"description":"Unauthorized"},"429":{"description":"Rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/payment/zibapay/orders/:reference":{"get":{"summary":"Get order","description":"Load one order by reference.","tags":["API reference"],"parameters":[{"name":"reference","in":"path","required":true,"description":"transactionReferenceId from the collect response, or the order reference.","schema":{"type":"string"}}],"responses":{"200":{"description":"The stored order.","content":{"application/json":{"example":{"orderId":"clx_ord_8f1c0b2e4a7d","amount":1000,"currency":"RWF","description":"Order 1042","status":"COMPLETED","createdAt":"2026-10-21T05:00:00.000Z"}}}},"400":{"description":"Bad request / validation failed"},"401":{"description":"Unauthorized"},"429":{"description":"Rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/payment/zibapay/banks":{"get":{"summary":"List banks","description":"List banks from TransactPay. This route has no auth middleware.","tags":["API reference"],"parameters":[],"responses":{"200":{"description":"Provider bank list.","content":{"application/json":{"example":[{"bankcode":"044","bankname":"Access Bank"},{"bankcode":"058","bankname":"Guaranty Trust Bank"},{"bankcode":"033","bankname":"United Bank for Africa"},{"bankcode":"057","bankname":"Zenith Bank"},{"bankcode":"011","bankname":"First Bank of Nigeria"}]}}},"400":{"description":"Bad request / validation failed"},"401":{"description":"Unauthorized"},"429":{"description":"Rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/payment/zibapay/stats":{"get":{"summary":"Order stats","description":"Transaction stats for the signed-in merchant.","tags":["API reference"],"parameters":[],"responses":{"200":{"description":"{ stats }.","content":{"application/json":{"example":{"stats":{"transactionsByBank":0,"transactionsByCard":1,"totalTransactions":1,"totalRevenue":1000}}}}},"400":{"description":"Bad request / validation failed"},"401":{"description":"Unauthorized"},"429":{"description":"Rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/transactions":{"get":{"summary":"List transactions","description":"List payment rows for the signed-in merchant.","tags":["API reference"],"parameters":[{"name":"page","in":"query","required":false,"description":"Page number. Defaults to 1.","schema":{"type":"number"}},{"name":"limit","in":"query","required":false,"description":"Page size. Defaults to 100. Maximum 100.","schema":{"type":"number"}},{"name":"sort","in":"query","required":false,"description":"Comma-separated fields: id, amount, method, status, createdAt. Prefix - for descending. Default is -createdAt.","schema":{"type":"string"}},{"name":"fields","in":"query","required":false,"description":"Comma-separated subset of id, userId, orderId, amount, method, status, createdAt.","schema":{"type":"string"}},{"name":"status","in":"query","required":false,"description":"Exact status filter.","schema":{"type":"string"}},{"name":"method","in":"query","required":false,"description":"Exact method filter.","schema":{"type":"string"}},{"name":"amount","in":"query","required":false,"description":"Exact amount, or amount[gte], amount[gt], amount[lte], amount[lt].","schema":{"type":"number"}}],"responses":{"200":{"description":"Page of payments.","content":{"application/json":{"example":{"status":"success","results":1,"data":{"payments":[{"id":1,"userId":"merchant-id","orderId":"clxorderid","amount":1000,"method":"MTN","status":"PENDING","createdAt":"2026-10-08T00:00:00.000Z"}]}}}}},"400":{"description":"Bad request / validation failed"},"401":{"description":"Unauthorized"},"429":{"description":"Rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/transactions/:id":{"get":{"summary":"Get transaction","description":"Load one payment by numeric id, including its order, for the signed-in merchant.","tags":["API reference"],"parameters":[{"name":"id","in":"path","required":true,"description":"Internal payment row numeric ID.","schema":{"type":"number"}}],"responses":{"200":{"description":"{ status: \"success\", data: { payment } }, including the associated order.","content":{"application/json":{"example":{"status":"success","data":{"payment":{"id":1,"amount":1000,"status":"COMPLETED","method":"MTN","orderId":"clxorderid","userId":"merchant-id","createdAt":"2026-10-21T05:00:00.000Z"}}}}}},"400":{"description":"Bad request / validation failed"},"401":{"description":"Unauthorized"},"429":{"description":"Rate limit exceeded"},"500":{"description":"Internal server error"}}}},"/transactions/statuses":{"get":{"summary":"Transaction statuses","description":"Distinct payment.status values currently stored in the database.","tags":["API reference"],"parameters":[],"responses":{"200":{"description":"{ status: \"success\", data: { statuses } }.","content":{"application/json":{"example":{"status":"success","data":{"statuses":["PENDING","PROCESSING","COMPLETED","FAILED","CANCELLED","EXPIRED","REVERSED"]}}}}},"400":{"description":"Bad request / validation failed"},"401":{"description":"Unauthorized"},"429":{"description":"Rate limit exceeded"},"500":{"description":"Internal server error"}}}}}}