Push events

Build the ingest call your workflow tool makes, field by field, and see which company the event lands on.

Everything enters through POST /ingest. Each call is validated against its data model, resolved to a company and a person, and committed whole, or refused whole with the exact field named.

POST /ingeststripe_invoice.paidraw payloadstripe_customer_idpiedpiper.comeventraw payloadidentity link
One call, one transaction: the event, its raw payload for evidence, and any new identity links, committed together or refused together.

1. Push your first event

Send one website visit for Pied Piper:

POST /ingest
{
  "source": "web",
  "content": {
    "text": "Laurie viewed /pricing",
    "metadata": {
      "event_type": "person_visited",
      "page_url": "/pricing",
      "visited_at": "2026-08-04T09:14:00Z",
      "channel": "organic",
      "linkedin_url": "https://www.linkedin.com/in/lauriebream",
      "full_name": "Laurie Bream"
    }
  },
  "identityLinks": [
    { "externalIdType": "domain", "externalIdValue": "piedpiper.com" }
  ],
  "timestamp": "2026-08-04T09:14:00Z"
}

In this request:

  1. source names the data model the payload is validated against.
  2. event_type is sent bare (person_visited) and stored source-prefixed (web_person_visited).
  3. The domain link finds Pied Piper, or mints it if this is the first time ackDB has seen it.
  4. timestamp is when it happened in the source, not when you pushed it.
  5. linkedin_url and full_name identify the visitor, so the event lands person-stamped and Laurie exists as a contact.

Note

Always send a domain link or an entityId. Source-specific links only match existing companies. Never send a blank domain; omit the link and let the item park unresolved instead.

2. What one call writes

One committed call writes the event to the timeline, the raw payload for evidence, and any new identity links. It can also mint the entity and create or update people passed in contacts.

It never computes. No enrichment, no derived fields, no side effects beyond what you sent.

3. Handle refusals

Nothing partial: a refused item writes nothing.

RefusalStatus
Unknown or disabled source422
Missing or wrong-typed metadata field422, names the field
No identity links at all422
entityId that does not exist404
Enum value outside its allowed values422, names the value
A person key already owned by a different human409, plus a merge candidate

GET /ingest/logs keeps the recent accept and reject trail with reasons.

4. Pick the data model

source names a data model, the contract the payload is validated against. Ten ship ready to receive, and you can define your own; discovering, creating, and editing them lives in Build. Each event type publishes an ingestExample to start from.

5. Attach files

files[] on any ingest call attaches documents: base64 content, 10MB per file by default. Text extraction and embedding run async; after that the document answers semantic search. List with GET /entities/{entityId}/files.

6. Push in bulk

POST /ingest/batch takes up to 500 items from one source for one company: one resolution, multi-row writes, per-item idempotency. A batch that violates validation fails whole, naming the offending item.