References and attribution
Which reference attributes a payment to an order, per rail — and why the answer differs between buying and selling.
Attribution answers "which order is this money for?". The answer differs by leg and by rail, and getting it wrong is the most common integration mistake.
There are three references in play. Keeping them straight is most of this page.
| Reference | Whose | Where it comes from |
|---|---|---|
partnerReference | Yours | You choose it. Your reconciliation handle. |
paymentReference | Ours | We issue it on the order. OL plus 10 characters. |
providerReference | The rail's | An M-PESA code, or a bank reference. |
partnerReference makes creation idempotent. paymentReference attributes a
payment. They are not interchangeable.
Buying — you send KES
On M-PESA the reference cannot be transmitted at all
M-PESA Pay Bill carries no narration field. There is nowhere to put
paymentReference, so keep it in your own records rather than trying to send
it. Your Account Number is your dedicated collection account — that is
what identifies you, and the amount plus the time window identify the order.
mpesa — pay the Pay Bill number, with your collection account number as the
Account Number. Pay the kesAmount exactly, and before expiresAt.
bank_transfer (PesaLink, RTGS, EFT) — put paymentReference in the
narration. It is delivered on these rails and gives exact attribution regardless
of amount. This is the stronger path; prefer it where you have the choice.
Two identical amounts in flight at once
On mpesa, two of your open orders with the same kesAmount inside the same
window are genuinely ambiguous. We will not guess: both are held rather than
one being picked arbitrarily. Avoid it by using bank_transfer for
same-amount orders, or by not holding two identical open orders at once.
Selling — you send USDT
Your Tron deposit address is long-lived and the same for every one of your orders, so it cannot tell two of your orders apart.
The transaction hash is what attributes a deposit. Attach it with
PATCH /v1/orders/{id} after you send. Until you do, nothing links your send to the
order you meant.
A hash is normalised before comparison — case and a leading 0x are ignored, because
those are the same on-chain transaction. One hash attributes exactly one order.
Reading both references back
Once a payment is attributed, GET /v1/orders/{id} carries the rail's own code
alongside ours:
{
"paymentReference": "OLA1B2C3D4E5",
"payment": {
"providerReference": "SBX0EXAMPLE",
"bankTransactionId": "SBXTRANS00000000EXAMPLE"
}
}providerReference is the code your own payer will recognise — the M-PESA code
from their handset, or their bank's reference. If you show your end user a receipt,
that is the number to show; ours means nothing to them. Both fields are null until
a payment is attributed.
The values above are placeholders. Rail codes have rail-specific formats that we do not control, so treat both fields as opaque strings: store them, show them, and do not parse them.
Rules of thumb
- One payment funds one order. Do not send a single payment intending to cover two orders; the surplus is not applied to the second.
- Never reuse a
paymentReference. It is issued per order and belongs to that one. partnerReferenceis for creation, not payment. Reusing it on create returns the original order, which is what makes retries safe — it does nothing for attribution.