Documentation

RPC API reference

The HTTP interface a node serves to wallets: four endpoints, JSON for status and errors, a compact binary encoding for blocks and payments.

Test network: the coins have no value

The base URL of the public test node is https://node.tint.top. The interface never sees a key or an amount: a wallet sends finished payments and reads whole blocks, which it decrypts itself.

Endpoints

Method and pathAnswers with
GET /v1/statusWhere the chain stands, as JSON.
GET /v1/blocks/{height}One finalized block, in the wire encoding.
GET /v1/blocks?from=NThe blocks with payments from height N on, as a block batch.
POST /v1/transactionsTakes a payment in the wire encoding; answers with its identifier as JSON.

GET /v1/status

request
curl -s https://node.tint.top/v1/status
response (example values)
{
  "chain_id": 6073471695170043905,
  "height": 128431,
  "tip": "9f3c…e21a",
  "genesis": "04b7…c9d0",
  "queued": 0,
  "pools": [
    { "asset": 1, "native": 20000000000000, "other": 10000000000000, "fee_bps": 30 }
  ]
}
FieldMeaning
chain_idIdentifier of the network, bound into every signature and block hash.
heightHeight of the latest finalized block.
tipHash of the latest finalized block, as hex.
genesisHash of the first block, as hex. Two test networks can share a chain_id; this tells them apart.
queuedPayments waiting for a block.
pools[].assetThe coin the pool trades against the native one (1 is TUSD).
pools[].native, pools[].otherWhat the pool holds, in units (1 coin = 100,000,000 units), as of the latest finalized block.
pools[].fee_bpsThe pool's fee in parts of ten thousand; 30 is 0.3%.

GET /v1/blocks/{height}

Returns one finalized block as application/octet-stream. A finalized block never changes, so the response carries Cache-Control: public, max-age=31536000, immutable. A non-numeric height answers invalid_height, an unknown one not_found.

GET /v1/blocks?from=N

Returns the blocks that hold payments from height N on, as one block batch (application/octet-stream), together with the last height the answer accounts for (through). A wallet catching up asks again from the height after through. The answer grows with the chain, so it is sent with Cache-Control: no-store. from must be a whole number.

POST /v1/transactions

Send a finished payment in the wire encoding as the request body. The wallet builds it; the format is defined in the wire.rs module of tint-core: fixed-width fields, one valid encoding per value, no trailing bytes.

request
curl -s -X POST https://node.tint.top/v1/transactions \
  -H 'content-type: application/octet-stream' \
  --data-binary @payment.bin
response
{ "txid": "5be1…07af" }

A transaction starts with the asset (u32), an expiry height (u64) and a kind (0 for a payment, 1 for a swap), followed by a bundle: flags, a value balance, an anchor, the number of actions and the actions with their proof. A swap adds the coin bought, the amount paid in and a second bundle.

Errors

Errors are JSON: {"error":{"code":"...","message":"..."}}.

HTTPcodeMeaning
400malformedThe body is not a payment.
400invalid_heightThe height or from is not a whole number.
404not_foundNo finalized block at this height, or no such resource.
409double_spendA note of this payment is already spent.
409conflictAnother waiting payment spends one of the same notes.
409price_movedThe pool no longer gives what this swap asks for.
413too_largeThe payment is larger than the chain allows.
422rejectedThe payment breaks a rule of the chain; the message says which.
429rate_limitedThis client address has used its request budget. Retry after the Retry-After header.
500internalThe node could not check or encode.
503busy, queue_fullThe node is verifying other payments, or its queue is full. Try again; Retry-After: 1.

Rate limits

By default each client address may make 50 requests per second sustained, with a burst of 100, and at most 4 payments are verified at once across all clients. Operators can change both. Behind a reverse proxy the node counts clients by the last address the proxy wrote in X-Forwarded-For; it does not believe earlier entries.

Example: follow the chain

python (server side)
import json, time, urllib.request

BASE = "https://node.tint.top"

while True:
    with urllib.request.urlopen(f"{BASE}/v1/status", timeout=10) as r:
        status = json.load(r)
    print(status["height"], status["queued"])
    time.sleep(5)

What a node operator can still learn from this interface is the network address a payment came from. Amounts, senders and recipients are inside the proof and the encrypted notes.