Skip to content

Staff Profiles & Work History API

The users endpoints live under /api/v1/users and cover individual staff profiles: personal details, portfolio, preferences, work history, organisation role, and client assignments.

Authentication: every request needs a per-user API key. See API Keys & Authentication.

Most endpoints here follow one permission pattern: you can always act on your own profile, and organisation admins and owners can act on the profiles of people in their organisation. Where an endpoint differs, its section says so.

Returns a user’s full profile. You can fetch your own profile; owners, admins, and managers can also fetch the profile of anyone who shares an organisation with them.

Path parameters

NameTypeRequiredDescription
idUUIDYesThe user’s id.

Example request

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

Response is the user object (with credentials removed). The main fields:

{
"id": "<user-uuid>",
"email": "priya@example.com",
"firstName": "Priya",
"lastName": "Shah",
"displayName": "Priya Shah",
"avatarUrl": null,
"phone": "+61 400 000 000",
"shortBio": "Producer with a broadcast background.",
"longBio": "...",
"yearsInIndustry": 9,
"yearsInCurrentRole": 3,
"currentTitle": "Senior Producer",
"portfolioUrl": "https://priya.example.com",
"skills": ["production", "editing"],
"preferredWorkTypes": ["campaigns"],
"acceptingProjects": true,
"preferences": { "...": "..." },
"hourlyRate": 160,
"actualCostRate": 95,
"defaultRateCardRoleId": "<rate-card-role-uuid>",
"status": "active",
"lastLoginAt": "2026-07-06T23:41:12.000Z",
"createdAt": "2024-11-20T22:14:00.000Z"
}

Errors

StatusWhen
403You are not the user and you do not hold an owner, admin, or manager role in an organisation the user belongs to.
404No user exists with that id.

Updates a user’s core profile fields. You can update your own profile; organisation admins and owners can update anyone who shares an organisation with them. Managers cannot edit other people through this endpoint.

Request body (all optional)

NameTypeRequiredDescription
emailstringNoA valid email address. Must not be in use by another account.
firstNamestringNoCannot be empty when supplied.
lastNamestringNoCannot be empty when supplied.
displayNamestringNoPreferred display name.
phonestringNoPhone number.
currentTitlestringNoJob title.
acceptingProjectsbooleanNoWhether the person is open to new project assignments.
statusstringNoOne of active, archived, or disabled.
preferencesobjectNoReplaces the user’s preferences object. Use the preferences endpoint below if you want merge behaviour.

Example request

Terminal window
curl -X PATCH https://api.runnit.io/api/v1/users/<user-id> \
-H 'Authorization: Bearer rnk_your_key' \
-H 'Content-Type: application/json' \
-d '{ "currentTitle": "Executive Producer", "acceptingProjects": false }'

Response is the full updated user object, in the same shape as GET /api/v1/users/:id.

Errors

StatusWhen
400A supplied field fails validation.
403You are not the user and not an admin or owner of a shared organisation.
404No user exists with that id.
409The email address is already in use.

Updates the portfolio section of a profile. Same permissions as PATCH /api/v1/users/:id: yourself, or admins and owners of a shared organisation.

Request body (all optional)

NameTypeRequiredDescription
shortBiostringNoShort biography.
longBiostringNoLong-form biography.
yearsInIndustrynumberNoBetween 0 and 50.
yearsInCurrentRolenumberNoBetween 0 and 50.
currentTitlestringNoJob title.
portfolioUrlstringNoMust start with http:// or https://. An empty string clears it.
skillsarray of stringsNoReplaces the skills list. An empty array clears it.
preferredWorkTypesarray of stringsNoReplaces the preferred work types. An empty array clears it.

Example request

Terminal window
curl -X PATCH https://api.runnit.io/api/v1/users/<user-id>/portfolio \
-H 'Authorization: Bearer rnk_your_key' \
-H 'Content-Type: application/json' \
-d '{ "shortBio": "Producer with a broadcast background.", "skills": ["production", "editing"] }'

Response returns the updated portfolio fields:

{
"id": "<user-uuid>",
"shortBio": "Producer with a broadcast background.",
"longBio": null,
"yearsInIndustry": 9,
"yearsInCurrentRole": 3,
"currentTitle": "Senior Producer",
"portfolioUrl": "https://priya.example.com",
"skills": ["production", "editing"],
"preferredWorkTypes": ["campaigns"]
}

If the body contains no recognised fields, the response is { "message": "No updates provided" } and nothing changes.

Errors

StatusWhen
400A field fails validation, for example yearsInIndustry outside 0 to 50.
403You are not the user and not an admin or owner of a shared organisation.
404No user exists with that id.

Updates your preferences. This endpoint is self-only: even admins cannot change another person’s preferences. The supplied object is merged into the existing preferences at the top level, so keys you omit are kept.

Request body

NameTypeRequiredDescription
preferencesobjectYesPreference keys to set or overwrite.

Example request

Terminal window
curl -X PATCH https://api.runnit.io/api/v1/users/<your-user-id>/preferences \
-H 'Authorization: Bearer rnk_your_key' \
-H 'Content-Type: application/json' \
-d '{ "preferences": { "timezone": "Australia/Melbourne" } }'

Response is the full merged preferences object.

Errors

StatusWhen
400preferences is missing or not an object.
403The id is not your own user id.

Changes a user’s role in an organisation. The caller must be an admin or owner of that organisation, with two extra rules: only owners can assign the owner role, and only owners can change another owner’s role.

Request body

NameTypeRequiredDescription
organizationIdUUIDYesThe organisation to change the role in. With an API key this must be the key’s organisation.
rolestringYesOne of member, manager, admin, or owner. The freelancer role cannot be assigned here.

Example request

Terminal window
curl -X PATCH https://api.runnit.io/api/v1/users/<user-id>/organization-role \
-H 'Authorization: Bearer rnk_your_key' \
-H 'Content-Type: application/json' \
-d '{ "organizationId": "<org-id>", "role": "manager" }'

Response

{
"message": "User role updated successfully",
"userId": "<user-uuid>",
"organizationId": "<org-uuid>",
"newRole": "manager"
}

Errors

StatusWhen
400organizationId is not a UUID, or role is not one of the four allowed values.
403You are not an active member of the organisation, you are not an admin or owner, you tried to assign owner without being an owner, or you tried to change an owner’s role without being an owner.
404The target user is not an active member of the organisation.

Work history entries (also called portfolio projects) describe past projects a person has worked on. They come from two sources: entries added through this API are always manual, and Runnit also creates entries automatically when delivery projects complete. Editing an automatic entry through the API converts it to manual, which stops the automatic sync from overwriting your change.

All five work history endpoints use the same permissions: yourself, or admins and owners of a shared organisation.

Lists a user’s work history entries.

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

Response is a JSON array:

[
{
"id": "<entry-uuid>",
"userId": "<user-uuid>",
"clientName": "Harbour Retail Group",
"projectName": "Winter Launch",
"briefSummary": "Campaign delivery across social and retail.",
"startDate": "2025-06-01",
"endDate": "2025-08-31",
"durationMonths": 3,
"projectRole": "Producer",
"technologies": ["premiere"],
"deliverables": ["30s hero film"],
"teamSize": 6,
"projectUrl": null,
"status": "completed",
"isFeatured": false,
"displayOrder": 0,
"source": "auto",
"sourceProjectId": "<project-uuid>"
}
]

source is manual or auto; sourceProjectId links an automatic entry to the delivery project it came from.

Adds a work history entry. Entries created here are always stored as manual.

Request body

NameTypeRequiredDescription
clientNamestringYesWho the work was for.
projectNamestringYesThe project’s name.
briefSummarystringYesShort description of the work.
startDatestringYesISO 8601 date, for example 2025-06-01.
endDatestringNoISO 8601 date.
projectRolestringYesThe person’s role on the project.
durationMonthsintegerNo0 or higher.
durationDaysintegerNo0 or higher.
teamSizeintegerNo1 or higher.
projectUrlstringNoMust be a valid URL.
technologiesarray of stringsNoTools and technologies used.
deliverablesarray of stringsNoWhat was delivered.

Example request

Terminal window
curl -X POST https://api.runnit.io/api/v1/users/<user-id>/projects \
-H 'Authorization: Bearer rnk_your_key' \
-H 'Content-Type: application/json' \
-d '{
"clientName": "Harbour Retail Group",
"projectName": "Winter Launch",
"briefSummary": "Campaign delivery across social and retail.",
"startDate": "2025-06-01",
"endDate": "2025-08-31",
"projectRole": "Producer"
}'

Response is 201 with the created entry, in the same shape as the list endpoint.

Errors

StatusWhen
400A required field is missing, a date is not ISO 8601, or a numeric field is out of range.
403You are not the user and not an admin or owner of a shared organisation.

PATCH /api/v1/users/:id/projects/:projectId

Section titled “PATCH /api/v1/users/:id/projects/:projectId”

Updates a work history entry. Accepts the same fields as creation, all optional, with the same constraints. Editing marks the entry as manual, so the automatic sync stops updating it.

Terminal window
curl -X PATCH https://api.runnit.io/api/v1/users/<user-id>/projects/<entry-id> \
-H 'Authorization: Bearer rnk_your_key' \
-H 'Content-Type: application/json' \
-d '{ "teamSize": 8 }'

Response is the updated entry. Returns 404 if the entry does not belong to the user.

DELETE /api/v1/users/:id/projects/:projectId

Section titled “DELETE /api/v1/users/:id/projects/:projectId”

Deletes a work history entry. Returns 204 No Content, or 404 if the entry does not belong to the user.

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

Sets the display order of a user’s work history entries.

Request body

NameTypeRequiredDescription
projectOrdersarrayYesOne object per entry: id (UUID of the entry) and order (integer, 0 or higher).

Example request

Terminal window
curl -X POST https://api.runnit.io/api/v1/users/<user-id>/projects/reorder \
-H 'Authorization: Bearer rnk_your_key' \
-H 'Content-Type: application/json' \
-d '{ "projectOrders": [ { "id": "<entry-id-1>", "order": 0 }, { "id": "<entry-id-2>", "order": 1 } ] }'

Response

{ "message": "Projects reordered successfully" }

These endpoints manage which clients a person is restricted to, within the organisation the API key is bound to. They pair with the client-side view in the Clients API.

Returns the clients this user is explicitly assigned to. You can view your own assignments; owners, admins, and managers can view anyone’s in the organisation.

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

Response

{
"hasSpecificAssignments": true,
"assignedClients": [
{ "id": "<client-org-uuid>", "name": "Harbour Retail Group", "slug": "harbour-retail" }
]
}

When hasSpecificAssignments is false, the person can work on every client that has no team restrictions.

Errors

StatusWhen
403You are not an active member of the organisation, or you are viewing someone else without an owner, admin, or manager role.

Replaces the user’s client assignments. Only organisation admins and owners can call it.

Request body

NameTypeRequiredDescription
clientIdsarray of UUIDsYesClient organisation ids the user is restricted to. An empty array gives the user all-client access.

Example request

Terminal window
curl -X PUT https://api.runnit.io/api/v1/users/<user-id>/clients \
-H 'Authorization: Bearer rnk_your_key' \
-H 'Content-Type: application/json' \
-d '{ "clientIds": ["<client-org-id>"] }'

Response

{
"success": true,
"hasAllClientAccess": false,
"clients": [
{ "id": "<client-org-uuid>", "name": "Harbour Retail Group", "slug": "harbour-retail" }
]
}

Errors

StatusWhen
400clientIds is missing, not an array, or contains a value that is not a UUID.
403You are not an admin or owner of the organisation.

DELETE /api/v1/users/:id exists but is designed for the Runnit app: it soft deletes your own account and requires your password in the request body. Avatar upload endpoints are also reserved for the app. None of these are recommended for integrations.

Manage memberships, roles, and rates at the organisation level with the Organisations & Staff API.