API reference

Notifications and protocols

Your notifications, and an organization's notification protocols.

See Notifications and Caity by phone for how events, channels, quiet hours and protocols work.

GET /v1/me/notifications/devices

The apps registered for push on your phones: one entry per app per phone (deviceId is the phone's install id), with appId, platform, and the name, model, osVersion and appVersion the app sent. No push tokens.

Auth: user access token or platform agent key

Response 200

{
  devices: {
    deviceId: string
    appId: string
    platform: "ios" | "android"
    name?: string
    model?: string
    osVersion?: string
    appVersion?: string
    createdAt?: number
    updatedAt?: number
  }[]
}

Errors

StatusMessage
403Notifications belong to people.

PUT /v1/me/notifications/devices/:deviceId

Registers or refreshes a mobile app's Expo push token on this phone (token, platform, appId, optional name, model, osVersion, appVersion). A mobile app's token ties the registration to its sign-in, so signing the app out removes it, and appId must be that app. People only, not assistants.

Auth: user access token or platform agent key

Path parameterDescription
:deviceIdDevice id: an agent's (dev_…); under /v1/me/notifications a phone's install id; under /v1/me/sign-in-approvals a phone that approves sign-ins (apd_…); under /v1/me/vault the id a device made for its vault (22 base64url characters).

Request body

FieldTypeRequiredDefaultNotes
tokenstringYes
platform"ios" | "android"Yes
appId"home" | "caity" | "tasks" | "brain" | "mail" | "drive" | "photos" | "git" | "cloud" | "maps" | "tenant" | "admin" | "docs" | "account" | "authenticator" | "mirage" | "health" | "weather" | "marketing" | "food"No"caity"
nameany JSONYes
modelany JSONYes
osVersionany JSONYes
appVersionany JSONYes

Response 200

{
  ok: true
}

Errors

StatusMessage
400Invalid device ID
400appId does not match the signed-in app
403Notifications belong to people.
403Register devices from the mobile app.

DELETE /v1/me/notifications/devices/:deviceId

Removes an app's push registration on this phone (appId, default caity). Signing the app out removes it too. People only, not assistants.

Auth: user access token or platform agent key

Path parameterDescription
:deviceIdDevice id: an agent's (dev_…); under /v1/me/notifications a phone's install id; under /v1/me/sign-in-approvals a phone that approves sign-ins (apd_…); under /v1/me/vault the id a device made for its vault (22 base64url characters).
Query parameterTypeRequiredDefaultNotes
appId"home" | "caity" | "tasks" | "brain" | "mail" | "drive" | "photos" | "git" | "cloud" | "maps" | "tenant" | "admin" | "docs" | "account" | "authenticator" | "mirage" | "health" | "weather" | "marketing" | "food"No"caity"

Response 204 with no body.

Errors

StatusMessage
403Notifications belong to people.
403Register devices from the mobile app.

GET /v1/me/notifications/live-activities

Your iPhone Live Activity registrations: per phone and app (maps or home), the push-to-start entry (kind: start) and each running flight activity (kind: activity, with orgId, hex, watchId or local), the APNs environment and, on the push-to-start entry, the flight activities the app last reported running (running). No tokens.

Auth: user access token or platform agent key

Response 200

{
  liveActivities: {
    kind: "start" | "activity"
    installId: string
    appId: string
    activityId: string
    environment: "production" | "development"
    orgId?: string
    hex?: string
    watchId?: string
    local?: boolean
    running?: string[]
    createdAt?: number
    updatedAt?: number
  }[]
}

Errors

StatusMessage
403Notifications belong to people.

PUT /v1/me/notifications/live-activities/start/:installId

Registers the Maps or Home app's push-to-start token on this iPhone (token in hex, appId, environment production or development, bundleId, and running: the hexes of the flight activities running in the app, sent again whenever they change), so a flight watch can start a Live Activity at takeoff. From the signed-in iPhone app only; tied to its sign-in.

Auth: user access token or platform agent key

Path parameterDescription
:installIdThe phone's install id (the same for every app on it).

Request body

FieldTypeRequiredNotes
tokenstringYes
appId"maps" | "home"Yes
environment"production" | "development"Yes
bundleIdstringYes
runningstring[]Noup to 20 items; each matches ^~?[0-9a-fA-F]{6}$

Response 200

{
  ok: true
}

Errors

StatusMessage
400appId does not match the signed-in app
400Invalid install ID
403Notifications belong to people.
403Register devices from the mobile app.
403Register Live Activities from the iPhone app.

DELETE /v1/me/notifications/live-activities/start/:installId

Removes the app's push-to-start token on this phone (appId). Signing the app out removes it too.

Auth: user access token or platform agent key

Path parameterDescription
:installIdThe phone's install id (the same for every app on it).
Query parameterTypeRequiredNotes
appId"maps" | "home"Yes

Response 204 with no body.

Errors

StatusMessage
400appId does not match the signed-in app
400Invalid install ID
403Notifications belong to people.
403Register devices from the mobile app.
403Register Live Activities from the iPhone app.

PUT /v1/me/notifications/live-activities/:activityId

Registers a running flight Live Activity's update token (token, appId, environment, bundleId, installId, orgId, hex, and watchId or local: true for one started with Track live). Needs maps:read in the org; from the signed-in iPhone app only.

Auth: user access token or platform agent key · Scope: maps:read

Path parameterDescription
:activityIdActivityKit's id for a running Live Activity on the phone.

Request body

FieldTypeRequiredNotes
tokenstringYes
appId"maps" | "home"Yes
environment"production" | "development"Yes
bundleIdstringYes
installIdstringYes
orgIdstringYes1–64 characters
hexstringYesmatches ^~?[0-9a-fA-F]{6}$
watchIdstringNo1–64 characters
localbooleanNo

Response 200

{
  ok: true
}

Errors

StatusMessage
400appId does not match the signed-in app
400Invalid install ID
400Invalid activity ID
403Notifications belong to people.
403Register devices from the mobile app.
403Register Live Activities from the iPhone app.

DELETE /v1/me/notifications/live-activities/:activityId

The activity ended or was dismissed on the phone: no more updates (installId, appId).

Auth: user access token or platform agent key

Path parameterDescription
:activityIdActivityKit's id for a running Live Activity on the phone.
Query parameterTypeRequiredNotes
installIdstringYes
appId"maps" | "home"Yes

Response 204 with no body.

Errors

StatusMessage
400appId does not match the signed-in app
400Invalid install ID
403Notifications belong to people.
403Register devices from the mobile app.
403Register Live Activities from the iPhone app.

GET /v1/me/notifications

Your notifications, newest first (cursor, limit): title, body, link, read, and whether one waits for an acknowledgement (escalating alerts). app: only that mobile app's notices (home: every app's). People only.

Auth: user access token or platform agent key

Query parameterTypeRequiredNotes
cursorstringNoup to 2,000 characters
limitintegerNo1–100; coerced from a string
app"home" | "caity" | "tasks" | "brain" | "mail" | "drive" | "photos" | "git" | "cloud" | "maps" | "tenant" | "admin" | "docs" | "account" | "authenticator" | "mirage" | "health" | "weather" | "marketing" | "food"No

Response 200

{
  notices: {
    noticeId: string
    orgId?: string
    event: string
    title: string
    body?: string
    url?: string
    read?: boolean
    requireAck?: boolean
    ackedAt?: number
    createdAt?: number
  }[]
  cursor: null | string
}

Errors

StatusMessage
403Notifications belong to people.

POST /v1/me/notifications/read

Marks notifications read (noticeIds, up to 100).

Auth: user access token or platform agent key

Request body

FieldTypeRequiredNotes
noticeIdsstring[]Yes1–100 items; each up to 64 characters

Response 200

{
  ok: true
}

Errors

StatusMessage
403Notifications belong to people.

POST /v1/me/notifications/:noticeId/ack

Acknowledges a notification: its escalation (later texts or calls) stops. acked: false when it already was.

Auth: user access token or platform agent key

Path parameterDescription
:noticeIdNotification id (nte_…).

Response 200

{
  acked: boolean
}

Errors

StatusMessage
403Notifications belong to people.

GET /v1/orgs/:orgId/notify/protocols/templates

Ready-made notification protocols (production on-call, meeting guard, invitation chaser, VIP mail, service desk SLA, agent jobs).

Auth: user access token or platform agent key

Path parameterDescription
:orgIdOrganization id (org_…).

Response 200

{
  templates: {
    id: string
    name: string
    description: string
    rules: {
      events: ("issue.sla_breached" | "deployment.ready" | "deployment.failed" | "maps.incident" | "maps.flight" | "assistant.briefing" | "account.new_sign_in" | "domain.verified" | "domain.failed" | "secret.rotation_due" | "issue.assigned" | "issue.mentioned" | "calendar.invite_unanswered" | "calendar.meeting_soon" | "page.mentioned" | "mail.vip" | "maps.watch" | "office.mention" | "video.captions" | "food.receipt" | "food.use_soon" | "agent.job_done" | "agent.job_failed" | "pipeline.failed" | "pipeline.approval" | "security.git_key" | "security.git_clone" | "security.repo_access" | "ops.alarm" | "marketing.approval" | "marketing.journey" | "mirage.report" | "feedback.bug")[]
      match?: {
        [key: string]: string[]
      }
      steps: {
        afterMinutes: number
        channels: object
      }[]
      beforeEvent?: boolean
      roles?: ("owner" | "admin" | "developer" | "viewer")[]
      userIds?: string[]
      overrideQuietHours?: boolean
    }[]
  }[]
}

GET /v1/orgs/:orgId/notify/protocols

The organization's notification protocols with their rules and what each is attached to.

Auth: user access token or platform agent key · Scope: org:read

Path parameterDescription
:orgIdOrganization id (org_…).

Response 200

{
  protocols: {
    protocolId: string
    orgId: string
    name: string
    description?: string
    enabled: boolean
    rules: {
      events: ("issue.sla_breached" | "deployment.ready" | "deployment.failed" | "maps.incident" | "maps.flight" | "assistant.briefing" | "account.new_sign_in" | "domain.verified" | "domain.failed" | "secret.rotation_due" | "issue.assigned" | "issue.mentioned" | "calendar.invite_unanswered" | "calendar.meeting_soon" | "page.mentioned" | "mail.vip" | "maps.watch" | "office.mention" | "video.captions" | "food.receipt" | "food.use_soon" | "agent.job_done" | "agent.job_failed" | "pipeline.failed" | "pipeline.approval" | "security.git_key" | "security.git_clone" | "security.repo_access" | "ops.alarm" | "marketing.approval" | "marketing.journey" | "mirage.report" | "feedback.bug")[]
      match?: {
        [key: string]: string[]
      }
      steps: {
        afterMinutes: number
        channels: object
      }[]
      beforeEvent?: boolean
      roles?: ("owner" | "admin" | "developer" | "viewer")[]
      userIds?: string[]
      overrideQuietHours?: boolean
    }[]
    createdBy: string
    updatedAt?: number
    attachments: {
      resourceType: "org" | "project" | "agent" | "calendar" | "mailbox" | "space"
      resourceId: string
      resourceLabel?: string
    }[]
  }[]
}

POST /v1/orgs/:orgId/notify/protocols

Creates a protocol from { template } or { name, description?, enabled?, rules } (rules: events, optional match on event attributes, steps with minutes and channels, roles, overrideQuietHours, beforeEvent). Owners and admins.

Auth: user access token or platform agent key · Scope: org:write

Path parameterDescription
:orgIdOrganization id (org_…).

Response 201

{
  protocol: {
    attachments: []
    protocolId: string
    orgId: string
    name: string
    description?: string
    enabled: boolean
    rules: {
      events: ("issue.sla_breached" | "deployment.ready" | "deployment.failed" | "maps.incident" | "maps.flight" | "assistant.briefing" | "account.new_sign_in" | "domain.verified" | "domain.failed" | "secret.rotation_due" | "issue.assigned" | "issue.mentioned" | "calendar.invite_unanswered" | "calendar.meeting_soon" | "page.mentioned" | "mail.vip" | "maps.watch" | "office.mention" | "video.captions" | "food.receipt" | "food.use_soon" | "agent.job_done" | "agent.job_failed" | "pipeline.failed" | "pipeline.approval" | "security.git_key" | "security.git_clone" | "security.repo_access" | "ops.alarm" | "marketing.approval" | "marketing.journey" | "mirage.report" | "feedback.bug")[]
      match?: {
        [key: string]: string[]
      }
      steps: {
        afterMinutes: number
        channels: ("email" | "sms" | "push" | "voice" | "inapp")[]
      }[]
      beforeEvent?: boolean
      roles?: ("owner" | "admin" | "developer" | "viewer")[]
      userIds?: string[]
      overrideQuietHours?: boolean
    }[]
    createdBy: string
    updatedAt?: number
  }
}

GET /v1/orgs/:orgId/notify/protocols/:protocolId

One protocol with its attachments.

Auth: user access token or platform agent key · Scope: org:read

Path parameterDescription
:orgIdOrganization id (org_…).
:protocolIdNotification protocol id (npr_…).

Response 200

{
  protocol: {
    protocolId: string
    orgId: string
    name: string
    description?: string
    enabled: boolean
    rules: {
      events: ("issue.sla_breached" | "deployment.ready" | "deployment.failed" | "maps.incident" | "maps.flight" | "assistant.briefing" | "account.new_sign_in" | "domain.verified" | "domain.failed" | "secret.rotation_due" | "issue.assigned" | "issue.mentioned" | "calendar.invite_unanswered" | "calendar.meeting_soon" | "page.mentioned" | "mail.vip" | "maps.watch" | "office.mention" | "video.captions" | "food.receipt" | "food.use_soon" | "agent.job_done" | "agent.job_failed" | "pipeline.failed" | "pipeline.approval" | "security.git_key" | "security.git_clone" | "security.repo_access" | "ops.alarm" | "marketing.approval" | "marketing.journey" | "mirage.report" | "feedback.bug")[]
      match?: {
        [key: string]: string[]
      }
      steps: {
        afterMinutes: number
        channels: ("email" | "sms" | "push" | "voice" | "inapp")[]
      }[]
      beforeEvent?: boolean
      roles?: ("owner" | "admin" | "developer" | "viewer")[]
      userIds?: string[]
      overrideQuietHours?: boolean
    }[]
    createdBy: string
    updatedAt?: number
    attachments: {
      resourceType: "org" | "project" | "agent" | "calendar" | "mailbox" | "space"
      resourceId: string
      resourceLabel?: string
    }[]
  }
}

PUT /v1/orgs/:orgId/notify/protocols/:protocolId

Replaces a protocol's name, description, on/off and rules. Owners and admins.

Auth: user access token or platform agent key · Scope: org:write

Path parameterDescription
:orgIdOrganization id (org_…).
:protocolIdNotification protocol id (npr_…).

Request body

FieldTypeRequiredNotes
namestringYes1–80 characters; trimmed
descriptionstringNoup to 300 characters
enabledbooleanNo
rulesobject[]Yes1–20 items
rules[].events[]Yesat least 1 item
rules[].matchobjectNovalues: string[] (up to 20 items, each up to 200 characters)
rules[].stepsobject[]Yes1–6 items
rules[].steps[].afterMinutesintegerYes0–10080
rules[].steps[].channels("inapp" | "push" | "email" | "sms" | "voice")[]Yesat least 1 item
rules[].beforeEventbooleanNo
rules[].roles("owner" | "admin" | "developer" | "viewer")[]No
rules[].userIdsstring[]Noup to 50 items; each up to 64 characters
rules[].overrideQuietHoursbooleanNo

Response 200

{
  protocol: {
    protocolId: string
    orgId: string
    name: string
    description?: string
    enabled: boolean
    rules: {
      events: ("issue.sla_breached" | "deployment.ready" | "deployment.failed" | "maps.incident" | "maps.flight" | "assistant.briefing" | "account.new_sign_in" | "domain.verified" | "domain.failed" | "secret.rotation_due" | "issue.assigned" | "issue.mentioned" | "calendar.invite_unanswered" | "calendar.meeting_soon" | "page.mentioned" | "mail.vip" | "maps.watch" | "office.mention" | "video.captions" | "food.receipt" | "food.use_soon" | "agent.job_done" | "agent.job_failed" | "pipeline.failed" | "pipeline.approval" | "security.git_key" | "security.git_clone" | "security.repo_access" | "ops.alarm" | "marketing.approval" | "marketing.journey" | "mirage.report" | "feedback.bug")[]
      match?: {
        [key: string]: string[]
      }
      steps: {
        afterMinutes: number
        channels: ("email" | "sms" | "push" | "voice" | "inapp")[]
      }[]
      beforeEvent?: boolean
      roles?: ("owner" | "admin" | "developer" | "viewer")[]
      userIds?: string[]
      overrideQuietHours?: boolean
    }[]
    createdBy: string
    updatedAt?: number
    attachments: {
      resourceType: "org" | "project" | "agent" | "calendar" | "mailbox" | "space"
      resourceId: string
      resourceLabel?: string
    }[]
  }
}

DELETE /v1/orgs/:orgId/notify/protocols/:protocolId

Deletes a protocol and its attachments. Owners and admins.

Auth: user access token or platform agent key · Scope: org:write

Path parameterDescription
:orgIdOrganization id (org_…).
:protocolIdNotification protocol id (npr_…).

Response 204 with no body.

POST /v1/orgs/:orgId/notify/protocols/:protocolId/attachments

Attaches the protocol to { type, id, label? }: the whole organization (org) or a Serverless App Service, Issues space, calendar, mailbox or agent. Events about it then follow the protocol. Owners and admins.

Auth: user access token or platform agent key · Scope: org:write

Path parameterDescription
:orgIdOrganization id (org_…).
:protocolIdNotification protocol id (npr_…).

Request body

FieldTypeRequiredNotes
type"org" | "project" | "space" | "calendar" | "mailbox" | "agent"Yes
idstringYes1–128 characters
labelstringNoup to 120 characters

Response 201

{
  ok: true
}

DELETE /v1/orgs/:orgId/notify/protocols/:protocolId/attachments/:resourceType/:targetId

Detaches the protocol from that resource. Owners and admins.

Auth: user access token or platform agent key · Scope: org:write

Path parameterDescription
:orgIdOrganization id (org_…).
:protocolIdNotification protocol id (npr_…).
:resourceTypeWhat the protocol is attached to: org, project, space, calendar, mailbox or agent; for a group's access, project or repository.
:targetIdId of what it's attached to (the org's own id for org, else prj_…, spc_…, cal_…, mbx_…, dev_…).

Response 204 with no body.

Errors

StatusMessage
400Unknown resource type.