Choose a flow
Four ways to take a deposit — redirect, iframe, your own UI, or a standing address per player — with the backend and frontend code for each.
Guide
What the platform does, and the shortest path from an API key to a first working deposit.
A crypto cashier for merchants: players deposit, you get told when the money settled, and you pay winnings back out. Nothing custodial happens on the payout side — the platform cannot move your funds without a signature from your own wallet.
| You want to | Use | Networks |
|---|---|---|
| Take a deposit with no UI of your own | Redirect or iframe to the hosted page | EVM |
| Take a deposit inside your own cashier UI | Self-hosted session | EVM |
| Give every player a permanent deposit address | Wallet address | EVM and Tron |
| Pay one player out | Payout | EVM and Tron |
| Pay up to 100 players with one signature | Batch payout | EVM and Tron |
| Know when money moved | Webhooks | all |
| See what your settlement wallet holds | Balance | EVM |
The shortest path from nothing to a payment link a player can actually pay.
API_KEY_ID and an API_KEY_SECRET. One active key per merchant —
issuing a new one revokes the previous. Keep the secret on your backend; it never belongs in a
browser. Without a key you also receive no webhooks, because every
callback we send is signed with it.
client := &time2pay.Client{
BaseURL: os.Getenv("BASE_URL"),
KeyID: os.Getenv("API_KEY_ID"),
Secret: os.Getenv("API_KEY_SECRET"),
}
ctx := context.Background()$client = new Time2payClient(getenv('BASE_URL'), getenv('API_KEY_ID'), getenv('API_KEY_SECRET'));const client = createClient({ baseUrl: env.BASE_URL, keyId: env.API_KEY_ID, secret: env.API_KEY_SECRET });client = Time2payClient(os.environ["BASE_URL"], os.environ["API_KEY_ID"], os.environ["API_KEY_SECRET"])const client = new Time2payClient({
baseUrl: process.env.BASE_URL,
keyId: process.env.API_KEY_ID,
secret: process.env.API_KEY_SECRET,
});sign function against the
test vector before you debug anything else — a wrong
signature and a wrong key look identical from the outside. Then run the
smoke test: one read-only call that proves the key, the clock and
the IP allowlist.
link, err := client.Call(ctx, "POST", "/v1/hpp/sessions", `{
"player_id": "player-123",
"external_order_id": "deposit-1001",
"amount": "125.50",
"network": "eth",
"token": "USDT",
"return_url": "https://casino.example/cashier/return"
}`)
if err != nil {
return err
}
fmt.Println(link["url"])$link = $client->call('POST', '/v1/hpp/sessions', [
'player_id' => 'player-123',
'external_order_id' => 'deposit-1001',
'amount' => '125.50',
'network' => 'eth',
'token' => 'USDT',
'return_url' => 'https://casino.example/cashier/return',
]);
echo $link['url'];const link = await client.call("POST", "/v1/hpp/sessions", {
player_id: "player-123",
external_order_id: "deposit-1001",
amount: "125.50",
network: "eth",
token: "USDT",
return_url: "https://casino.example/cashier/return",
});
console.log(link.url);link = client.call("POST", "/v1/hpp/sessions", {
"player_id": "player-123",
"external_order_id": "deposit-1001",
"amount": "125.50",
"network": "eth",
"token": "USDT",
"return_url": "https://casino.example/cashier/return",
})
print(link["url"])const link = await client.call("POST", "/v1/hpp/sessions", {
player_id: "player-123",
external_order_id: "deposit-1001",
amount: "125.50",
network: "eth",
token: "USDT",
return_url: "https://casino.example/cashier/return",
});
console.log(link.url);{
"session": "sess_9f2c1e",
"token": "E59YRa6MDSiUunx2oZbU1C3-P_jufO18n7ZRj_xeVBE",
"url": "https://time2pay.tech/p/E59YRa6MDSiUunx2oZbU1C3-P_jufO18n7ZRj_xeVBE",
"expires_at": "2026-07-28T18:12:25Z"
}
X-Idempotency-Key and credit exactly
once.
external_order_id is what makes a retry safe. Repeating a create with the
same reference and the same parameters returns the order you already have instead of opening a
second one — and you cannot tell "the request never arrived" from "the response never came back",
so you will retry sooner or later.
Four ways to take a deposit — redirect, iframe, your own UI, or a standing address per player — with the backend and frontend code for each.
EVM and Tron differences, address formats, decimals, and how to turn base units into an amount without a float ever touching it.
Single and batch withdrawals, the one-time allowance they need, and why a stolen API key still cannot move your money.
Everything to tick off before real money flows, and a smoke test that proves your setup in one call.
Unauthenticated, for your load balancer rather than your integration.
| Endpoint | Purpose |
|---|---|
GET /healthz | The process is up. Returns {"status":"ok"}. |
GET /readyz | Dependencies are reachable. 503 means this instance should not receive traffic. |