Web Rabbit MediaDocs
Transactions

Retrieve a transaction

Fetch a single transaction by id.

Fetch the live status of a single transaction by its transaction_id. If the transaction is still pending we poll the upstream provider and reconcile our ledger before responding; terminal transactions (approved or failed) are served straight from our ledger.

iRequires read access
Any valid key (read or read + write) can call this endpoint.

Endpoint

GET/v1/transactions/{transaction_id}
iID format
transaction_id is the 12-digit id returned from /v1/collect/momo or /v1/checkout/session.

Request

shell
curl https://api.webrabbitmedia.com/v1/transactions/521888807466 \
  -H "Authorization: Bearer wr_test_..."

Response

Response · 200
{
  "transaction_id": "521888807466",
  "code": "00",
  "reason_code": "approved",
  "reason": "Transaction Successful",
  "status": "approved",
  "resolved_status": "approved",
  "settled_at": "2026-09-11T11:54:31.402Z"
}

Which field to trust

  • status and resolved_status are always the same value and both come from our ledger. Either is safe to act on. A collection only becomes approved after the upstream provider returns an explicit terminal success for that transaction — an acknowledgement of the request ("transaction initiated") never approves it.
  • reason_code is the machine-readable outcome and is the field to switch on: approved, pending, prompt_sent, prompt_expired, insufficient_funds, declined, cancelled, reversed, failed, upstream_error.
  • code is the upstream provider's numeric status code (00 success · 01 failed · 02 pending · 03 processing) or null. It is never a word — use reason_code for logic and reason for display.
  • settled_at is stamped only when the payment is confirmed collected, never at initiation. A pending transaction has settled_at: null.
  • correction is present (non-null) only on a transaction that was reported approved in error and has since been put right. Such a transaction reads status: "failed", reason_code: "settled_in_error", settled_at: null, reversed_at: null, and correction.previously_reported_status: "approved" with correction.corrected_at. The money was never collected, so this is a correction, not a reversal — if you credited on the earlier approval, unwind it.
ireason_code on transactions created before 11 September 2026
reason_code is recorded at settlement time from that date onward. On older transactions it was filled in afterwards from the provider's message, so it is a faithful reading of what the provider said but was not captured at the moment of settlement.

Unknown transaction — HTTP 404

If the id does not exist for your business + mode, we return HTTP 404 — never a synthetic failed body. Treat 404 as "no record yet"; if you have an Idempotency-Key for the request, look it up before assuming the payment did not happen.

Response · 404
{
  "error": "transaction_not_found",
  "transaction_id": "000000000000"
}

Polling pattern

Poll every ~3 seconds for up to 60 seconds. If you're still pending after that, keep the transaction open in your UI and continue polling at a slower cadence (e.g. every 10s) — MoMo prompts can take longer than a minute to approve. See Webhooks — signed HMAC-SHA256 webhooks are live today and are the recommended path; polling is the fallback.

shell
# poll every 3s until the transaction is no longer pending
for i in $(seq 1 20); do
  out=$(curl -s https://api.webrabbitmedia.com/v1/transactions/521888807466 \
    -H "Authorization: Bearer wr_test_...")
  echo "$out"
  echo "$out" | grep -q '"resolved_status":"pending"' || break
  sleep 3
done