# Update a contact

`PATCH /v1/contacts/{id}`

Requires an API key with the `contacts:write` scope. [About keys and scopes](/docs/api/authentication)

Merges the supplied fields into an existing contact; omitted fields are left alone, and `attributes` is merged key by key rather than replaced; a key set to `null` is removed (JSON Merge Patch). Agent keys cannot mutate contacts or consent and are refused with 403.

## Path parameters

- `id` (string, required, uuid)

## Request body

- `externalId` (string | null, optional, 1–255 characters) — Your own id for the contact, up to 255 characters. Identify matches on it first.
- `email` (string | null, optional, email)
- `firstName` (string | null, optional, 1–100 characters)
- `lastName` (string | null, optional, 1–100 characters)
- `phone` (string | null, optional) — Phone number; normalised to E.164 (a leading `+` and country code).
- `timezone` (string | null, optional, up to 100 characters) — IANA timezone, e.g. `Europe/London`; used for send-time scheduling.
- `country` (string | null, optional) — ISO 3166-1 alpha-2 code. Omitted, it is inferred from the phone, else the timezone.
- `dates` (ContactDatesInput, optional) — Named calendar dates, merged key by key; `null` removes one.
- `attributes` (object, optional) — Custom attributes, merged key by key; `null` removes one. At most 50 keys and 16 KB.
- `emailConsent` (boolean, optional) — Consent to email. Omitted, the current value is kept.
- `pushConsent` (boolean, optional) — Consent to push. Omitted, the current value is kept.
- `consentStatement` (ConsentStatementInput, optional) — How the contact agreed, recorded with any consent this request grants.
  - `basis` (string, required, one of `opted_in`, `existing_customer`) — The legal basis the contacts agreed under.
  - `evidence` (string, required, 1–500 characters) — Where and how they agreed, e.g. "Checkout opt-in on shop.example.com".

## Returns

Returns `200 OK` with a `ContactDetail` in `data`. Otherwise returns an error; [Errors](/docs/api/errors) lists every code and which to retry.

- `id` (string, required, uuid)
- `externalId` (string | null, required) — Your own id for the contact, if set.
- `email` (string | null, required, email)
- `firstName` (string | null, required)
- `lastName` (string | null, required)
- `phone` (string | null, required) — Phone number in E.164 format.
- `timezone` (string | null, required) — IANA timezone, e.g. `Europe/London`.
- `country` (string | null, required) — ISO 3166-1 alpha-2 code: as written, or inferred from the phone, else the timezone.
- `dates` (object, required) — Named calendar dates, e.g. `birthday`, as `YYYY-MM-DD` or `--MM-DD`.
- `attributes` (object, required) — Custom attributes, keyed by attribute name.
- `emailConsent` (boolean, required) — Whether the contact has consented to email.
- `pushConsent` (boolean, required) — Whether the contact has consented to push.
- `createdAt` (string, required, date-time)
- `updatedAt` (string, required, date-time)
- `emailSuppression` (object, required)
  - `suppressed` (boolean, required) — Whether email to this contact is blocked.
  - `reason` (string | null, required) — Why email to this contact is suppressed: `bounced`, `complained`, `complained_transactional`, `unsubscribed`, `manual`, `imported`, or `other_workspace` (a bounce or complaint in another workspace with the same owner or partner).

## Example

```bash
curl -X PATCH https://api.kirora.io/v1/contacts/018f2a4e-6b1c-7d3e-9f40-37386ae05a6b \
  -H "Authorization: Bearer $KIRORA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "externalId": "user_8812",
    "email": "amaka@juniperkitchen.com",
    "firstName": "Amaka",
    "lastName": "Eze",
    "phone": "+447700900123",
    "timezone": "Europe/London",
    "country": "GB",
    "dates": {},
    "attributes": {},
    "emailConsent": true,
    "pushConsent": true,
    "consentStatement": {
      "basis": "opted_in",
      "evidence": "evidence_example"
    }
  }'
```

Response `200`:

```json
{
  "data": {
    "id": "018f2a4e-6b1c-7d3e-9f40-37386ae05a6b",
    "externalId": "user_8812",
    "email": "amaka@juniperkitchen.com",
    "firstName": "Amaka",
    "lastName": "Eze",
    "phone": "+447700900123",
    "timezone": "Europe/London",
    "country": "GB",
    "dates": {},
    "attributes": {},
    "emailConsent": true,
    "pushConsent": true,
    "createdAt": "2030-03-14T09:30:00Z",
    "updatedAt": "2030-03-14T09:30:00Z",
    "emailSuppression": {
      "suppressed": true,
      "reason": "reason_example"
    }
  }
}
```
