T-MARKET API
Market data and spot trading through the same execution engine and ledger as Bitcofy.
Connect to T-MARKET
Manage keys in T-MARKET → API in your Bitcofy account. A new key starts with read access. Enable trading separately to place or cancel orders. Keys expire after the selected period and can be revoked at any time.
API keys cannot withdraw funds or transfer balances between Main, Trading or Gaming. Only your Trading account is accessible. Fund it through the Bitcofy interface.
https://bitcofy.pro/api/t-market/v1
Use HTTPS. Send the key in the header, never in a query string or URL:
Authorization: Bearer $BITCOFY_API_KEY
The credential contains a UUIDv4 and a random 256-bit secret. It is shown once. Bitcofy stores a SHA-256 digest. If the credential is lost, revoke the key and create a replacement. Do not put keys in browser applications distributed to other users, public repositories, screenshots or logs.
Revocation blocks new requests. It does not cancel existing orders or undo a command already accepted for processing. Turn off trading access without revoking the key to keep read access.
Exact amounts and market rules
All prices, quantities, balances, fees, timestamps and large counters are returned as strings. Use an exact decimal or integer library; avoid binary floating point for amounts. The API accepts financial inputs as JSON strings, not JSON numbers. Extra request fields are rejected.
Call GET /markets for authoritative market IDs, network names, enabled status, price/quantity increments, minimum execution value, maximum price/quantity, per-order value limit and open-order limit. An asset’s network is part of its unique asset key; abbreviated tickers are not unique.
Fees are deducted from the asset received by each side at execution: buyers pay in the base asset, sellers in the quote asset. Rates: maker 0.001 = 0.1%, taker 0.002 = 0.2%. Read current rates from /markets. Existing orders retain the fee schedule accepted when created. Fills and fees settle atomically in the ledger.
USDT is real USDT from BSC Mainnet. USDT market minimums are disabled by default and can be configured per market by the administrator. A configured minimum applies to each fill; a smaller remainder is canceled and its reserve released. Read the current minimum and maximum quantity from the catalog. Trading may pause if a network cannot be verified; read access and order cancellation remain available where the engine permits them.
Order types and execution
Limit: type="limit", price in quote per one base asset, quantity in base units. Default time-in-force is GTC: the remaining quantity rests until filled or canceled. IOC executes immediately available quantity and cancels the remainder. FOK fills the entire quantity immediately or cancels it.
Post-only: set post_only=true for a GTC limit order. An order that would immediately cross the book is rejected rather than charged a taker fee.
Market: type="market" always uses IOC, is never post-only and never leaves a resting order. price is mandatory as a worst permitted execution price: maximum for a buy, minimum for a sell. This protects against uncontrolled slippage in a thin book. quantity is the maximum base quantity.
Market buys additionally require max_spend: a quote-asset budget for the spend principal. It is not supported for limit orders or sells. Exhausted budget, missing liquidity, minimum execution and self-trade prevention may produce a partial fill or cancellation. HTTP success means the engine has returned a result; inspect status, reason and filled/remaining quantities.
The engine reserves required balances, applies deterministic ordering, prevents self-trading and posts trades, fees and reserve release atomically. API orders use the same wallet, limits and execution rules as interface orders.
Idempotency and recovery
Every place/cancel command requires Idempotency-Key containing a UUIDv4. Generate a new ID only for a genuinely new action. Persist the ID and exact request payload before sending.
Retry the same command with the same ID and payload after a network error or unknown confirmation. Duplicate execution is prevented by the shared command sequencer and database. Reusing the ID for a different request yields HTTP 409. IDs belong to the user account across API keys and interface commands.
Use GET /commands/{operation_id} to retrieve a committed result. HTTP 404 means no result is visible yet; it does not prove that a previous request cannot still complete. Continue retrying the original request with the original ID. Never replace its ID merely because an HTTP timeout occurred.
Cancellation has its own command UUID. The original placement UUID is the order ID. Repeating a cancel command is safe; cancellation cannot undo fills that have already committed.
import os, uuid, requests
base = "https://bitcofy.pro/api/t-market/v1"
headers = {"Authorization": "Bearer " + os.environ["BITCOFY_API_KEY"],
"Idempotency-Key": str(uuid.uuid4())}
order = {"market": "BTC_TESTNET4__USDT_BSC", "side": "buy",
"type": "limit", "tif": "GTC", "post_only": False,
"price": "2.50", "quantity": "0.01"}
# Persist headers["Idempotency-Key"] and order before submitting.
r = requests.post(base + "/orders", headers=headers, json=order, timeout=25)
print(r.status_code, r.json())
# On an unknown outcome, retry with exactly the same headers and order.This example can spend real USDT. Read the market rules and available balance before using it.
Limits and errors
Rate limits use token buckets shared across API processes. Public traffic: 30 requests/s per IP, burst 60. Authenticated reads additionally allow 10 requests/s per key and user, burst 30. Trading additionally allows 5 requests/s per key and user, burst 10. The IP bucket also applies to private and invalid-authentication requests. Creating extra keys does not bypass the user limit. Reverse-proxy/network protections may impose lower limits.
HTTP 429 includes Retry-After in seconds. Back off instead of immediately retrying in a loop. If the limiter is unavailable, the public API fails closed with 503. Read concurrency and the engine’s command queue are bounded. JSON command bodies are limited to 16 KiB. Requests and responses must not be cached.
| Status | Action |
|---|---|
| 400 / 422 | Correct invalid types, increments, range or unsupported parameters. |
| 401 | Check key, expiration and revocation. |
| 403 | Trading permission is missing or the account is restricted. |
| 404 | Resource not found or not owned; for commands follow recovery rules. |
| 409 | Inspect the error code: idempotency conflict, balance/risk rejection or disabled trading. |
| 413 | Reduce JSON body size. |
| 429 | Respect Retry-After and reduce request rate. |
| 502 / 503 / timeout | Back off; preserve the command UUID and payload until its outcome is known. |
Errors use {"detail": "message"} or {"detail": {"code": "machine_code", "message": "message"}}. Validation errors use FastAPI’s structured detail array. Never infer a new order ID from an error.
Endpoints
Expand an endpoint for parameters and behavior. Download the OpenAPI 3.1 specification for generated clients. API v1 is REST; this version does not expose an authenticated public WebSocket stream.
GET/time
Public. Returns current server Unix time in milliseconds as a string.
GET/markets
Public. Asset definitions, network-specific market IDs, exact increments, current fees and readiness. Parameters include quantity_step, price_tick, min_execution, max_quantity, max_price, max_order_quote and max_open_orders.
GET/book
Public. One consistent snapshot of bids (descending) and asks (ascending), each bounded by limit (1–200, default 100). Levels contain price, quantity, price_ticks and lots. For deeper levels pass after_bid_price_ticks / after_ask_price_ticks from the returned next_bids_price_ticks / next_asks_price_ticks. Paging is live: check sequence and restart from the top when reconciling a moving book.
GET parameters
| Name | Type / default | Required |
|---|---|---|
market | string | yes |
limit | integer / 100 | no |
after_bid_price_ticks | [{'type': 'integer', 'maximum': 9223372036854775807, 'exclusiveMinimum': 0}, {'type': 'null'}] | no |
after_ask_price_ticks | [{'type': 'integer', 'maximum': 9223372036854775807, 'exclusiveMinimum': 0}, {'type': 'null'}] | no |
GET/trades
Public. Newest executions first. limit 1–500 (default 100). Both before_sequence and before_fill_index are required together for a cursor. Each record includes id, sequence, fill_index, accepted_ms, exact price and quantity plus integer ticks/lots. next_cursor is null at the end. Participant identities are not public.
GET parameters
| Name | Type / default | Required |
|---|---|---|
market | string | yes |
limit | integer / 100 | no |
before_sequence | [{'type': 'integer', 'maximum': 9223372036854775807, 'minimum': 1}, {'type': 'null'}] | no |
before_fill_index | [{'type': 'integer', 'maximum': 2147483647, 'minimum': 0}, {'type': 'null'}] | no |
GET/candles
Public. Only Bitcofy executions are aggregated. Empty periods are omitted; no artificial candles are created. seconds: 15, 60, 300, 900, 3600, 14400, 86400, 604800, 2592000. Weeks start Monday UTC; month candles use calendar months UTC, not a rolling 30 days. limit 1–1000 (default 500); before_ms excludes candles opening at/after that millisecond. Candles are oldest first and contain time (Unix seconds), open/high/low/close, volume (base) and lots.
GET parameters
| Name | Type / default | Required |
|---|---|---|
market | string | yes |
seconds | integer / 60 | no |
before_ms | [{'type': 'integer', 'maximum': 9223372036854775807, 'minimum': 1}, {'type': 'null'}] | no |
limit | integer / 500 | no |
GET/account
Read key. Returns only your Trading balances: available, held and total by unique asset key, plus snapshot sequence. Missing wallets report zero; Main and Gaming funds are not implicitly spendable.
GET / POST/orders
GET: read key. Orders owned by your account across all keys and interface. status=open (default), closed or all; optional market. limit 1–100 (default 50). Continue with before_sequence=next_sequence. POST: trading key. Submit the exact string fields described below and preserve Idempotency-Key.
GET parameters
| Name | Type / default | Required |
|---|---|---|
market | [{'type': 'string'}, {'type': 'null'}] | no |
status | string / open | no |
limit | integer / 50 | no |
before_sequence | [{'type': 'integer', 'maximum': 9223372036854775807, 'minimum': 1}, {'type': 'null'}] | no |
POST parameters
| Name | Type / default | Required |
|---|---|---|
Idempotency-Key | [{'type': 'string'}, {'type': 'null'}] | yes |
POST JSON
{"market":"BTC_TESTNET4__USDT_BSC", "side":"buy",
"type":"limit", "price":"2.50", "quantity":"0.01",
"tif":"GTC", "post_only":false}Required: market, side (buy/sell), price, quantity. Optional: type=limit, tif=GTC, post_only=false. Market buy additionally requires max_spend as an exact quote amount for the spend principal. Unrecognized fields, including user IDs, are rejected.
Command response
{"operation_id":"UUIDv4", "order_id":"UUIDv4", "sequence":"123",
"status":"open", "reason":"", "filled_lots":"0", "remaining_lots":"1000000"}GET/orders/{order_id}
Read key. Own order only. Includes exact price, quantity, remaining, filled, created_ms, ticks/lots and up to 500 newest fills with quote/base amounts, your fee and fee_asset, maker/taker role, sequence and accepted_ms. Other users’ IDs return 404.
GET parameters
| Name | Type / default | Required |
|---|---|---|
order_id | string | yes |
GET/commands/{operation_id}
Read key. Retrieve a committed command result owned by your account. Result fields: operation_id, order_id, sequence, status, reason, filled_lots, remaining_lots. A pending command may return 404; retry the original command with the same UUID.
GET parameters
| Name | Type / default | Required |
|---|---|---|
operation_id | string | yes |
POST/orders/{order_id}/cancel
Trading key. POST an empty JSON object and a new Idempotency-Key UUIDv4. The order must belong to your account. The command uses the same ordered sequencer as interface cancellations.
POST parameters
| Name | Type / default | Required |
|---|---|---|
order_id | string | yes |
Idempotency-Key | [{'type': 'string'}, {'type': 'null'}] | yes |