People

The people list screen, and the REST API endpoints for managing people within your organization.

The people list

People in the sidebar opens the list of everyone in your organization, at /app/<your-org>/people. Each row shows:

ColumnWhat it holds
NameThe person's first and last name, next to their initials. Clicking it opens the person's details for editing.
Job titleTheir role, or — when it is not set.
CompanyThe company they are linked to. Clicking it opens that company's record page. Reads — for a person with no company.
EmailTheir email address.
PhoneTheir phone number, or — when it is not set.

A person has no page of their own — they open in a dialog, from this list and from a company's People tab alike. New person above the list creates one.

The dialog's Company field links the person to a company. Type to search your companies by name and pick one, choose No company to leave the person unlinked — an empty company is a normal record, not an incomplete one — or, when what you typed matches no existing company, choose Create "…" to create that company then and there and link the person to it. The new company is created with the name you typed and nothing else: it starts at the Lead lifecycle stage with the source Other, which you can change later on its record page. Opening the dialog from a company's People tab pre-fills this field with the company you came from.

Search the list with the box above it — it matches first name, last name and email. Narrow it with the Company filter, whose one option, No company, shows only the people who are not linked to any company. Sort by clicking the Name or Email header; the other three columns cannot be sorted.

Your search, filter, sort and page number all live in the address bar, so a filtered list is a link you can send to a colleague or bookmark.

Each row's ⋯ menu repeats Edit — the same dialog as the name — and adds Delete. Nothing blocks deleting a person; the confirmation is the only step.

Endpoints

All endpoints require a valid API key in the Authorization header. See Authentication for details.

Base URL: /api/v1

A person may be linked to a company through companyId, but the link is optional: a person with no company is a normal record, not an incomplete one. People carry no lifecycle stage — that belongs to the company alone.


List People

GET /api/v1/people

Query parameters:

ParameterTypeDefaultDescription
limitnumber25Number of results (1-100)
offsetnumber0Pagination offset
querystring—Search by first name, last name or email
sortBystring"createdAt"Sort field: firstName, lastName, email, createdAt, updatedAt
sortOrderstring"asc"Sort direction: asc or desc
companyIdstring—Comma-separated company UUIDs
hasCompanystring—true for people with a company, false for people without
createdAtstring—Comma-separated date ranges (e.g., today,this-week)

Date range values: today, this-week, this-month, older

These windows are cut at midnight UTC, not at midnight in any user's timezone — see Data Formats.

Omit hasCompany to get either; true and false are the only values it takes, and anything else is a 422. It combines with companyId rather than overriding it, so hasCompany=false alongside a companyId list is a contradiction and matches nobody.

query is split into words, and a person matches when every word appears in their first name, last name or email — in any order, case-insensitive — so Ada Lovelace and lovelace ada both find Ada Lovelace. A word that matches none of the three excludes the person; the company name is not searched. query takes up to 200 characters, and a longer one is a 422. Words past the eighth are ignored, and a query of only spaces is the same as none.

Returns { "data": [...], "total": number }.


Get Person

GET /api/v1/people/:id

Responds 400 when the ID is not a UUID, and 404 when no person with that ID exists in your organization.


Create Person

POST /api/v1/people
Content-Type: application/json
FieldTypeRequiredDescription
firstNamestringYesFirst name (1-100 characters)
lastNamestringYesLast name (1-100 characters)
emailstringYesEmail address, stored lowercase (up to 255 chars)
phonestringNoPhone number (up to 50 characters)
jobTitlestringNoJob title (up to 200 characters)
companyIdstringNoUUID of a company in your organization, or null

Returns 201 with { "data": ... }.

Responds 400 when the body is not valid JSON, 422 when a field fails validation, and 404 with { "error": "Company not found" } when companyId does not exist or belongs to another organization.


Update Person

PATCH /api/v1/people/:id
Content-Type: application/json

Body: same fields as Create (all optional). phone, jobTitle and companyId accept null to clear them.

Responds 400 for an invalid ID or a body that is not valid JSON, and 422 when a field fails validation. A 404 names the record that was missing: { "error": "Person not found" } or { "error": "Company not found" }.


Delete Person

DELETE /api/v1/people/:id

Returns { "success": true } on success. Responds 400 when the ID is not a UUID, and 404 when the person is not in your organization.


Response shape

{
  "id": "3f8a1c22-...",
  "organizationId": "9a2d...",
  "companyId": "0c1f5b8e-...",
  "firstName": "Ada",
  "lastName": "Lovelace",
  "email": "[email protected]",
  "phone": null,
  "jobTitle": "Head of Engineering",
  "createdAt": "2026-09-01T14:54:01.000Z",
  "updatedAt": "2026-09-01T14:54:01.000Z",
  "company": { "id": "0c1f5b8e-...", "name": "Acme Inc." }
}

companyId and company are both null for a person who is not linked to a company.

createdAt and updatedAt are ISO 8601 in UTC. The API is not localized, whatever language the app itself is showing you — see Data Formats.


Examples

cURL

# List people
curl https://your-app.com/api/v1/people \
  -H "Authorization: Bearer ba_a1b2c3d4e5f6..."

# List with filters
curl "https://your-app.com/api/v1/people?companyId=UUID_HERE&sortBy=lastName&sortOrder=asc&limit=10" \
  -H "Authorization: Bearer ba_a1b2c3d4e5f6..."

# List people with no company
curl "https://your-app.com/api/v1/people?hasCompany=false" \
  -H "Authorization: Bearer ba_a1b2c3d4e5f6..."

# Get a single person
curl https://your-app.com/api/v1/people/UUID_HERE \
  -H "Authorization: Bearer ba_a1b2c3d4e5f6..."

# Create a person
curl -X POST https://your-app.com/api/v1/people \
  -H "Authorization: Bearer ba_a1b2c3d4e5f6..." \
  -H "Content-Type: application/json" \
  -d '{"firstName":"Ada","lastName":"Lovelace","email":"[email protected]"}'

# Update a person
curl -X PATCH https://your-app.com/api/v1/people/UUID_HERE \
  -H "Authorization: Bearer ba_a1b2c3d4e5f6..." \
  -H "Content-Type: application/json" \
  -d '{"jobTitle":"CTO","companyId":null}'

# Delete a person
curl -X DELETE https://your-app.com/api/v1/people/UUID_HERE \
  -H "Authorization: Bearer ba_a1b2c3d4e5f6..."

JavaScript / TypeScript

const API_KEY = "ba_a1b2c3d4e5f6...";
const BASE_URL = "https://your-app.com/api/v1";

// List people
const response = await fetch(
  `${BASE_URL}/people?hasCompany=true&limit=10&sortOrder=desc`,
  { headers: { Authorization: `Bearer ${API_KEY}` } },
);
const { data, total } = await response.json();

// Create a person
const createRes = await fetch(`${BASE_URL}/people`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    firstName: "Ada",
    lastName: "Lovelace",
    email: "[email protected]",
    companyId: "0c1f5b8e-...",
  }),
});
const { data: newPerson } = await createRes.json();

Python

import requests

API_KEY = "ba_a1b2c3d4e5f6..."
BASE_URL = "https://your-app.com/api/v1"

# List people
response = requests.get(
    f"{BASE_URL}/people",
    headers={"Authorization": f"Bearer {API_KEY}"},
    params={"companyId": "UUID_HERE", "limit": 10, "sortOrder": "desc"},
)
data = response.json()

# Create a person
response = requests.post(
    f"{BASE_URL}/people",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={"firstName": "Ada", "lastName": "Lovelace", "email": "[email protected]"},
)
new_person = response.json()

On this page