PaymentOrder object
Last updated: 2026-09-26
PaymentOrder is returned by pay-in and payout operations, payment reads, and
webhooks. Fields that do not apply to the selected flow can be omitted or empty.
The OpenAPI schema does not mark response properties as required, so the
presence labels below describe normal response semantics rather than a JSON
Schema guarantee.
| Field | JSON type | Presence | Merchant meaning |
|---|---|---|---|
id | string | Core | Payment order UUID |
merchantReference | string | Core | Merchant-provided reference |
paymentMethod | enum | Core | Selected PAYMENT_METHOD_* value |
type | enum | Core | PAYMENT_ORDER_TYPE_PAYMENT_IN or PAYMENT_ORDER_TYPE_PAYMENT_OUT |
status | enum | Core | Current payment lifecycle status |
amount | string (int64) | Core | Requested amount in minor units; unchanged after creation |
actualAmount | string (int64) | Core | Recognized gross payment amount in minor units; can differ from the requested amount |
currencyCode | string | Core | Payment currency |
currencyMinorUnits | integer (int32) | Optional | Currency exponent captured when the payment was created |
paymentUrl | string | Conditional | Hosted or authorization URL when a redirect is available |
redirectUrl | string | Optional | Merchant return URL stored on the payment |
failureReason | string | Conditional | Public failure reason for a negative outcome |
failureReasonCode | string (int64) | Conditional | Numeric failure code encoded as a JSON string |
createdAt | string (date-time) | Core | Creation timestamp |
updatedAt | string (date-time) | Core | Last update timestamp |
trafficVertical | enum | Core | Transaction vertical classification |
customerSegment | enum | Core | Customer lifecycle segment |
bankTransferDetails | object | Conditional | Generated bank-transfer account state and details |
mobileMoneyTransferDetails | object | Conditional | Transfer instruction availability and safe details; can change while payment status remains pending |
paymentSubMethod | string | Conditional | Public submethod code; currently moniepoint for bank transfer |
See Mobile money transfer objects for
async instructions. Deduplicate webhooks by Idempotency-Key; the same status
can accompany new details.
Requested and recognized amounts
For pay-ins, amount is the full amount the customer is expected to pay.
actualAmount is returned for every payment, including when it equals amount.
Fees are accounted separately; they do not reduce this
gross value. Keep both fields as lossless minor-unit integers.
amount is not a remaining balance: it does not decrease after a partial
transfer. If the completed payment has a different actualAmount, reconcile
that difference against your order; do not assume every method accepts under-
or overpayment.
actualAmount alone is not a completion signal. Credit a customer for a pay-in
only when the reconciled status is PAYMENT_ORDER_STATUS_COMPLETED, and make
that credit idempotent per payment ID across reads and webhooks. For payouts,
use the value for payout reconciliation, not another customer credit.
For payouts, the completed amount must match the requested beneficiary amount. If those values disagree, reconcile the payment instead of accepting a partial payout or issuing another customer credit.
Historical payments completed before actual-amount tracking retain the requested amount in this field. This is not new payment confirmation and must not initiate another customer credit. Once recorded, the value is retained for audit even if the payment status later changes.
Later amount corrections
A later webhook can report a corrected actualAmount for the same payment ID,
including when the status is again PAYMENT_ORDER_STATUS_COMPLETED. This is an
update to the existing payment, not a second payment.
For example, you may first receive a completed pay-in with actualAmount: "10000"
and later receive a correction to "11000". Both updates refer to the same id.
Record the new value against that payment, read the current payment if needed,
and reconcile the difference with your existing records. Do not issue another
full "11000" customer credit simply because another completed webhook arrived.
You may also receive a FAILED update for that same payment before its corrected
completion. For example, observations can be COMPLETED with "10000", then
FAILED retaining "10000", then COMPLETED with "11000". They all belong to
one payment ID. Do not discard the failed update just because completion was
seen earlier, and do not treat it as a separate failed payment. Read the current
payment and reconcile the observations together. A failed update does not
guarantee that another completion will follow.
Deduplicate repeated deliveries by Idempotency-Key, but do not discard every
future update for a payment just because its first completion was processed.
Contact support when the corrected amount and your records cannot be reconciled.
Status
Payment status values are:
PAYMENT_ORDER_STATUS_CREATEDPAYMENT_ORDER_STATUS_PENDINGPAYMENT_ORDER_STATUS_COMPLETEDPAYMENT_ORDER_STATUS_CANCELLEDPAYMENT_ORDER_STATUS_EXPIREDPAYMENT_ORDER_STATUS_FAILED
Treat PAYMENT_ORDER_STATUS_UNSPECIFIED as an unknown/default enum value, not a
successful business outcome. See Payment lifecycle for
reconciliation and Bank transfer details
for the nested bank-transfer object.