# Users

> Part of the Cowliss docs. Markdown for every page: append `index.md` to its URL. Site map: /llms.txt

<!-- GENERATED by apps/docs/scripts/generate-api-reference.ts. Do not edit. Regenerate with `pnpm -F cowliss-docs generate`. -->

A profile holds what an app knows about a recipient: traits, identifiers, the consent map, merged event history, and segment membership. When a profile is merged into another, requests to its `usr_` id redirect to the survivor's URL. GDPR export and erasure can target a single profile by its `usr_` id, taking everything merged into it, or every profile across your apps that carries an identifier. All routes require session-token authentication, and erasure requires `org:admin`.

## GET /v1/users

List and search profiles

**Auth:** Session token.

**Query parameters**

```json
{
  "cursor": "string",
  "limit": 50,
  "direction": "asc",
  "q": "string",
  "appId": "string",
  "trait": "string",
  "traitValue": "string",
  "segmentId": "string"
}
```

| Field | Type | Required | Constraints |
| --- | --- | --- | --- |
| `cursor` | string | no |  |
| `limit` | integer | no | default `50`; 1 ≤ x ≤ 100 |
| `direction` | "asc" \| "desc" | no | default `"asc"` |
| `q` | string | no | length 0–200 |
| `appId` | string | no | length 0–200 |
| `trait` | string | no | length 1–200 |
| `traitValue` | string | no | length 1–500 |
| `segmentId` | string | no | length 1–200 |

**Response 200**

```json
{
  "data": [
    {
      "id": "string",
      "orgId": "string",
      "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,
      "lastEventAt": "2026-01-15T09:30:00.000Z",
      "liveAutomations": 42,
      "lastDeliveryAt": "2026-01-15T09:30:00.000Z"
    }
  ],
  "meta": {
    "requestId": "string",
    "nextCursor": "string",
    "hasMore": true,
    "warnings": [
      {
        "code": "string",
        "message": "string",
        "suggestion": "string"
      }
    ]
  }
}
```

| Field | Type | Required | Constraints |
| --- | --- | --- | --- |
| `data` | object[] | yes |  |
| `data[]` | object | yes |  |
| `data[].id` | string | yes |  |
| `data[].orgId` | string | 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 |  |
| `data[].lastEventAt` | string (date-time) \| null | yes |  |
| `data[].liveAutomations` | integer | yes | 0 ≤ x ≤ ∞ |
| `data[].lastDeliveryAt` | string (date-time) \| null | yes |  |
| `meta` | object | no |  |
| `meta.requestId` | string | no |  |
| `meta.nextCursor` | string \| null | no |  |
| `meta.hasMore` | boolean | no |  |
| `meta.warnings` | object[] | no |  |
| `meta.warnings[]` | object | no |  |
| `meta.warnings[].code` | string | yes |  |
| `meta.warnings[].message` | string | yes |  |
| `meta.warnings[].suggestion` | string | no |  |

Errors follow the [shared envelope and code table](/api-conventions/#errors).

## GET /v1/users/find

Find a profile by one identifier (<kind>:<value>)

**Auth:** Session token.

**Query parameters**

```json
{
  "identifier": "string"
}
```

| Field | Type | Required | Constraints |
| --- | --- | --- | --- |
| `identifier` | string | yes | length 3–220 |

**Response 200**

```json
{
  "data": {
    "id": "string",
    "orgId": "string",
    "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",
        "sourceId": "string",
        "sourceName": "string"
      }
    ],
    "anonymous": true,
    "mergedIds": [
      "string"
    ],
    "email": {
      "address": "string",
      "source": "string"
    }
  },
  "meta": {
    "requestId": "string",
    "nextCursor": "string",
    "hasMore": true,
    "warnings": [
      {
        "code": "string",
        "message": "string",
        "suggestion": "string"
      }
    ]
  }
}
```

| Field | Type | Required | Constraints |
| --- | --- | --- | --- |
| `data` | object | yes |  |
| `data.id` | string | yes |  |
| `data.orgId` | string | 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.identifiers[].sourceId` | string \| null | yes |  |
| `data.identifiers[].sourceName` | string \| null | yes |  |
| `data.anonymous` | boolean | yes |  |
| `data.mergedIds` | string[] | yes |  |
| `data.email` | object \| null | yes |  |
| `data.email.address` | string | yes |  |
| `data.email.source` | string | yes |  |
| `meta` | object | no |  |
| `meta.requestId` | string | no |  |
| `meta.nextCursor` | string \| null | no |  |
| `meta.hasMore` | boolean | no |  |
| `meta.warnings` | object[] | no |  |
| `meta.warnings[]` | object | no |  |
| `meta.warnings[].code` | string | yes |  |
| `meta.warnings[].message` | string | yes |  |
| `meta.warnings[].suggestion` | string | no |  |

Errors follow the [shared envelope and code table](/api-conventions/#errors).

## POST /v1/users/export

Export everything held on the people one identifier names

**Auth:** Session token.

**Request body**

```json
{
  "data": {
    "kind": "anonymousId",
    "value": "string"
  }
}
```

| Field | Type | Required | Constraints |
| --- | --- | --- | --- |
| `data` | object | yes |  |
| `data.kind` | "anonymousId" \| "userId" \| "clerkId" \| "email" | yes |  |
| `data.value` | string | yes | length 1–200 |

**Response 200**

```json
{
  "data": {
    "exportedAt": "2026-01-15T09:30:00.000Z",
    "users": [
      {
        "id": "string",
        "orgId": "string",
        "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",
            "sourceId": "string",
            "sourceName": "string"
          }
        ],
        "anonymous": true,
        "mergedIds": [
          "string"
        ],
        "email": {
          "address": "string",
          "source": "string"
        }
      }
    ],
    "events": [
      {
        "id": "string",
        "orgId": "string",
        "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",
        "client": "string"
      }
    ],
    "eventSummaries": [
      {
        "orgId": "string",
        "appId": "string",
        "profileId": "string",
        "event": "string",
        "count": 42,
        "firstAt": "2026-01-15T09:30:00.000Z",
        "lastAt": "2026-01-15T09:30:00.000Z",
        "recent": [
          "2026-01-15T09:30:00.000Z"
        ]
      }
    ],
    "automations": [
      {
        "id": "string",
        "orgId": "string",
        "automation": "string",
        "profileId": "string",
        "workflowId": "string",
        "runId": "string",
        "completedAt": "2026-01-15T09:30:00.000Z",
        "sent": true,
        "createdAt": "2026-01-15T09:30:00.000Z"
      }
    ],
    "deliveries": [
      {
        "id": "string",
        "orgId": "string",
        "profileId": "string",
        "automation": "string",
        "executionId": "string",
        "appId": "string",
        "broadcastId": "string",
        "kind": "automation",
        "step": "string",
        "channel": "email",
        "status": "sent",
        "dryRun": true,
        "recipient": "string",
        "providerId": "string",
        "error": "string",
        "createdAt": "2026-01-15T09:30:00.000Z",
        "updatedAt": "2026-01-15T09:30:00.000Z",
        "sentAt": "2026-01-15T09:30:00.000Z",
        "settledAt": "2026-01-15T09:30:00.000Z",
        "openedAt": "2026-01-15T09:30:00.000Z",
        "openCount": 42,
        "spamScore": 42,
        "spamSymbols": [
          "string"
        ]
      }
    ],
    "suppressedAddresses": [
      {
        "id": "string",
        "orgId": "string",
        "address": "string",
        "type": "bounce",
        "reason": "string",
        "source": "string",
        "suppressedAt": "2026-01-15T09:30:00.000Z",
        "createdAt": "2026-01-15T09:30:00.000Z",
        "updatedAt": "2026-01-15T09:30:00.000Z"
      }
    ],
    "emailAddresses": [
      {
        "id": "string",
        "orgId": "string",
        "address": "string",
        "verifiedAt": "2026-01-15T09:30:00.000Z",
        "verificationMethod": "link",
        "createdAt": "2026-01-15T09:30:00.000Z",
        "updatedAt": "2026-01-15T09:30:00.000Z"
      }
    ]
  },
  "meta": {
    "requestId": "string",
    "nextCursor": "string",
    "hasMore": true,
    "warnings": [
      {
        "code": "string",
        "message": "string",
        "suggestion": "string"
      }
    ]
  }
}
```

| Field | Type | Required | Constraints |
| --- | --- | --- | --- |
| `data` | object | yes |  |
| `data.exportedAt` | string (date-time) | yes |  |
| `data.users` | object[] | yes |  |
| `data.users[]` | object | yes |  |
| `data.users[].id` | string | yes |  |
| `data.users[].orgId` | string | yes |  |
| `data.users[].appId` | string | yes |  |
| `data.users[].sourceId` | string | yes |  |
| `data.users[].traits` | record\<string, any> | yes |  |
| `data.users[].consent` | record\<string, boolean> | yes |  |
| `data.users[].mergedInto` | string \| null | yes |  |
| `data.users[].createdAt` | string (date-time) | yes |  |
| `data.users[].updatedAt` | string (date-time) | yes |  |
| `data.users[].identifiers` | object[] | yes |  |
| `data.users[].identifiers[]` | object | yes |  |
| `data.users[].identifiers[].kind` | "anonymousId" \| "userId" \| "clerkId" \| "email" | yes |  |
| `data.users[].identifiers[].value` | string | yes |  |
| `data.users[].identifiers[].createdAt` | string (date-time) | yes |  |
| `data.users[].identifiers[].sourceId` | string \| null | yes |  |
| `data.users[].identifiers[].sourceName` | string \| null | yes |  |
| `data.users[].anonymous` | boolean | yes |  |
| `data.users[].mergedIds` | string[] | yes |  |
| `data.users[].email` | object \| null | yes |  |
| `data.users[].email.address` | string | yes |  |
| `data.users[].email.source` | string | yes |  |
| `data.events` | object[] | yes |  |
| `data.events[]` | object | yes |  |
| `data.events[].id` | string | yes |  |
| `data.events[].orgId` | string | yes |  |
| `data.events[].appId` | string | yes |  |
| `data.events[].sourceId` | string | yes |  |
| `data.events[].profileId` | string | yes |  |
| `data.events[].event` | string | yes |  |
| `data.events[].properties` | record\<string, any> | yes |  |
| `data.events[].timestamp` | string (date-time) | yes |  |
| `data.events[].receivedAt` | string (date-time) | yes |  |
| `data.events[].messageId` | string \| null | yes |  |
| `data.events[].client` | string \| null | yes |  |
| `data.eventSummaries` | object[] | yes |  |
| `data.eventSummaries[]` | object | yes |  |
| `data.eventSummaries[].orgId` | string | yes |  |
| `data.eventSummaries[].appId` | string | yes |  |
| `data.eventSummaries[].profileId` | string | yes |  |
| `data.eventSummaries[].event` | string | yes |  |
| `data.eventSummaries[].count` | integer | yes |  |
| `data.eventSummaries[].firstAt` | string (date-time) | yes |  |
| `data.eventSummaries[].lastAt` | string (date-time) | yes |  |
| `data.eventSummaries[].recent` | string (date-time)[] | yes |  |
| `data.automations` | object[] | yes |  |
| `data.automations[]` | object | yes |  |
| `data.automations[].id` | string | yes |  |
| `data.automations[].orgId` | string | yes |  |
| `data.automations[].automation` | string | yes |  |
| `data.automations[].profileId` | string | yes |  |
| `data.automations[].workflowId` | string | yes |  |
| `data.automations[].runId` | string | yes |  |
| `data.automations[].completedAt` | string (date-time) | yes |  |
| `data.automations[].sent` | boolean | yes |  |
| `data.automations[].createdAt` | string (date-time) | yes |  |
| `data.deliveries` | object[] | yes |  |
| `data.deliveries[]` | object | yes |  |
| `data.deliveries[].id` | string | yes |  |
| `data.deliveries[].orgId` | string | yes |  |
| `data.deliveries[].profileId` | string \| null | yes |  |
| `data.deliveries[].automation` | string \| null | yes |  |
| `data.deliveries[].executionId` | string \| null | yes |  |
| `data.deliveries[].appId` | string \| null | yes |  |
| `data.deliveries[].broadcastId` | string \| null | yes |  |
| `data.deliveries[].kind` | "automation" \| "test" \| "api" \| "broadcast" | yes |  |
| `data.deliveries[].step` | string | yes |  |
| `data.deliveries[].channel` | "email" \| "webhook" | yes |  |
| `data.deliveries[].status` | "sent" \| "delivered" \| "bounced" \| "complained" \| "failed" \| "skipped_disabled" \| "skipped_paused" \| "skipped_suspended" \| "skipped_suppressed" \| "skipped_quota" \| "skipped_unknown_purpose" \| "skipped_frequency_cap" \| "skipped_consent" \| "skipped_domain" \| "skipped_ssrf" \| "skipped_spam" \| "would_send" \| "would_skip_disabled" \| "would_skip_paused" \| "would_skip_suspended" \| "would_skip_suppressed" \| "would_skip_quota" \| "would_skip_unknown_purpose" \| "would_skip_frequency_cap" \| "would_skip_consent" \| "would_skip_domain" \| "would_skip_ssrf" \| "would_skip_spam" | yes |  |
| `data.deliveries[].dryRun` | boolean | yes |  |
| `data.deliveries[].recipient` | string \| null | yes |  |
| `data.deliveries[].providerId` | string \| null | yes |  |
| `data.deliveries[].error` | string \| null | yes |  |
| `data.deliveries[].createdAt` | string (date-time) | yes |  |
| `data.deliveries[].updatedAt` | string (date-time) | yes |  |
| `data.deliveries[].sentAt` | string (date-time) \| null | yes |  |
| `data.deliveries[].settledAt` | string (date-time) \| null | yes |  |
| `data.deliveries[].openedAt` | string (date-time) \| null | yes |  |
| `data.deliveries[].openCount` | integer | yes | -2147483648 ≤ x ≤ 2147483647 |
| `data.deliveries[].spamScore` | number \| null | yes |  |
| `data.deliveries[].spamSymbols` | string[] \| null | yes |  |
| `data.suppressedAddresses` | object[] | yes |  |
| `data.suppressedAddresses[]` | object | yes |  |
| `data.suppressedAddresses[].id` | string | yes |  |
| `data.suppressedAddresses[].orgId` | string | yes |  |
| `data.suppressedAddresses[].address` | string | yes |  |
| `data.suppressedAddresses[].type` | "bounce" \| "complaint" \| "manual" \| null | yes |  |
| `data.suppressedAddresses[].reason` | string \| null | yes |  |
| `data.suppressedAddresses[].source` | string \| null | yes |  |
| `data.suppressedAddresses[].suppressedAt` | string (date-time) | yes |  |
| `data.suppressedAddresses[].createdAt` | string (date-time) | yes |  |
| `data.suppressedAddresses[].updatedAt` | string (date-time) | yes |  |
| `data.emailAddresses` | object[] | yes |  |
| `data.emailAddresses[]` | object | yes |  |
| `data.emailAddresses[].id` | string | yes |  |
| `data.emailAddresses[].orgId` | string | yes |  |
| `data.emailAddresses[].address` | string | yes |  |
| `data.emailAddresses[].verifiedAt` | string (date-time) \| null | yes |  |
| `data.emailAddresses[].verificationMethod` | "link" \| "imported" \| "provider" \| null | yes |  |
| `data.emailAddresses[].createdAt` | string (date-time) | yes |  |
| `data.emailAddresses[].updatedAt` | string (date-time) | yes |  |
| `meta` | object | no |  |
| `meta.requestId` | string | no |  |
| `meta.nextCursor` | string \| null | no |  |
| `meta.hasMore` | boolean | no |  |
| `meta.warnings` | object[] | no |  |
| `meta.warnings[]` | object | no |  |
| `meta.warnings[].code` | string | yes |  |
| `meta.warnings[].message` | string | yes |  |
| `meta.warnings[].suggestion` | string | no |  |

Errors follow the [shared envelope and code table](/api-conventions/#errors).

## POST /v1/users/erase

Erase every person one identifier names (GDPR)

Admin only. Terminates active automation executions, then permanently deletes every profile across your apps that carries the identifier, along with their merged profiles, and their event and delivery history. This action cannot be undone.

**Auth:** Session token.

**Request body**

```json
{
  "data": {
    "kind": "anonymousId",
    "value": "string"
  }
}
```

| Field | Type | Required | Constraints |
| --- | --- | --- | --- |
| `data` | object | yes |  |
| `data.kind` | "anonymousId" \| "userId" \| "clerkId" \| "email" | yes |  |
| `data.value` | string | yes | length 1–200 |

**Response 200**

```json
{
  "data": {
    "profileIds": [
      "string"
    ],
    "terminatedInstances": 42
  },
  "meta": {
    "requestId": "string",
    "nextCursor": "string",
    "hasMore": true,
    "warnings": [
      {
        "code": "string",
        "message": "string",
        "suggestion": "string"
      }
    ]
  }
}
```

| Field | Type | Required | Constraints |
| --- | --- | --- | --- |
| `data` | object | yes |  |
| `data.profileIds` | string[] | yes |  |
| `data.terminatedInstances` | integer | yes | 0 ≤ x ≤ ∞ |
| `meta` | object | no |  |
| `meta.requestId` | string | no |  |
| `meta.nextCursor` | string \| null | no |  |
| `meta.hasMore` | boolean | no |  |
| `meta.warnings` | object[] | no |  |
| `meta.warnings[]` | object | no |  |
| `meta.warnings[].code` | string | yes |  |
| `meta.warnings[].message` | string | yes |  |
| `meta.warnings[].suggestion` | string | no |  |

Errors follow the [shared envelope and code table](/api-conventions/#errors).

## GET /v1/users/{profileId}

Fetch one profile with its identifiers

**Auth:** Session token.

**Response 200**

```json
{
  "data": {
    "id": "string",
    "orgId": "string",
    "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",
        "sourceId": "string",
        "sourceName": "string"
      }
    ],
    "anonymous": true,
    "mergedIds": [
      "string"
    ],
    "email": {
      "address": "string",
      "source": "string"
    }
  },
  "meta": {
    "requestId": "string",
    "nextCursor": "string",
    "hasMore": true,
    "warnings": [
      {
        "code": "string",
        "message": "string",
        "suggestion": "string"
      }
    ]
  }
}
```

| Field | Type | Required | Constraints |
| --- | --- | --- | --- |
| `data` | object | yes |  |
| `data.id` | string | yes |  |
| `data.orgId` | string | 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.identifiers[].sourceId` | string \| null | yes |  |
| `data.identifiers[].sourceName` | string \| null | yes |  |
| `data.anonymous` | boolean | yes |  |
| `data.mergedIds` | string[] | yes |  |
| `data.email` | object \| null | yes |  |
| `data.email.address` | string | yes |  |
| `data.email.source` | string | yes |  |
| `meta` | object | no |  |
| `meta.requestId` | string | no |  |
| `meta.nextCursor` | string \| null | no |  |
| `meta.hasMore` | boolean | no |  |
| `meta.warnings` | object[] | no |  |
| `meta.warnings[]` | object | no |  |
| `meta.warnings[].code` | string | yes |  |
| `meta.warnings[].message` | string | yes |  |
| `meta.warnings[].suggestion` | string | no |  |

Errors follow the [shared envelope and code table](/api-conventions/#errors).

## DELETE /v1/users/{profileId}

Erase a user (GDPR)

Admin only. Terminates active automation executions, then permanently deletes the profile, any profiles merged into it, and their event and delivery history. This action cannot be undone.

**Auth:** Session token.

**Response 200**

```json
{
  "data": {
    "profileIds": [
      "string"
    ],
    "terminatedInstances": 42
  },
  "meta": {
    "requestId": "string",
    "nextCursor": "string",
    "hasMore": true,
    "warnings": [
      {
        "code": "string",
        "message": "string",
        "suggestion": "string"
      }
    ]
  }
}
```

| Field | Type | Required | Constraints |
| --- | --- | --- | --- |
| `data` | object | yes |  |
| `data.profileIds` | string[] | yes |  |
| `data.terminatedInstances` | integer | yes | 0 ≤ x ≤ ∞ |
| `meta` | object | no |  |
| `meta.requestId` | string | no |  |
| `meta.nextCursor` | string \| null | no |  |
| `meta.hasMore` | boolean | no |  |
| `meta.warnings` | object[] | no |  |
| `meta.warnings[]` | object | no |  |
| `meta.warnings[].code` | string | yes |  |
| `meta.warnings[].message` | string | yes |  |
| `meta.warnings[].suggestion` | string | no |  |

Errors follow the [shared envelope and code table](/api-conventions/#errors).

## GET /v1/users/{profileId}/export

Export everything held on a user (GDPR)

**Auth:** Session token.

**Response 200**

```json
{
  "data": {
    "exportedAt": "2026-01-15T09:30:00.000Z",
    "users": [
      {
        "id": "string",
        "orgId": "string",
        "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",
            "sourceId": "string",
            "sourceName": "string"
          }
        ],
        "anonymous": true,
        "mergedIds": [
          "string"
        ],
        "email": {
          "address": "string",
          "source": "string"
        }
      }
    ],
    "events": [
      {
        "id": "string",
        "orgId": "string",
        "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",
        "client": "string"
      }
    ],
    "eventSummaries": [
      {
        "orgId": "string",
        "appId": "string",
        "profileId": "string",
        "event": "string",
        "count": 42,
        "firstAt": "2026-01-15T09:30:00.000Z",
        "lastAt": "2026-01-15T09:30:00.000Z",
        "recent": [
          "2026-01-15T09:30:00.000Z"
        ]
      }
    ],
    "automations": [
      {
        "id": "string",
        "orgId": "string",
        "automation": "string",
        "profileId": "string",
        "workflowId": "string",
        "runId": "string",
        "completedAt": "2026-01-15T09:30:00.000Z",
        "sent": true,
        "createdAt": "2026-01-15T09:30:00.000Z"
      }
    ],
    "deliveries": [
      {
        "id": "string",
        "orgId": "string",
        "profileId": "string",
        "automation": "string",
        "executionId": "string",
        "appId": "string",
        "broadcastId": "string",
        "kind": "automation",
        "step": "string",
        "channel": "email",
        "status": "sent",
        "dryRun": true,
        "recipient": "string",
        "providerId": "string",
        "error": "string",
        "createdAt": "2026-01-15T09:30:00.000Z",
        "updatedAt": "2026-01-15T09:30:00.000Z",
        "sentAt": "2026-01-15T09:30:00.000Z",
        "settledAt": "2026-01-15T09:30:00.000Z",
        "openedAt": "2026-01-15T09:30:00.000Z",
        "openCount": 42,
        "spamScore": 42,
        "spamSymbols": [
          "string"
        ]
      }
    ],
    "suppressedAddresses": [
      {
        "id": "string",
        "orgId": "string",
        "address": "string",
        "type": "bounce",
        "reason": "string",
        "source": "string",
        "suppressedAt": "2026-01-15T09:30:00.000Z",
        "createdAt": "2026-01-15T09:30:00.000Z",
        "updatedAt": "2026-01-15T09:30:00.000Z"
      }
    ],
    "emailAddresses": [
      {
        "id": "string",
        "orgId": "string",
        "address": "string",
        "verifiedAt": "2026-01-15T09:30:00.000Z",
        "verificationMethod": "link",
        "createdAt": "2026-01-15T09:30:00.000Z",
        "updatedAt": "2026-01-15T09:30:00.000Z"
      }
    ]
  },
  "meta": {
    "requestId": "string",
    "nextCursor": "string",
    "hasMore": true,
    "warnings": [
      {
        "code": "string",
        "message": "string",
        "suggestion": "string"
      }
    ]
  }
}
```

| Field | Type | Required | Constraints |
| --- | --- | --- | --- |
| `data` | object | yes |  |
| `data.exportedAt` | string (date-time) | yes |  |
| `data.users` | object[] | yes |  |
| `data.users[]` | object | yes |  |
| `data.users[].id` | string | yes |  |
| `data.users[].orgId` | string | yes |  |
| `data.users[].appId` | string | yes |  |
| `data.users[].sourceId` | string | yes |  |
| `data.users[].traits` | record\<string, any> | yes |  |
| `data.users[].consent` | record\<string, boolean> | yes |  |
| `data.users[].mergedInto` | string \| null | yes |  |
| `data.users[].createdAt` | string (date-time) | yes |  |
| `data.users[].updatedAt` | string (date-time) | yes |  |
| `data.users[].identifiers` | object[] | yes |  |
| `data.users[].identifiers[]` | object | yes |  |
| `data.users[].identifiers[].kind` | "anonymousId" \| "userId" \| "clerkId" \| "email" | yes |  |
| `data.users[].identifiers[].value` | string | yes |  |
| `data.users[].identifiers[].createdAt` | string (date-time) | yes |  |
| `data.users[].identifiers[].sourceId` | string \| null | yes |  |
| `data.users[].identifiers[].sourceName` | string \| null | yes |  |
| `data.users[].anonymous` | boolean | yes |  |
| `data.users[].mergedIds` | string[] | yes |  |
| `data.users[].email` | object \| null | yes |  |
| `data.users[].email.address` | string | yes |  |
| `data.users[].email.source` | string | yes |  |
| `data.events` | object[] | yes |  |
| `data.events[]` | object | yes |  |
| `data.events[].id` | string | yes |  |
| `data.events[].orgId` | string | yes |  |
| `data.events[].appId` | string | yes |  |
| `data.events[].sourceId` | string | yes |  |
| `data.events[].profileId` | string | yes |  |
| `data.events[].event` | string | yes |  |
| `data.events[].properties` | record\<string, any> | yes |  |
| `data.events[].timestamp` | string (date-time) | yes |  |
| `data.events[].receivedAt` | string (date-time) | yes |  |
| `data.events[].messageId` | string \| null | yes |  |
| `data.events[].client` | string \| null | yes |  |
| `data.eventSummaries` | object[] | yes |  |
| `data.eventSummaries[]` | object | yes |  |
| `data.eventSummaries[].orgId` | string | yes |  |
| `data.eventSummaries[].appId` | string | yes |  |
| `data.eventSummaries[].profileId` | string | yes |  |
| `data.eventSummaries[].event` | string | yes |  |
| `data.eventSummaries[].count` | integer | yes |  |
| `data.eventSummaries[].firstAt` | string (date-time) | yes |  |
| `data.eventSummaries[].lastAt` | string (date-time) | yes |  |
| `data.eventSummaries[].recent` | string (date-time)[] | yes |  |
| `data.automations` | object[] | yes |  |
| `data.automations[]` | object | yes |  |
| `data.automations[].id` | string | yes |  |
| `data.automations[].orgId` | string | yes |  |
| `data.automations[].automation` | string | yes |  |
| `data.automations[].profileId` | string | yes |  |
| `data.automations[].workflowId` | string | yes |  |
| `data.automations[].runId` | string | yes |  |
| `data.automations[].completedAt` | string (date-time) | yes |  |
| `data.automations[].sent` | boolean | yes |  |
| `data.automations[].createdAt` | string (date-time) | yes |  |
| `data.deliveries` | object[] | yes |  |
| `data.deliveries[]` | object | yes |  |
| `data.deliveries[].id` | string | yes |  |
| `data.deliveries[].orgId` | string | yes |  |
| `data.deliveries[].profileId` | string \| null | yes |  |
| `data.deliveries[].automation` | string \| null | yes |  |
| `data.deliveries[].executionId` | string \| null | yes |  |
| `data.deliveries[].appId` | string \| null | yes |  |
| `data.deliveries[].broadcastId` | string \| null | yes |  |
| `data.deliveries[].kind` | "automation" \| "test" \| "api" \| "broadcast" | yes |  |
| `data.deliveries[].step` | string | yes |  |
| `data.deliveries[].channel` | "email" \| "webhook" | yes |  |
| `data.deliveries[].status` | "sent" \| "delivered" \| "bounced" \| "complained" \| "failed" \| "skipped_disabled" \| "skipped_paused" \| "skipped_suspended" \| "skipped_suppressed" \| "skipped_quota" \| "skipped_unknown_purpose" \| "skipped_frequency_cap" \| "skipped_consent" \| "skipped_domain" \| "skipped_ssrf" \| "skipped_spam" \| "would_send" \| "would_skip_disabled" \| "would_skip_paused" \| "would_skip_suspended" \| "would_skip_suppressed" \| "would_skip_quota" \| "would_skip_unknown_purpose" \| "would_skip_frequency_cap" \| "would_skip_consent" \| "would_skip_domain" \| "would_skip_ssrf" \| "would_skip_spam" | yes |  |
| `data.deliveries[].dryRun` | boolean | yes |  |
| `data.deliveries[].recipient` | string \| null | yes |  |
| `data.deliveries[].providerId` | string \| null | yes |  |
| `data.deliveries[].error` | string \| null | yes |  |
| `data.deliveries[].createdAt` | string (date-time) | yes |  |
| `data.deliveries[].updatedAt` | string (date-time) | yes |  |
| `data.deliveries[].sentAt` | string (date-time) \| null | yes |  |
| `data.deliveries[].settledAt` | string (date-time) \| null | yes |  |
| `data.deliveries[].openedAt` | string (date-time) \| null | yes |  |
| `data.deliveries[].openCount` | integer | yes | -2147483648 ≤ x ≤ 2147483647 |
| `data.deliveries[].spamScore` | number \| null | yes |  |
| `data.deliveries[].spamSymbols` | string[] \| null | yes |  |
| `data.suppressedAddresses` | object[] | yes |  |
| `data.suppressedAddresses[]` | object | yes |  |
| `data.suppressedAddresses[].id` | string | yes |  |
| `data.suppressedAddresses[].orgId` | string | yes |  |
| `data.suppressedAddresses[].address` | string | yes |  |
| `data.suppressedAddresses[].type` | "bounce" \| "complaint" \| "manual" \| null | yes |  |
| `data.suppressedAddresses[].reason` | string \| null | yes |  |
| `data.suppressedAddresses[].source` | string \| null | yes |  |
| `data.suppressedAddresses[].suppressedAt` | string (date-time) | yes |  |
| `data.suppressedAddresses[].createdAt` | string (date-time) | yes |  |
| `data.suppressedAddresses[].updatedAt` | string (date-time) | yes |  |
| `data.emailAddresses` | object[] | yes |  |
| `data.emailAddresses[]` | object | yes |  |
| `data.emailAddresses[].id` | string | yes |  |
| `data.emailAddresses[].orgId` | string | yes |  |
| `data.emailAddresses[].address` | string | yes |  |
| `data.emailAddresses[].verifiedAt` | string (date-time) \| null | yes |  |
| `data.emailAddresses[].verificationMethod` | "link" \| "imported" \| "provider" \| null | yes |  |
| `data.emailAddresses[].createdAt` | string (date-time) | yes |  |
| `data.emailAddresses[].updatedAt` | string (date-time) | yes |  |
| `meta` | object | no |  |
| `meta.requestId` | string | no |  |
| `meta.nextCursor` | string \| null | no |  |
| `meta.hasMore` | boolean | no |  |
| `meta.warnings` | object[] | no |  |
| `meta.warnings[]` | object | no |  |
| `meta.warnings[].code` | string | yes |  |
| `meta.warnings[].message` | string | yes |  |
| `meta.warnings[].suggestion` | string | no |  |

Errors follow the [shared envelope and code table](/api-conventions/#errors).

## PATCH /v1/users/{profileId}/consent

Update consent purposes

**Auth:** Session token.

**Request body**

```json
{
  "data": {
    "marketing.newsletter": true
  }
}
```

| Field | Type | Required | Constraints |
| --- | --- | --- | --- |
| `data` | record\<string, boolean> | yes |  |

**Response 200**

```json
{
  "data": {
    "id": "string",
    "orgId": "string",
    "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",
        "sourceId": "string",
        "sourceName": "string"
      }
    ],
    "anonymous": true,
    "mergedIds": [
      "string"
    ],
    "email": {
      "address": "string",
      "source": "string"
    }
  },
  "meta": {
    "requestId": "string",
    "nextCursor": "string",
    "hasMore": true,
    "warnings": [
      {
        "code": "string",
        "message": "string",
        "suggestion": "string"
      }
    ]
  }
}
```

| Field | Type | Required | Constraints |
| --- | --- | --- | --- |
| `data` | object | yes |  |
| `data.id` | string | yes |  |
| `data.orgId` | string | 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.identifiers[].sourceId` | string \| null | yes |  |
| `data.identifiers[].sourceName` | string \| null | yes |  |
| `data.anonymous` | boolean | yes |  |
| `data.mergedIds` | string[] | yes |  |
| `data.email` | object \| null | yes |  |
| `data.email.address` | string | yes |  |
| `data.email.source` | string | yes |  |
| `meta` | object | no |  |
| `meta.requestId` | string | no |  |
| `meta.nextCursor` | string \| null | no |  |
| `meta.hasMore` | boolean | no |  |
| `meta.warnings` | object[] | no |  |
| `meta.warnings[]` | object | no |  |
| `meta.warnings[].code` | string | yes |  |
| `meta.warnings[].message` | string | yes |  |
| `meta.warnings[].suggestion` | string | no |  |

Errors follow the [shared envelope and code table](/api-conventions/#errors).

## GET /v1/users/{profileId}/segments

The segments a profile belongs to

**Auth:** Session token.

**Query parameters**

```json
{
  "cursor": "string",
  "limit": 50
}
```

| Field | Type | Required | Constraints |
| --- | --- | --- | --- |
| `cursor` | string | no |  |
| `limit` | integer | no | default `50`; 1 ≤ x ≤ 100 |

**Response 200**

```json
{
  "data": [
    {
      "segmentId": "string",
      "name": "string",
      "since": "2026-01-15T09:30:00.000Z"
    }
  ],
  "meta": {
    "requestId": "string",
    "nextCursor": "string",
    "hasMore": true,
    "warnings": [
      {
        "code": "string",
        "message": "string",
        "suggestion": "string"
      }
    ]
  }
}
```

| Field | Type | Required | Constraints |
| --- | --- | --- | --- |
| `data` | object[] | yes |  |
| `data[]` | object | yes |  |
| `data[].segmentId` | string | yes |  |
| `data[].name` | string | yes |  |
| `data[].since` | string (date-time) | yes |  |
| `meta` | object | no |  |
| `meta.requestId` | string | no |  |
| `meta.nextCursor` | string \| null | no |  |
| `meta.hasMore` | boolean | no |  |
| `meta.warnings` | object[] | no |  |
| `meta.warnings[]` | object | no |  |
| `meta.warnings[].code` | string | yes |  |
| `meta.warnings[].message` | string | yes |  |
| `meta.warnings[].suggestion` | string | no |  |

Errors follow the [shared envelope and code table](/api-conventions/#errors).

## GET /v1/users/{profileId}/timeline

Everything that happened to a profile, newest first

Its events, the sends made to it, its automation runs (each start, each wait an event answered, each end) and the segments it entered and left, in one list. A profile that absorbed others in a merge includes their history too. `types` narrows it, for example `run,delivery`.

**Auth:** Session token.

**Query parameters**

```json
{
  "cursor": "string",
  "limit": 50,
  "types": "string"
}
```

| Field | Type | Required | Constraints |
| --- | --- | --- | --- |
| `cursor` | string | no |  |
| `limit` | integer | no | default `50`; 1 ≤ x ≤ 100 |
| `types` | string | no |  |

**Response 200**

```json
{
  "data": [
    {
      "id": "string",
      "at": "2026-01-15T09:30:00.000Z",
      "type": "event",
      "eventId": "string",
      "event": "string",
      "properties": {
        "key": {}
      }
    }
  ],
  "meta": {
    "requestId": "string",
    "nextCursor": "string",
    "hasMore": true,
    "warnings": [
      {
        "code": "string",
        "message": "string",
        "suggestion": "string"
      }
    ]
  }
}
```

| Field | Type | Required | Constraints |
| --- | --- | --- | --- |
| `data` | array of variants | yes |  |
| `data[]` | one of | yes |  |
| `data[]〈event〉` | object | yes |  |
| `data[]〈event〉.id` | string | yes |  |
| `data[]〈event〉.at` | string (date-time) | yes |  |
| `data[]〈event〉.type` | "event" | yes |  |
| `data[]〈event〉.eventId` | string | yes |  |
| `data[]〈event〉.event` | string | yes |  |
| `data[]〈event〉.properties` | record\<string, any> | yes |  |
| `data[]〈segment〉` | object | yes |  |
| `data[]〈segment〉.id` | string | yes |  |
| `data[]〈segment〉.at` | string (date-time) | yes |  |
| `data[]〈segment〉.type` | "segment" | yes |  |
| `data[]〈segment〉.eventId` | string | yes |  |
| `data[]〈segment〉.change` | "entered" \| "exited" | yes |  |
| `data[]〈segment〉.segmentId` | string | yes |  |
| `data[]〈segment〉.segmentName` | string | yes |  |
| `data[]〈segment〉.cause` | object \| null | yes |  |
| `data[]〈segment〉.cause.eventId` | string \| null | yes |  |
| `data[]〈segment〉.cause.event` | string | yes |  |
| `data[]〈segment〉.cause.segmentName` | string \| null | yes |  |
| `data[]〈delivery〉` | object | yes |  |
| `data[]〈delivery〉.id` | string | yes |  |
| `data[]〈delivery〉.at` | string (date-time) | yes |  |
| `data[]〈delivery〉.type` | "delivery" | yes |  |
| `data[]〈delivery〉.deliveryId` | string | yes |  |
| `data[]〈delivery〉.step` | string | yes |  |
| `data[]〈delivery〉.channel` | "email" \| "webhook" | yes |  |
| `data[]〈delivery〉.status` | "sent" \| "delivered" \| "bounced" \| "complained" \| "failed" \| "skipped_disabled" \| "skipped_paused" \| "skipped_suspended" \| "skipped_suppressed" \| "skipped_quota" \| "skipped_unknown_purpose" \| "skipped_frequency_cap" \| "skipped_consent" \| "skipped_domain" \| "skipped_ssrf" \| "skipped_spam" \| "would_send" \| "would_skip_disabled" \| "would_skip_paused" \| "would_skip_suspended" \| "would_skip_suppressed" \| "would_skip_quota" \| "would_skip_unknown_purpose" \| "would_skip_frequency_cap" \| "would_skip_consent" \| "would_skip_domain" \| "would_skip_ssrf" \| "would_skip_spam" | yes |  |
| `data[]〈delivery〉.error` | string \| null | yes |  |
| `data[]〈delivery〉.automation` | string \| null | yes |  |
| `data[]〈delivery〉.executionId` | string \| null | yes |  |
| `data[]〈run〉` | object | yes |  |
| `data[]〈run〉.id` | string | yes |  |
| `data[]〈run〉.at` | string (date-time) | yes |  |
| `data[]〈run〉.type` | "run" | yes |  |
| `data[]〈run〉.change` | "started" \| "resumed" \| "ended" | yes |  |
| `data[]〈run〉.executionId` | string | yes |  |
| `data[]〈run〉.appId` | string | yes |  |
| `data[]〈run〉.automationKey` | string | yes |  |
| `data[]〈run〉.status` | "running" \| "waiting" \| "completed" \| "failed" \| "cancelled" | yes |  |
| `data[]〈run〉.step` | string \| null | yes |  |
| `data[]〈run〉.error` | string \| null | yes |  |
| `data[]〈run〉.cause` | object \| null | yes |  |
| `data[]〈run〉.cause.eventId` | string \| null | yes |  |
| `data[]〈run〉.cause.event` | string | yes |  |
| `data[]〈run〉.cause.segmentName` | string \| null | yes |  |
| `meta` | object | no |  |
| `meta.requestId` | string | no |  |
| `meta.nextCursor` | string \| null | no |  |
| `meta.hasMore` | boolean | no |  |
| `meta.warnings` | object[] | no |  |
| `meta.warnings[]` | object | no |  |
| `meta.warnings[].code` | string | yes |  |
| `meta.warnings[].message` | string | yes |  |
| `meta.warnings[].suggestion` | string | no |  |

Errors follow the [shared envelope and code table](/api-conventions/#errors).

## GET /v1/users/{profileId}/runs

The automations a profile has completed

**Auth:** Session token.

**Query parameters**

```json
{
  "cursor": "string",
  "limit": 50
}
```

| Field | Type | Required | Constraints |
| --- | --- | --- | --- |
| `cursor` | string | no |  |
| `limit` | integer | no | default `50`; 1 ≤ x ≤ 100 |

**Response 200**

```json
{
  "data": [
    {
      "id": "string",
      "appId": "string",
      "automationKey": "string",
      "completedAt": "2026-01-15T09:30:00.000Z",
      "executionId": "string"
    }
  ],
  "meta": {
    "requestId": "string",
    "nextCursor": "string",
    "hasMore": true,
    "warnings": [
      {
        "code": "string",
        "message": "string",
        "suggestion": "string"
      }
    ]
  }
}
```

| Field | Type | Required | Constraints |
| --- | --- | --- | --- |
| `data` | object[] | yes |  |
| `data[]` | object | yes |  |
| `data[].id` | string | yes |  |
| `data[].appId` | string | yes |  |
| `data[].automationKey` | string | yes |  |
| `data[].completedAt` | string (date-time) | yes |  |
| `data[].executionId` | string \| null | yes |  |
| `meta` | object | no |  |
| `meta.requestId` | string | no |  |
| `meta.nextCursor` | string \| null | no |  |
| `meta.hasMore` | boolean | no |  |
| `meta.warnings` | object[] | no |  |
| `meta.warnings[]` | object | no |  |
| `meta.warnings[].code` | string | yes |  |
| `meta.warnings[].message` | string | yes |  |
| `meta.warnings[].suggestion` | string | no |  |

Errors follow the [shared envelope and code table](/api-conventions/#errors).
