Guide
The Ingest API imports contacts and events into an Instasent project so every downstream surface — audiences, campaigns, analytics — sees the same source of truth.
The Ingest API is the door that customer data walks through on its way into Instasent. Every contact you create, every event you record, lands in a project as a datasource and feeds the audience that your campaigns, segments and analytics read from.
It is a focused subset of the Product API: three write endpoints for contacts and events, plus a handful of read endpoints for validating your payloads against the datasource specs. If you already run Product API calls, the same tokens work here — see Authentication.
When to reach for it
Pick the Ingest API when an external system of record owns your customer data and Instasent needs a steady feed of it:
- CRM or e-commerce syncs — push new and updated contacts as your source platform mutates them.
- Product event streams — record purchases, sign-ups, page views or any custom interaction you want to segment on.
- Backfills — load historical data into a fresh project before flipping campaigns on.
If instead you need to read back an audience, trigger a campaign, or orchestrate messaging, that is the Product API's job.
Mental model
Three nouns and one rule of thumb:
- Contacts — the people in your audience. Identified by a
_user_idthat is unique within your datasource. Sending the same_user_idagain updates the existing record. - Events — time-stamped interactions tied to a contact (
purchase,viewed_product,reservation_made, anything you define). Events are immutable once accepted. - Datasource — the logical stream your API token writes to. A project can have several datasources, and when two disagree about the same contact, the Ingest datasource wins.
The rule of thumb: treat Ingest writes as idempotent for contacts and append-only for events. Your client should be safe to retry contact uploads; event uploads must use a stable _event_id so duplicates are discarded on our side.
A day in the life of a contact
Your CRM emits a change
A new customer signs up, or an existing one updates their phone number. Your integration catches the change event.
POST /stream/contacts
Send the contact —
_user_id, identity fields, any custom attributes — as a single-item array. Omit attributes you do not own; nothing you leave out gets overwritten.Instasent merges the record
The datasource is updated synchronously; the audience view is refreshed within seconds.
Later: POST /stream/events
The same customer places an order. You POST a
purchaseevent with_user_idand_event_parameters. The event lands on the contact's timeline and becomes queryable for segmentation.
Shape of the API
All endpoints live under https://api.instasent.com/v1/project/{project}/datasource/{datasource}/:
| Endpoint | Purpose |
|---|---|
POST /stream/contacts | Create or update up to 100 contacts per call. |
DELETE /stream/contacts/{userId} | Permanently remove a contact. |
POST /stream/events | Record up to 100 events per call. |
GET /stream | Stream metadata and quota — also the simplest auth probe. |
GET /stream/specs/* | Discover the attributes, event types and per-event parameters the datasource accepts. |
Per-parameter detail lives in the API Reference.
How contacts are merged
Attributes in a contact payload follow a few simple rules:
- Omitted attribute → existing value kept. Send partial updates without fear.
- Explicit
null→ attribute cleared. - Same
_user_idacross datasources → contacts merge automatically into one audience record, and Ingest values take precedence when they collide.
How events flow
Two shapes for POST /stream/events:
- Event-only — just
_user_id,_event_id,_event_typeand_event_parameters. Skipped silently if the contact does not exist. - Event with embedded contact — add
_user_datato create or update the contact in the same call. Saves a round-trip when your source system can produce both at once.
_event_id must be stable and unique per event. Resend the same id and we drop the duplicate — that is what makes safe retries possible.
Automations and the event time window
Every event you send is stored on the contact's timeline regardless of its date, but only events whose _event_date is close to reception time trigger automations. The Ingest API applies a symmetric window of ±1 hour around the moment we receive the request:
abs(_event_date − reception_time) ≤ 1 hour
Events outside that window are accepted, persisted and queryable for segmentation — they just do not fire any automation. This is a safeguard: without it, a single backfill of historical orders, a producer with clock drift, or a queue replayed after a long stall could enqueue thousands of SMS, emails and other messages for things that already happened.
In practice:
- Omit
_event_datewhen the event is happening "now" — it defaults to the current time and is guaranteed to be inside the window. - Send
_event_dateonly when you genuinely need a specific timestamp, and make sure it is within ±1h of reception. - Backfills of historical events for segmentation or analytics should be sent with their real dates. Automations will not fire for them — by design.