Token ATH API code examples

Submit an all-time-high job and poll for the result, in curl, JavaScript (fetch) and Python (requests). Shows pool mode (the reliable path), token mode with a fallback, and branching on the pending / estimated / exact states.

All examples read the key from TRIPORT_API_KEY and call https://triport.io/rpc/{chain}. See the Token ATH API overview for how the computation works and the method reference for every field.

Submit a job (curl)

Pool mode — pass the specific pool you want measured:

curl -X POST "https://triport.io/rpc/eth" \
  -H "x-token: $TRIPORT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"triport_getTokenATH",
       "params":[{"chain":"eth","pool":{"address":"0xYOUR_POOL_ADDRESS"},"budget":400}]}'
# -> {"jsonrpc":"2.0","id":1,"result":{"job_id":"ath_01J…","status":"pending","poll_after_s":5}}

Token mode is the same call with "token":"0x…" instead of pool. It may answer pool_selection_incomplete; if it does, retry in pool mode.

Poll for the result (curl)

Wait poll_after_s seconds, then poll with the job_id:

curl -X POST "https://triport.io/rpc/eth" \
  -H "x-token: $TRIPORT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":2,"method":"triport_getTokenATHResult",
       "params":["ath_01J…"]}'
# status "pending" -> poll again later; "estimated" or "exact" -> the result is in `result`

Submit then poll (JavaScript)

The loop respects poll_after_s, stops at a terminal status, gives up after a deadline, and falls back from token mode to pool mode on pool_selection_incomplete.

const URL = "https://triport.io/rpc/eth";


async function rpc(method, params) {
  const res = await fetch(URL, {
    method: "POST",
    headers: { "x-token": process.env.TRIPORT_API_KEY, "Content-Type": "application/json" },
    body: JSON.stringify({ jsonrpc: "2.0", id: 1, method, params }),
  });
  const body = await res.json();
  if (body.error) throw Object.assign(new Error(body.error.message || "rpc_error"), { code: body.error.code });
  return body.result;
}


async function tokenAth(target, { budget = 400, deadlineMs = 16 * 60 * 1000 } = {}) {
  // target: { token } or { pool: { address } }
  const submit = await rpc("triport_getTokenATH", [{ chain: "eth", budget, ...target }]);
  let wait = (submit.poll_after_s ?? 5) * 1000;
  const until = Date.now() + deadlineMs;
  while (Date.now() < until) {
    await new Promise((r) => setTimeout(r, wait));
    const r = await rpc("triport_getTokenATHResult", [submit.job_id]);
    if (r.status === "estimated" || r.status === "exact") return r;
    wait = Math.min(wait * 1.5, 30_000); // seconds, not a tight loop
  }
  throw new Error("ath_timeout");
}


async function athForToken(token) {
  try {
    return await tokenAth({ token });
  } catch (e) {
    if (e.code === "pool_selection_incomplete") {
      // look up the token's primary pool yourself, then:
      // return await tokenAth({ pool: { address: poolAddress } });
    }
    throw e;
  }
}


const ath = await tokenAth({ pool: { address: "0xYOUR_POOL_ADDRESS" } });
console.log(ath.status, ath.ath_trade.block, ath.ath_trade.tx);

Submit then poll (Python)

import os, time, requests


URL = "https://triport.io/rpc/eth"
HEADERS = {"x-token": os.environ["TRIPORT_API_KEY"], "Content-Type": "application/json"}


def rpc(method, params):
    r = requests.post(URL, headers=HEADERS,
                      json={"jsonrpc": "2.0", "id": 1, "method": method, "params": params},
                      timeout=60)
    body = r.json()
    if "error" in body and body["error"]:
        raise RuntimeError(body["error"].get("code") or body["error"].get("message"))
    return body["result"]


def token_ath(target, budget=400, deadline_s=16 * 60):
    submit = rpc("triport_getTokenATH", [{"chain": "eth", "budget": budget, **target}])
    wait = submit.get("poll_after_s", 5)
    end = time.time() + deadline_s
    while time.time() < end:
        time.sleep(wait)
        res = rpc("triport_getTokenATHResult", [submit["job_id"]])
        if res["status"] in ("estimated", "exact"):
            return res
        wait = min(wait * 1.5, 30)
    raise TimeoutError("ath_timeout")


ath = token_ath({"pool": {"address": "0xYOUR_POOL_ADDRESS"}})
num = int(ath["ath_trade"]["price"]["numerator"])
den = int(ath["ath_trade"]["price"]["denominator"])
print(ath["status"], num / den, ath["ath_trade"]["block"])

Reading the result

  • Branch on status: pending means keep polling; estimated and exact are terminal. estimated is a sampled heuristic — check warnings.
  • The price is a rational, ath_trade.price.numerator / .denominator, as strings. Divide with arbitrary precision; do not round before you need to.
  • The peak is in the resolved pool.quote asset and within scope — per pool, not token-global (not_token_global_ATH).
  • On pool_selection_incomplete, resubmit in pool mode with an explicit pool.address.
  • On ath_busy or ath_chain_unavailable, back off and retry later; neither means the token has no ATH.