Apps
One app per product you run; every event and profile carries its appId. An app is the attribution unit and carries no kind, no configuration, and no credential of its own. Every inbound pipe into it is a source created under it, including the first-party api source that the SDK and HTTP path write through, created with the app. All of an app’s sources land on the same app, and therefore on the same profiles. Routes that address a source by its own id (including the public webhook receiver) are on the Sources page. See the Apps and sources guide.
POST /v1/apps
Section titled “POST /v1/apps”Create an app
Auth: Clerk session token.
Request body
{ "data": { "name": "string", "environment": "production" }}| Field | Type | Required | Constraints |
|---|---|---|---|
data |
object | yes | |
data.name |
string | yes | length 1–100 |
data.environment |
“development” | “production” | no | default "production" |
Response 201
{ "data": { "id": "string", "orgId": "string", "environment": "development", "name": "string", "status": "active", "createdAt": "2026-01-15T09:30:00.000Z", "updatedAt": "2026-01-15T09:30:00.000Z", "archivedAt": "2026-01-15T09:30:00.000Z", "sourceCount": 42, "lastReceivedAt": "2026-01-15T09:30:00.000Z" }, "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.name |
string | yes | |
data.status |
“active” | “archived” | yes | |
data.createdAt |
string (date-time) | yes | |
data.updatedAt |
string (date-time) | yes | |
data.archivedAt |
string (date-time) | null | yes | |
data.sourceCount |
integer | yes | -9007199254740991 ≤ x ≤ ∞ |
data.lastReceivedAt |
string (date-time) | null | 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.
GET /v1/apps
Section titled “GET /v1/apps”List apps
Auth: Clerk session token.
Query parameters
{ "cursor": "string", "limit": 50, "q": "string", "status": "all"}| Field | Type | Required | Constraints |
|---|---|---|---|
cursor |
string | no | |
limit |
integer | no | default 50; 1 ≤ x ≤ 100 |
q |
string | no | length 0–200 |
status |
“active” | “archived” | “all” | no | default "all" |
Response 200
{ "data": [ { "id": "string", "orgId": "string", "environment": "development", "name": "string", "status": "active", "createdAt": "2026-01-15T09:30:00.000Z", "updatedAt": "2026-01-15T09:30:00.000Z", "archivedAt": "2026-01-15T09:30:00.000Z", "sourceCount": 42, "lastReceivedAt": "2026-01-15T09:30:00.000Z" } ], "meta": { "requestId": "string", "nextCursor": "string", "hasMore": true }}| Field | Type | Required | Constraints |
|---|---|---|---|
data |
object[] | yes | |
data[] |
object | yes | |
data[].id |
string | yes | |
data[].orgId |
string | yes | |
data[].environment |
“development” | “production” | yes | |
data[].name |
string | yes | |
data[].status |
“active” | “archived” | yes | |
data[].createdAt |
string (date-time) | yes | |
data[].updatedAt |
string (date-time) | yes | |
data[].archivedAt |
string (date-time) | null | yes | |
data[].sourceCount |
integer | yes | -9007199254740991 ≤ x ≤ ∞ |
data[].lastReceivedAt |
string (date-time) | null | 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.
GET /v1/apps/{id}
Section titled “GET /v1/apps/{id}”Fetch one app
Auth: Clerk session token.
Response 200
{ "data": { "id": "string", "orgId": "string", "environment": "development", "name": "string", "status": "active", "createdAt": "2026-01-15T09:30:00.000Z", "updatedAt": "2026-01-15T09:30:00.000Z", "archivedAt": "2026-01-15T09:30:00.000Z", "sourceCount": 42, "lastReceivedAt": "2026-01-15T09:30:00.000Z" }, "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.name |
string | yes | |
data.status |
“active” | “archived” | yes | |
data.createdAt |
string (date-time) | yes | |
data.updatedAt |
string (date-time) | yes | |
data.archivedAt |
string (date-time) | null | yes | |
data.sourceCount |
integer | yes | -9007199254740991 ≤ x ≤ ∞ |
data.lastReceivedAt |
string (date-time) | null | 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.
PATCH /v1/apps/{id}
Section titled “PATCH /v1/apps/{id}”Rename or archive an app
Auth: Clerk session token.
Request body
{ "data": { "name": "string", "status": "archived" }}| Field | Type | Required | Constraints |
|---|---|---|---|
data |
object | yes | |
data.name |
string | no | length 1–100 |
data.status |
“archived” | no |
Response 200
{ "data": { "id": "string", "orgId": "string", "environment": "development", "name": "string", "status": "active", "createdAt": "2026-01-15T09:30:00.000Z", "updatedAt": "2026-01-15T09:30:00.000Z", "archivedAt": "2026-01-15T09:30:00.000Z", "sourceCount": 42, "lastReceivedAt": "2026-01-15T09:30:00.000Z" }, "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.name |
string | yes | |
data.status |
“active” | “archived” | yes | |
data.createdAt |
string (date-time) | yes | |
data.updatedAt |
string (date-time) | yes | |
data.archivedAt |
string (date-time) | null | yes | |
data.sourceCount |
integer | yes | -9007199254740991 ≤ x ≤ ∞ |
data.lastReceivedAt |
string (date-time) | null | 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.
POST /v1/apps/{appId}/sources
Section titled “POST /v1/apps/{appId}/sources”Add a source to an app
Auth: Clerk session token.
Request body
{ "data": { "kind": "api", "config": {} }}| Field | Type | Required | Constraints |
|---|---|---|---|
data |
one of | yes | |
data〈api〉 |
object | yes | |
data〈api〉.kind |
“api” | yes | |
data〈api〉.config |
object | no | default {} |
data〈clerk〉 |
object | yes | |
data〈clerk〉.kind |
“clerk” | yes | |
data〈clerk〉.config |
object | no | default {} |
data〈clerk〉.config.signingSecret |
string | no | length 1–∞ |
Response 201
{ "data": { "id": "string", "orgId": "string", "appId": "string", "kind": "api", "config": "string", "lastReceivedAt": "2026-01-15T09:30:00.000Z", "createdAt": "2026-01-15T09:30:00.000Z", "updatedAt": "2026-01-15T09:30:00.000Z", "archivedAt": "2026-01-15T09:30:00.000Z", "configured": true }, "meta": { "requestId": "string", "nextCursor": "string", "hasMore": true }}| Field | Type | Required | Constraints |
|---|---|---|---|
data |
object | yes | |
data.id |
string | yes | |
data.orgId |
string | yes | |
data.appId |
string | yes | |
data.kind |
“api” | “clerk” | yes | |
data.config |
string | number | boolean | null | record<string, any> | any[] | yes | |
data.lastReceivedAt |
string (date-time) | null | yes | |
data.createdAt |
string (date-time) | yes | |
data.updatedAt |
string (date-time) | yes | |
data.archivedAt |
string (date-time) | null | yes | |
data.configured |
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.
GET /v1/apps/{appId}/sources
Section titled “GET /v1/apps/{appId}/sources”List an app’s sources
Auth: Clerk session token.
Query parameters
{ "cursor": "string", "limit": 50}| Field | Type | Required | Constraints |
|---|---|---|---|
cursor |
string | no | |
limit |
integer | no | default 50; 1 ≤ x ≤ 100 |
Response 200
{ "data": [ { "id": "string", "orgId": "string", "appId": "string", "kind": "api", "config": "string", "lastReceivedAt": "2026-01-15T09:30:00.000Z", "createdAt": "2026-01-15T09:30:00.000Z", "updatedAt": "2026-01-15T09:30:00.000Z", "archivedAt": "2026-01-15T09:30:00.000Z", "configured": true } ], "meta": { "requestId": "string", "nextCursor": "string", "hasMore": true }}| Field | Type | Required | Constraints |
|---|---|---|---|
data |
object[] | yes | |
data[] |
object | yes | |
data[].id |
string | yes | |
data[].orgId |
string | yes | |
data[].appId |
string | yes | |
data[].kind |
“api” | “clerk” | yes | |
data[].config |
string | number | boolean | null | record<string, any> | any[] | yes | |
data[].lastReceivedAt |
string (date-time) | null | yes | |
data[].createdAt |
string (date-time) | yes | |
data[].updatedAt |
string (date-time) | yes | |
data[].archivedAt |
string (date-time) | null | yes | |
data[].configured |
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.