codai docs
API referenceGateway

Triggers

Webhook triggers that turn GitHub, Sentry, monitoring or custom events into agent sessions, plus the notification inbox.

A trigger is a signed inbound webhook bound to your account. Each delivery is verified with the trigger's own secret, normalised into an event card, run through the trigger policy (filters, budget, rate limit, dedupe) and then either opens a session, appends to an open one or only posts a notification.

Signing generic deliveries

Custom senders sign with the codai scheme:

x-codai-signature: t=<unix seconds>,v1=<hex HMAC-SHA256(secret, "<t>.<raw body>")>
x-codai-delivery: <your delivery id>
  • The HMAC covers the timestamp, a literal . and the raw request body, byte for byte — sign before any re-serialisation.
  • t must be within 5 minutes of the gateway clock; older or future timestamps are rejected as stale_timestamp.
  • x-codai-delivery is the idempotency key: a repeated delivery id is recorded once. Without it the gateway derives an id from t and a hash of the body.
  • GitHub (X-Hub-Signature-256) and Sentry (Sentry-Hook-Signature) sources use their native signatures instead.

Ingress

The trigger policy field ingress decides where deliveries are accepted:

  • public (default) — the internet-facing POST /v1/hooks/{id}.
  • local — LAN-only sources. The public URL answers 404; deliveries arrive through the codaid daemon or the desktop app broker on your network, which forward them with the same signature check.
  • both — either path.

Use rotate-secret to mint a new generated secret, or PUT …/secret to set the secret a third-party service already signs with. POST …/test fires a signed sample delivery through the full pipeline.

GET
/v1/triggers

Authorization

bearerAuth
headerAuthorizationBearer <codai_…>

A codai API key (codai_ prefix). Ephemeral tokens from POST /v1/tokens are accepted only by the media surfaces matching their scope (/v1/realtime, /v1/audio/*, /v1/embeddings).

Header Parameters

x-request-id?string

Client correlation id; echoed back as x-codai-trace-id and persisted on the usage row.

Lengthlength <= 128

Response Body

The caller's triggers.

application/json
  1. response
data*array<>
sources*array<>
Example Request
curl -X GET 'https://ai.codai.ro/v1/triggers'
Example Response
{  "data": [    {      "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",      "name": "string",      "source": "github",      "enabled": true,      "policy": {        "mode": "notify",        "smart": {          "assistedAt": "info",          "autopilotAt": "info",          "keywords": {            "property1": "notify",            "property2": "notify"          }        },        "subjects": [          "string"        ],        "minSeverity": "info",        "permissions": "read",        "quietHours": {          "from": "string",          "to": "string",          "tz": "Europe/Bucharest"        },        "budgetMicroUsdPerEvent": 2000000,        "budgetMicroUsdPerDay": 10000000,        "maxSessionsPerHour": 6,        "dedupeWindowMin": 1440,        "promptTemplate": "string",        "skill": "string",        "target": {          "kind": "any",          "id": "string"        },        "ttlMin": 240      },      "hook_url": "http://example.com",      "last_event_at": "2019-08-24T14:15:22Z",      "created_at": "2019-08-24T14:15:22Z"    }  ],  "sources": [    "github"  ]}
POST
/v1/triggers

Authorization

bearerAuth
headerAuthorizationBearer <codai_…>

A codai API key (codai_ prefix). Ephemeral tokens from POST /v1/tokens are accepted only by the media surfaces matching their scope (/v1/realtime, /v1/audio/*, /v1/embeddings).

Header Parameters

x-request-id?string

Client correlation id; echoed back as x-codai-trace-id and persisted on the usage row.

Lengthlength <= 128

Request Body

application/json
  1. body
name*string
Length1 <= length <= 120
source*TriggerSource

How deliveries are authenticated and normalized (see POST /v1/hooks/{id}).

Value in"github""sentry""gcp""generic""form""manual"
policy?

Partial TriggerPolicy; omitted keys take their defaults, invalid values are a 400.

enabled?boolean
Defaulttrue

Response Body

Created; secret is shown once.

application/json
  1. response
id*string
Formatuuid
name*string
source*TriggerSource

How deliveries are authenticated and normalized (see POST /v1/hooks/{id}).

Value in"github""sentry""gcp""generic""form""manual"
enabled*boolean
policy*

The trigger policy with every default filled in (as returned by the API).

hook_url*string

Where the sender posts, https://api.codai.ro/v1/hooks/<id> in production.

Formaturi
last_event_at*|
Formatdate-time
created_at*string
Formatdate-time
secret*string

Signing secret, whsec_ prefix. Shown only in this response.

Example Request
curl -X POST 'https://ai.codai.ro/v1/triggers' \  -H 'Content-Type: application/json' \  -d '{  "name": "string",  "source": "github"}'
Example Response
{  "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",  "name": "string",  "source": "github",  "enabled": true,  "policy": {    "mode": "notify",    "smart": {      "assistedAt": "info",      "autopilotAt": "info",      "keywords": {        "property1": "notify",        "property2": "notify"      }    },    "subjects": [      "string"    ],    "minSeverity": "info",    "permissions": "read",    "quietHours": {      "from": "string",      "to": "string",      "tz": "Europe/Bucharest"    },    "budgetMicroUsdPerEvent": 2000000,    "budgetMicroUsdPerDay": 10000000,    "maxSessionsPerHour": 6,    "dedupeWindowMin": 1440,    "promptTemplate": "string",    "skill": "string",    "target": {      "kind": "any",      "id": "string"    },    "ttlMin": 240  },  "hook_url": "http://example.com",  "last_event_at": "2019-08-24T14:15:22Z",  "created_at": "2019-08-24T14:15:22Z",  "secret": "string"}
PATCH
/v1/triggers/{id}

Authorization

bearerAuth
headerAuthorizationBearer <codai_…>

A codai API key (codai_ prefix). Ephemeral tokens from POST /v1/tokens are accepted only by the media surfaces matching their scope (/v1/realtime, /v1/audio/*, /v1/embeddings).

Path Parameters

id*string

Trigger UUID. A malformed, unknown or foreign id is 404.

Formatuuid

Header Parameters

x-request-id?string

Client correlation id; echoed back as x-codai-trace-id and persisted on the usage row.

Lengthlength <= 128

Request Body

application/json
  1. body
name?string
Length1 <= length <= 120
policy?

Replaces the stored policy (not merged); omitted keys take their defaults.

enabled?boolean

Response Body

The updated trigger.

application/json
  1. response
id*string
Formatuuid
name*string
source*TriggerSource

How deliveries are authenticated and normalized (see POST /v1/hooks/{id}).

Value in"github""sentry""gcp""generic""form""manual"
enabled*boolean
policy*

The trigger policy with every default filled in (as returned by the API).

hook_url*string

Where the sender posts, https://api.codai.ro/v1/hooks/<id> in production.

Formaturi
last_event_at*|
Formatdate-time
created_at*string
Formatdate-time
Example Request
curl -X PATCH 'https://ai.codai.ro/v1/triggers/497f6eca-6276-4993-bfeb-53cbbbba6f08' \  -H 'Content-Type: application/json' \  -d '{}'
Example Response
{  "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",  "name": "string",  "source": "github",  "enabled": true,  "policy": {    "mode": "notify",    "smart": {      "assistedAt": "info",      "autopilotAt": "info",      "keywords": {        "property1": "notify",        "property2": "notify"      }    },    "subjects": [      "string"    ],    "minSeverity": "info",    "permissions": "read",    "quietHours": {      "from": "string",      "to": "string",      "tz": "Europe/Bucharest"    },    "budgetMicroUsdPerEvent": 2000000,    "budgetMicroUsdPerDay": 10000000,    "maxSessionsPerHour": 6,    "dedupeWindowMin": 1440,    "promptTemplate": "string",    "skill": "string",    "target": {      "kind": "any",      "id": "string"    },    "ttlMin": 240  },  "hook_url": "http://example.com",  "last_event_at": "2019-08-24T14:15:22Z",  "created_at": "2019-08-24T14:15:22Z"}
DELETE
/v1/triggers/{id}

Authorization

bearerAuth
headerAuthorizationBearer <codai_…>

A codai API key (codai_ prefix). Ephemeral tokens from POST /v1/tokens are accepted only by the media surfaces matching their scope (/v1/realtime, /v1/audio/*, /v1/embeddings).

Path Parameters

id*string

Trigger UUID. A malformed, unknown or foreign id is 404.

Formatuuid

Header Parameters

x-request-id?string

Client correlation id; echoed back as x-codai-trace-id and persisted on the usage row.

Lengthlength <= 128

Response Body

Deleted.

application/json
  1. response
id*string
Formatuuid
deleted*true
Value intrue
Example Request
curl -X DELETE 'https://ai.codai.ro/v1/triggers/497f6eca-6276-4993-bfeb-53cbbbba6f08'
Example Response
{  "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",  "deleted": true}
POST
/v1/triggers/{id}/rotate-secret

Authorization

bearerAuth
headerAuthorizationBearer <codai_…>

A codai API key (codai_ prefix). Ephemeral tokens from POST /v1/tokens are accepted only by the media surfaces matching their scope (/v1/realtime, /v1/audio/*, /v1/embeddings).

Path Parameters

id*string

Trigger UUID. A malformed, unknown or foreign id is 404.

Formatuuid

Header Parameters

x-request-id?string

Client correlation id; echoed back as x-codai-trace-id and persisted on the usage row.

Lengthlength <= 128

Response Body

The new secret (shown once).

application/json
  1. response
id*string
Formatuuid
secret*string

New signing secret, whsec_ prefix. Never returned again.

Example Request
curl -X POST 'https://ai.codai.ro/v1/triggers/497f6eca-6276-4993-bfeb-53cbbbba6f08/rotate-secret'
Example Response
{  "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",  "secret": "string"}
PUT
/v1/triggers/{id}/secret

Authorization

bearerAuth
headerAuthorizationBearer <codai_…>

A codai API key (codai_ prefix). Ephemeral tokens from POST /v1/tokens are accepted only by the media surfaces matching their scope (/v1/realtime, /v1/audio/*, /v1/embeddings).

Path Parameters

id*string

Trigger UUID. A malformed, unknown or foreign id is 404.

Formatuuid

Header Parameters

x-request-id?string

Client correlation id; echoed back as x-codai-trace-id and persisted on the usage row.

Lengthlength <= 128

Request Body

application/json
  1. body
secret*string
Length16 <= length <= 512

Response Body

Secret replaced.

application/json
  1. response
id*string
Formatuuid
replaced*boolean
Example Request
curl -X PUT 'https://ai.codai.ro/v1/triggers/497f6eca-6276-4993-bfeb-53cbbbba6f08/secret' \  -H 'Content-Type: application/json' \  -d '{  "secret": "stringstringstri"}'
Example Response
{  "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",  "replaced": true}
POST
/v1/triggers/{id}/test

Authorization

bearerAuth
headerAuthorizationBearer <codai_…>

A codai API key (codai_ prefix). Ephemeral tokens from POST /v1/tokens are accepted only by the media surfaces matching their scope (/v1/realtime, /v1/audio/*, /v1/embeddings).

Path Parameters

id*string

Trigger UUID. A malformed, unknown or foreign id is 404.

Formatuuid

Header Parameters

x-request-id?string

Client correlation id; echoed back as x-codai-trace-id and persisted on the usage row.

Lengthlength <= 128

Request Body

application/json
  1. body
title?string
Lengthlength <= 200
message?string
Lengthlength <= 4000
severity?TriggerSeverity
Value in"info""low""medium""high""critical"
url?string
Formaturi
subject?string
Lengthlength <= 200

Response Body

The recorded event and the policy decision.

application/json
  1. response
event_id*integer

Id of the recorded delivery (see GET /v1/triggers/{id}/events).

decision*

What the policy decided for one event and why (reason is shown on the session).

session_id*|

Session started or appended to; null for notify/ignore decisions.

Formatuuid
card*

A delivery normalized into one source-independent shape.

Example Request
curl -X POST 'https://ai.codai.ro/v1/triggers/497f6eca-6276-4993-bfeb-53cbbbba6f08/test' \  -H 'Content-Type: application/json' \  -d '{}'
Example Response
{  "event_id": 0,  "decision": {    "action": "ignore",    "reason": "string",    "mode": "notify",    "wanted": "notify",    "sessionId": "f6567dd8-e069-418e-8893-7d22fcf12459"  },  "session_id": "1ffd059c-17ea-40a8-8aef-70fd0307db82",  "card": {    "source": "github",    "kind": "string",    "title": "string",    "summary": "string",    "severity": "info",    "url": "string",    "subject": "string",    "dedupeKey": "string",    "labels": [      "string"    ],    "resolved": true  }}
GET
/v1/triggers/{id}/events

Authorization

bearerAuth
headerAuthorizationBearer <codai_…>

A codai API key (codai_ prefix). Ephemeral tokens from POST /v1/tokens are accepted only by the media surfaces matching their scope (/v1/realtime, /v1/audio/*, /v1/embeddings).

Path Parameters

id*string

Trigger UUID. A malformed, unknown or foreign id is 404.

Formatuuid

Query Parameters

limit?integer

Page size, clamped to 1–200; anything non-numeric falls back to 50.

Range1 <= value <= 200
Default50

Header Parameters

x-request-id?string

Client correlation id; echoed back as x-codai-trace-id and persisted on the usage row.

Lengthlength <= 128

Response Body

Deliveries ordered by receivedAt descending.

application/json
  1. response
data*array<>
Example Request
curl -X GET 'https://ai.codai.ro/v1/triggers/497f6eca-6276-4993-bfeb-53cbbbba6f08/events'
Example Response
{  "data": [    {      "id": 0,      "deliveryId": "string",      "status": "received",      "card": {        "source": "github",        "kind": "string",        "title": "string",        "summary": "string",        "severity": "info",        "url": "string",        "subject": "string",        "dedupeKey": "string",        "labels": [          "string"        ],        "resolved": true      },      "decision": {        "action": "ignore",        "reason": "string",        "mode": "notify",        "wanted": "notify",        "sessionId": "f6567dd8-e069-418e-8893-7d22fcf12459"      },      "sessionId": "f6567dd8-e069-418e-8893-7d22fcf12459",      "attempts": 0,      "error": "string",      "receivedAt": "2019-08-24T14:15:22Z",      "processedAt": "2019-08-24T14:15:22Z"    }  ]}
POST
/v1/hooks/{id}

Path Parameters

id*string

Trigger UUID (the last segment of hook_url).

Formatuuid

Query Parameters

token?string

gcp source only: the trigger secret, when the sender cannot set an Authorization header.

Header Parameters

x-hub-signature-256?string

github source: sha256= followed by the hex HMAC-SHA256 of the raw body.

x-github-delivery?string

github source (required there): the delivery GUID, used as the idempotency key.

x-github-event?string

github source: the event type (issues, pull_request, workflow_run, …).

sentry-hook-signature?string

sentry source: hex HMAC-SHA256 of the raw body with the trigger secret.

sentry-hook-resource?string

sentry source: the resource the event is about (issue, event_alert, metric_alert, …).

request-id?string

sentry source: delivery id used as the idempotency key.

x-codai-signature?string

generic / form / manual sources: t=<unix>,v1=<hex HMAC-SHA256 of "<t>.<raw body>">.

x-codai-delivery?string

generic / form / manual sources: optional idempotency key for the delivery.

Request Body

application/json
  1. body

The sender's own JSON payload. generic / form / manual senders may use title, message, severity (info…critical), url, subject and kind to shape the event card.

[key: string]?any

Response Body

Accepted (recorded; processed after the response).

application/json
  1. response
accepted*true
Value intrue
duplicate*boolean

true when this delivery id was already recorded; it is not processed again.

event_id*integer

Id of the recorded delivery.

Example Request
curl -X POST 'https://ai.codai.ro/v1/hooks/497f6eca-6276-4993-bfeb-53cbbbba6f08' \  -H 'Content-Type: application/json' \  -d '{}'
Example Response
{  "accepted": true,  "duplicate": true,  "event_id": 0}
GET
/v1/notifications

Authorization

bearerAuth
headerAuthorizationBearer <codai_…>

A codai API key (codai_ prefix). Ephemeral tokens from POST /v1/tokens are accepted only by the media surfaces matching their scope (/v1/realtime, /v1/audio/*, /v1/embeddings).

Query Parameters

unread?"1"

1 to return only unread notifications.

Value in"1"
limit?integer

Page size, clamped to 1–200; anything non-numeric falls back to 50.

Range1 <= value <= 200
Default50

Header Parameters

x-request-id?string

Client correlation id; echoed back as x-codai-trace-id and persisted on the usage row.

Lengthlength <= 128

Response Body

Notifications ordered by createdAt descending.

application/json
  1. response
data*array<>
Example Request
curl -X GET 'https://ai.codai.ro/v1/notifications'
Example Response
{  "data": [    {      "id": 0,      "userId": "2c4a230c-5085-4924-a3e1-25fb4fc5965b",      "kind": "string",      "severity": "info",      "title": "string",      "body": "string",      "url": "string",      "sessionId": "f6567dd8-e069-418e-8893-7d22fcf12459",      "triggerEventId": 0,      "readAt": "2019-08-24T14:15:22Z",      "createdAt": "2019-08-24T14:15:22Z"    }  ]}
POST
/v1/notifications/read

Authorization

bearerAuth
headerAuthorizationBearer <codai_…>

A codai API key (codai_ prefix). Ephemeral tokens from POST /v1/tokens are accepted only by the media surfaces matching their scope (/v1/realtime, /v1/audio/*, /v1/embeddings).

Header Parameters

x-request-id?string

Client correlation id; echoed back as x-codai-trace-id and persisted on the usage row.

Lengthlength <= 128

Request Body

application/json
  1. body
ids?array<>
Itemsitems <= 500

Response Body

How many notifications were updated.

application/json
  1. response
read*integer
Range0 <= value
Example Request
curl -X POST 'https://ai.codai.ro/v1/notifications/read' \  -H 'Content-Type: application/json' \  -d '{}'
Example Response
{  "read": 0}
DELETE
/v1/notifications/{id}

Authorization

bearerAuth
headerAuthorizationBearer <codai_…>

A codai API key (codai_ prefix). Ephemeral tokens from POST /v1/tokens are accepted only by the media surfaces matching their scope (/v1/realtime, /v1/audio/*, /v1/embeddings).

Path Parameters

id*integer
Range1 <= value

Header Parameters

x-request-id?string

Client correlation id; echoed back as x-codai-trace-id and persisted on the usage row.

Lengthlength <= 128

Response Body

How many notifications were deleted (0 or 1).

application/json
  1. response
deleted*integer
Range0 <= value
Example Request
curl -X DELETE 'https://ai.codai.ro/v1/notifications/1'
Example Response
{  "deleted": 0}
POST
/v1/notifications/delete

Authorization

bearerAuth
headerAuthorizationBearer <codai_…>

A codai API key (codai_ prefix). Ephemeral tokens from POST /v1/tokens are accepted only by the media surfaces matching their scope (/v1/realtime, /v1/audio/*, /v1/embeddings).

Header Parameters

x-request-id?string

Client correlation id; echoed back as x-codai-trace-id and persisted on the usage row.

Lengthlength <= 128

Request Body

application/json
  1. body
ids*array<>
Items1 <= items <= 200

Response Body

How many notifications were deleted.

application/json
  1. response
deleted*integer
Range0 <= value
Example Request
curl -X POST 'https://ai.codai.ro/v1/notifications/delete' \  -H 'Content-Type: application/json' \  -d '{  "ids": [    1  ]}'
Example Response
{  "deleted": 0}

Last updated:

On this page