Action policies
Read and set the per-tool rung (never, ask, auto) and caps for nima's outbound actions, and mark tracker projects internal.
An action policy decides how nima may send one kind of outbound message in your workspace. The rule for a tool is a rung: never (nima may not send it), ask (a person approves each one) or auto (nima sends it without approval, only where every other safety rule allows). You can scope a policy to the whole workspace, to one tracker project, or to one watch, and you can add a daily cap and a cooldown per target. A second operation marks a tracker project as internal, which is required before a ticket reply can ever go auto. The concepts behind rungs and approvals are on Outbound actions.
Off until a workspace owner or admin turns it on: outbound dispatch is on for
the platform, but each workspace must set dispatchEnabled to true with
PATCH /organizations/settings. That route needs a signed-in owner or admin
session and no admin-panel control exists for it, so you can also ask the nima
team. The policy routes below work with the switch off, but nothing is sent
until it is on. See Workspace settings.
Action policy operations
| Method | Path | Scope | MCP tool |
|---|---|---|---|
GET | /v1/dispatch/policies | integrations:write | none |
PATCH | /v1/dispatch/policies | integrations:write | set_action_policy |
POST | /v1/dispatch/project-audience | integrations:write | assert_project_audience |
Paths are relative to https://api.getnima.io. Every call carries Authorization: Bearer <token>, is scoped to the workspace of the token, and needs the workspace role to hold integration management, which owners and admins do and members do not. A member gets 403 INSUFFICIENT_PERMISSIONS.
integrations:write is an admin scope. It is not offered on the MCP consent screen and a default API key does not carry it. Mint a 30-day key that holds it from Slack with /nima mcp-key integrations and confirm on the card. Only an owner or admin can run the command. A signed-in admin session can also call these routes directly. See Scopes and permissions.
Every write here is recorded in the action audit log (policy_changed or audience_asserted), with ids and reasons and never message text.
List action policies
/v1/dispatch/policiesintegrations:writeReturns every live policy in the workspace as an array of ActionPolicyDto. It takes no parameters, is not paginated, and has no MCP tool. Use it to read what set_action_policy stored.
iduuidThe policy row id.
toolNamestringThe effect tool the policy governs, reply_on_ticket or send_dm.
scopeKindenumorg, project or subscription (one watch).
scopeRefstring | nullnull for org. For project, the lowercase provider, a colon and the upper-case project key, for example jira:ENG. For subscription, the watch id.
rungenumnever, ask or auto. A removed policy is not listed.
conditionsobjectThe auto conditions. Only askerIsMember is understood. {} when none are set.
dailyCapinteger | nullMaximum actions per target per rolling 24 hours. null means the default: 3 for tracker replies, no per-target cap for send_dm.
perTargetCooldownSinteger | nullSeconds between two actions on the same target. null means the default: 600 seconds for tracker replies, none for send_dm.
createdByUserIduuid | nullThe admin who created the row.
updatedAtstringISO 8601 UTC timestamp.
Set an action policy
/v1/dispatch/policiesintegrations:writeMCP toolset_action_policySets, changes or removes the rung, caps and auto conditions for one effect tool at one scope. It answers 200 with the policy as stored. The most specific live policy wins when nima resolves a rung: a watch beats a project, and a project beats the workspace. With no policy, the tool's default applies: send_dm defaults to auto, reply_on_ticket to ask.
toolNamestringrequiredThe effect tool, 1 to 80 characters. reply_on_ticket is a comment on a tracker ticket and send_dm is a Slack direct message. A name nima does not register is rejected with 400. Other registered tools are accepted, each with its own maximum rung, but nothing in the product proposes them today.
scopeenumrequiredorg for the whole workspace, project for one tracker project, subscription for one watch, either a personal watch or a workspace rule.
providerstringRequired when scope is project. The tracker, 1 to 40 characters, for example jira.
projectKeystringRequired when scope is project. 1 to 80 characters, for example ENG. Case does not matter.
subscriptionIduuidRequired when scope is subscription. The watch id from Watches. It must belong to this workspace, else 404.
rungenumrequirednever, ask, auto or remove. remove deletes the policy so the broader scope applies.
askerIsMemberbooleanWith auto, send without approval only when the person who asked is a verified member of the workspace. Leaving it out clears a stored condition.
dailyCapinteger | null0 to 1000 actions per target per rolling 24 hours. null restores the default. The default for tracker replies is 3. 0 blocks every action on each target. Whatever the policy says, a workspace can have at most 200 outbound actions proposed per rolling hour.
perTargetCooldownSinteger | null0 to 604800 seconds (7 days) between two actions on the same target. null restores the default. The default for tracker replies is 600.
Each call replaces the whole policy for that tool and scope. It does not merge. If you leave out dailyCap or perTargetCooldownS, it resets to the default, the same as sending null. If you leave out askerIsMember or send false, the auto condition is cleared. To change one field, first read the policy with GET /v1/dispatch/policies, then send every field again.
The response fields are toolName, scopeKind, scopeRef, rung (null after a remove), dailyCap, perTargetCooldownS, conditions and changed. Writing what is already stored returns changed: false and audits nothing, so the call is safe to repeat.
A rung above what the tool allows is refused, not silently lowered. reply_on_ticket and send_dm can both reach auto. Other tools that nima registers have their own maximum rung and are not proposed by anything in the product today.
Setting auto opens a door, not a guarantee. A tracker reply still goes to approval unless the project is marked internal, the asker is a member with a verified link, every person the message mentions is linked with high assurance, no non-member text is in play, and the writer credential is not the connecting user's own account. See Mark a tracker project as internal and Outbound actions.
Errors from setting an action policy
| Status | When |
|---|---|
400 | The body fails validation. toolName is unknown: the error lists the known tool names in details.known. scope is project without provider and projectKey, or subscription without subscriptionId. The rung is above the tool's maximum. |
403 | The caller is not a live workspace admin: INSUFFICIENT_PERMISSIONS, "Changing an action policy needs integration admin rights". Membership is re-checked on every write, so a demoted admin is refused even with a valid key. A key or token without integrations:write gets 403 INSUFFICIENT_PERMISSIONS with details.requiredScopes. |
404 | subscriptionId does not belong to this workspace. |
409 | Two admins changed the same policy at the same moment: "This policy was changed at the same time; try again". Retry the call. |
See Errors for the shared error shape.
Mark a tracker project as internal
/v1/dispatch/project-audienceintegrations:writeMCP toolassert_project_audienceTells nima that everyone who can read a tracker project is inside your organization. Without this assertion, nima treats every project as possibly visible to outsiders and forces its replies on that project to approval. It answers 200 with the body you sent. Marking a project internal is required before a reply_on_ticket policy set to auto can send without approval; the other conditions are listed under Set an action policy.
providerstringrequiredThe tracker, 1 to 40 characters, for example jira. A GitHub repository (owner/repo) can be marked the same way, though nothing in the product replies on GitHub today.
projectKeystringrequiredThe project key, 1 to 80 characters, for example ENG. For GitHub use owner/repo. Keys are compared case-insensitively.
internalbooleanrequiredtrue asserts the project is internal. false withdraws the assertion.
The call is idempotent: repeating it changes and audits nothing. A workspace can hold at most 100 internal projects, and the 101st assertion fails with 400 "Too many internal projects". The same list can be replaced in one write through dispatch.internalProjects in Workspace settings.
Errors: 400 for a malformed body or the 100-project limit, and 403 INSUFFICIENT_PERMISSIONS when the caller is not an integration admin.
Audit of action policy changes
Every policy write and every audience assertion is stored as an event on the action ledger: policy_changed for PATCH /v1/dispatch/policies, audience_asserted for POST /v1/dispatch/project-audience. Events carry ids and reasons, never message text, and a call that changes nothing writes no event. Members cannot change rungs. Approvers approve or discard the actions routed to them on the Slack approval card; see Outbound actions.