time2pay Developer Docs

API reference

Wallet

A standing address per player that takes deposits with no session to open.

What this is

A wallet address is a permanent address that belongs to one of your players on one network. You ask for it once, show it in your cashier, and the player sends to it from any wallet or exchange, as often as they like. There is no session to open and no amount to agree on beforehand: every token enabled on that network is accepted at the same address.

The platform generates and holds the key. That is the difference from the deposit flows, where the player pays a router from their own wallet: here the funds land in an address we control, and from there they are settled to you.

Addresses are bound to (network, player_id). The same pair always returns the same address, so the call is safe to repeat on every cashier visit instead of caching the result. The same player has a different address on each network — an EVM address on eth and bsc, a T… address on tron.

Wallet addresses are switched on per network for your merchant. A network that is not switched on answers 400 unsupported; it is not a signing or permission problem, and a retry will not help.

Wallet

A permanent deposit address per player, per network, held by the platform. No session and no amount: the player sends whatever they like, whenever they like, to the same address.

POST /v1/wallet/address signed

Get a player's deposit address

Returns the player's wallet address on a network, issuing one on the first call. Show it to the player once and they can keep using it: there is no session to open and no amount to agree on beforehand. Every token enabled on that network is accepted at the same address.

Idempotent on (network, player_id). Calling it again is free and returns the same address, so it is safe to call on every visit to the cashier rather than caching it yourself.

Addresses are per network: the same player has a different address on tron and on bsc.

Request body

FieldTypeRequiredDescription
network string yes Network id, lower-case. Only networks with wallet addresses enabled for your merchant are accepted.
player_id string yes Your identifier for the player. The address is bound to it: the same (network, player_id) always returns the same address.

Request

curl -X POST "$BASE_URL/v1/wallet/address" \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: $API_KEY_ID" \
  -H "X-Timestamp: $TS" \
  -H "X-Nonce: $NONCE" \
  -H "X-Signature: $SIG" \
  -d '{"network":"tron","player_id":"player-1042"}'
res, err := client.Call(ctx, "POST", "/v1/wallet/address", `{
	"network": "tron",
	"player_id": "player-1042"
}`)
$res = $client->call('POST', '/v1/wallet/address', [
    'network' => 'tron',
    'player_id' => 'player-1042',
]);
const res = await client.call("POST", "/v1/wallet/address", {
    "network": "tron",
    "player_id": "player-1042"
});
res = client.call("POST", "/v1/wallet/address", {
    "network": "tron",
    "player_id": "player-1042",
})
const res = await client.call("POST", "/v1/wallet/address", {
    "network": "tron",
    "player_id": "player-1042"
});

The client is the one on Signing requests: it signs, sends, and turns an error into an exception carrying its code.

Response 200

The player's address on that network, new or existing.

{
  "address": "TFbu1gKVsrs6c96r3FyuD9aUs3Gdi1HmH3",
  "network": "tron",
  "player_id": "player-1042",
  "created_at": "2026-09-18T12:00:00Z"
}

Errors

400 unsupported A missing or over-long player_id, a missing network, or a network that does not issue wallet addresses for your merchant (code unsupported). Not retryable as sent.
{
  "error": {
    "code": "unsupported",
    "message": "network \"eth\" does not issue deposit addresses for this merchant"
  }
}
401 unauthorized The signature, key, timestamp or nonce did not check out: a missing header, an unknown key id, a timestamp more than 5 minutes from ours, a signature that does not match, or a nonce already used inside the window. Do not retry without rebuilding the request — a retry needs a new timestamp, a new nonce and a new signature.
{
  "error": {
    "code": "unauthorized",
    "message": "invalid signature"
  }
}
403 forbidden The credential is valid but the caller's IP is not in the allowlist configured for your merchant. Not retryable.
{
  "error": {
    "code": "forbidden",
    "message": "client IP not allowed for this merchant"
  }
}

Showing the address

  • Name the network and the token next to the address — "USDT, Tron (TRC-20)". A player who sends BEP-20 USDT to a Tron address, or an unsupported token to any address, has sent it somewhere we do not credit.
  • Offer a QR code and a copy button. Nobody types a 34-character address correctly.
  • Show the minimum. A transfer at or below the processing fee is kept as the fee and never credited — see below.
  • Say it is reusable. The player can save it and top up later without opening your cashier first.

Crediting a deposit

Every transfer that lands on the address and becomes final sends a deposit.confirmed webhook, one per transfer, with its own deposit_id. It carries three amounts:

FieldMeaning
amountWhat the player sent, in whole units.
feeThe processing fee taken from it — a fixed amount per token, set for your merchant — in whole units.
creditedamount − fee, in whole units. Credit the player this.
amount_rawcredited in base units, for ledgers that store integers.

Deduplicate on deposit_id (or X-Idempotency-Key) and credit player_id with credited of token. The event handler on the Webhooks page does exactly that.

A transfer at or below the processing fee is not a deposit. It credits nobody and sends no webhook — the whole amount is kept as the processing fee, and the player loses it. Tell players the minimum next to the address: anything above the fee for that token.

Your commission on wallet deposits is a separate matter between you and the platform: it is never taken from the player, does not appear in this event, and is deducted when your wallet-deposit balance is settled to you.