Skip to content

Update a contact

Change a contact's details, properties or subscription state.

http
PATCH /v1/contacts/{id}

Requires a Full access API key.

Path parameters

ParameterTypeRequiredDescription
idstringYesThe contact id, or the contact's email address.

Body parameters

Every field is optional — send only what you're changing. A field you leave out is left alone.

ParameterTypeRequiredDescription
emailstringNoA new address. Max 254 characters, lower-cased on save, still unique within your team.
first_namestring | nullNoMax 120 characters. null clears it.
last_namestring | nullNoMax 120 characters. null clears it.
unsubscribedbooleanNotrue unsubscribes the contact globally from all broadcasts and stamps unsubscribed_at. false resubscribes them and clears it.
propertiesobjectNoA map of property key → value. Only the keys you send are touched; unknown keys are ignored. null or "" clears a value.

Example

bash
curl -X PATCH "https://api.sendgrail.com/v1/contacts/ada@example.com" \
  -H "Authorization: Bearer $SENDGRAIL_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "first_name": "Ada",
    "properties": { "seats": 24 }
  }'
js
const res = await fetch(
  `https://api.sendgrail.com/v1/contacts/${encodeURIComponent('ada@example.com')}`,
  {
    method: 'PATCH',
    headers: {
      Authorization: `Bearer ${process.env.SENDGRAIL_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      first_name: 'Ada',
      properties: { seats: 24 },
    }),
  },
);

const contact = await res.json();

Response

The body carries just the contact's id — fetch the full contact object with retrieve if you need the updated record back:

json
{
  "object": "contact",
  "id": "3f1c9a0e-6c5e-4a2b-9f2d-2b1a7c8e4d31"
}

A contact.updated webhook event fires on success.

Properties merge, they don't replace

Sending { "properties": { "seats": 24 } } sets seats and leaves every other property as it was. There is no way to wipe all properties in one call — clear them individually by sending null.

The properties in the response is the resolved map: every property defined on your team, with its fallback applied where the contact has no value of its own. So a key you just cleared reappears with its fallback rather than disappearing. See The contact object.

A value for a number-typed property must be numeric or the whole request is a 422 — nothing is saved.

Unsubscribing

unsubscribed: true is the global opt-out: it sets unsubscribed_at to now, and the contact stops receiving broadcasts entirely, regardless of topics. Setting it back to false clears unsubscribed_at.

This is deliberately blunt. To opt someone out of one category only, use Contact topics instead.

Changing the address

Changing email moves the contact's identity — the address is what uniquely identifies them within your team. If the new address already belongs to another contact, the request is a 422; SendGrail will not merge two contacts for you, because there is no correct answer to which one's properties should win.

See Errors.

Transactional email on your own domain.