Skip to main content
Optional. /events returns lead-history events — stage changes, notes, and other per-lead timeline entries. If you do not implement it, return 404 — HunterAI skips it and the sync still succeeds. It is incremental.

Purpose

An event is one entry in a lead’s history — a stage change, a note, or another timeline moment. HunterAI reads /events to reconstruct per-lead activity timelines and stage-change history, so a lead’s progress can be replayed step by step. Every event must point at a lead through lead_id; there is no lead-independent event.

Request

You must return events ordered ascending by the same timestamp that drives the watermark (updated_at if you send it, otherwise created_at). HunterAI advances its watermark page by page and relies on that order; an out-of-order page can cause older events on a later page to be skipped. Events are typically immutable, so most sources sort by created_at.

Response envelope

200 OK
The envelope (data, has_more, page, limit) is the same on every endpoint — see How sync works → The envelope. Only data and has_more are read.

Fields

value_before / value_after accept a scalar, an object, or an array. A scalar such as "stg-new" is stored wrapped as { "value": "stg-new" }; an object or an array is stored unchanged. There is no fixed schema — send whatever best describes the change. HunterAI also keeps the full raw event, so nothing is lost. These two fields are not timestamps and never drive the watermark.

Timestamp format

created_at and updated_at accept a calendar date and time in these concrete forms:
  • With an explicit offset — 2025-07-02T16:45:00+05:00.
  • With a trailing Z for UTC — 2025-07-02T16:45:00Z.
  • With no zone at all — 2025-07-02T16:45:00, which is read as UTC.
  • The date and time may be separated by a T or by a single space (2025-07-02 16:45:00).
  • A bare date — 2025-07-02 — is accepted; the time becomes 00:00 UTC.
Prefer the explicit-offset form. An unparseable value becomes null for that field, and no error is raised — the event is still ingested.
Consequence for the watermark: an event’s watermark timestamp is updated_at if you send it, otherwise created_at. If that timestamp is null or absent — for example an unparseable created_at with no updated_at — the event carries no position and cannot advance the watermark, so it drops out of incremental sync. Keep at least one of the two a valid, advancing timestamp.

Fields the adapter ignores

Sending any of these has no effect on analytics — do not spend effort populating them:
  • created_by — dropped from the mapped columns; there is no actor column on an event. Attribute activity through the lead and its owner instead. See Limitations → Fields dropped entirely.
  • Any other key not listed in the Fields table — events keep your full raw payload, so an unlisted key survives in the raw copy for future reprocessing, but it is not mapped and has no effect on v1.0 analytics.

Identity & cross-references

  • Identity: id is the stable primary key. HunterAI upserts by (connection, id), so an event’s id must never change — a changed id is ingested as a brand-new event.
  • lead_id → resolves against /leads. Every event must carry one; there is no lead-independent event.
  • Events point at no other entity.

Incremental sync

/events is incremental. HunterAI sends updated_since; return only events whose watermark timestamp is greater than or equal to it (inclusive — re-returning the boundary event is harmless, since the upsert is idempotent).
  • The watermark prefers updated_at and falls back to created_at. If you send updated_at, it drives incremental selection, ordering, and the watermark; if you do not, created_at does. updated_at is read for the watermark only and is not stored — send it as a requirement, not as data you expect back.
  • You must return events ordered by the watermark timestamp ascending, so the watermark can advance page by page without skipping an older event on a later page.
  • Whichever timestamp drives the watermark must advance whenever the event changes. An event that never changes keeps a fixed position, which is expected — events are typically immutable.
See How sync works for the shared model.

Deletion behaviour

Events have no tombstone — there is no is_deleted on an event. Because the upsert only inserts and updates, an event you delete in your CRM, or simply stop returning, is not removed from HunterAI; its historical row persists. Only leads support deletion, via is_deleted — see Limitations → Tombstones.

Failure modes

A page of events (up to 100 records) is validated and written as one transaction. The consequences:
  • A single malformed event fails the whole page. If any event on a page cannot be processed — a missing id, an over-length id, or a missing lead_id — none of the events on that page are saved. This is page-level, not per-record.
  • A failed page fails the events entity, not the whole sync. Because /events is optional, a page that fails takes the events entity down and reports it failed, but the overall sync still succeeds — unlike a required entity, whose failure fails the sync. Pages that already committed stay committed, and the next run resumes from the watermark.
  • A missing lead_id is the most common cause. lead_id is hard-required; an event without one fails its page and thus the events entity. Always attach every event to a lead.
  • type never fails. An absent type becomes an empty string; an over-length one is truncated to 100 chars.
  • An unparseable timestamp does not fail anything — the field becomes null and the event is still ingested. See the watermark consequence above.
  • 429, 5xx, and request timeouts are retried with exponential backoff up to 5 times, then the entity fails; a timeout is retried the same way as a 5xx. HunterAI applies its request rate limit per connection, so two connections to the same base URL are throttled independently.
  • A repeated or unbounded page — a page whose IDs match the previous page, or a run past the page ceiling — fails the entity. See How sync works → Paging.

If this endpoint is missing

/events is optional. Returning 404 skips it cleanly — the entity reports success with zero records and the overall sync still succeeds.
Without /events, HunterAI cannot reconstruct per-lead activity timelines or stage-change history. Everything else — leads, their current stage, contacts, tasks, and calls — is unaffected; only the historical replay of how each lead got to its current state is lost.