---
title: Transaction Idempotency
permalink: /en/notes/onlinePayment/bestPractices/paystatus/
createTime: '2025/03/07 16:01:49'
description: 'Understand idempotency logic for order transactions in different scenarios.'
---
## Idempotency Modes
There are two supported idempotency modes, you can choose the appropriate idempotency mode from below:
1. Non-Failure Final State (default)
2. Failure Final State
## Transaction Status List
The following are possible transaction statuses that may be returned in different scenarios:
### Automatic Capture
| Status | Description |
|:-----------------------------------------------------------------|:-----------------------------------------------|
| `SUCCESS` | Payment successful, transaction successful |
| `CLOSED` | Transaction result due to timeout/closure |
| `FAILED` | Payment failed, user can retry payment |
| `CANCEL` | Risk control review rejected, final state |
| `PROCESSING` | Intermediate state, merchant should wait for PingPongCheckout asynchronous result before business processing. |
| `INIT` | Order initialization |
### Manual Capture
| Status | Description |
|:----------------------------------------------------------------------|:---------------------------------------------------------------|
| `SUCCESS` | Final CAPTURE successful |
| `AUTH_SUCCESS` | AUTH operation successful, still need to initiate CAPTURE operation |
| `CLOSED` | Transaction result due to timeout/closure |
| `FAILED` | Payment failed, user can retry payment |
| `CANCEL` | AUTH operation successful, calling VOID for pre-authorization void |
| `PROCESSING` | Intermediate state, cannot initiate CAPTURE operation, merchant should wait for PingPongCheckout asynchronous result before business processing. |
| `INIT` | Order initialization |
## Order Lifecycle
### Cashier Mode
In Cashier mode, the merchant creates a payment session first. The order enters `PROCESSING` from `INIT`, and the shopper completes the payment flow on PingPong Checkout.
```mermaid
flowchart LR
START((Create Order)) --> INIT[INIT]
INIT --> PROCESSING[PROCESSING]
PROCESSING -->|Payment Successful Sale| SUCCESS[SUCCESS]
PROCESSING -->|Authorization Successful| AUTH_SUCCESS[AUTH_SUCCESS]
AUTH_SUCCESS -->|Capture| SUCCESS
AUTH_SUCCESS -.->|Void| CANCEL[CANCEL]
PROCESSING -.->|Non-terminal Failure / Alternative Payment Method Re-attempt| FAILED[FAILED]
FAILED -.-> PROCESSING
PROCESSING -.->|Rejected by Risk Control| CANCEL
PROCESSING -.->|Closed Due to Timeout| CLOSED[CLOSED]
SUCCESS --> END((END))
CANCEL --> END
CLOSED --> END
```
```mermaid
flowchart LR
START((Create Order)) --> INIT[INIT]
INIT --> PROCESSING[PROCESSING]
PROCESSING -->|Payment Successful Sale| SUCCESS[SUCCESS]
PROCESSING -->|Authorization Successful| AUTH_SUCCESS[AUTH_SUCCESS]
AUTH_SUCCESS -->|Capture| SUCCESS
AUTH_SUCCESS -.->|Void| CANCEL[CANCEL]
PROCESSING -.->|Payment Failed| FAILED[FAILED]
PROCESSING -.->|Rejected by Risk Control| CANCEL
PROCESSING -.->|Closed Due to Timeout| CLOSED[CLOSED]
SUCCESS --> END((END))
FAILED --> END
CANCEL --> END
CLOSED --> END
```
### API Only Mode
In API Only mode, the merchant server creates and advances the payment request through APIs. The status usually starts from `PROCESSING`; in non-terminal failure mode, the shopper can place a new payment request for re-attempt.
```mermaid
flowchart LR
START((Create Order)) --> PROCESSING[PROCESSING]
PROCESSING -->|Payment Successful Sale| SUCCESS[SUCCESS]
PROCESSING -->|Authorization Successful| AUTH_SUCCESS[AUTH_SUCCESS]
AUTH_SUCCESS -->|Capture| SUCCESS
AUTH_SUCCESS -.->|Void| CANCEL[CANCEL]
PROCESSING -.->|Payment Failed| FAILED[FAILED]
FAILED -.->|Non-terminal Failure, New requestId Required for Re-attempt| START
PROCESSING -.->|Rejected by Risk Control| CANCEL
PROCESSING -.->|Closed Due to Timeout| CLOSED[CLOSED]
SUCCESS --> END((END))
CANCEL --> END
CLOSED --> END
```
```mermaid
flowchart LR
START((Create Order)) --> PROCESSING[PROCESSING]
PROCESSING -->|Payment Successful Sale| SUCCESS[SUCCESS]
PROCESSING -->|Authorization Successful| AUTH_SUCCESS[AUTH_SUCCESS]
AUTH_SUCCESS -->|Capture| SUCCESS
AUTH_SUCCESS -.->|Void| CANCEL[CANCEL]
PROCESSING -.->|Payment Failed| FAILED[FAILED]
PROCESSING -.->|Rejected by Risk Control| CANCEL
PROCESSING -.->|Closed Due to Timeout| CLOSED[CLOSED]
SUCCESS --> END((END))
FAILED --> END
CANCEL --> END
CLOSED --> END
```
Status Transition Description
+ The following statuses will send transaction asynchronous notifications:
- `SUCCESS`
- `FAILED`
- `CANCEL`
+ For scenarios where transaction status is not in the above status list, the order API or query interface will synchronously respond with `PROCESSING`, merchants should wait for PingPongCheckout asynchronous result before business processing.
+ When the merchant sends the order closure notification URL (closeNotificationUrl) in the order placement interface, an order closure asynchronous notification will be sent after the order is closed:
- `CLOSED`
+ This status is the order's final state. This notification is associated with merchantTransactionId (merchant transaction ID) to ensure accurate tracking and identification of specific orders.
## Order Association Relationship
```mermaid
%%{init: {
'theme': 'base',
'themeVariables': {
'primaryColor': '#2196F3',
'primaryTextColor': '#FFFFFF',
'primaryBorderColor': '#1976D2',
'lineColor': '#1565C0',
'secondaryColor': '#E3F2FD',
'tertiaryColor': '#BBDEFB',
'background': '#F8FBFF',
'mainBkg': '#E3F2FD',
'nodeBorder': '#1976D2'
}
}}%%
erDiagram
PAYMENT_ORDER ||--o{ PAYMENT_REQUEST : "1:N"
PAYMENT_ORDER ||--o{ REFUND_ORDER : "1:N"
PAYMENT_REQUEST ||--o| VOID_REQUEST : "1:1"
PAYMENT_REQUEST ||--o{ CAPTURE_REQUEST : "1:N"
PAYMENT_REQUEST ||--o{ REFUND_REQUEST : "1:N"
PAYMENT_ORDER {
string merchantTransactionId PK "Payment Order ID"
string status "Order Status"
}
PAYMENT_REQUEST {
string requestId PK "Payment Request ID"
string status "Request Status"
}
REFUND_ORDER {
string refundId PK "Refund Order ID"
string status "Refund Status"
}
VOID_REQUEST {
string voidId PK "Void Request ID"
string status "Void Status"
}
CAPTURE_REQUEST {
string captureId PK "Capture Request ID"
string status "Capture Status"
}
REFUND_REQUEST {
string refundRequestId PK "Refund Request ID"
string status "Refund Status"
}
```
## Transaction Idempotency Rules
+ Payment orders require merchantTransactionId (merchant website order number) to be globally unique; if duplicate orders are placed, the system will idempotently return the payment order information. (Cashier Mode)
+ Payment requests are uniquely identified by merchantTransactionId + requestId; if duplicate payment requests are made, the system will idempotently return the payment request status information (S2S Mode)
Based on the above idempotency rules, we provide some retry windows (see detailed Transaction Recovery)