The Deal object
The following fields are accepted on write via POST /api/v1/deals.
| Field | Type | Notes |
|---|---|---|
id | string | CUID, assigned on create (read-only) |
name | string (required) | Max 200 characters |
value | number | Nonnegative; defaults to 0 if omitted on create |
stage | enum | NEW (default) · QUALIFIED · PROPOSAL · NEGOTIATION · WON · LOST |
stageId | string | Write only. A pipeline stage id from GET /api/v1/pipelines. Moves the deal onto that stage and its pipeline. Send stage or stageId, not both |
expectedCloseDate | string (ISO 8601 date) | null | When the deal is expected to close |
notes | string | null | Max 10,000 characters |
externalId | string | null | Your system's ID — upsert key and dedupe handle (max 200 chars) |
contactId | string | null | Link to an existing contact by its agentlyleads record ID |
companyId | string | null | Link to an existing company by its agentlyleads record ID |
offeringId | string | null | Link to an existing offering/product by its agentlyleads record ID |
campaignId | string | null | The campaign this deal came out of, by its agentlyleads campaign ID. Must belong to the workspace; null unlinks |
contactExternalId | string | null | Resolve the linked contact by its externalId instead of contactId (max 200 chars) |
companyExternalId | string | null | Resolve the linked company by its externalId instead of companyId (max 200 chars) |
offeringExternalId | string | null | Resolve the linked offering by its externalId instead of offeringId (max 200 chars) |
createdAt | string (ISO 8601) | Assigned on create (read-only) |
updatedAt | string (ISO 8601) | Updated on every write (read-only) |
Example object
{
"id": "cmq1abc2def3ghi4jkl5",
"name": "Acme Corp — Annual Contract",
"value": 12000,
"stage": "QUALIFIED",
"expectedCloseDate": "2026-09-30",
"notes": null,
"externalId": "hs_deal_789",
"contactId": null,
"companyId": null,
"offeringId": null,
"campaign": null,
"createdAt": "2025-06-01T12:00:00.000Z",
"updatedAt": "2025-06-01T12:00:00.000Z"
}Notes on specific fields
name is the only required field. All other fields are optional on write.
value defaults to 0 when omitted on create. On update, only fields explicitly included in the request body are changed.
externalId is the upsert key. A row with an externalId that matches an existing deal in the workspace updates that deal instead of creating a duplicate.
Linking a contact, company, or offering can be done either by agentlyleads record ID (contactId/companyId/offeringId) or by an external system's ID (contactExternalId/companyExternalId/offeringExternalId), which is resolved against that record's own externalId. If an *ExternalId is supplied but no matching record exists in the workspace, that row fails — it does not fall back to leaving the deal unlinked.
campaignId records which campaign produced the deal, so won revenue rolls up to that campaign (and to its offering) on the campaign page. Campaigns have no external ID, so this is always the agentlyleads campaign ID (available from the campaign's URL or the MCP list_campaigns tool). A campaignId from another workspace fails the row with Campaign not found.. On read, the deal carries campaign: { "id", "name" } or null.