agentlyleads docs
Deals API

The Deal object

The following fields are accepted on write via POST /api/v1/deals.

FieldTypeNotes
idstringCUID, assigned on create (read-only)
namestring (required)Max 200 characters
valuenumberNonnegative; defaults to 0 if omitted on create
stageenumNEW (default) · QUALIFIED · PROPOSAL · NEGOTIATION · WON · LOST
stageIdstringWrite 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
expectedCloseDatestring (ISO 8601 date) | nullWhen the deal is expected to close
notesstring | nullMax 10,000 characters
externalIdstring | nullYour system's ID — upsert key and dedupe handle (max 200 chars)
contactIdstring | nullLink to an existing contact by its agentlyleads record ID
companyIdstring | nullLink to an existing company by its agentlyleads record ID
offeringIdstring | nullLink to an existing offering/product by its agentlyleads record ID
campaignIdstring | nullThe campaign this deal came out of, by its agentlyleads campaign ID. Must belong to the workspace; null unlinks
contactExternalIdstring | nullResolve the linked contact by its externalId instead of contactId (max 200 chars)
companyExternalIdstring | nullResolve the linked company by its externalId instead of companyId (max 200 chars)
offeringExternalIdstring | nullResolve the linked offering by its externalId instead of offeringId (max 200 chars)
createdAtstring (ISO 8601)Assigned on create (read-only)
updatedAtstring (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.

On this page