Skip to content

Permissions & Search API

This page covers two related resources:

  • /api/v1/permissions reads who can do what in your organisation and manages project team membership, with a summary of the advanced permission-administration endpoints.
  • /api/v1/search finds people by meaning rather than exact keywords, using semantic search over staff profiles.

Authentication: every endpoint requires an API key. See API Keys & Authentication.

All permissions endpoints take your organisation’s ID as the first path segment. It must be the organisation your key is bound to; other organisations return 403.

Runnit’s built-in roles, from least to most access, are freelancer, member, manager, admin, and owner. Organisations can also define custom roles that adjust what a base role can do.

List every active member of the organisation with their role, profile details, client access summary, and whether they can update project status.

Managers, admins, and owners can call this.

Example request

Terminal window
curl https://api.runnit.io/api/v1/permissions/<org-id>/members \
-H 'Authorization: Bearer rnk_your_key'

Response

{
"success": true,
"members": [
{
"id": "a6c840eb-...",
"userId": "213ae491-...",
"organizationId": "ddf75d91-...",
"role": "owner",
"isPrimary": true,
"isFreelancer": false,
"hourlyRate": 289.33,
"currency": "AUD",
"joinedAt": "2026-05-29T20:50:45.017Z",
"isActive": true,
"user": { "id": "213ae491-...", "email": "mark@example.com", "firstName": "Mark", "lastName": "Tolson", "displayName": "Mark Tolson" },
"hasAllClientAccess": true,
"accessibleClientCount": null,
"canUpdateProjectStatus": true
}
]
}

hasAllClientAccess is true when the member is not restricted to specific clients; otherwise accessibleClientCount says how many clients they can see.

Errors

  • 403 if your role is below manager.

GET /api/v1/permissions/:orgId/users/:userId/access

Section titled “GET /api/v1/permissions/:orgId/users/:userId/access”

Get one member’s complete access picture: role, effective capability list with where each capability came from, client assignments, and project memberships.

Managers, admins, and owners can call this.

Path parameters

NameTypeRequiredDescription
orgIdUUIDYesYour organisation.
userIdUUIDYesThe member to inspect.

Example request

Terminal window
curl https://api.runnit.io/api/v1/permissions/<org-id>/users/<user-id>/access \
-H 'Authorization: Bearer rnk_your_key'

Response

{
"success": true,
"user": {
"userId": "213ae491-...",
"role": "member",
"customRoleId": null,
"isActive": true,
"capabilities": ["project:view", "task:view", "..."],
"capabilityProvenance": { "project:view": ["role"] },
"permissions": { "canUpdateProjectStatus": true },
"hasAllClientAccess": false,
"clientAssignments": [ { "clientOrganizationId": "b2c3d4e5-...", "clientName": "Northwind", "clientSlug": "northwind" } ],
"projects": [ { "id": "1f0e9a52-...", "name": "Winter Launch", "status": "active", "clientName": "Northwind" } ]
}
}

capabilities lists the member’s effective permission identifiers, and capabilityProvenance records whether each one came from their role, a custom role, or an individual grant.

Errors

  • 403 if your role is below manager.
  • 404 if the user is not a member of the organisation.

GET /api/v1/permissions/:orgId/me/capabilities

Section titled “GET /api/v1/permissions/:orgId/me/capabilities”

Get your own role and effective capability list. Useful for deciding which actions your integration should offer before attempting them.

Any organisation member can call this.

Example request

Terminal window
curl https://api.runnit.io/api/v1/permissions/<org-id>/me/capabilities \
-H 'Authorization: Bearer rnk_your_key'

Response

{ "success": true, "role": "manager", "customRoleId": null, "capabilities": ["project:view", "project:create", "..."] }

GET /api/v1/permissions/:orgId/role-matrix

Section titled “GET /api/v1/permissions/:orgId/role-matrix”

Get the built-in role-to-capability matrix: which capabilities each of the five built-in roles includes.

Any organisation member can call this.

Example request

Terminal window
curl https://api.runnit.io/api/v1/permissions/<org-id>/role-matrix \
-H 'Authorization: Bearer rnk_your_key'

Response

{
"success": true,
"roles": ["freelancer", "member", "manager", "admin", "owner"],
"capabilities": ["project:view", "project:create", "..."],
"matrix": { "member": ["project:view", "task:view", "..."] }
}

List the organisation’s projects (up to 200) with access information: member count, owner, and whether the project’s client restricts who can see it.

Managers, admins, and owners can call this.

Example request

Terminal window
curl https://api.runnit.io/api/v1/permissions/<org-id>/projects \
-H 'Authorization: Bearer rnk_your_key'

Response

{
"success": true,
"projects": [
{
"id": "1f0e9a52-...",
"name": "Winter Launch",
"status": "active",
"clientOrganizationId": "b2c3d4e5-...",
"clientName": "Northwind",
"memberCount": 4,
"clientRestricted": false,
"ownerId": "213ae491-..."
}
]
}

Errors

  • 403 if your role is below manager.

GET /api/v1/permissions/:orgId/projects/:projectId/members

Section titled “GET /api/v1/permissions/:orgId/projects/:projectId/members”

List a project’s team members with their user details, project role title, rates, and allocations.

Any organisation member can call this.

Path parameters

NameTypeRequiredDescription
orgIdUUIDYesYour organisation.
projectIdUUIDYesProject to inspect.

Example request

Terminal window
curl https://api.runnit.io/api/v1/permissions/<org-id>/projects/<project-id>/members \
-H 'Authorization: Bearer rnk_your_key'

Response

{
"success": true,
"members": [
{
"id": "e2f4a6b8-...",
"projectId": "1f0e9a52-...",
"userId": "d3a6f0c1-...",
"isAdmin": false,
"roleTitle": "Copywriter",
"hourlyRate": 140,
"currency": "AUD",
"rateCardRoleId": "f7a1c3e5-...",
"billableRateSnapshot": 180,
"billableCurrencySnapshot": "AUD",
"allocatedHours": 40,
"maxHoursPerWeek": 20,
"joinedAt": "2026-07-01T00:00:00.000Z",
"user": { "id": "d3a6f0c1-...", "email": "alex@example.com", "firstName": "Alex", "lastName": "Chen", "displayName": "Alex Chen" }
}
]
}

The rate and allocation fields are absent when they were never set for the member.

POST /api/v1/permissions/:orgId/projects/:projectId/members

Section titled “POST /api/v1/permissions/:orgId/projects/:projectId/members”

Add a member to a project’s team, optionally with a role title, rates, and hour allocations.

Managers, admins, and owners can call this.

Request body

NameTypeRequiredDescription
userIdUUIDYesUser to add.
isAdminbooleanNoMake the member a project admin. Defaults to false.
roleTitlestringNoRole on this project, up to 120 characters.
hourlyRatenumberNoInternal hourly rate, 0 or more.
currencystringNoThree-letter currency code, e.g. AUD.
rateCardRoleIdUUIDNoRate card role that drives the billable rate.
billableRateSnapshotnumberNoBillable rate captured for this project, 0 or more.
billableCurrencySnapshotstringNoThree-letter currency code for the billable rate.
allocatedHoursnumberNoTotal hours allocated on this project, 0 or more.
maxHoursPerWeeknumberNoWeekly cap for this member on this project, 0 or more.

Example request

Terminal window
curl -X POST https://api.runnit.io/api/v1/permissions/<org-id>/projects/<project-id>/members \
-H 'Authorization: Bearer rnk_your_key' \
-H 'Content-Type: application/json' \
-d '{ "userId": "<user-id>", "roleTitle": "Copywriter", "allocatedHours": 40 }'

Response

{ "success": true, "member": { "projectId": "1f0e9a52-...", "userId": "d3a6f0c1-...", "roleTitle": "Copywriter" } }

The addition is also recorded in the project’s history feed.

Errors

  • 400 if userId is missing or a field fails validation (negative rates or hours, role title over 120 characters, currency not 3 letters).
  • 403 if your role is below manager.

PATCH /api/v1/permissions/:orgId/projects/:projectId/members/:userId

Section titled “PATCH /api/v1/permissions/:orgId/projects/:projectId/members/:userId”

Update a project member’s assignment. Send only the fields you want to change; the fields and constraints match the add endpoint (everything except userId, which moves into the path).

Managers, admins, and owners can call this.

Example request

Terminal window
curl -X PATCH https://api.runnit.io/api/v1/permissions/<org-id>/projects/<project-id>/members/<user-id> \
-H 'Authorization: Bearer rnk_your_key' \
-H 'Content-Type: application/json' \
-d '{ "roleTitle": "Senior Copywriter", "maxHoursPerWeek": 25 }'

Response

{ "success": true, "member": { "userId": "d3a6f0c1-...", "roleTitle": "Senior Copywriter", "maxHoursPerWeek": 25 } }

Errors

  • 400 if a field fails validation.
  • 403 if your role is below manager.

DELETE /api/v1/permissions/:orgId/projects/:projectId/members/:userId

Section titled “DELETE /api/v1/permissions/:orgId/projects/:projectId/members/:userId”

Remove a member from a project’s team. This does not remove them from the organisation.

Managers, admins, and owners can call this.

Example request

Terminal window
curl -X DELETE https://api.runnit.io/api/v1/permissions/<org-id>/projects/<project-id>/members/<user-id> \
-H 'Authorization: Bearer rnk_your_key'

Response

{ "success": true, "message": "Member removed from project" }

Errors

  • 403 if your role is below manager.

The remaining permissions endpoints administer roles and access rules. They mirror the Admin area in the app; most integrations only need the read endpoints above. All of them follow the same { "success": true, ... } envelope and the organisation binding described at the top of this page.

Method and pathWhat it doesWho can call it
PATCH /:orgId/members/:userId/roleChange a member’s built-in role (body: role). Assigning admin or owner requires the owner role. You cannot change your own role unless you are the owner.Admins and owners
PATCH /:orgId/members/:userId/project-status-permissionAllow or block a member from updating project status (body: canUpdateProjectStatus, boolean).Admins and owners
GET /:orgId/capability-catalogCapability metadata (labels, groups, descriptions) plus the role matrix, for building admin UI.Any member
GET /:orgId/custom-rolesList the organisation’s custom roles.Custom-role managers
POST /:orgId/custom-rolesCreate a custom role (body: key, name, baseRole, optional description, addedCapabilities, removedCapabilities). Returns 201.Custom-role managers
PATCH /:orgId/custom-roles/:roleIdUpdate a custom role’s name, base role, description, or capability adjustments.Custom-role managers
DELETE /:orgId/custom-roles/:roleIdDelete a custom role.Custom-role managers
GET /:orgId/role-presetsList the ready-made custom role presets.Custom-role managers
POST /:orgId/role-presets/installInstall the system presets as custom roles.Custom-role managers
POST /:orgId/members/:userId/custom-roleAssign a custom role to a member (body: customRoleId).Role managers
GET /:orgId/members/:userId/grantsList a member’s individual capability grants.Grant managers
POST /:orgId/members/:userId/grantsGrant or deny one capability for a member (body: capability, optional effect of allow or deny, scopeType, scopeId, reason, expiresAt). Returns 201.Grant managers
DELETE /:orgId/grants/:grantIdRevoke a capability grant.Grant managers
GET /:orgId/audit-logPermission change history, filterable by targetUserId, action, decision, with limit (up to 500) and offset.Audit viewers
GET /:orgId/settings and PATCH /:orgId/settingsRead or update organisation-wide permission settings, including the enforcement mode.Settings managers

The “who can call it” labels reflect capabilities that admins and owners hold by default and that can be granted to others through custom roles or grants.

Search staff profiles with a natural-language query. Results are ranked by semantic similarity, so “someone who can lead a rebrand” matches profiles that never use those exact words.

Any organisation member can call this. Results only include people in the organisation you search.

Query parameters

NameTypeRequiredDescription
qstringYesThe search query, in plain language.
organizationIdUUIDNoOrganisation to search. Defaults to your key’s organisation. Must be an organisation you belong to.
limitintegerNo1 to 50. Defaults to 10.
thresholdnumberNoMinimum similarity between 0 and 1. Defaults to 0.5. Lower it for broader matches.

Example request

Terminal window
curl "https://api.runnit.io/api/v1/search/users?q=creative%20director%20with%20campaign%20experience&limit=5" \
-H 'Authorization: Bearer rnk_your_key'

Response

{
"query": "creative director with campaign experience",
"count": 1,
"threshold": 0.5,
"organizationId": "ddf75d91-...",
"results": [
{
"id": "213ae491-...",
"email": "mark@example.com",
"displayName": "Mark Tolson",
"currentTitle": "Chief Creative Officer",
"skills": ["Creative Direction", "Campaign Leadership"],
"shortBio": "Chief Creative Officer with 21 years in agency delivery.",
"similarity": 0.82
}
]
}

Each result is a full staff profile plus a similarity score between 0 and 1. Profiles that have not been indexed yet do not appear.

Errors

  • 400 if q is missing, or limit or threshold is out of range.
  • 403 if you request an organisation you do not belong to.

Find people with specific skills. The skills you list are expanded into an expertise-focused semantic query with a broader match threshold than the general search.

Any organisation member can call this.

Query parameters

NameTypeRequiredDescription
skillsstringYesSkills to look for, e.g. motion design, After Effects.
organizationIdUUIDNoOrganisation to search. Defaults to your key’s organisation.
limitintegerNo1 to 50. Defaults to 10.

Example request

Terminal window
curl "https://api.runnit.io/api/v1/search/users/expertise?skills=motion%20design" \
-H 'Authorization: Bearer rnk_your_key'

Response

{ "query": "motion design", "searchType": "expertise", "count": 2, "organizationId": "ddf75d91-...", "results": [] }

results has the same profile-plus-similarity shape as the general user search.

Errors

  • 400 if skills is missing.
  • 403 if you request an organisation you do not belong to.

Find people who have worked on similar projects, optionally narrowed by client or technology.

Any organisation member can call this.

Query parameters

NameTypeRequiredDescription
projectTypestringYesThe kind of project, e.g. brand campaign.
clientstringNoSimilar client context.
technologiesstringNoTools or technologies used.
organizationIdUUIDNoOrganisation to search. Defaults to your key’s organisation.
limitintegerNo1 to 50. Defaults to 10.

Example request

Terminal window
curl "https://api.runnit.io/api/v1/search/users/projects?projectType=brand%20campaign&technologies=Figma" \
-H 'Authorization: Bearer rnk_your_key'

Response

{ "projectType": "brand campaign", "client": null, "technologies": "Figma", "count": 3, "organizationId": "ddf75d91-...", "results": [] }

Errors

  • 400 if projectType is missing.
  • 403 if you request an organisation you do not belong to.

Find people whose profiles are similar to a given person, for example to build a team around a proven profile or find cover for someone unavailable. The comparison uses the person’s title, skills, and bio; the person themselves is excluded from the results.

Any organisation member can call this for people who share an organisation with them.

Path parameters

NameTypeRequiredDescription
userIdUUIDYesThe person to match against.

Query parameters

NameTypeRequiredDescription
limitintegerNo1 to 20. Defaults to 5.

Example request

Terminal window
curl "https://api.runnit.io/api/v1/search/users/<user-id>/similar?limit=3" \
-H 'Authorization: Bearer rnk_your_key'

Response

{ "userId": "213ae491-...", "count": 1, "results": [ { "id": "d3a6f0c1-...", "displayName": "Alex Chen", "similarity": 0.71 } ] }

If the person’s profile has no title, skills, or bio to compare, the endpoint returns an empty result list.

Errors

  • 403 if you do not share an organisation with the person.
  • 404 if the user does not exist.

Manage organisation membership itself (invites, removals, and rates) through the Organisations API, or review report access with the Reports API.