Skip to main content
Until webhooks ship in v2, polling is the way to learn that a customer’s KYC or AML status changed. Done well, polling is deterministic (never misses a record) and frugal (only one or two API calls per polling interval).

The pattern in one paragraph

Track a “high water mark” timestamp in your own database. Each poll asks for customers updated after that timestamp, walks all pages, and advances the watermark to the latest updated_at you saw. That’s it.

Implementation

async function pollChangedCustomers({ watermark, apiKey }) {
  let cursor = null;
  let newWatermark = watermark;

  do {
    const url = new URL('https://app.instantcompliance.ai/api/v1/customers');
    url.searchParams.set('limit', '100');
    url.searchParams.set('updated_since', watermark);
    if (cursor) url.searchParams.set('cursor', cursor);

    const res = await fetch(url, {
      headers: { Authorization: `Bearer ${apiKey}` }
    });

    if (res.status === 429) {
      const wait = Number(res.headers.get('Retry-After') ?? 30);
      await new Promise((r) => setTimeout(r, wait * 1000));
      continue;
    }
    if (!res.ok) throw new Error(`Poll failed: ${res.status}`);

    const { data, has_more, next_cursor } = await res.json();
    for (const customer of data) {
      await upsertIntoYourCrm(customer);
      if (customer.updated_at > newWatermark) {
        newWatermark = customer.updated_at;
      }
    }
    if (!has_more) break;
    cursor = next_cursor;
  } while (true);

  return newWatermark;
}
Persist newWatermark after the loop completes. On the next run, start from where you left off.

How often should I poll?

Use caseInterval
Customer-facing status display1–5 minutes
Internal compliance dashboard5–15 minutes
CRM sync15–60 minutes
Daily reportingOnce per day
A 5-minute poll on a typical org generates ~12 calls/hour — well below the 60/min burst limit.

Edge cases

  • Resume from crash. Persist the watermark after the records are written to your store, not before. Re-runs are safe because every customer write is idempotent against your own primary key.
  • Clock skew. Always use the server’s updated_at value, never Date.now(), as the watermark. Otherwise drift between your clock and ours causes drops or duplicates.
  • Large catch-up after a long outage. The loop handles it — there’s no hard limit on backfill except rate limits. Pace your daily quota.

Stop polling: v2 webhooks

When webhooks ship you can decommission this loop — we’ll push the same events to your endpoint with HMAC signatures and automatic retries. Until then, polling is the safe path.