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.
Identity link routes and MCP tools
| Method | Path | Scope | MCP tool |
|---|---|---|---|
POST | /v1/identities/link | integrations:write or identities:write, plus owner or admin | link_external_identity |
POST | /v1/identities/link-me | identities:write | link_my_identity |
GET | /v1/identities/unlinked | integrations:write, plus owner or admin | list_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.
Account fields shared by identity link calls
Every link call names one external account with three fields. The same fields
come back in the IdentityView response.
providerenumrequiredslack, jira, linear or notion. GitHub is not supported: GitHub
mentions always render as plain names.
providerScopestringrequiredThe installation the account lives in, 1 to 200 characters. Slack team id
(T...), Jira cloud id, Linear organization id or Notion workspace id.
externalIdstringrequiredThe account id inside that installation, 1 to 200 characters. Slack user id
(U...), Atlassian account id, Linear user id or Notion user id.
Link an external account to a member
/v1/identities/linkintegrations:write or identities:writeMCP toollink_external_identityAn 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.
providerenumrequiredproviderScopestringrequiredexternalIdstringrequireduserIduuidrequiredThe 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
| Status | error | When |
|---|---|---|
400 | VALIDATION_ERROR | A 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). |
401 | TOKEN_INVALID | Missing, malformed, revoked or expired credential. |
403 | INSUFFICIENT_PERMISSIONS | The 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. |
Link your own external account
/v1/identities/link-meidentities:writeapp session onlyMCP toollink_my_identityA 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.
providerenumrequiredproviderScopestringrequiredexternalIdstringrequiredlinkTokenstringA 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
| Status | error | When |
|---|---|---|
400 | VALIDATION_ERROR | A field is missing or out of range, or the caller is no longer a live member. |
401 | TOKEN_INVALID | Missing, malformed, revoked or expired credential. |
403 | INSUFFICIENT_PERMISSIONS | The credential lacks identities:write. |
409 | CONFLICT | Another 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
/v1/identities/unlinkedintegrations:writeMCP toollist_unlinked_identitiesThe 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.
limitintegerMaximum rows, 1 to 100. Defaults to 50.
The response is { "identities": IdentityView[] }. The list is not paginated.
Errors from listing unlinked accounts
| Status | error | When |
|---|---|---|
400 | VALIDATION_ERROR | limit is not an integer from 1 to 100. |
401 | TOKEN_INVALID | Missing, malformed, revoked or expired credential. |
403 | INSUFFICIENT_PERMISSIONS | The 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.
iduuidThe identity row id.
providerstringslack, jira, linear or notion.
providerScopestringThe installation id.
externalIdstringThe account id in that installation.
userIduuid | nullThe member who holds the account. null while it is unlinked or only
claimed.
displayNamestring | nullThe label nima has for the account, when it has one.
linkedViastringHow 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).
assurancestringhigh or low. See Link assurance.
claimedByobject | nullPresent 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.
Link assurance
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.
Rules that apply to every identity link
- 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.