Claim Earnings
Commission is claimed on-chain. POST /api/v1/referral/claim creates a claim order (snapshotting all currently claimable earnings), returns an EIP-712 signature from the backend signer, and the user then submits that signature to the ZtdxRewardRouter contract by calling redeemReward(...). There is no off-chain instant-credit mode.
Claimable = Σ referral_earnings.commission
WHERE chain_sync_status = 'synced' AND status = 'pending'
Only earnings that have already been batch-synced to the contract (chain_sync_status = 'synced') and not yet claimed (status = 'pending') are claimable. Earnings still awaiting on-chain sync count toward pending_commission on the dashboard but cannot be claimed yet.
Create Claim
POST /api/v1/referral/claim
Authorization: Bearer <token>
Content-Type: application/json
Request Body
Empty object {}. The claim always covers the user's full claimable balance.
Response
{
"success": true,
"claim_no": "CLM-1a2b3c4d5e6f",
"status": "processing",
"amount": "45000000",
"nonce": 0,
"deadline": 1772097006,
"signature": "0x9efb5f986acf3dafdd...",
"contract_address": "0x...",
"message": "请使用返回的签名调用合约 redeemReward() 方法完成链上领取"
}
| Field | Type | Description |
|---|---|---|
success | bool | Whether the claim order was created |
claim_no | string | Claim order number (CLM- prefix); track it via GET /api/v1/referral/claims |
status | string | Always "processing" — becomes "success" after the on-chain redeem is confirmed |
amount | string | Claim amount as an integer string in on-chain 6-decimal precision (amount × 10^6, e.g., "45000000" = 45 USDT) |
nonce | uint64 | Current on-chain reward nonce for the user (increments after each redeem) |
deadline | uint64 | Signature expiry (Unix timestamp, seconds; 1 hour from issuance) |
signature | string | Backend-generated EIP-712 signature |
contract_address | string | ZtdxRewardRouter contract address |
message | string | Human-readable instruction |
Smart Contract Call
Submit the returned values to the contract:
// redeemReward(uint256 amount, uint256 deadline, bytes signature)
ZtdxRewardRouter(contractAddress).redeemReward(amount, deadline, signature)
The signature covers the EIP-712 struct:
RedeemReward(address account,uint256 value,uint256 nonce,uint256 deadline)
EIP-712 domain: name = "ZTDX Reward Router" (configurable via EIP712_REFERRAL_DOMAIN_NAME), version = "1", chainId = deployment chain, verifyingContract = the ZtdxRewardRouter address returned in contract_address.
After the contract emits RewardRedeemed, the backend event listener (polling every 30 seconds) marks the covered earnings as status = 'claimed' and finalizes the claim order to status = 'success' with the transaction hash.
Error Codes
| HTTP | Code | Description |
|---|---|---|
| 409 | CLAIM_ALREADY_PROCESSING | A previous claim order is still processing — wait for on-chain confirmation |
| 400 | NO_CLAIMABLE | No synced, unclaimed commission available |
| 400 | BELOW_MINIMUM | Claimable amount is below the 10 USDT minimum |
| 500 | CLAIM_PERSIST_ERROR | Failed to create the claim order |
| 500 | SIGNATURE_ERROR | Failed to generate the claim signature |
On-Chain Claim Signature (Custom Amount)
Generate an EIP-712 signature for an arbitrary amount without creating a claim order. Prefer POST /api/v1/referral/claim for the normal flow — this endpoint does not check the claimable balance.
POST /api/v1/referral/on-chain/claim-signature
Authorization: Bearer <token>
Content-Type: application/json
Request Body
{
"amount": "50.00"
}
| Field | Type | Required | Description |
|---|---|---|---|
amount | string | Yes | USDT amount to claim (must be > 0) |
Response
{
"amount": "50000000",
"nonce": 0,
"deadline": 1772097006,
"signature": "0x9efb5f986acf3dafdd...",
"contract_address": "0x..."
}
| Field | Type | Description |
|---|---|---|
amount | string | Amount in on-chain USDT precision (6 decimals, i.e., amount × 10^6) |
nonce | uint64 | Current user nonce (increments after each on-chain claim) |
deadline | uint64 | Signature expiry (Unix timestamp, seconds) |
signature | string | Backend-generated EIP-712 signature |
contract_address | string | ZtdxRewardRouter contract address |
Error Codes
| HTTP | Code | Description |
|---|---|---|
| 400 | INVALID_AMOUNT | Amount format is invalid or ≤ 0 |
| 500 | SIGNATURE_ERROR | Failed to generate claim signature |
Code Examples
Python — Create Claim + Redeem
import requests
BASE_URL = "https://api.prex.world/api/v1"
JWT_TOKEN = "your_jwt_token"
resp = requests.post(
f"{BASE_URL}/referral/claim",
headers={"Authorization": f"Bearer {JWT_TOKEN}", "Content-Type": "application/json"},
json={},
)
data = resp.json()
print(f"Claim {data['claim_no']} [{data['status']}]")
print(f"Amount (6-decimal): {data['amount']}, Nonce: {data['nonce']}, Deadline: {data['deadline']}")
print(f"Signature: {data['signature']}")
print(f"Contract: {data['contract_address']}")
# Next step: call ZtdxRewardRouter.redeemReward(amount, deadline, signature) on-chain.
# The claim order flips to 'success' once RewardRedeemed is observed by the backend.