TeePayDocs
Payments

Payment status

How to read a payment's status, poll responsibly and treat final states.

Webhooks are the fastest way to learn a result, but networks fail. Always be able to read the status yourself.

ProductRead endpointFinal when
Mobile money pushGET /v1/collections/{public_reference}succeeded, failed, reversed, refunded
Checkout sessionGET /v1/checkout-sessions/{id}paid, expired
Control NumberGET /v1/control-numbers/{id}Each payment's status is verified
PayoutGET /v1/disbursements/{reference}succeeded, failed, reversed

Polling pattern

While a customer is approving a prompt, poll every 3 to 5 seconds for up to about 3 minutes, then fall back to the webhook and a background check.

async function waitForPayment(reference: string) {
  for (let attempt = 0; attempt < 45; attempt++) {
    const response = await fetch(`https://api.teepay.me/v1/collections/${reference}`, {
      headers: { Authorization: `Bearer ${process.env.TEEPAY_API_KEY}` },
    });
    if (response.status === 429 || response.status === 503) {
      await sleep(Number(response.headers.get('Retry-After') ?? 5) * 1000);
      continue;
    }
    const payment = await response.json();
    if (['succeeded', 'failed', 'reversed', 'refunded'].includes(payment.status)) return payment;
    await sleep(4000);
  }
  return null; // still pending: rely on the webhook and reconcile later
}

Reconciliation

Once a day, list your collections and compare them with your orders:

curl "https://api.teepay.me/v1/collections?status=succeeded&limit=100" \
  -H "Authorization: Bearer $TEEPAY_API_KEY"

Follow next_cursor until it is null. Each item includes fee and net when known, so you can match the amount credited to your TeePay balance.

On this page