Where
Settings→API & Integrations
Your role needs
Update access to Lead intake API
update-companies. Admin have it by default.Authenticated by a workspace API key, not by a signed-in session. Creating a key needs the same permission as the rest of the API settings tab.
The three endpoints
Every timestamp these three return is UTC ISO-8601 with microseconds:
2026-08-21T09:14:02.000000Z.
Status codes
GET /me
No scope is required for this one. Any key, whatever it’s scoped for, can call it. That makes it the fastest way to confirm a credential works before you build anything else on it, and the right endpoint to wire into your own monitoring as a health check.Response
rate_limit to keep it short. It’s the two integer fields in the table above. See Idempotency, deduplication and rate limits for what they’re currently set to.
GET /tags
Returns every tag in the workspace the key belongs to, ordered by name. There’s no pagination on this list: by design, since a workspace has tens of tags, not thousands, so there’s nothing here worth adding a cursor for. By default only tags withactive: true come back. Pass include_archived=true to also get the ones that have been archived.
Query parameters
Response
GET /leads/
Needs its ownleads:read scope, separate from leads:write, which only guards the two POST routes. It is not a default scope: tick it when you create the key, or the call is a 403 insufficient_scope.
{id} is either the numeric id from a create response or a URL-encoded email address (jane.doe%40acme.com). A LinkedIn profile URL or a phone number work too. It is resolved with the same precedence POST /leads deduplicates on (email, then LinkedIn, then phone, oldest match first), so the lead this returns for an address is exactly the one a POST with that address would have updated.
A lead outside the key’s workspace returns the exact same 404 as an id or email that doesn’t exist anywhere:
404 Not Found
404 the signal an integration wants: this person is not in the workspace yet, so POST /leads will create rather than update them.
Response
The body is{ data }, with no meta: there’s nothing to report about an action, since nothing changed. data is the same lead shape POST /leads returns in its own data field, plus two blocks the POST response does not carry: outreach and campaigns. Every relation is loaded on every call (emails, phones, links, location, tags, and the company’s own links and tags), so none of these fields is ever left out here for lacking an eager load.
This is deliberately not the shape the app’s own screens use internally: no admin-triage columns, CRM bookkeeping, possibility scores or phone-reveal state, and contacts come back as plain string arrays (
"emails": ["jane@…"]) instead of objects. So an integration reads lead.emails[0] directly.company, when present:
outreach, which covers email only, since email is what this API feeds:
replied uses the same rule the app’s own dashboard and reply detection use: an out-of-office never counts as a reply, and a reply the classifier hasn’t looked at yet does. If this endpoint says replied: true, the campaign has stopped following up with that person.campaigns:
Related
API overview
Authentication, scopes and what counts as a stable contract.
Lead fields reference
Every field POST /leads accepts, grouped and described one by one.
Status vocabularies
Every value
stage, source and status can hold, and what each renders as.