PayMeNow

Statuses & expiry

Payment status values for pay-ins and pay-outs, plus the transaction expiry rules.

Generated from public-api.mdVersion 1.2.0Last updated 2026-09-20

#Payment Statuses

These are the statuses a transaction can hold. status is returned by GET /v1/payments/{id} and at creation.

StatusDescription
pendingCreated, awaiting customer payment (deposit) or review/dispatch (withdraw)
processingHanded to the payment/payout provider
pending_approvalHeld for manual approval (e.g. a payout that needs review)
completedSuccessfully completed
failedFailed, or cancelled by you via POST /v1/payments/{id}/cancel
expiredThe deposit window elapsed without a matching payment
refundedA completed deposit was reversed by an operator
cancelledDefined in the data model but not produced for payments created through this API

Transitions that are actually allowed:

  • pending → processing, pending_approval, completed, failed, expired
  • processing → pending_approval, completed, failed, expired
  • pending_approval → completed, failed
  • completed → refunded
  • failed / expired → pending_approval, completed (this is how a slip upload or an operator rescue revives a transaction)
  • refunded is terminal

Expiry produces expired, not failed. An unpaid deposit ends at expired with an internal failure reason of Transaction expired, and the webhook carries status: "expired" / event transaction.expired. (An earlier revision of this document claimed expiry mapped to failed; that was never the behaviour of the shipped code.)

#Transaction Expiry

  • Deposits expire 10 minutes after creation by default. The exact instant is returned as expires_at; always use that value rather than assuming a duration.
  • If the customer does not pay in time:
    • Status becomes expired (not failed), with an internal failure reason of Transaction expired.
    • A webhook is sent with status: "expired" and event transaction.expired.
  • The expiry sweeper runs every 1 minute and considers pending and processing deposits, so a webhook can arrive up to a minute after expires_at.
  • An expired deposit is not necessarily lost: if the customer did pay, upload the slip within 24 hours via POST /v1/payments/{id}/upload-slip to rescue and credit it.

A PromptPay QR does not expire at the bank. A customer can still scan and pay after expires_at; that payment surfaces as an unmatched transfer for operations to resolve, not as an automatic credit.