Order States
Understanding order states is crucial for building reliable payment integrations. HashNut uses a numeric state system to track orders throughout their lifecycle.
State Overview
Active States (In Progress)
State 0: Unpaid
Code: 0
Status: unpaid
Description: Order has been created but no payment has been received.
What Happens:
- Order is waiting for customer payment
- Payment link is active
- Customer can proceed with payment
Merchant Actions:
- ✅ View payment link
- ✅ Cancel order
- ✅ Monitor order status
Next States:
- →
1(Not Completed) - Customer initiates payment - →
-2(Expired) - Order expires - →
-3(Cancelled) - Merchant cancels
State 1: Not Completed
Code: 1
Status: notCompleted
Description: Payment transaction has been initiated but not yet completed.
What Happens:
- Customer has started payment
- Transaction is being prepared
- Waiting for wallet confirmation
Merchant Actions:
- ✅ Monitor order
- ✅ Can cancel if needed
- ⚠️ Wait for completion
Next States:
- →
2(Waiting for Confirmation) - Transaction broadcast - →
-1(Failed) - Transaction rejected
State 2: Waiting for Blockchain Confirmation
Code: 2
Status: waitingForBlockchainConfirmation
Description: Transaction has been broadcast to blockchain, awaiting confirmation.
What Happens:
- Transaction is on blockchain
- Waiting for block inclusion
- Confirmation count increasing
Merchant Actions:
- ✅ Monitor confirmation progress
- ✅ Check transaction on blockchain explorer
- ⚠️ Wait for confirmations
Next States:
- →
3(Confirming) - Block confirmed - →
-1(Failed) - Transaction failed
State 3: Confirming
Code: 3
Status: confirming
Description: Transaction confirmed on blockchain, system is verifying payment details.
What Happens:
- Transaction confirmed
- HashNut verifying:
- Amount matches
- Address is correct
- Token is correct
- Sufficient confirmations
Merchant Actions:
- ✅ Order is being processed
- ⚠️ Wait for verification
Next States:
- →
4(Success) - Payment verified - →
-1(Failed) - Verification failed
State 4: Success
Code: 4
Status: success
Description: Payment successfully received and verified, order is complete.
What Happens:
- ✅ Payment verified
- ✅ Funds in smart contract
- ✅ Webhook sent (if configured)
- ✅ Order complete
Merchant Actions:
- ✅ Fulfill order
- ✅ Update database
- ✅ Process business logic
Next States: None (terminal state)
Terminal States (Final)
State -1: Failed
Code: -1
Status: failed
Description: Payment transaction failed or was rejected.
Common Causes:
- Customer rejected transaction
- Insufficient balance
- Transaction execution failed
- Network error
Merchant Actions:
- ✅ Review failure reason
- ✅ Create new order if needed
- ✅ Contact customer if necessary
Next States: None (terminal state)
State -2: Expired
Code: -2
Status: expired
Description: Order expired without payment within the configured time limit.
What Happens:
- Order is no longer valid
- Payment link is inactive
- Customer cannot pay
Merchant Actions:
- ✅ Create new order if needed
- ✅ Notify customer
- ✅ Clean up expired orders
Next States: None (terminal state)
State -3: Cancelled
Code: -3
Status: cancelled
Description: Order was cancelled by merchant or system.
What Happens:
- Order intentionally cancelled
- Payment link is inactive
- No payment can be made
Merchant Actions:
- ✅ Order closed
- ✅ Create new order if needed
Next States: None (terminal state)
State Reference Table
| State | Code | Status | Type | Description |
|---|---|---|---|---|
| Unpaid | 0 | unpaid | Active | Awaiting payment |
| Not Completed | 1 | notCompleted | Active | Payment initiated |
| Waiting for Confirmation | 2 | waitingForBlockchainConfirmation | Active | Transaction broadcast |
| Confirming | 3 | confirming | Active | Verifying payment |
| Success | 4 | success | Terminal | Payment complete |
| Failed | -1 | failed | Terminal | Payment failed |
| Expired | -2 | expired | Terminal | Order expired |
| Cancelled | -3 | cancelled | Terminal | Order cancelled |
Handling States in Code
Check Order State
- JavaScript
- Python
import { QueryOrderRequest } from '@hashnut/sdk';
const queryRequest = new QueryOrderRequest.Builder()
.withPayOrderId(payOrderId)
.withMerchantOrderId(merchantOrderId)
.withAccessSign(accessSign)
.build();
const queryResponse = await service.queryOrder(queryRequest);
const order = queryResponse.data;
// Handle different states
switch (order.state) {
case 0:
console.log('Order unpaid - waiting for payment');
break;
case 1:
case 2:
case 3:
console.log('Payment in progress...');
break;
case 4:
console.log('Payment successful!');
await fulfillOrder(merchantOrderId);
break;
case -1:
console.log('Payment failed');
await handlePaymentFailure(merchantOrderId);
break;
case -2:
console.log('Order expired');
await handleExpiredOrder(merchantOrderId);
break;
case -3:
console.log('Order cancelled');
break;
}
from hashnut import QueryOrderRequest
query_request = QueryOrderRequest.Builder() \
.with_pay_order_id(pay_order_id) \
.with_merchant_order_id(merchant_order_id) \
.with_access_sign(access_sign) \
.build()
query_response = service.query_order(query_request)
order = query_response.data
# Handle different states
if order.state == 0:
print('Order unpaid - waiting for payment')
elif order.state in [1, 2, 3]:
print('Payment in progress...')
elif order.state == 4:
print('Payment successful!')
fulfill_order(merchant_order_id)
elif order.state == -1:
print('Payment failed')
handle_payment_failure(merchant_order_id)
elif order.state == -2:
print('Order expired')
handle_expired_order(merchant_order_id)
elif order.state == -3:
print('Order cancelled')
Webhook State Handling
app.post('/webhook', async (req, res) => {
const { state, merchantOrderId } = req.body;
// Only process terminal states
if (state === 4) {
// Payment successful
await fulfillOrder(merchantOrderId);
} else if (state < 0) {
// Payment failed, expired, or cancelled
await handleOrderTermination(merchantOrderId, state);
}
// Active states (0-3) are informational only
res.send('success');
});
State Transitions
Normal Flow
0 (Unpaid)
→ 1 (Not Completed)
→ 2 (Waiting for Confirmation)
→ 3 (Confirming)
→ 4 (Success)
Failure Flow
0 (Unpaid)
→ 1 (Not Completed)
→ -1 (Failed) [Transaction rejected]
0 (Unpaid)
→ 1 (Not Completed)
→ 2 (Waiting for Confirmation)
→ -1 (Failed) [Transaction failed]
Expiration Flow
0 (Unpaid)
→ -2 (Expired) [Timeout]
Cancellation Flow
0 (Unpaid)
→ -3 (Cancelled) [Manual cancellation]
Best Practices
State Monitoring
- Poll Active Orders: Regularly check orders in states 0-3
- Handle Terminal States: Always handle states 4, -1, -2, -3
- Idempotency: Ensure state changes are idempotent
- Logging: Log all state transitions for debugging
State-Based Actions
const stateHandlers = {
0: () => console.log('Waiting for payment'),
1: () => console.log('Payment initiated'),
2: () => console.log('Transaction confirming'),
3: () => console.log('Verifying payment'),
4: async (orderId) => {
await fulfillOrder(orderId);
await sendConfirmationEmail(orderId);
},
'-1': async (orderId) => {
await notifyCustomer(orderId, 'Payment failed');
await createRetryOrder(orderId);
},
'-2': async (orderId) => {
await notifyCustomer(orderId, 'Order expired');
},
'-3': () => console.log('Order cancelled'),
};
Next Steps
- Manage Orders: Filter and search by state
- Webhook Integration: Receive state updates
- Error Handling: Handle failed states
Understand states? Learn about Order Management →