docs
API

Watches and inbox

Create, list, update and pause watches, read the event-type catalog, and read your nima inbox over the API.

A watch is a standing request: when a supported event happens to one signal, beacon, spec or pull request, nima tells you. It sends a Slack DM, keeps an item in your inbox, and folds lower-priority items into a 09:00 local-time digest. The routes below create and manage your watches, list the events a watch can react to, and read the inbox. For how watches behave, see Watches and reminders.

Off until a workspace owner or admin turns it on. Watches need the workspace setting triggersEnabled, which defaults to off. The only control is PATCH /organizations/settings with {"triggersEnabled": true}, called from a signed-in owner or admin session (no API key, no MCP tool, no admin-panel switch), or ask the nima team. Until then POST /v1/watches and PATCH /v1/watches/{id} answer 409 with "Subscriptions are not enabled for this workspace". See Workspace settings and Availability.

Watches and inbox items are personal. Every route below is scoped to your workspace and to you: there is no way to list anyone else's watches or inbox, and another person's watch id answers 404, exactly like an id that does not exist.

Watch and inbox operations

MethodPathScopeMCP tool
GET/v1/triggers/event-typessubscriptions:readlist_event_types
POST/v1/watchessubscriptions:writecreate_subscription
PATCH/v1/watches/{id}subscriptions:writeupdate_subscription
GET/v1/watchessubscriptions:readlist_watches
DELETE/v1/watches/{id}subscriptions:writeunwatch
GET/v1/inboxinbox:readget_inbox

Paths are relative to https://api.getnima.io. Every call carries Authorization: Bearer <your key>. The three scopes are in the default set an MCP client is asked to consent to. See Scopes and permissions and Authentication. The tools are documented on Watch and inbox tools.

Creating, updating or pausing a watch needs a member, admin or owner role. Your membership is checked again every time a watch fires. To read what happened to a subject, use GET /v1/events.

List the event types a watch can react to

GET/v1/triggers/event-types
scopesubscriptions:readMCP toollist_event_types

The fixed catalog of events nima can notice. Read it before you create a watch: triggerTypes and payloadEquals are validated against it. It takes no parameters.

The response is { subjectKinds, eventTypes }. Each entry of eventTypes has these fields.

typestring

The event type, for example beacon.ready.

subjectKindstring

What the event happens to: signal, beacon, spec, pr or ticket.

descriptionstring

One line saying when the event fires.

materialboolean

true means the event can interrupt someone already told about the subject. pr.drift_checked does so only when the verdict is drifted on an open pull request. Non-material events about a subject you were recently told about fold into the 09:00 digest.

payloadSchemaobject

A JSON Schema of the event payload. It names the fields you can use in payloadEquals.

The catalog has 16 event types:

SubjectEvent types
signalsignal.attached_to_beacon
beaconbeacon.ready, beacon.promoted, beacon.held, beacon.dismissed
specspec.generation_completed, spec.question_asked, spec.status_changed, spec.shipped
beacon (a spec run that failed)spec.generation_failed
prpr.linked_to_spec, pr.merged, pr.drift_checked
ticketticket.opened, ticket.assigned, ticket.comment_added

Ticket events come from a connected tracker (Jira). nima records them only while outbound dispatch is on for the workspace (dispatchEnabled, see Workspace settings). A watch on ticket.* events is accepted without it but never fires. ticket.comment_added also needs nima's Jira writer connected (see Jira), and ticket.opened fires only for an issue created in the last 24 hours. Ticket events carry the issue's ids, key, title, URL and flags, never its description or comment text. A workspace rule hears every ticket event in the workspace. A personal watch on a signal, beacon or spec can also list ticket event types. It hears them only for a tracker issue whose card carries that spec, or a spec downstream of the watched signal or beacon.

Create a watch

POST/v1/watches
scopesubscriptions:writeMCP toolcreate_subscription

Creates a personal watch on one existing signal, beacon, spec or pull request. Returns the watch. A watch acts on future events only: events recorded before it existed never fire it. It hears events on the subject itself and on the items downstream of it, so a watch on a signal also hears events on that signal's beacon, spec and pull request.

The body is strict: an unknown field is rejected.

subjectKindstringrequired

signal, beacon, spec or pr. The API also accepts ticket, the id of a tracker issue, which you can take from the subjectId of an inbox item about a ticket.

subjectIduuidrequired

The id of the subject, from the list tools. It must exist in your workspace.

triggerTypesstring[]required

One or more event types from the catalog.

instructionsstringrequired

1 to 4000 characters. What the AI should analyze and answer when the event fires.

namestring

1 to 160 characters. A short title.

contextstring

1 to 8000 characters. Preferences to carry into every answer.

payloadEqualsobject

Conditions. Values are strings, numbers or booleans, and every field must equal exactly. Each field must exist on every event type in triggerTypes. There are no ranges, not or or.

expiresAtISO 8601

When the watch expires. Must be in the future. Omit for no expiry.

scopestring

user (default) or org. See Create a workspace rule.

A watch follows its subject downstream only. The subject kinds run in the order signal, beacon, spec, pr, ticket, and an event whose subject kind comes before the watched subject is refused with 400. A watch on a spec cannot subscribe to beacon.ready.

Repeating an identical active request returns the existing watch instead of creating a second one.

Errors from creating a watch

StatusWhen
400Unknown field; conditions are not valid for the chosen events ("Unsupported event conditions"); expiresAt is in the past; an event type that comes before the subject kind; handler or templateKey sent without scope: "org".
403The key lacks subscriptions:write, or your role no longer allows it.
404"Subscription subject not found": the subject id does not exist in your workspace.
409"Subscriptions are not enabled for this workspace".

Update or resume a watch

PATCH/v1/watches/{id}
scopesubscriptions:writeMCP toolupdate_subscription

Changes one of your conversational watches (the ones with an AI handler) and returns it. Send any of name, triggerTypes, payloadEquals, instructions, context and expiresAt. The subject cannot change: create a new watch instead. Send payloadEquals: {} to clear conditions. Send state: "active" to resume a paused watch.

Resuming a watch restarts its clock: it does not fire on events from the period it was paused or expired. To resume a watch whose expiresAt has passed, send a new future expiresAt (or null) in the same call. Over MCP the tool takes the same fields plus id.

Only watches created by you over the API, MCP or Slack conversation can be edited. Automatic watches (the bell reaction and the ones nima adds when you promote a beacon or a spec is written) and workspace rules cannot.

Errors from updating a watch

StatusWhen
400"Only conversational subscriptions can be edited", or the same validation errors as creating.
403Your role no longer allows it.
404"Watch not found": the id is missing or belongs to someone else. Also "Subscription subject not found" when the watched subject no longer exists.
409"An identical subscription is already active", or triggers are not enabled for the workspace.

List your watches

GET/v1/watches
scopesubscriptions:readMCP toollist_watches

Returns an array of your watches: active first, then paused and expired, newest first within each group. It returns at most 200 and takes no query parameters, so there is no pagination.

The list includes the watches you created, the automatic watches nima added for you (createdVia of implicit or reaction) and any workspace rules you own.

Pause a watch

DELETE/v1/watches/{id}
scopesubscriptions:writeMCP toolunwatch

Pauses one of your watches and returns it with HTTP 200 (not 204). Nothing is deleted, so past notifications stay explainable. The watch's state becomes paused and pausedReason becomes unwatched. Its pending digest items stop with it.

Pausing an already paused or expired watch changes nothing and returns it as it is. To bring a watch back, resume it. An id that is missing or belongs to someone else answers 404.

Read your inbox

GET/v1/inbox
scopeinbox:readMCP toolget_inbox

Everything nima has told you about what you watch, newest first, as a paginated list of inbox items. It is your own inbox only.

pageinteger

Starts at 1.

limitinteger

1 to 100. Defaults to 20. A value outside the range is a 400.

The response is PaginatedResponse<InboxItemDto>. See Pagination.

Create a workspace rule for tracker tickets

POST /v1/watches with "scope": "org" creates a workspace rule instead of a personal watch: one rule over every ticket event in a connected tracker (Jira). It is separate from personal watches and has stricter requirements.

All of these must hold, and a failed check answers 403 or 409:

  • The caller has the owner or admin role.
  • The call comes from a signed-in owner or admin session. No API key, MCP connection or other OAuth token can create a workspace rule today. The route needs subscriptions:write, and a token also needs integrations:write to create a workspace rule, but no key or token can carry both. API keys and the MCP consent screen offer only the consumer scopes, and the key from /nima mcp-key integrations in Slack carries only integrations:write, so POST /v1/watches refuses it with 403. Otherwise, ask the nima team.
  • triggersEnabled is on, and outbound dispatch is on for the workspace (dispatchEnabled), or the call answers 409 "Outbound dispatch is not enabled for this workspace".

A workspace rule takes no subjectKind or subjectId. Its triggerTypes are one or more of ticket.opened, ticket.assigned and ticket.comment_added. Its handler is one of:

  • { "kind": "notify", "to": { "role": "owner" | "assignee" | "reporter" | "spec_owner" }, "fallback": "owner" | "none" } with templateKey: "tracker_assignee_reminder". fallback defaults to none. The mention option is rejected today.
  • { "kind": "agent", "instructions": "...", "context": "...", "tools": ["reply_on_ticket"], "maxActions": 1 }. context is optional, 1 to 8000 characters. maxActions can only be 1, and the actions the rule proposes still go through approval.

A rule fires only on events created after the rule. It cannot be edited or resumed through PATCH. Pausing a rule with DELETE is final; create a new rule to start again.

The watch object

The watch object is what every watch route returns: POST, PATCH and DELETE return one, GET /v1/watches returns an array.

iduuid

The watch id.

namestring | null

The title. Defaults to Your requested update for a personal watch and Ticket rule for a workspace rule. null for automatic watches.

handlerobject

What runs when the watch fires. kind is ai_response (a conversational watch), notify (a templated message) or agent (a workspace rule that proposes actions).

payloadEqualsobject | null

The exact-equality conditions, or null.

subjectKindstring | null

The watched subject kind. null for workspace rules.

subjectIduuid | null

The watched subject. null for workspace rules.

triggerTypesstring[]

The event types the watch listens for.

templateKeystring | null

The message template, or null for a watch you wrote yourself.

createdViastring

How the watch came to exist: api (created over the API, MCP or a Slack conversation), implicit (nima added it) or reaction (a bell reaction in Slack).

statestring

active, paused or expired.

pausedReasonstring | null

Why a paused watch stopped: user_stop (a stop DM to the bot), no_bell (the no-bell reaction) or unwatched (the pause route). null otherwise.

expiresAtISO 8601 | null

When the watch expires, or null.

lastFiredAtISO 8601 | null

The last time the watch fired.

fireCountinteger

How many times the watch has fired.

createdAtISO 8601

When the watch was created.

{
  "id": "0b8d4c52-0000-4000-8000-000000000000",
  "name": "Your requested update",
  "handler": { "kind": "ai_response" },
  "payloadEquals": { "verdict": "drifted" },
  "subjectKind": "spec",
  "subjectId": "6f1c2a3e-0000-4000-8000-000000000000",
  "triggerTypes": ["pr.drift_checked"],
  "templateKey": null,
  "createdVia": "api",
  "state": "active",
  "pausedReason": null,
  "expiresAt": null,
  "lastFiredAt": null,
  "fireCount": 0,
  "createdAt": "2026-09-30T09:00:00.000Z"
}

The handler value above is abbreviated: an ai_response handler also stores your saved instructions and context, and list_watches returns them.

The inbox item object

An inbox item is one message nima sent you, or held for you, about something you watch.

iduuid

The item id.

kindstring

inform (a watch notification), reminder (a ticket-rule reminder), approval (an approval card) or question (a question nima relayed to you).

statestring

Where the item is in delivery, sent, delivered, digested, stopped or failed.

ruleIdstring | null

What produced the item: the watch id for a watch you wrote or a workspace rule, or the template key (for example spec_generated) for an automatic watch. null when neither applies.

subjectKindstring | null

What the item was about.

subjectIduuid | null

The subject id.

titlestring

The item title.

bodystring

The item text.

linksobject[]

Links attached to the item.

channelstring

slack_dm (sent as a Slack DM), digest (folded into the 09:00 local-time digest) or inbox (kept here only, for example when your Slack account is not linked).

deliveredAtISO 8601 | null

When the DM was sent, or null.

digestedAtISO 8601 | null

When the item was folded into a digest, or null.

createdAtISO 8601

When nima created the item.

Errors from watch and inbox routes

The routes use the standard error envelope. Beyond the per-route errors above, these apply unless noted:

StatuserrorWhen
401TOKEN_INVALIDMissing, malformed, revoked or expired key.
403INSUFFICIENT_PERMISSIONSThe key lacks the scope in the operations table, or your membership no longer allows the call. details.requiredScopes names what was needed.
404RESOURCE_NOT_FOUNDOn PATCH/DELETE: the watch id is missing or belongs to someone else. On POST/PATCH: the subject does not exist.
429RATE_LIMITEDSee Rate limits.

What watches do not do

  • A watch pins one existing signal, beacon, spec or pull request. There are no topic or keyword watches, and no watch on items that do not exist yet.
  • Conditions are exact equality only. There are no timers, after or unless conditions and no recurring schedules.
  • Personal watches deliver only to their owner, by Slack DM, the inbox and the 09:00 digest (a workspace rule can instead notify a ticket's assignee, reporter or spec owner). There is no webhook, pull feed or channel posting.
  • To be reminded at a time you choose, use scheduled messages.