Skip to content

Reading a transaction state machine

Pending, queued, processing, success, failed. Knowing which states are terminal is the difference between a correct integration and a polling loop that never stops.

A purchase is not an event, it is a lifecycle. Treating it as a single call that returns success or failure works right up until the first time an upstream provider takes ninety seconds to answer, at which point the model breaks and the workarounds begin.

Ureh models purchases as an explicit state machine. Every transaction is in exactly one state, transitions are recorded, and the set of states is closed. Knowing that set is most of what you need.

The states, and what each one is telling you

  • Pending. Accepted and recorded. Funds are reserved. Nothing has been sent upstream yet.
  • Queued. Handed to the background worker. This is the normal state for the first moment after a 202 response.
  • Processing. In flight with the provider. Genuinely in progress, not stuck.
  • Success. Terminal. The value was delivered.
  • Failed. Terminal. It did not happen, and the wallet has been credited back.
  • Reconciliation required. The provider's answer was ambiguous or absent. Not terminal and not a failure. A human or an automated requery will resolve it.

The first three are transient. The next two are final. The last one is the interesting case, and it is the one integrations most often model incorrectly.

Do not treat ambiguity as failure

The tempting shortcut is to map anything that is not success to failure and move on. This is wrong in a specific and expensive way: a transaction awaiting reconciliation may still settle successfully. If you have already told your user it failed and refunded them locally, you now have a delivered purchase and a refunded customer.

Model the ambiguous state as its own outcome in your system. Show the user that it is in progress. Wait for the resolution, which arrives as a webhook or is visible on a status lookup.

Accepted is not completed

A 202 response means accepted for processing. It carries a reference and it is a genuine commitment that the request will be resolved, but it is not a delivery confirmation. Code that reads a 202 and marks an order fulfilled is making a claim the response did not make.

Store the reference. Wait for a terminal state. The reference is the identity of that purchase everywhere else in the platform, including in reconciliation and in support conversations.

Webhooks first, polling as the fallback

Webhooks tell you about a state change when it happens. Polling asks repeatedly and mostly gets the same answer. Build on webhooks, and use a status lookup as a backstop for deliveries you never received, on a slow cadence, for transactions that have been transient for an unusually long time.

A polling loop that runs every second against every open transaction will hit rate limits and still be slower than the webhook you already had.

Building against the Ureh API?

The reference documents every endpoint, request and response shape.

Get API keys API reference

Related Articles

Payments

Why wallets debit before they settle

Debiting a wallet before the upstream provider confirms looks backwards until you think about what happens when two purchases arrive at once.