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
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
Zfor 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
Tor by a single space (2025-07-02 16:45:00). - A bare date —
2025-07-02— is accepted; the time becomes00:00UTC.
null for that
field, and no error is raised — the event is still ingested.
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:
idis the stable primary key. HunterAI upserts by(connection, id), so an event’sidmust never change — a changedidis 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_atand falls back tocreated_at. If you sendupdated_at, it drives incremental selection, ordering, and the watermark; if you do not,created_atdoes.updated_atis 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.
Deletion behaviour
Events have no tombstone — there is nois_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-lengthid, or a missinglead_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
/eventsis 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_idis the most common cause.lead_idis hard-required; an event without one fails its page and thus the events entity. Always attach every event to a lead. typenever fails. An absenttypebecomes an empty string; an over-length one is truncated to 100 chars.- An unparseable timestamp does not fail anything — the field becomes
nulland 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 a5xx. 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./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.