Explore in Telegram

apiton guide

How to get alerts on a TON address through the API

Updated

Open in @apitonBotcheck any username, number or domain live in Telegram

v2.Watch in the apiton API follows an address for you, so your code does not have to read the chain in a loop. You name an address, and apiton stores an event for every change and pushes it to your server, or keeps it for you to collect. If you want no code at all, @apitonBot sends alerts in Telegram: tap Watch on a card.

A watch is one address, and the server works out what kind it is:

  • An NFT: a Telegram username, a +888 number, a .ton domain, a gift or any other NFT. Its sale and auction are followed.
  • Any other address: its transactions are followed, above an amount you choose.
Event Means
listed put on sale
price the sale price changed
delisted the sale or auction ended with the same owner
sold the sale or auction ended with a new owner
auction_start an auction began
bid a higher bid
auction_ending under 2 hours left
tx a wallet's transaction

1. Get a key

Send /get_api to @apitonBot. The key looks like 123456789:aB3dE… and goes in the Authorization: Bearer header of every call. A free key is enough. Without a key v2.Watch answers unauthenticated, because a watch has to belong to somebody.

2. Create a watch

curl -X POST https://app.apiton.org/v2.Watch/Create \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer 123456789:aB3dE…' \
  -d '{"address":"UQCdqXGvONLwOr3zCNX5FjapflorB6ZsOdcdfLrjsDLt3AF4",
       "webhook_url":"https://example.com/apiton","min_amount":1}'

The answer has the watch and a webhook_secret starting with whsec_. It is shown once, so store it now. It signs your deliveries, and it is not your API key.

  • address: raw, EQ… or UQ…, mainnet only, no .ton names. The address converter changes one form into another.
  • webhook_url: optional. HTTPS on port 443 or 8443 on a public host. Redirects are not followed.
  • min_amount: for a wallet, the smallest amount that raises an event, in GRAM, 1 by default. 0 means every transaction.

The watch starts from the state it finds: what happened before Create raises nothing.

3. Check the webhook signature

Each event arrives as a POST of JSON with the headers X-Apiton-Signature, X-Apiton-Timestamp and X-Apiton-Event-Id. The signature is sha256= plus the hex HMAC-SHA256 of <timestamp>.<body>, keyed with your secret. Check it over the raw body: parsing the JSON and serialising it again gives different bytes.

import hashlib, hmac, time


def verify(secret: str, headers, body: bytes) -> bool:
    ts = headers.get("X-Apiton-Timestamp", "0")
    if abs(time.time() - int(ts)) > 300:
        return False  # a replayed request
    want = hmac.new(secret.encode(), ts.encode() + b"." + body, hashlib.sha256).hexdigest()
    return hmac.compare_digest("sha256=" + want, headers.get("X-Apiton-Signature", ""))
  • Answer first, work later. Only a 2xx within 5 seconds counts as delivered, even if your work finished.
  • Drop repeats. Delivery is at least once: if your 2xx gets lost, the event comes again with the same id.
  • Try it with Test. It sends a test event right away and tells you what your endpoint answered:
curl -X POST https://app.apiton.org/v2.Watch/Test \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer 123456789:aB3dE…' -d '{"id":"41"}'

4. When your endpoint is down

A failed delivery is retried after 1, 5 and 30 minutes, then every 30 minutes. After about 24 hours of failures the webhook is paused, and nothing is pushed until a Test gets through. List shows each webhook's state and last error. Nothing is lost: events stay readable for 7 days.

5. No server: read with a cursor

Leave out webhook_url. Every event is stored anyway, so a script or a cron job can collect them:

curl -X POST https://app.apiton.org/v2.Watch/Poll \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer 123456789:aB3dE…' \
  -d '{"after_id":"0","limit":50}'

Send next_after_id as the next after_id. Ids only grow, so a stored cursor never skips an event. Each Poll is one request of your plan, while webhook deliveries cost none. A free key's 10,000 requests a month is one Poll every 4½ minutes and nothing else.

6. Limits

Plan Watches Each address read every Webhook pushes per hour Price for 30 days
free 3 3 minutes 10 0
builder 30 30 seconds 100 5 GRAM or 1,000 Stars
pro 30 30 seconds 100 30 GRAM or 6,000 Stars

Events above the hourly cap stay in Poll. The bot's Premium plan has free's numbers here. /upgrade in @apitonBot shows the paid plans.

7. Worth knowing

  • A status change arrives one read later. listed, sold and the like are reported when two reads in a row agree, so one bad read cannot fire a false event. Prices and bids need only one.
  • A busy wallet. One read returns up to 16 transactions. A wallet with more between two reads gets the newest 16 and truncated: true; read the rest with Address/Transactions.

The full handler is in the blog post, and every field is in the reference at docs.apiton.org.

Try it in @apitonBotfree: look up, watch and get alerts in Telegram

Read more on the blog

More guides

Explore the catalog

Search

Open in @apitonBot