/api/v1/accountAccount info
Profile, the key mode in use (test/live), balance, level, and limits. The fastest way to confirm your key and IP are correct.
H2H Partner API documentation: find products, create orders, and follow the results. All examples use fictional data; replace the SKU with one from your account catalog.
https://h2h.indotopup.com/api/v1One Bearer token per key: send the header Authorization: Bearer <key> with every request (except /lookups/games and /lookups/quota). The test key and live key are two different tokens; never put either in public browser code.
Orders with the test key complete within seconds with an SBX-… serial and send webhooks as usual. Targets ending in 9999 simulate a failure. Orders from the dashboard are always live.
Set the Webhook URL in the dashboard. We send a JSON POST when an API order finishes (order.succeeded or order.failed), and order.verification_required when an order needs a code. Orders from the dashboard do not send webhooks. Event envelope:
The H2H-Signature header has the form t=<unix>,v1=<hex>. Compute HMAC-SHA256 of the string "<t>.<raw body>" with the webhook secret, compare using a constant-time comparison, and reject if t is older than 5 minutes. Reply with HTTP 2xx. On failure, we retry after 1 minute, 5 minutes, 15 minutes, 1 hour, and 6 hours. Deduplicate by event id.
All errors take the form { "error": { "code": "…", "message": "…", "fields": { … } } }. Use error.code for program logic, not the message text.
| HTTP | error.code | Meaning |
|---|---|---|
| 400 | bad_request | Body is not valid JSON. |
| 401 | unauthorized / invalid_key | The Authorization: Bearer <key> header is missing or the key is unknown. |
| 402 | insufficient_balance | Insufficient balance to hold the order cost (or a paid player lookup). |
| 403 | live_not_enabled / ip_not_allowed / account_suspended | A live key was used while the account is not yet in Production, the IP is not registered, or the account is suspended. |
| 404 | not_found | The order, batch, product, or endpoint was not found or does not belong to you. |
| 409 | conflict | The reference was reused with different content, the invoice is not yet available, or the verification action is stale. |
| 422 | validation_failed / product_not_found / max_price_too_low / product_out_of_stock | Invalid input. Per-field details are in error.fields. |
| 429 | rate_limited / quota_exceeded | Request limit or lookup quota exceeded. Wait according to the Retry-After header. |
| 500 | server_error | An error on our side. It is safe to retry with the same reference. |
| 502 | provider_unavailable | The player lookup service is temporarily unavailable (no quota consumed). |
/api/v1/accountProfile, the key mode in use (test/live), balance, level, and limits. The fastest way to confirm your key and IP are correct.
/api/v1/catalog/brandsBrands that have products. Limited to 30 requests/minute across all catalog endpoints; store the catalog on your side and sync it periodically.
| Name | Type | Description |
|---|---|---|
| type | string | standard | fallback |
/api/v1/catalog/productsProducts with prices for your account level and their attached input fields (fields). Fallback products (type=fallback) must use max_price when ordered.
| Name | Type | Description |
|---|---|---|
| brand | string | Brand ID or slug. |
| type | string | standard | fallback |
| q | string | Search by product name. |
| limit | integer | Number of items (1–200). |
| after | string | Copy paging.next_after from the previous page. |
/api/v1/catalog/products/{code}A single product by code.
| Name | Type | Description |
|---|---|---|
| code * | string | Product code, e.g. P12319. |
/api/v1/ordersCreates a single order. 201 means the order was accepted; check status for the outcome (queued → processing → succeeded / failed). reference is your idempotency key: if the response is uncertain, resend the same request and you will receive the original order (200 + Idempotent-Replay: true header), not a new one. The Idempotency-Key header is accepted in place of reference. The full max_price (if any) is held upfront; the remainder is refunded on success, and everything is refunded on failure.
| Name | Type | Description |
|---|---|---|
| product * | string | Product code from the catalog (P… standard, F… fallback). |
| target.id * | string | Player ID / destination number. |
| target.zone | string|null | Server/zone if the product requires it (use the option value, not the label). |
| target.extra | object|null | Other additional inputs; keys come from the product fields. |
| reference * | string | Your own unique reference, max 64 characters. |
| max_price | integer|null | Final cost cap (Rupiah). Required for fallback products. |
/api/v1/ordersFallback products (F… codes) try the cheapest route first and switch routes on failure. Send max_price as the price cap; the final cost never exceeds it and the difference is refunded.
| Name | Type | Description |
|---|---|---|
| product * | string | Fallback product code (F…). |
| target.id * | string | Player ID. |
| target.zone | string|null | Server/zone. |
| reference * | string | Unique reference. |
| max_price * | integer | Maximum price cap (≥ current price). |
/api/v1/orders/{id}Retrieve an order by ID or reference. serial contains the voucher/serial code if any; failure is populated on failure (balance is refunded automatically).
| Name | Type | Description |
|---|---|---|
| id * | string | Order ID (ord_…) or your own reference. |
/api/v1/ordersNewest orders first.
| Name | Type | Description |
|---|---|---|
| status | string | queued | processing | succeeded | failed |
| mode | string | test | live |
| from | string | Start date/time (ISO 8601). |
| to | string | End date/time. |
| limit | integer | Number of items (1–200). |
| after | string | Copy paging.next_after from the previous page. |
/api/v1/orders/{id}/verificationSome orders ask the buyer for a code: order.verification.state = "required" and can_submit = true. Submit the code here. 202 only means the code was accepted for processing, not that it is valid. Resending the same code returns the previous result; a different code is rejected with 409. Limited to 5 requests/minute per order.
| Name | Type | Description |
|---|---|---|
| id * | string | Order ID (ord_…) or your own reference. |
| Name | Type | Description |
|---|---|---|
| code * | string | Code from the buyer, 1–128 characters. |
| action_id | string | Latest verification.id. |
| version | integer | Latest verification.version. |
/api/v1/batchesOne standard product, one destination, 1–100 sequential orders. The entire cost is deducted upfront and the price is locked. reference is unique; resending an identical request returns the original batch, while a different request with the same reference is rejected with 409.
| Name | Type | Description |
|---|---|---|
| product * | string | Product code from the catalog (P… standard, F… fallback). |
| target.id * | string | Player ID / destination number. |
| target.zone | string|null | Server/zone if the product requires it (use the option value, not the label). |
| target.extra | object|null | Other additional inputs; keys come from the product fields. |
| reference * | string | Unique batch reference. |
| count * | integer | Number of orders, 1–100. |
/api/v1/batchesNewest batches first.
| Name | Type | Description |
|---|---|---|
| status | string | queued | processing | completed | partially_failed | failed |
| from | string | Start (ISO 8601). |
| to | string | End. |
| limit | integer | Number of items (1–200). |
| after | string | Copy paging.next_after from the previous page. |
/api/v1/batches/{id}Status and progress counts.
| Name | Type | Description |
|---|---|---|
| id * | string | Batch ID (bat_…) or your own reference. |
/api/v1/batches/{id}/ordersSequential child orders (sequence field), each with its own ID.
| Name | Type | Description |
|---|---|---|
| id * | string | Batch ID (bat_…) or your own reference. |
| Name | Type | Description |
|---|---|---|
| limit | integer | Number of items (1–200). |
| after | string | Copy paging.next_after from the previous page. |
/api/v1/batches/{id}/invoiceA single PDF summarizing costs and refunds after all orders are complete. 409 if not yet complete or if it is a test batch. A successful response is an application/pdf file.
| Name | Type | Description |
|---|---|---|
| id * | string | Batch ID (bat_…) or your own reference. |
/api/v1/lookups/gamespublicList of game codes and zone requirements. Public, no key needed.
/api/v1/lookups/quotapublicDaily free quota and additional rates. Public. Player lookup and purchase limit checks share the same quota; resets at 00:00 UTC.
/api/v1/lookups/playerValidate the player ID before ordering. Both found and not-found results consume quota. 404 account does not exist, 402 insufficient balance for a paid lookup, 429 quota exhausted.
| Name | Type | Description |
|---|---|---|
| game * | string | Game code from /lookups/games. |
| id * | string | Player account ID. |
| zone | string|null | Server/zone if required. |
/api/v1/lookups/purchase-limit/mobile-legendsCheck whether the weekly pass/double diamond packages have reached the purchase limit. Uses the same quota as player lookup.
| Name | Type | Description |
|---|---|---|
| id * | string | Account ID. |
| zone * | string | Zone. |
/api/v1/webhooks/testSends a signed webhook.test event to your Webhook URL so you can test your receiver without creating an order. Set your Webhook URL and create a webhook secret in the dashboard first.