Skip to content

The ingest API

The ingest API is the single entry point for events coming into 2mee. Sending an event can start or advance a flow. It is the same endpoint whether you POST directly, use a generic webhook, or connect a provider like Segment.

POST https://hooks.2mee.com/v1/in/{inboundKey}
Content-Type: application/json
webhook-id: msg_01H... # stable message id (idempotency key)
webhook-timestamp: 1718703600 # unix seconds, for replay rejection
webhook-signature: v1,<base64> # HMAC-SHA256 over the raw body — see signing
{
"version": "1",
"messageId": "msg_01HZX9...",
"occurredAt": "2026-06-18T10:00:00Z",
"eventType": "purchase_completed",
"clientUserId": "user_8842",
"attributes": {
"email": "sam@example.com",
"plan": "pro",
"basketValue": 149.0
},
"endpoints": {
"email": "sam@example.com",
"phone": "+447700900000"
},
"raw": { }
}
FieldTypeRequiredNotes
versionstringyesIngest contract version. Currently "1".
messageIdstringyesStable across retries — used as the idempotency key.
occurredAtstring (ISO-8601)yesWhen the event happened, UTC.
eventTypestringyesYour event name. Trigger routing matches on this.
clientUserIdstringnoYour id for the person. Links the event to a visitor/participant; held if not yet linked.
attributesobjectnoKey/value data mapped onto the visitor and tested by conditions.
endpointsobjectnoemail / phone for reaching the person (used by campaigns).
rawobjectnoYour original payload, retained for audit.
StatusMeaning
202 AcceptedReceived, signature valid, queued for the engine.
401 UnauthorizedSignature missing or wrong.
404 Not FoundUnknown inboundKey.
409 ConflictDuplicate messageId (already processed) — safe to treat as success.
413 Payload Too LargeBody exceeds the size cap (256 KB).
429 Too Many RequestsRate limited — honour Retry-After.

See the error model and rate limits.

  • Send a stable messageId that doesn’t change across retries. 2mee dedupes on it, so re-delivering the same message can’t restart someone’s flow.
  • Include webhook-timestamp. Events outside a 5-minute window (with small clock-skew tolerance) are rejected as replays.

See retries & idempotency.

When you connect a named provider, you don’t build this envelope yourself — the provider’s native payload (e.g. a Segment track) is normalised into it on the way in. See Connect Segment.

Was this page helpful? Tell us / report an issue ↗