Polling

Polling keeps your system right even if a webhook is missed.

The pattern

  1. First run: GET /v1/leads?since=2000-01-01T00:00:00Z. Follow next_cursor while has_more is true. That loads every lead, oldest change first.
  2. Save next_since from the last page.
  3. Every 5 to 15 minutes: GET /v1/leads?since=<saved next_since>, following next_cursor the same way.
  4. For each lead, insert it or update your copy, matched on id. Skip it if your copy has the same or newer updated_at.
  5. Save the new next_since.
const BASE = 'https://zqawbbylldymdfzineqq.supabase.co/functions/v1/pro-api/v1/leads';
async function sync(store, key) {
  let since = (await store.get('since')) || '2000-01-01T00:00:00Z';
  let cursor = null;
  do {
    const url = new URL(BASE);
    if (cursor) url.searchParams.set('cursor', cursor); else url.searchParams.set('since', since);
    const r = await fetch(url, { headers: { Authorization: `Bearer ${key}` } });
    if (r.status === 429) return;                         // try again next run
    if (!r.ok) throw new Error(`leads ${r.status}`);
    const page = await r.json();
    for (const lead of page.leads) await upsertById(lead);
    cursor = page.has_more ? page.next_cursor : null;
    if (page.next_since) since = page.next_since;
  } while (cursor);
  await store.set('since', since);
}

Notes

  • A change being saved at the very moment you read can carry a time a moment earlier than next_since. If you want to be certain, send since a minute or two earlier than you saved; matching on id and updated_at handles the repeats.
  • Messages, charges and reviews have their own lists (since or date filters) and webhook events.
  • Every 5 minutes is 12 calls an hour; your limit is 600 (see limits).