apiton guide
How to get alerts on a TON address through the API
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…orUQ…, mainnet only, no.tonnames. 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.0means 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,soldand 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 withAddress/Transactions.
The full handler is in the blog post, and every field is in the reference at docs.apiton.org.