Order Status
Check the current status of a single order by reference ID.
Query the current status of a specific order using your ref_id. Use this as a fallback when your webhook callback was missed or if you did not configure one.
Replaces POST /check-status
This GET endpoint replaces the deprecated POST /api/v1/check-status. No request body needed, just pass ref_id as a query parameter.
Endpoint
Request Headers
Headers
| Parameter | Type | Required | Description |
|---|---|---|---|
X-Api-Key | String | Yes | Your API Key. |
X-Timestamp | String | Yes | Current Unix timestamp in ms. |
X-Signature | String | Yes | HMAC-SHA256 signature. For GET requests, sign the timestamp only: HMAC(timestamp, apiSecret). |
Query Parameters
Query Params
| Parameter | Type | Required | Description |
|---|---|---|---|
ref_id | String | Yes | Your unique transaction reference ID (max 100 characters). |
Response (Success)
{
"success": true,
"data": {
"order_id": "d7e8f9a0-b1c2-3d4e-5f6a-7b8c9d0e1f2a",
"order_code": "AGN-D7E8F9A0B1C2",
"ref_id": "R-12345",
"product_code": "ALGAN-MLBB-86",
"product_name": "Mobile Legends 86 Diamonds",
"target_id": "12345678",
"zone_id": "1234",
"price": 25000,
"status": "success",
"serial_number": "ALG-A1B2C3D4EF",
"created_at": "2026-05-14T10:30:00.000Z",
"completed_at": "2026-05-14T10:30:05.123Z",
"failure_code": null,
"failure_reason": null
}
}Response (Failed Order)
A failed order now tells you why. status and message are unchanged; failure_code and failure_reason were added beside them.
{
"success": true,
"data": {
"order_id": "b4c5d6e7-...",
"order_code": "AGN-B4C5D6E7F8A9",
"ref_id": "R-12346",
"product_code": "ALGAN-MLBB-86",
"product_name": "Mobile Legends 86 Diamonds",
"target_id": "12345678",
"zone_id": "1234",
"price": 25000,
"status": "failed",
"serial_number": null,
"created_at": "2026-05-14T10:30:00.000Z",
"completed_at": "2026-05-14T10:30:04.881Z",
"failure_code": "PRODUCT_UNAVAILABLE",
"failure_reason": "The order was rejected: product not found"
}
}Failure Codes
failure_code values
| Parameter | Required | Description |
|---|---|---|
NO_SUPPLIER_AVAILABLE | No | We could not source this product at the time of the order. Usually temporary, retry later. |
PRODUCT_UNAVAILABLE | No | The product is delisted or out of stock upstream. Stop offering it until GET /products reports it active again. |
SUPPLIER_MAINTENANCE | No | The game or publisher is in maintenance. Retry later. |
SUPPLIER_UNREACHABLE | No | A network or upstream transport failure (timeout, 5xx, rate limit). Retry later. |
SUPPLIER_REJECTED | No | Rejected for a reason we have not classified. failure_reason carries the upstream wording. |
INVALID_ID | No | The ID checker explicitly confirmed this account does not exist. Re-check the User ID and Zone ID with POST /validation before retrying. |
REGION_LOCK | No | The account's verified region cannot receive this product. Re-check the account region with POST /validation before retrying with a different product. |
PURCHASE_LIMIT | No | The account already used its purchase allowance for this limit-gated product (a first top-up tier or a weekly/monthly pass). Not retryable for the same account. |
WDP_LIMIT_LIKELY | No | A Weekly Diamond Pass order failed for a valid account in a matching region. The most probable cause is the in-game WDP stack limit (max 10 active), which no upstream exposes; the player can confirm the remaining limit in the in-game Diamond shop. LIKELY is deliberate: this is a classified inference, not an upstream confirmation. |
Treat failure_code as an open set
New codes are added whenever we can name a failure more precisely. Switch on the codes you handle and fall back to displaying failure_reason for anything you do not recognise; do not reject unknown codes.
Both fields can be null on a failed order
Some upstream failures reach us as a bare “failed” with no explanation. We report failure_code: null rather than inventing a reason. Orders that failed before this field shipped are also null.
Response (Not Found)
{
"success": false,
"error": "PRODUCT_NOT_FOUND",
"message": "Order not found",
"request_id": "a1b2c3d4-e5f6-..."
}Serial Number Format
The serial_number is always branded with an ALG- prefix. What follows depends on the product type:
serial_number by Type
| Parameter | Type | Required | Description |
|---|---|---|---|
instant / direct | ALG-XXXXXXXXXX | No | A branded reference token only (e.g. ALG-A1B2C3D4EF). There is no code to redeem; the top-up has already been delivered to the target account. Use it as your proof-of-fulfillment reference. |
voucher | ALG-XXXXXXXXXX/CODE | No | The real redeemable voucher code is appended after the slash, e.g. ALG-A1B2C3D4EF/STEAMPH-9XQ2-K7MP-44TZ. Give the customer everything after the "/" to redeem. |
Parsing voucher codes
For type: "voucher" products, split serial_number on the first /. The left side is our branded reference; the right side is the actual code your customer redeems. For instant/direct products there is no /; the whole value is just a reference token.
{
"success": true,
"data": {
"order_id": "f1a2b3c4-d5e6-7890-abcd-ef1234567890",
"order_code": "AGN-F1A2B3C4D5E6",
"ref_id": "R-99001",
"product_code": "ALGAN-STEAM-PHP-500",
"product_name": "Steam Voucher PHP 500",
"target_id": "[email protected]",
"zone_id": null,
"price": 135000,
"status": "success",
"serial_number": "ALG-A1B2C3D4EF/STEAMPH-9XQ2-K7MP-44TZ",
"created_at": "2026-05-14T10:30:00.000Z",
"completed_at": "2026-05-14T10:30:05.123Z",
"failure_code": null,
"failure_reason": null
}
}Important Notes
Field Behavior
| Parameter | Required | Description |
|---|---|---|
order_code | No | NEW: a short, human-quotable rendering of order_id (AGN- + 12 characters), for support chats and invoices. Added beside order_id, never in place of it; order_id is unchanged. If a 36-character UUID is awkward in your database or on your invoices, store this one instead: it is derived from order_id, its format is frozen so it never changes, and it is safe to show your own customers. Not an idempotency key; ref_id remains the only key we deduplicate on. |
serial_number | No | Only returned when status is "success". Null for all other statuses. Format depends on product type; see Serial Number Format above. |
completed_at | No | Only set for terminal statuses (success, failed, refunded). Null while processing. It is now stamped once, at the moment the order reached its final state, and never moves afterwards; callback delivery and retries no longer shift it. Orders completed before this change carry an approximate value. |
zone_id | No | Null if the game does not require a Zone ID. |
failure_code | No | NEW: stable failure category, or null. See Failure Codes above. |
failure_reason | No | NEW: a human-readable sentence you can show your customer, or null. Never names our upstream provider. |
Status Enum
The status field can return one of the following values:
processingThe order is currently being asynchronously processed by us.successThe order was successfully completed. serial_number is available.failedThe order failed (e.g., incorrect target ID). Balance has been automatically refunded.refundedThe order was cancelled and the balance has been refunded manually by an admin.Example cURL
API_KEY="algan_live_..."
API_SECRET="sk_live_..."
TIMESTAMP=$(python3 -c "import time; print(int(time.time() * 1000))")
SIGNATURE=$(echo -n "${TIMESTAMP}" | \
openssl dgst -sha256 -hmac "${API_SECRET}" | awk '{print $2}')
curl -s "https://algan.id/api/v1/order-status?ref_id=R-12345" \
-H "X-Api-Key: ${API_KEY}" \
-H "X-Timestamp: ${TIMESTAMP}" \
-H "X-Signature: ${SIGNATURE}"
Example (Node.js)
const crypto = require('crypto');
const API_KEY = 'algan_live_...';
const API_SECRET = 'sk_live_...';
const timestamp = Date.now().toString();
const refId = 'R-12345';
// GET request → sign timestamp only
const signature = crypto
.createHmac('sha256', API_SECRET)
.update(timestamp)
.digest('hex');
const response = await fetch(
`https://algan.id/api/v1/order-status?ref_id=${refId}`,
{
headers: {
'X-Api-Key': API_KEY,
'X-Timestamp': timestamp,
'X-Signature': signature,
},
}
);
const result = await response.json();
console.log(result.data.status); // "success" | "processing" | ...