跳至主要内容

Payment and Order State Model

This page documents the lifecycle of payments and orders on the Aghanim platform: every status, every transition, and how payment status changes drive order status. Use it to understand which webhook fires when, when a player can retry, and how to avoid duplicate charges or premature entitlement revocation.

What's stable and what isn't

The webhook events and API status values described here are part of the public integration contract. The specific intermediate transitions between statuses described on this page are documented for technical clarity but are an implementation detail. They may evolve as the platform grows. Build your integration against the webhook events and API status values, not against a specific transition graph.

Overview

Aghanim separates two entities in the purchase lifecycle:

  • Payment — a single attempt to charge the player through a payment provider. A single order may have multiple payment attempts (for example, after a card decline). Each attempt is a separate payment record.
  • Order — the logical purchase record (a player buying an item, bundle, or subscription). The platform updates the order status in response to payment transitions.

An order terminates only when one of its payments succeeds, when a refund completes, or when a dispute is resolved against the player.

Before a new payment record is created, the platform locks the order by moving it from created (or reattempted) to captured. This lock prevents two concurrent payment attempts on the same order.

Payment lifecycle

Payment statuses

StatusTerminalMeaning
createdNoPayment initiated. The player has started the transaction and Aghanim is waiting for the payment provider to confirm the outcome. payment.pending is emitted at this point.
doneNoPayment captured successfully. May still move to dispute or refund_requested later.
disputeNoA chargeback or refund request has been opened against a previously successful payment. Resolution moves it back to done (defense won or refund declined) or to canceled (chargeback accepted or lost).
refund_requestedNoA refund has been filed but not yet confirmed by the payment provider.
refundedYesRefund confirmed by the payment provider, although funds may not have returned to the player's account yet.
failedYesPayment declined or errored during processing.
expiredYesPayment session expired without capture (the player abandoned checkout, or the payment provider timed out the session).
voidedYesPayment was authorized but voided before capture, typically due to a post-authorization check (country mismatch, anti-fraud).
rejectedYesPayment rejected before submission, typically by the anti-fraud system.
canceledYesReached from dispute only, when a chargeback is accepted.

Payment transitions

FromToCauseTerminal
createddonePayment provider confirms successful captureNo
createdfailedPayment provider declines the payment or returns an errorYes
createdrejectedAnti-fraud declines the paymentYes
createdexpiredPayment provider session times out or the player abandons checkoutYes
createdvoidedPost-authorization check fails (country mismatch, anti-fraud)Yes
donedisputeChargeback initiated or refund requested against a successful paymentNo
donerefund_requestedRefund filed but pending payment provider confirmationNo
donerefundedPayment provider confirms refund immediatelyYes
refund_requestedrefundedPayment provider confirms the pending refundYes
refund_requesteddoneRefund could not be processedNo
disputedoneChargeback reversed or refund declinedNo
disputecanceledChargeback accepted or refund succeededYes

Payment state diagram

Payment state diagram

Order lifecycle

The order status values visible to your integration:

StatusTerminalMeaning
createdNoOrder created. No payment attempt started yet.
capturedNoA payment attempt is in progress. The order is locked against parallel payment attempts.
reattemptedNoThe previous payment attempt failed in a non-terminal way. The order is open for a new payment attempt.
paidNoA payment on this order succeeded. The order proceeds to delivery.
disputedNoA payment on this order is under dispute.
refund_requestedNoA refund has been filed.
refundedYesRefund completed.
canceledYesReached via a resolved dispute.

How payment status drives order status

Order status changes are triggered by payment transitions:

Payment transitionOrder statusEffect
(before payment record is created)created or reattemptedcapturedOrder locked against concurrent payment attempts
createddonecapturedpaiditem.add fired
createdfailedcapturedreattemptedPlayer can retry
createdrejectedcapturedreattemptedPlayer can retry
createdexpiredcapturedreattemptedPlayer can retry
createdvoidedcapturedreattemptedPlayer can retry
donedisputepaiddisputedDispute workflow
donerefund_requestedpaidrefund_requestedRefund pending
done / refund_requestedrefundedrefundedTerminal; item.remove fired
disputecanceleddisputedcanceledTerminal; item.remove fired
disputedonedisputedpaidDispute resolved; entitlement remains

Order state diagram

Order state diagram

Webhooks emitted during the lifecycle

The transitions above drive the webhooks delivered to your integration:

  • payment.pending — emitted when a payment enters created (the player starts the transaction).
  • item.add — emitted only on the success path: when a payment transitions created → done and the order moves to paid.
  • item.remove — emitted on two terminal order outcomes: when an order reaches refunded (covers refund_requested → refunded) and when disputed → canceled (chargeback accepted). Opening a dispute (paid → disputed) and filing a refund (paid → refund_requested) do not emit item.remove — only the terminal resolution does.
  • A payment that ends in failed, rejected, expired, or voided does not produce item.add. The order returns to reattempted and the player may retry.

For a player to complete a purchase, one of their payment attempts must reach done. All other terminal statuses leave the order open for another attempt. Once a payment is done, only → refunded or disputed → canceled revoke the entitlement via item.remove.

Practical guidance

Some payment methods — telco billing such as Beeline or MTS, certain wallets, and PayPal in specific flows — can keep a payment in created for minutes or longer before the payment provider confirms the outcome. To handle these flows correctly and avoid duplicate charges or premature entitlement revocation, your integration should:

  1. Treat payment.pending as the signal to show the player that the purchase is in progress and to block repeated purchase attempts on the same item in your client.
  2. If item.add does not arrive within a reasonable time (10–20 minutes for most methods), call Get Order with the order_id returned at checkout to inspect the current order status.
  3. Release the block when one of the following happens:
    • item.add arrives — the payment succeeded.
    • The order returns to reattempted — a retry is available.
    • The order reaches a terminal status (refunded or canceled).
  4. Treat item.remove as the only signal to revoke entitlement. Do not revoke on paid → disputed or paid → refund_requested — both can be reversed (a dispute may be won, a refund may be declined) and the player keeps the items.
  5. All Aghanim webhook deliveries carry an idempotency_key. Use it to deduplicate repeated deliveries on your side. See Idempotency for the full contract.

需要技术支持?
联系我们的集成技术团队: [email protected]