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
| Method | Path | Scope | MCP tool |
|---|---|---|---|
GET | /v1/triggers/event-types | subscriptions:read | list_event_types |
POST | /v1/watches | subscriptions:write | create_subscription |
PATCH | /v1/watches/{id} | subscriptions:write | update_subscription |
GET | /v1/watches | subscriptions:read | list_watches |
DELETE | /v1/watches/{id} | subscriptions:write | unwatch |
GET | /v1/inbox | inbox:read | get_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
/v1/triggers/event-typessubscriptions:readMCP toollist_event_typesThe 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.
typestringThe event type, for example beacon.ready.
subjectKindstringWhat the event happens to: signal, beacon, spec, pr or ticket.
descriptionstringOne line saying when the event fires.
materialbooleantrue 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.
payloadSchemaobjectA JSON Schema of the event payload. It names the fields you can use in payloadEquals.
The catalog has 16 event types:
| Subject | Event types |
|---|---|
| signal | signal.attached_to_beacon |
| beacon | beacon.ready, beacon.promoted, beacon.held, beacon.dismissed |
| spec | spec.generation_completed, spec.question_asked, spec.status_changed, spec.shipped |
| beacon (a spec run that failed) | spec.generation_failed |
| pr | pr.linked_to_spec, pr.merged, pr.drift_checked |
| ticket | ticket.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
/v1/watchessubscriptions:writeMCP toolcreate_subscriptionCreates 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.
subjectKindstringrequiredsignal, 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.
subjectIduuidrequiredThe id of the subject, from the list tools. It must exist in your workspace.
triggerTypesstring[]requiredOne or more event types from the catalog.
instructionsstringrequired1 to 4000 characters. What the AI should analyze and answer when the event fires.
namestring1 to 160 characters. A short title.
contextstring1 to 8000 characters. Preferences to carry into every answer.
payloadEqualsobjectConditions. 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 8601When the watch expires. Must be in the future. Omit for no expiry.
scopestringuser (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
| Status | When |
|---|---|
400 | Unknown 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". |
403 | The 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
/v1/watches/{id}subscriptions:writeMCP toolupdate_subscriptionChanges 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
| Status | When |
|---|---|
400 | "Only conversational subscriptions can be edited", or the same validation errors as creating. |
403 | Your 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
/v1/watchessubscriptions:readMCP toollist_watchesReturns 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
/v1/watches/{id}subscriptions:writeMCP toolunwatchPauses 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
/v1/inboxinbox:readMCP toolget_inboxEverything nima has told you about what you watch, newest first, as a paginated list of inbox items. It is your own inbox only.
pageintegerStarts at 1.
limitinteger1 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 needsintegrations:writeto 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 integrationsin Slack carries onlyintegrations:write, soPOST /v1/watchesrefuses it with403. Otherwise, ask the nima team. triggersEnabledis on, and outbound dispatch is on for the workspace (dispatchEnabled), or the call answers409"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" }withtemplateKey: "tracker_assignee_reminder".fallbackdefaults tonone. Thementionoption is rejected today.{ "kind": "agent", "instructions": "...", "context": "...", "tools": ["reply_on_ticket"], "maxActions": 1 }.contextis optional, 1 to 8000 characters.maxActionscan only be1, 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.
iduuidThe watch id.
namestring | nullThe title. Defaults to Your requested update for a personal watch and Ticket rule for a workspace rule. null for automatic watches.
handlerobjectWhat 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 | nullThe exact-equality conditions, or null.
subjectKindstring | nullThe watched subject kind. null for workspace rules.
subjectIduuid | nullThe watched subject. null for workspace rules.
triggerTypesstring[]The event types the watch listens for.
templateKeystring | nullThe message template, or null for a watch you wrote yourself.
createdViastringHow 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).
statestringactive, paused or expired.
pausedReasonstring | nullWhy 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 | nullWhen the watch expires, or null.
lastFiredAtISO 8601 | nullThe last time the watch fired.
fireCountintegerHow many times the watch has fired.
createdAtISO 8601When 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.
iduuidThe item id.
kindstringinform (a watch notification), reminder (a ticket-rule reminder), approval (an approval card) or question (a question nima relayed to you).
statestringWhere the item is in delivery, sent, delivered, digested, stopped or failed.
ruleIdstring | nullWhat 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 | nullWhat the item was about.
subjectIduuid | nullThe subject id.
titlestringThe item title.
bodystringThe item text.
linksobject[]Links attached to the item.
channelstringslack_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 | nullWhen the DM was sent, or null.
digestedAtISO 8601 | nullWhen the item was folded into a digest, or null.
createdAtISO 8601When 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:
| Status | error | When |
|---|---|---|
401 | TOKEN_INVALID | Missing, malformed, revoked or expired key. |
403 | INSUFFICIENT_PERMISSIONS | The key lacks the scope in the operations table, or your membership no longer allows the call. details.requiredScopes names what was needed. |
404 | RESOURCE_NOT_FOUND | On PATCH/DELETE: the watch id is missing or belongs to someone else. On POST/PATCH: the subject does not exist. |
429 | RATE_LIMITED | See 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,
afterorunlessconditions 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.