Key Concepts
Understand the core building blocks of Wajub — payment lifecycle, sandbox vs live, session tokens, API keys, and the orchestration model.
Before writing code, take a few minutes to understand the core concepts. They'll make every API call and webhook event immediately clear.
Payment lifecycle
A payment goes through a well-defined state machine:
pending → processing → succeeded
→ failed
→ expired
→ cancelled| State | Meaning | Next action |
|---|---|---|
pending | Initialized, waiting for the customer to act. | Redirect the customer to the payment page. |
processing | The provider is processing the charge. | Wait. Real-time updates arrive via webhook or Pusher. |
succeeded | Funds received. You can fulfill the order. | Deliver the product/service. |
failed | Declined or expired. | Show an error, offer to retry. |
cancelled | Cancelled by the customer or merchant. | No action needed. |
expired | The payment window closed before completion. | Re-initiate if needed. |
partial | Part of the amount was captured (split payments). | Track remaining via Sync. |
refunded | A succeeded payment was fully refunded. | Handle the return. |
partially_refunded | A partial refund was applied. | Track the remaining amount. |
How payments move through states
- You call
POST /payments— creates a transaction inpending. - The customer completes the payment on the hosted page (
pay.wajub.com). - Wajub processes the charge with the best available provider (see Orchestration).
- Wajub sends a
payment.succeededwebhook to your server. - You verify the status via
GET /payments/{id}and fulfill.
Sandbox vs Live
Wajub provides two completely isolated environments. A single base URL serves both — the environment is determined by the API key you use.
| Sandbox | Live | |
|---|---|---|
| Keys | pk_test.… / sk_test.… | pk.… / sk.… |
| Money | No real fund movement | Real payments |
| Test data | Test phone numbers | Real customer data |
| Reset | Can be reset from the Dashboard | Cannot be reset |
Never mix environments
A sandbox key cannot access live data, and vice versa. Store keys in separate environment variables per environment.
API keys
Three key types, each with a specific purpose:
Public key (pk.… / pk_test.…)client-safeoptionalPrivate key (sk.… / sk_test.…)server onlyoptionalRestricted key (rk.… / rk_test.…)server onlyoptionalPrivate keys are blocked in browsers
Wajub rejects any request made with a private key from a browser or mobile app (detected via
Origin/Referer headers). This is a safety net — store sk.… in environment variables, never in
client-side code.
Session tokens
The hosted checkout page (pay.wajub.com) uses a session token — not an API key:
- Returned by
POST /paymentsasauthorization_token. - Scoped to a single transaction.
- Browser-safe — can be exposed in the frontend.
- Expires when the transaction reaches a terminal state.
- Used by
@wajub/jsSDK assessionId.
// Backend creates the session
const { authorization_token } = await wajub.payments.create({...});
// Frontend uses the token
wajub.mount("#checkout", { sessionId: authorization_token });Orchestration model
When you process a payment, Wajub doesn't just forward it — it orchestrates:
- Routing — Selects the best provider for the channel, country and amount.
- Execution — Calls the provider's API.
- Fallback — If the primary provider fails, retries with the next one.
- Reconciliation — Matches provider callbacks with the original transaction.
All of this is transparent to you — you just create a payment and listen for the webhook.
Watch orchestration in real time
Open Konsole → Event Stream to see the routing decision and provider responses as they happen.
References
Resource identifiers use a prefix_ format, making them immediately readable in logs and code:
| Prefix | Resource | Example |
|---|---|---|
trx_ | Payment transaction | trx_01JXXXXXXXXXXXXX |
trf_ | Transfer | trf_01JXXXXXXXXXXXXX |
cus_ | Customer | cus_01JXXXXXXXXXXXXX |
evt_ | Webhook event | evt_01JXXXXXXXXXXXXX |
rfd_ | Refund | rfd_01JXXXXXXXXXXXXX |
inv_ | Invoice | inv_01JXXXXXXXXXXXXX |
Amounts
Unlike many payment providers, Wajub expresses amounts in the major unit of the
currency (e.g. 5000 = 5 000 XAF, not 500 000 centimes). CFA franc currencies have no
common subunit, so this avoids confusion.
"Payment" vs "transaction"
Wajub uses both terms, and they refer to the same object:
- Payment — the business concept. You create a payment, a customer pays, you fulfill.
- Transaction — the internal representation. The API response uses
"transaction": {...}as the root key, and theidfield is prefixedtrx_.
In practice: you call POST /payments, receive transaction.id = "trx_xxx", and listen for
payment.succeeded webhooks. The terms are interchangeable in this documentation.
Next steps
- Quickstart — code your first payment.
- Orchestration — how routing and fallback work.
- Webhooks — receive
payment.succeededreliably.
Was this page helpful?