Lead context and notes
Access lead context through REST and conversation label history through MCP.
# Lead context and notes
Use the conversation's `threadId` to read its campaign contacts, including
custom variables, LinkedIn URLs, and known recipient provider and security
gateway. Each enrollment appears separately; campaign fields take precedence
over shared lead fields. Use the returned `leadId` for notes and emails.
Conversations without a linked campaign contact return an empty contact list.
| REST operation | Required permission |
| --- | --- |
| `GET /v1/unibox/threads/{threadId}/contacts` | `unibox:read`, `lead:read` |
| `GET /v1/workspaces/{workspaceId}/unibox/threads/{threadId}/label-history` | `unibox:read` |
| `GET /v1/leads/{leadId}/notes` | `lead:read` |
| `POST /v1/leads/{leadId}/notes` | `lead:update` |
| `DELETE /v1/leads/{leadId}/notes/{noteId}` | `lead:update` |
| `POST /v1/leads/{leadId}/emails` | `lead:update` |
Notes belong to the shared lead and are internal plain text. Create one with
`{"body":"Requested a follow-up next week."}` (1–20,000 characters after
trimming); notes are never sent to the lead. API-key-created notes have no human
author attribution. Deleting a note requires its owning lead ID.
Add an associated email with `{"email":"alternate@example.com"}`. This preserves
the existing primary address. Repeating an address is a no-op and does not
reactivate an address marked bad. An address belonging to another lead in the
workspace returns a conflict. Active associated emails are eligible for the
campaign email waterfall.
Notes return `items` and `nextCursor`, newest first, with up to 50 entries.
See the [API reference](/rest-api/reference) for query parameter schemas.
## Conversation label history
For MCP-only clients (including Composio), first call `list_unibox_threads`:
```json
{
"name": "list_unibox_threads",
"arguments": {
"workspaceId": "11111111-1111-4111-8111-111111111111",
"folder": "inbox",
"search": "lead@example.com",
"showAllEmails": true,
"limit": 20
}
}
```
Search is optional. The list defaults to the inbox and 20 threads per page;
`limit` accepts 1–100. Use another `folder` for archived, sent, starred, trash,
or warmup conversations. Pass the list's opaque `nextCursor` unchanged as
`cursor` to continue browsing.
`showAllEmails` is optional and defaults to `false`, limiting the inbox to managed
conversations. Set it to `true`, as in the example, to include other inbound inbox
mail, such as manually labeled conversations with no managed-send evidence.
Other folders retain their usual rules. Workspace permissions, search, and
pagination still apply. This option affects discovery, not stored history.
Select an item and pass its `id` (local UUID) as `threadId`, and its
`organizationId` (owning Workspace UUID) as `workspaceId`, to the history tool.
The illustrative UUID below must be replaced with that returned `id`;
`providerThreadId` is not a valid substitute.
```json
{
"name": "list_thread_label_history",
"arguments": {
"workspaceId": "11111111-1111-4111-8111-111111111111",
"threadId": "22222222-2222-4222-8222-222222222222",
"limit": 50
}
}
```
The tool returns `{ "items": [...], "nextCursor": "..." }`. Each item contains
`id`, `threadId`, `labelId`, `labelType`, `labelName`, `hexColor`, `action`,
`source`, `actorUserId`, `actorName`, and `occurredAt`. Actor fields can be null.
Pass the opaque `nextCursor` unchanged as `arguments.cursor`; null means no
more events. The default page size is 50; `limit` accepts 1–100.
A Workspace/thread mismatch is rejected even if you can access both Workspaces.
REST clients can discover the same IDs with
`GET /v1/workspaces/{workspaceId}/unibox/threads`. The history route is
`GET /v1/workspaces/{workspaceId}/unibox/threads/{threadId}/label-history`. For example:
```sh
curl --get 'https://api.schedulerzero.com/v1/workspaces/11111111-1111-4111-8111-111111111111/unibox/threads/22222222-2222-4222-8222-222222222222/label-history' \
--header 'x-api-key: YOUR_API_KEY' \
--data-urlencode 'limit=50'
```
REST and MCP return the same flat items and opaque `nextCursor`; pass it
unchanged as REST's `cursor` query parameter or MCP's `arguments.cursor`.
There is no MCP response wrapper or cursor conversion. The required Workspace
path and local thread UUID are checked by the existing authorized API handler.
The older `/v1/unibox/threads/...` route and its object cursor are not mounted
by the production Effect API and must not be used for this tool.
These are **conversation/thread reply labels**, and several labels can coexist.
Each event records an **added** or **removed** label, with its name and color
snapshotted at the time, source, timestamp, and human actor when available.
They are not an atomic single-label `from`/`to` record or a single-valued lead
status. A removal of A and addition of B remain two events; other labels may
still apply. Tracking has no pre-tracking backfill, so a complete historical
label set cannot be reconstructed reliably. Renaming or deleting a label does
not rewrite its stored name/color; actor names reflect the current user record.