OpenSequence
DocsAPI referenceSDKs and CLIReference
Contacts

Contact events

Tell the service what it cannot see: meetings booked elsewhere, replies seen in another tool, opt-outs and do-not-contact flags.

Edit on GitHub
curl
curl -X POST $SEQ/v1/contacts/p_7/events -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"id":"cal_evt_8812","type":"meeting_booked","occurred_at":"2026-10-13T14:00:00Z","data":{"starts_at":"2026-10-15T09:00:00Z"}}'
# 201 {"success":true,"data":{"signal":"sig_…","created":true}}   (200 and created:false on a repeat of the same id)

POST /v1/contacts/{id}/events, scope enroll. The event becomes a signal and takes effect on every active enrollment of the contact (exit, attribute, wake), exactly like a signal the service detected itself. Idempotent by id: a retry returns the same signal with created: false. Processing is asynchronous (within about 30 seconds); the webhook signal.received tells you when it is done.

FieldMeaning
idyour idempotency key, up to 200 characters; a calendar event id, a CRM activity id, dnc-<contact>-<date>
typemeeting_booked, opt_out, suppressed, reply
occurred_atwhen it happened (default now); attribution uses it
channelemail, sms, linkedin or all. For opt_out the channel to suppress (default all); for reply the channel the reply arrived on
reasonfor suppressed: do_not_contact, bad_number, invalid_email, left_company, or your own (default client)
dataanything you want on the signal payload

The four types

TypeWhat it does
meeting_bookedcounts as a meeting for the enrollment whose last touch is within the attribution window (14 days by default), credited to the latest touch; exits when exit_on contains meeting_booked. Idempotent with calendar detection: a booking the sender's Google Calendar already showed does not count twice for the same enrollment (the first meeting per enrollment is attributed, later ones are none)
replya reply you saw elsewhere (a LinkedIn inbox, a shared mailbox, a form): credited to the latest touch on that channel, exits when exit_on contains reply, wakes a wait_for reply
opt_outwrites a suppression on the channel (or all), exits every active enrollment with opt_out
suppressedwrites an all suppression with your reason, exits with suppressed

In bulk

POST /v1/contacts:events takes up to 500 events, each with a contact (id or external id) next to the fields above, for a nightly sync of your CRM's do-not-contact list or a calendar backfill. It returns [{ id, signal, created }] in order.

curl
curl -X POST $SEQ/v1/contacts:events -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" -d '{"events":[
  {"contact":"p_7","id":"dnc-p_7","type":"suppressed","reason":"do_not_contact"},
  {"contact":"p_9","id":"dnc-p_9","type":"suppressed","reason":"left_company"}
]}'

These calls are not optional

The service detects replies only in threads it started, bounces, STOP texts, unsubscribe clicks, out-of-office messages, calendar bookings on connected calendars, and Allo call results. A meeting booked through another tool, a person marked do-not-contact in your CRM, someone who left the company, a reply that landed in a shared inbox: all invisible, all yours to report. Treat the suppressed and opt_out reports as mandatory in your integration, and DELETE /v1/contacts/{id} on deletion.

On this page