Developers

Build with TRAT.

From a 3-line balance query to a full booking integration. Everything you need to integrate Tratok into your app — copy-pasteable code, real contract addresses, and live API endpoints.

Developer Portal → GitHub Quickstart

Quick reference

Chain

Ethereum Mainnet (Chain ID 1), with wTRAT on Binance Smart Chain (Chain ID 56) via the Tratok Bridge.

Contract

0x35bC519E9fe5F04053079e8a0BF2a876D95D2B33

#

Decimals

5 — not 18. Smallest unit: 0.00001 TRAT. This is the most common integration bug.

🔑

API portal

Register at developer.tratok.net. Free tier: 1,000 requests/month. Overage: 1 TRAT per 10 requests.

Reading the TRAT contract

The token is a standard ERC-20 — any RPC provider (Infura, Alchemy, QuickNode, or your own node) reads it identically. Pick your language below.

// JavaScript · ethers.js v6
import { ethers } from "ethers";

const TRAT   = "0x35bC519E9fe5F04053079e8a0BF2a876D95D2B33";
const ABI    = [
    "function balanceOf(address) view returns (uint256)",
    "function totalSupply() view returns (uint256)",
    "function decimals() view returns (uint8)",
    "function symbol() view returns (string)"
];

const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
const contract = new ethers.Contract(TRAT, ABI, provider);

const [symbol, decimals, supply, balance] = await Promise.all([
    contract.symbol(),
    contract.decimals(),
    contract.totalSupply(),
    contract.balanceOf("0xYourAddressHere")
]);

console.log(`${symbol} has ${decimals} decimals`);
console.log(`Supply:  ${ethers.formatUnits(supply,  decimals)}`);
console.log(`Balance: ${ethers.formatUnits(balance, decimals)}`);
// → TRAT has 5 decimals
// → Supply:  100000000000.00000
// → Balance: 1234.56789
// TypeScript · Viem
import { createPublicClient, http, formatUnits } from "viem";
import { mainnet } from "viem/chains";

const TRAT = "0x35bC519E9fe5F04053079e8a0BF2a876D95D2B33" as const;
const erc20Abi = [
    { inputs: [{ type: "address" }], name: "balanceOf",  outputs: [{ type: "uint256" }], stateMutability: "view", type: "function" },
    { inputs: [],                    name: "totalSupply", outputs: [{ type: "uint256" }], stateMutability: "view", type: "function" },
    { inputs: [],                    name: "decimals",    outputs: [{ type: "uint8"   }], stateMutability: "view", type: "function" },
    { inputs: [],                    name: "symbol",      outputs: [{ type: "string"  }], stateMutability: "view", type: "function" }
] as const;

const client = createPublicClient({ chain: mainnet, transport: http(process.env.RPC_URL!) });

const [symbol, decimals, supply, balance] = await Promise.all([
    client.readContract({ address: TRAT, abi: erc20Abi, functionName: "symbol" }),
    client.readContract({ address: TRAT, abi: erc20Abi, functionName: "decimals" }),
    client.readContract({ address: TRAT, abi: erc20Abi, functionName: "totalSupply" }),
    client.readContract({ address: TRAT, abi: erc20Abi, functionName: "balanceOf", args: ["0xYourAddressHere"] })
]);

console.log(`${symbol}: ${formatUnits(balance as bigint, decimals as number)} of ${formatUnits(supply as bigint, decimals as number)}`);
# Python · web3.py
from web3 import Web3
import os

TRAT = Web3.to_checksum_address("0x35bC519E9fe5F04053079e8a0BF2a876D95D2B33")
ABI = [
    {"inputs": [{"type": "address"}], "name": "balanceOf",  "outputs": [{"type": "uint256"}], "stateMutability": "view", "type": "function"},
    {"inputs": [],                    "name": "totalSupply","outputs": [{"type": "uint256"}], "stateMutability": "view", "type": "function"},
    {"inputs": [],                    "name": "decimals",   "outputs": [{"type": "uint8"  }], "stateMutability": "view", "type": "function"},
    {"inputs": [],                    "name": "symbol",     "outputs": [{"type": "string" }], "stateMutability": "view", "type": "function"},
]

w3 = Web3(Web3.HTTPProvider(os.environ["RPC_URL"]))
token = w3.eth.contract(address=TRAT, abi=ABI)

symbol   = token.functions.symbol().call()
decimals = token.functions.decimals().call()
supply   = token.functions.totalSupply().call()
balance  = token.functions.balanceOf("0xYourAddressHere").call()

fmt = lambda n: n / (10 ** decimals)
print(f"{symbol} has {decimals} decimals")
print(f"Supply:  {fmt(supply):,.5f}")
print(f"Balance: {fmt(balance):,.5f}")
# cURL · JSON-RPC · call balanceOf(address)
# Function selector for balanceOf(address): 0x70a08231
# Then append the 32-byte padded address (remove 0x prefix, left-pad to 64 hex chars)

curl -X POST $RPC_URL \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method":  "eth_call",
    "params": [{
      "to":   "0x35bC519E9fe5F04053079e8a0BF2a876D95D2B33",
      "data": "0x70a08231000000000000000000000000YourAddressPaddedTo64Chars"
    }, "latest"],
    "id": 1
  }'

# Response: {"jsonrpc":"2.0","id":1,"result":"0x...balance_in_hex"}
# Convert hex to int and divide by 10^5 (5 decimals) for human-readable balance
!

Remember: TRAT uses 5 decimals

The ERC-20 default in most libraries is 18. If you hard-code 18 when formatting a TRAT balance, you'll display the user as 10¹³× richer than they actually are. Always read decimals() or hard-code the correct value (5).

Sending a TRAT transfer

Same contract, just needs a signer. Amount must be scaled by 10^5.

// JavaScript · ethers.js v6
import { ethers } from "ethers";

const TRAT = "0x35bC519E9fe5F04053079e8a0BF2a876D95D2B33";
const ABI  = ["function transfer(address to, uint256 amount) returns (bool)"];

// Connect wallet — in a dapp this is window.ethereum via BrowserProvider
const provider = new ethers.BrowserProvider(window.ethereum);
const signer   = await provider.getSigner();

const token    = new ethers.Contract(TRAT, ABI, signer);
const to       = "0xRecipientAddressHere";
const amount   = ethers.parseUnits("100.5", 5);   // 100.5 TRAT with 5 decimals

const tx = await token.transfer(to, amount);
console.log("Tx sent:", tx.hash);
const receipt = await tx.wait();
console.log("Confirmed in block:", receipt.blockNumber);

Gas is paid in ETH (or BNB on BSC). Expect to spend a few cents on an L2 or a few dollars on L1 depending on network conditions.

Tratok Labs APIs

Three inventory APIs — accommodation, car rental, cruise — served with a published SLA (249ms average latency, stress-tested to 100K queries/minute).

Accommodation

2.2M rooms across 185 countries

GET /v1/accommodations/search

Car rental

130,000+ rental packages

GET /v1/cars/search

Cruise

9,000+ cruise listings

GET /v1/cruises/search

Authentication

API keys are issued via developer.tratok.net after account verification. Pass the key in an Authorization header.

# Example: search accommodation — sketch based on typical REST API conventions
curl -X GET "https://api.tratok.net/v1/accommodations/search?city=Barcelona&checkin=2026-06-12&checkout=2026-06-15&guests=2" \
  -H "Authorization: Bearer $TRATOK_API_KEY" \
  -H "Accept: application/json"

Full endpoint reference, parameters, and response schemas are published in the developer portal. This page keeps integration examples at the pattern level — the portal is the source of truth for exact syntax.

Pricing

Using the Bridge programmatically

Most users bridge via the UI at bridge.tratok.com. If you're building a programmatic integration, here's the flow:

  1. Approve the bridge vault contract to spend your TRAT (standard ERC-20 approve call)
  2. Deposit by calling the vault's deposit function — this emits a TokensLocked event with nonce, sender, amount, destination
  3. Wait for relayer attestations to reach the threshold (typically under 5 minutes)
  4. Receive wTRAT minted on BSC automatically — no action needed by the user at the destination
  5. Reverse by burning wTRAT on BSC; TRAT is unlocked on Ethereum

Bridge contract ABIs are available in the GitHub repo under the Tratok-blockchain-bridge directory.

Listening for events

Standard ERC-20 events work for TRAT. Listen to Transfer and Approval like any other token.

// Listen to all Transfer events involving a specific address
import { ethers } from "ethers";

const TRAT  = "0x35bC519E9fe5F04053079e8a0BF2a876D95D2B33";
const ABI   = ["event Transfer(address indexed from, address indexed to, uint256 value)"];

const provider = new ethers.WebSocketProvider(process.env.WSS_URL);
const token    = new ethers.Contract(TRAT, ABI, provider);

// Filter: any transfer where `to` is the watched address
const filter = token.filters.Transfer(null, "0xYourWatchedAddress");

token.on(filter, (from, to, value, event) => {
    const amount = ethers.formatUnits(value, 5);
    console.log(`Received ${amount} TRAT from ${from} in block ${event.blockNumber}`);
});

Tools & ecosystem

Testing & development tips

Use an ENS-friendly RPC

Any mainnet RPC works for reading. For development, Alchemy and Infura both offer free tiers well above typical integration needs. QuickNode, Ankr, and LlamaRPC are viable alternatives.

Testnet availability

Tratok's production contracts live on Ethereum mainnet and BSC. For client-side integration testing, use a forked mainnet (Hardhat, Foundry, Anvil) and snapshot the real contract state — that way you exercise the actual bytecode, not a stub.

Format at the edge

A common pattern: store amounts internally as bigint at base-unit precision (multiply by 105), format with decimals() only at display time. Avoids floating-point surprises.

Always verify before you sign

Modern wallets preview transaction effects. If a signature prompt says it's transferring millions of TRAT when you intended to transfer 100, reject. Read the preview.

Ship something

Get an API key in 15 minutes.

Sign up at the developer portal, send your first test call, and ship. The free tier is enough to build a meaningful v1.

Buy TRAT Whitepaper