Skip to content

Ingestion

The write path. These three endpoints authenticate with an org-scoped Clerk API key (Authorization: Bearer <key>), sit behind the per-org rate limiter and the billing hard stop (429 over_quota), and dedupe retries via Idempotency-Key / messageId. All three name the pipe they arrive through: a sourceId of an api source, from which the server derives the app it belongs to and stamps both ids. An unknown id, or the id of a provider source such as Clerk, is a 422; an archived one is a 403. track also rejects an event name starting with system. with a 422, and a batch item carrying one comes back as that item’s own failed result: the prefix is reserved for the events Cowliss records itself (see Event patterns).

Create or merge a profile

Auth: Org API key (Authorization: Bearer <key>).

Request body

{
"data": {
"sourceId": "string",
"identifiers": {
"anonymousId": "string"
},
"traits": {},
"timestamp": "2026-01-15T09:30:00.000Z",
"messageId": "string"
}
}
Field Type Required Constraints
data object yes
data.sourceId string yes length 1–∞
data.identifiers record<anonymousId | userId | clerkId | email, string> yes
data.traits object no default {}
data.timestamp string (date-time) no
data.messageId string no

Response 200

{
"data": {
"id": "string",
"orgId": "string",
"environment": "development",
"appId": "string",
"sourceId": "string",
"traits": {
"key": {}
},
"consent": {
"key": true
},
"mergedInto": "string",
"createdAt": "2026-01-15T09:30:00.000Z",
"updatedAt": "2026-01-15T09:30:00.000Z",
"identifiers": [
{
"kind": "anonymousId",
"value": "string",
"createdAt": "2026-01-15T09:30:00.000Z"
}
],
"anonymous": true
},
"meta": {
"requestId": "string",
"nextCursor": "string",
"hasMore": true
}
}
Field Type Required Constraints
data object yes
data.id string yes
data.orgId string yes
data.environment “development” | “production” yes
data.appId string yes
data.sourceId string yes
data.traits record<string, any> yes
data.consent record<string, boolean> yes
data.mergedInto string | null yes
data.createdAt string (date-time) yes
data.updatedAt string (date-time) yes
data.identifiers object[] yes
data.identifiers[] object yes
data.identifiers[].kind “anonymousId” | “userId” | “clerkId” | “email” yes
data.identifiers[].value string yes
data.identifiers[].createdAt string (date-time) yes
data.anonymous boolean yes
meta object no
meta.requestId string no
meta.nextCursor string | null no
meta.hasMore boolean no

Errors follow the shared envelope and code table.

Record one event

Auth: Org API key (Authorization: Bearer <key>).

Request body

{
"data": {
"sourceId": "string",
"identifiers": {
"anonymousId": "string"
},
"event": "string",
"properties": {},
"timestamp": "2026-01-15T09:30:00.000Z",
"messageId": "string"
}
}
Field Type Required Constraints
data object yes
data.sourceId string yes length 1–∞
data.identifiers record<anonymousId | userId | clerkId | email, string> yes
data.event string yes length 1–200
data.properties object no default {}
data.timestamp string (date-time) no
data.messageId string yes length 1–∞

Response 200

{
"data": {
"id": "string",
"orgId": "string",
"environment": "development",
"appId": "string",
"sourceId": "string",
"profileId": "string",
"event": "string",
"properties": {
"key": {}
},
"timestamp": "2026-01-15T09:30:00.000Z",
"receivedAt": "2026-01-15T09:30:00.000Z",
"messageId": "string"
},
"meta": {
"requestId": "string",
"nextCursor": "string",
"hasMore": true
}
}
Field Type Required Constraints
data object | object yes
meta object no
meta.requestId string no
meta.nextCursor string | null no
meta.hasMore boolean no

Errors follow the shared envelope and code table.

Import one source’s calls in one request

Auth: Org API key (Authorization: Bearer <key>).

Request body

{
"data": {
"sourceId": "string",
"items": [
{}
]
}
}
Field Type Required Constraints
data object yes
data.sourceId string yes length 1–∞
data.items any[] yes items 1–500

Response 200

{
"data": {
"results": [
{
"ok": true,
"type": "identify",
"id": "string"
}
]
},
"meta": {
"requestId": "string",
"nextCursor": "string",
"hasMore": true
}
}
Field Type Required Constraints
data object yes
data.results object | object | object[] yes
meta object no
meta.requestId string no
meta.nextCursor string | null no
meta.hasMore boolean no

Errors follow the shared envelope and code table.