Your databaseupsert by id
Your serverwebhook + cron
Toltplatform.tolt.com
1POST partner.updated
2upsert part_8fKq…
3GET ?updated_after=…
4200 data[], next_cursor
5upsert missed rows
id into the same tables, so it does not matter which one gets there first.
Handle webhooks
Add an endpoint in Dashboard → Settings → Webhooks and copy its signing secret (whsec_...). Verify every request with @tolt/webhooks, then upsert.
app/api/webhooks/tolt/route.ts
partner, link, customer, transaction and commission, each with .created and .updated. There are no delete events, see Handle deletions. API refunds change commissions without a commission.* event, which is one more reason to poll. Test locally with the CLI, setting TOLT_WEBHOOK_SECRET to the signing secret tolt listen prints (see Local development):
Backfill and reconcile
Page through a resource ordered byupdated_at, oldest first, between your last cutoff and now. Store the cutoff after each run. The first run, with no updated_after, is your full backfill.
updated_before keeps the window steady while you page. Each run re-reads the last ten minutes, so a clock that drifts ahead of Tolt’s can’t skip rows; upsertIfNewer makes the repeats harmless. Run the same loop for partners, links, customers and transactions.
Why the window has an upper bound
Why the window has an upper bound
updated_after is inclusive and updated_before is exclusive. A row’s updated_at can become visible slightly after the time it carries; ending the window a few minutes in the past means every row in it has already committed. See Pagination for the full rules.Handle deletions
Customers, links, transactions and commissions can be deleted. A deleted row sends no webhook and simply drops out of list results, so neither path above removes it from your copy. Once a day, collect every id Tolt still has and delete the local rows that are gone.customers, links and transactions too. Partners have no delete endpoint; suspending or rejecting one arrives as partner.updated.
