Payments
Initialize, retrieve, list and cancel payments via the Payments API.
The Payment (transaction) object represents a payment collection attempt. Its lifecycle goes from
pending to succeeded (or failed). All routes share the base https://api.wajub.com.
Before you begin
Create a payment from your server with your private key (sk. or sk_test.), or from a browser
with your public key (pk. or pk_test.). Both are in the
Wajub dashboard.
Marketplaces: acting on behalf of a subaccount
Platforms can attribute a payment to a connected subaccount by sending an X-Sync header
alongside their own key. See Subaccounts for the full contract and error
cases.
Endpoints
| Method | Path | Description |
|---|---|---|
POST | /payments | Initialize a payment |
POST | /payments/{id} | Charge a payment from your server |
POST | /payments/{id}/confirm | Confirm a step of a charge (code, PIN, provider window) |
POST | /payments/{id}/splits | Charge the next instalment (Mobile Money in live) |
POST | /payments/{id}/close | Close a payment paid in part in instalments |
GET | /payments/{id} | Retrieve a payment |
GET | /payments | List payments |
DELETE | /payments/{id} | Cancel a payment |
GET | /payments/{id}/refunds | List refunds for a payment |
PATCH | /payments/{id} | Change a prepared payment's amount |
POST | /payments/{id}/activate | Create a prepared payment once the order is placed |
Prepared payments
A payment created with deferred: true is only prepared. It exists for
payment fields mounted on your
checkout before the order does, and it stays out of everything else until you activate it.
| Prepared | Activated | |
|---|---|---|
In GET /payments and the dashboard | No | Yes |
GET /payments/{id} | Reads as pending, then expired or cancelled; answers 404 an hour after it expired or was cancelled | The payment |
payment.created | Not sent | Sent on activation |
| Amount and currency | PATCH /payments/{id} | Fixed |
| Can be charged | No | Yes |
DELETE /payments/{id} | Ends the session, no webhook | Cancels, sends payment.cancelled |
Activation keeps the id and the session token you already handed to the browser. A prepared
payment that is never activated expires with its session, and no trace of it reaches your
payments or your webhook endpoint, as long as you sent no customer while preparing it: that
customer is created, with its customer.created.
The Payment object
Create response vs. retrieval response
The POST /payments (create) response includes two additional fields,
authorization_url and authorization_token. That are not present on subsequent retrieval
responses. These are the two most important fields in the create response.
A field with no value is left out of the response rather than sent as null.
idstringoptionaltrx_ followed by 20 characters, trx_test_ in sandbox. This is the identifier to use in every API call (GET /payments/{id}, POST /refunds body, etc.).authorization_urlstringoptionalPOST /payments only.** The hosted payment page URL to redirect your customer to. An opaque session URL, do not parse or construct it manually.authorization_tokenstringoptionalPOST /payments only.** Browser-safe session token scoped to this payment. Pass as sessionId to Wajub Components for embedded checkout. It works on every call of the payment page until the payment is final, then for 5 more minutes after a success and 1 minute after a failure.referencestringoptionalreference you sent on POST /payments: your own order reference, stored and returned as is. It is not an API identifier, and Wajub never checks that it is unique.statusenumoptionalpending, processing, succeeded, failed, cancelled, expired, partial, refunded, partially_refunded. The last two are read from API version 2026-10-11: on an earlier version a refunded payment keeps reading succeeded.amountnumberoptionalamount_paidnumberoptionalamount while a payment paid in instalments is partial, and on such a payment closed before its last instalment (POST /payments/{id}/close).currencystringoptionalSLL.channelstring?optionalcm.mtn, cm.orange, sn.wave).payment_methodobject?optional{ channel, account }.descriptionstring?optionalitemsarray?optionalname, description and quantity. Displayed on the payment page, they carry no price and never change amount.taxobject?optional{ amount, taxable_amount, rate, name, country, inclusive }. Never present in sandbox.failure_reasonstring?optionalstatus=failed.failure_messagestring?optionalfailure_reason, for your logs and your support team. Present only when status=failed.receipt_urlstring?optionalcustomerobject?optional{ id, name, email, phone }.shipping_addressobject?optional{ address_line1, address_line2, city, state, postal_code, country }.billing_addressobject?optionalmetadataobject?optionalinvoicestring?optionalid of the invoice this payment settles, when it was made on an invoice's page. Absent otherwise.callbackstring?optionalbearerstringoptionalmerchant, or customer when the payer pays it on top of amount.expires_atdatetime?optionalexpires.in at creation. Past it the payment turns expired.themingobject?optionaltheming object passed at creation, given back as it was stored. Nothing reads it today: the payment page follows your Dashboard branding, and an embedded checkout its appearance ([Branding](/libraries/components/branding)).sandboxbooleanoptionaltrue for test-mode transactions.credited_atdatetime?optionalcreated_atdatetimeoptional+00:00).updated_atdatetimeoptionalLifecycle
Events
| Event | Trigger |
|---|---|
payment.created | Payment initialized, or a prepared payment activated |
payment.processing | Payment submitted to the provider |
payment.succeeded | Payment successfully validated |
payment.failed | Payment failed (see failure_reason) |
payment.attempt_failed | An attempt was refused at once and the payment is pending again |
payment.expired | The payment's deadline (expires_at) passed before it was paid |
payment.cancelled | Payment cancelled with DELETE /payments/{id} or the Cancel button of the hosted page |
payment.split.processing | An instalment was sent to the payer |
payment.split.succeeded | An instalment was paid, and credited to your balance |
payment.split.failed | An instalment was declined; the next call charges it again |
See the full event catalog for refund-specific events. A refund on a
payment does not re-emit a payment.* event, it emits refund.* events instead.