docs
API

Identities

Link external Slack, Jira, Linear and Notion accounts to workspace members and list unlinked ones.

An identity is the link between an account in another tool (a Slack user, an Atlassian account, a Linear user, a Notion user) and a member of your nima workspace. nima uses these links to direct messages to the right person and to tag people by name instead of printing a plain display name. The three operations below create a link as an admin, create a link for yourself, and list the accounts nima has seen that no member holds yet. For the model behind them, see People and identities and Outbound actions.

On for every workspace. The identity routes have no workspace switch. Links only matter once outbound dispatch is on for the workspace, because that is when nima messages or tags people. Tagging also needs the workspace's mentions setting on; see Outbound actions.

MethodPathScopeMCP tool
POST/v1/identities/linkintegrations:write or identities:write, plus owner or adminlink_external_identity
POST/v1/identities/link-meidentities:writelink_my_identity
GET/v1/identities/unlinkedintegrations:write, plus owner or adminlist_unlinked_identities

Paths are relative to https://api.getnima.io. Every call is scoped to the workspace of the caller.

Which credentials can call these routes today. A signed-in session can call link-me for any member, and all three for an owner or admin. Among API keys, only a key that carries integrations:write reaches the two admin routes, and that scope comes only from the Slack command /nima mcp-key integrations. identities:write cannot be minted by anyone yet, so link-me and link_my_identity are not reachable with a key or an OAuth client. See Scopes and permissions.

Every link call names one external account with three fields. The same fields come back in the IdentityView response.

providerenumrequired

slack, jira, linear or notion. GitHub is not supported: GitHub mentions always render as plain names.

providerScopestringrequired

The installation the account lives in, 1 to 200 characters. Slack team id (T...), Jira cloud id, Linear organization id or Notion workspace id.

externalIdstringrequired

The account id inside that installation, 1 to 200 characters. Slack user id (U...), Atlassian account id, Linear user id or Notion user id.

POST/v1/identities/link
scopeintegrations:write or identities:writeMCP toollink_external_identity

An owner or admin links any external account to any member of the workspace. Use it when nima reports that an assignee or reporter is not linked, or to accept a pending claim that a member could not prove. The route answers 200 with the IdentityView. Linking the same account to the same member again is safe.

providerScopestringrequired
userIduuidrequired

The nima user who owns the account. The user must be a live member of the workspace.

An admin link has high assurance and linkedVia set to admin. If the account was held by another member, the link moves to the new member. The link is audited, with ids only.

Errors from linking an account

StatuserrorWhen
400VALIDATION_ERRORA field is missing or out of range, or userId is not a live member of this workspace (The user is not a member of this organization).
401TOKEN_INVALIDMissing, malformed, revoked or expired credential.
403INSUFFICIENT_PERMISSIONSThe key lacks integrations:write (a key holding only identities:write never carries the owner or admin permission this route checks), or the caller is not an owner or admin.
POST/v1/identities/link-me
scopeidentities:writeapp session onlyMCP toollink_my_identity

A member links their own external account to their own nima user. The caller is always the subject: there is no way to name another user. Any workspace member (owner, admin or member) can call it from a signed-in session. The route answers 200 with the IdentityView. What comes back depends on whether nima can prove the account is the caller's.

providerScopestringrequired
linkTokenstring

A signed link token for exactly this account and this caller, 1 to 2000 characters. nima does not issue link tokens through any flow today, so leave it out.

The self link is applied only when it is proven. It is proven when the account's email equals the caller's own nima email (case-insensitive), or when a valid linkToken is sent. A proven self link has low assurance and linkedVia set to self_link.

An unproven claim is recorded as pending instead: the response has userId set to null and linkedVia set to self_pending, and an admin decides with /v1/identities/link. The first member to claim an account keeps the claim. Repeating a link that already belongs to the caller returns the existing row unchanged.

Errors from linking your own account

StatuserrorWhen
400VALIDATION_ERRORA field is missing or out of range, or the caller is no longer a live member.
401TOKEN_INVALIDMissing, malformed, revoked or expired credential.
403INSUFFICIENT_PERMISSIONSThe credential lacks identities:write.
409CONFLICTAnother member already holds the account (That account is already linked to another member), or another live member already has a pending claim on it.

List unlinked external accounts

GET/v1/identities/unlinked
scopeintegrations:writeMCP toollist_unlinked_identities

The external accounts nima has seen that no workspace member holds, most recently updated first. These are accounts on events, such as Jira assignees and reporters, and accounts a member claimed without proof. Every row carries claimedBy, which is null when there is no pending claim. Send a row's provider, providerScope and externalId, with the userId of the member it belongs to (for a pending claim, claimedBy.userId), to /v1/identities/link to resolve one. An account still linked to a member who left the workspace is not listed; relink it with /v1/identities/link. Owner or admin only.

limitinteger

Maximum rows, 1 to 100. Defaults to 50.

The response is { "identities": IdentityView[] }. The list is not paginated.

Errors from listing unlinked accounts

StatuserrorWhen
400VALIDATION_ERRORlimit is not an integer from 1 to 100.
401TOKEN_INVALIDMissing, malformed, revoked or expired credential.
403INSUFFICIENT_PERMISSIONSThe key lacks integrations:write, or the caller is not an owner or admin.

The IdentityView object

IdentityView is what every identity route returns for one account. It holds ids and labels only, never an email address.

iduuid

The identity row id.

providerstring

slack, jira, linear or notion.

providerScopestring

The installation id.

externalIdstring

The account id in that installation.

userIduuid | null

The member who holds the account. null while it is unlinked or only claimed.

displayNamestring | null

The label nima has for the account, when it has one.

linkedViastring

How the row was made: admin (an admin link), self_link (a proven self link), self_pending (a claim waiting for an admin), email_match (nima matched the account's email to a member), slack_mapping (mirrored from the Slack user mapping) or observed (seen on an event, such as a Jira assignee, with no member yet).

assurancestring

high or low. See Link assurance.

claimedByobject | null

Present on every row from the unlinked route: { userId, name } of the live member with a pending claim on the account, or null when there is none. Absent on the link routes.

Assurance says how much nima trusts a link. high comes from an admin link or from the Slack user mapping. low comes from a proven self link or from an email match. A low link can receive nudges and can be tagged, but a message that tags a low account, or that a low-assurance asker triggered, always waits for approval. A low link never makes someone an approver.

  • The target user must be a live member: still in the workspace and active. Otherwise the call fails with 400.
  • One external account maps to at most one member, and one member holds at most one account per installation and provider. Linking a member to a new account in the same installation replaces the account they held there.
  • nima matches accounts to members by email on its own for Slack, Jira, Linear and Notion. There is no GitHub identity provider.
  • When nima looks for a member's account by email and the provider has none, it remembers the miss for 15 minutes before asking again. An account seen on an event with no matching member is kept as an unlinked row, which the unlinked list shows. nima re-checks it by email each time the account appears on a new event, and at most once every 15 minutes when it looks the account up.
  • Each link is written to the audit trail as identity_linked, with ids only.