Skip to content
PayDirect Docs

Docs › Core concepts

Transactions and statuses

The transaction types, the three statuses, which transitions are possible, and how to resolve a PENDING transaction.

Every movement of money is a Transaction: one row, one id, one status. Whatever endpoint created it, you read it back the same way and it obeys the same state rules.

Transaction types

Type Created by Direction
COLLECTION POST /transactions/collect, hosted checkout Money in
PAYOUT POST /transactions/disburse and its payout-credit-transfer alias Money out
WITHDRAWAL POST /transactions/withdraw Money out, to your own settlement account
PAY_BILL POST /transactions/pay-bill, pay-bill-ext Money out, to a biller
SEND_MONEY POST /transactions/send-money Two-leg: collect then disburse
MONEY_REQUEST_DISBURSEMENT The Request Money flow Money out

The three statuses

Status Means What you should do
PENDING Dispatch is in flight, or awaiting confirmation from the rail. We do not know yet. Wait for a webhook, or reconcile. Do not assume either outcome.
SUCCESS Confirmed by the rail. Money arrived. Fulfil.
FAILED Rejected, or confirmed failed. Money did not leave. A ledger debit taken for it is returned to your balance. Do not fulfil. Retry with a new reference if you still want to pay.

There is no fourth value. If you ever see something not on this list, treat it as PENDING - unknown, resolve it before acting.

Terminality

Note

For PAYOUT and WITHDRAWAL, SUCCESS and FAILED are terminal statuses: once one of these resolves, reconciliation does not change it, and you can build on it as final.

The status records what the rail told us. A bank or network can occasionally recall or return a payment after the fact, outside the API. That is rare, it is handled with you directly through support, and it never silently rewrites a status you have already read. Other flows have their own reconciliation logic; if you need to rely on terminality for a specific path (a bill payment, say, rather than a direct payout), ask us to confirm it.

For PAYOUT and WITHDRAWAL, SUCCESS and FAILED are terminal statuses.

Why mobile money is usually PENDING first

A wallet collection needs the payer to approve a prompt on their handset. We return as soon as the request is accepted by the rail, which is before the human has touched anything - so PENDING is the normal, healthy first response, not a warning sign.

Disbursement varies by destination. Many payouts resolve in the same request, but some wallet networks confirm later, so a payout can also come back PENDING. Handle both on every destination rather than assuming one per network.

Resolving a PENDING transaction

Webhooks first. Configure a webhookUrl and we push the outcome as soon as we have it. This is the lowest-latency, lowest-cost option and it is what production integrations should rely on. See Webhooks overview.

Reconcile when you need to ask. Each flow has a reconcile endpoint that re-checks the rail and updates our record:

Flow Endpoint
Collection POST /transactions/collect/{id}/reconcile
Payout POST /transactions/payout-credit-transfer/{id}/reconcile (alias: /transactions/disburse/{id}/reconcile)
Withdrawal POST /transactions/withdraw/{id}/reconcile
Bill payment POST /transactions/pay-bill/{id}/reconcile, POST /transactions/pay-bill-ext/{id}/reconcile
Send money POST /transactions/send-money/{id}/reconcile

Read without re-checking. GET /transactions/find/{id} returns our stored state. Use this once a webhook has already told you the transaction resolved - it is cheaper than a reconcile and does not touch the rail.

Tip

Reconcile on a backoff - 10s, 30s, 2m, 5m, then every 15 minutes - rather than in a tight loop. Combine it with webhooks: webhooks handle the normal case, the reconcile sweep catches anything whose delivery you missed.

Querying

You query with our id, returned in the response that created the transaction. There is currently no lookup by your own reference - persist the id.

Endpoint Returns
GET /transactions/find/{id} The transaction
GET /transactions/details/{id} The transaction with expanded detail
GET /transactions/{id}/journey-snapshot Step-by-step history of what happened and when
GET /transactions/list Your transactions, paginated and filterable

journey-snapshot is the first thing to pull when something looks wrong - it shows each stage of the journey with timestamps, and it is the most useful thing to attach to a support ticket. GET /transactions/{id}/send-money-snapshot is an older name for the same endpoint. It still works, but use journey-snapshot in new code.

Filtering the list

Query parameter Filters on
pg, ipp Page number and items per page
from, to Creation date range
status PENDING, SUCCESS or FAILED
type A transaction type from the table above, e.g. PAYOUT
recipientStatus The recipient-side status
q Free-text search over the description and the recipient's name, email, country and number

Receipts

GET /transactions/receipts/{id} returns the receipt for a SUCCESS transaction, where {id} is the transaction id. It needs the TRANSACTIONS_READ scope. A transaction that is PENDING or FAILED has no receipt yet.

Distinguishing "never seen" from "failed"

You get Means
404 Transaction not found We have no record of this id. Nothing was created.
200 with data.status: "FAILED" It exists and definitively failed.

They are distinguishable by HTTP status code, not by the body alone.

Next

Amounts and charges - which amount field is which.