Skip to content
View as Markdown

Update a lead ​

PATCH /v1/leads/{lead_id}

Merges more details into a lead, typically from later steps of a form.

Scope: leads:write

Access: The key's member must be allowed to manage leads in the lead's campaign.

Takes the same optional details as POST /v1/leads, with the same limits and merge rules, plus deal_value. Custom field slugs are checked against the lead's campaign.

campaign_id and phone cannot be sent: a lead's phone number is its identity, so to capture a different number POST a new lead.

PATCH never creates or moves the lead's pipeline card and never changes a time zone the lead already has. custom_fields and deal_value are saved on the card the lead already has; if it has none, a PATCH carrying either fails with 409 no_pipeline_card and writes nothing. For a member who may open only a follow-through card of the lead, they are saved on the deal that card shares with the main card, and pipeline_lead_id is the follow-through card.

The lead must belong to a campaign the key may write to and be one the key's member can see in DialEcho, otherwise 404, checked before the member's permission to manage leads.

Path parameters ​

NameTypeRequiredDescription
lead_idUUIDYesThe lead, as POST /v1/leads returned it.

Body ​

Content type: application/json

NameTypeRequiredDescription
first_namestringNoFirst name. Up to 100 characters.
last_namestringNoLast name. Up to 100 characters.
emailstringNoAn email address that can receive mail. Anything else, including an address over 254 characters, is rejected with field code email_invalid. Up to 254 characters.
addressstringNoStreet address. Up to 500 characters.
citystringNoCity. Up to 100 characters.
statestringNoA US state name or 2-letter code; sets the lead's time zone when it has none. Up to 100 characters.
postal_codestringNoA US ZIP sets the lead's state (and its time zone, if it has none) when neither state nor address names one and none is stored. Up to 20 characters.
companystringNoCompany name. Up to 200 characters.
notesstringNoFree-text notes on the lead. Up to 5,000 characters.
custom_fieldsobjectNoValues for the campaign's own custom fields, keyed by field slug. Each value is a string, number, boolean or null. Saved on the lead's pipeline card as text, exactly as if your team typed it: true/false for checkbox fields, numbers as sent (12 becomes "12"), strings trimmed. A slug that is not one of the campaign's fields, or is a file or image field, is reported as custom_fields.<slug> with not_allowed (upload files with POST /v1/leads/{lead_id}/files); a bad value (another type, or a string too long) is reported once, as custom_fields. Up to 100 entries. Keys 1 to 100 characters; string values up to 2,000 characters.
attributionobjectNoMarketing attribution, stored on the lead under the same key names and returned by the conversion report for ad-platform matching. Any key not listed here is rejected with not_allowed.
attribution.utm_sourcestringNoUTM source of the visit. Up to 500 characters.
attribution.utm_mediumstringNoUTM medium. Up to 500 characters.
attribution.utm_campaignstringNoUTM campaign. Up to 500 characters.
attribution.utm_termstringNoUTM term. Up to 500 characters.
attribution.utm_contentstringNoUTM content. Up to 500 characters.
attribution.utm_idstringNoUTM id, for example the Meta campaign id. Up to 500 characters.
attribution.adset_idstringNoAd set id of the ad the visitor came from. Up to 500 characters.
attribution.ad_idstringNoAd id of the ad the visitor came from. Up to 500 characters.
attribution.fbclidstringNoMeta's click id from the landing page URL. Up to 500 characters.
attribution.fbpstringNoThe visitor's Meta _fbp cookie. Up to 500 characters.
attribution.fbcstringNoThe visitor's Meta _fbc cookie. Up to 500 characters.
attribution.gclidstringNoGoogle's click id. Up to 500 characters.
attribution.meta_event_idstringNoThe event ID your Meta Pixel's browser Lead event used for this submission, so a Lead sent from the conversion report deduplicates against it. Up to 200 characters.
attribution.page_urlstringNoThe page the form was submitted on. Up to 2,048 characters.
attribution.form_namestringNoYour name for the form or form step. Up to 200 characters.
attribution.referrerstringNoThe referring page. Up to 2,048 characters.
deal_valuenumberNoThe deal value of the lead's pipeline card, as your team sees it on the card. 0 is a value and is saved; null or leaving it out keeps the stored value. The number is checked exactly as written in your JSON, never rounded first, so 100000000.000000001 is rejected and 12.500 is saved as 12.5. Read it back as card.deal_value from GET /v1/leads/{lead_id}. 0 to 100,000,000 with at most 2 decimal places. Strings and booleans are rejected.

Response ​

Status: 200 OK

Identifiers only.

NameTypeDescription
lead_idUUIDThe lead.
contact_idUUID | nullThe CRM contact the lead is linked to.
pipeline_lead_idUUID | nullThe lead's card on the campaign's board, the card GET /v1/leads/{lead_id} returns as card (for a member who may open only a follow-through card of the lead, that card). null only when the lead could not be placed (for example the first stage only accepts cards placed by a person); sending the same POST again retries the placement.

Example request ​

curl

bash
curl -X PATCH "https://development.agencydevworks.ai/v1/leads/aaaaaaaa-0000-4000-8000-000000000001" \
  -H "Authorization: Bearer dei_your_key" \
  -H "Content-Type: application/json" \
  -d '{
  "last_name": "Lee",
  "address": "1 Market St",
  "city": "San Francisco",
  "postal_code": "94105",
  "custom_fields": {
    "roof_age": 12
  },
  "attribution": {
    "form_name": "quote-step-2"
  },
  "deal_value": 12500.5
}'

JavaScript

js
const response = await fetch("https://development.agencydevworks.ai/v1/leads/aaaaaaaa-0000-4000-8000-000000000001", {
  method: "PATCH",
  headers: {
    "Authorization": "Bearer dei_your_key",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "last_name": "Lee",
    "address": "1 Market St",
    "city": "San Francisco",
    "postal_code": "94105",
    "custom_fields": {
      "roof_age": 12
    },
    "attribution": {
      "form_name": "quote-step-2"
    },
    "deal_value": 12500.5
  }),
});
const data = await response.json();

Example response ​

Status: 200 OK

json
{
  "lead_id": "aaaaaaaa-0000-4000-8000-000000000001",
  "contact_id": "bbbbbbbb-0000-4000-8000-000000000001",
  "pipeline_lead_id": "dddddddd-0000-4000-8000-000000000001"
}

Errors ​

HTTPCodeWhen
403insufficient_scopeThe key does not have leads:write. Checked before the body is validated.
403permission_deniedThe key's member may not manage leads in the lead's campaign. Only for a lead they can see; any other lead is 404.
404not_foundThe lead does not exist or the key cannot reach it (other organization, a campaign outside the key, or a lead its member cannot see).
409no_pipeline_cardcustom_fields or deal_value were sent but the lead has no pipeline card (or it was deleted while the request ran). Nothing was written.
413payload_too_largeThe body is larger than 1 MB. It was not read and nothing was written.
422invalid_requestlead_id is not a UUID, or the body is invalid: campaign_id or phone sent, unknown fields, values too long, an invalid email, unknown or file/image custom fields, or a deal_value outside its rules. error.fields lists every problem.

Every endpoint can also answer 401 invalid_api_key, 429 rate_limited and 503 dependency_unavailable. See Errors in the overview.