> For the complete documentation index, see [llms.txt](https://flapjax.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://flapjax.gitbook.io/docs/rest-api/reference/people-events/patch-person-by-external-id.md).

# Patch Person by External ID

## Patch person by external ID (partial update)

> Performs a \*\*partial update\*\* on a person identified by their external ID. Only the fields you include in the request body are updated. All other fields on the person remain unchanged.\
> \
> This is ideal for updating a single field like \`last\_name\` or adding a new custom attribute without affecting the rest of the person's data.\
> \
> The request body schema is the same as the \`PUT\` endpoint, but only provided fields are applied. Relationship attributes in \`attribute\_values\` are normalized and any referenced entities that don't exist are auto-created.<br>

```json
{"openapi":"3.0.3","info":{"title":"Listener API","version":"1.0.0"},"tags":[{"name":"patch-person-by-external-id"}],"servers":[{"url":"https://{domain}/v1","variables":{"domain":{"default":"your-domain","description":"Your deployment domain"}}}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"JWT token with the required scope for the endpoint. Pass via the `Authorization: Bearer <token>` header.\n"}},"parameters":{"PersonExternalId":{"name":"external_id","in":"path","required":true,"description":"The external identifier assigned to the person.","schema":{"type":"string"}}},"schemas":{"UpdatePersonRequest":{"type":"object","description":"Request body for updating or patching a person. For `PUT`, omitted fields are cleared. For `PATCH`, omitted fields are left unchanged.\n","properties":{"external_id":{"type":"string","description":"New external identifier."},"first_name":{"type":"string","description":"First name."},"last_name":{"type":"string","description":"Last name."},"email":{"type":"string","format":"email","description":"Email address."},"mobile_prefix":{"type":"string","description":"Mobile phone country prefix."},"mobile_number":{"type":"string","description":"Mobile phone number."},"date_of_birth":{"type":"string","description":"Date of birth."},"language":{"type":"string","description":"Preferred language code."},"email_consent":{"type":"boolean","description":"Email channel consent. This is a summary of the person's consent answers on the email channel: `false` refuses every consent purpose on the channel, `true` grants only the purpose marked as that channel's default and leaves the other purposes on their own defaults. Use `consents` to answer individual purposes.\n"},"sms_consent":{"type":"boolean","description":"SMS channel consent. Behaves like `email_consent` on the SMS channel.\n"},"push_notification_consent":{"type":"boolean","description":"Push notification consent. A plain flag — consent purposes only apply to the `email` and `sms` channels.\n"},"consents":{"type":"array","description":"Individual consent answers written alongside the person's own fields. Each entry answers one consent purpose on one channel.\n\nCells are applied **after** the person update succeeds. An invalid cell fails the request with **400** — a consent type that is unknown or archived, one that is mandatory (mandatory purposes can never be refused, so they cannot be answered), or one that does not apply to the given channel.\n\nOmitted purposes are left untouched: a purpose the person has never answered keeps resolving to the consent type's default state.\n","items":{"$ref":"#/components/schemas/PersonConsentAssignment"}},"attribute_values":{"type":"object","description":"Custom attribute key-value pairs. Relationship attributes are normalized and auto-created.\n","additionalProperties":true}}},"PersonConsentAssignment":{"type":"object","description":"One consent answer: this consent purpose, on this channel, in this state. Consent types are configured per organization; their numeric IDs come from your organization's consent settings.\n","required":["consent_type_id","channel","state"],"properties":{"consent_type_id":{"type":"integer","minimum":1,"description":"Identifier of the consent type being answered. Must reference an active, non-mandatory consent type on your organization.\n"},"channel":{"type":"string","description":"Channel the answer applies to. The consent type must be configured for this channel.\n","enum":["email","sms"]},"state":{"type":"boolean","description":"The answer. `true` grants the purpose on the channel, `false` refuses it. Writing an answer replaces any previous answer, and the channel summary flag (`email_consent` / `sms_consent`) is recomputed from the stored answers.\n"}}},"SuccessResponse":{"type":"object","description":"Standard success response envelope.","properties":{"status":{"type":"string","enum":["Success"]},"data":{"type":"boolean"}}},"ErrorResponse":{"type":"object","description":"Standard error response envelope.","properties":{"error":{"type":"string","description":"Machine-readable error type. Use this for programmatic error handling.\n","enum":["operation_failed","failed_binding_json","invalid_json","invalid_parameter","not_found","duplicate_entry","rate_limit_exceeded"]},"errorstack":{"type":"object","nullable":true,"description":"Detailed error stack (only present for server errors)."}}}}},"paths":{"/people/{external_id}":{"patch":{"summary":"Patch person by external ID (partial update)","operationId":"patchPersonByExternalId","tags":["patch-person-by-external-id"],"description":"Performs a **partial update** on a person identified by their external ID. Only the fields you include in the request body are updated. All other fields on the person remain unchanged.\n\nThis is ideal for updating a single field like `last_name` or adding a new custom attribute without affecting the rest of the person's data.\n\nThe request body schema is the same as the `PUT` endpoint, but only provided fields are applied. Relationship attributes in `attribute_values` are normalized and any referenced entities that don't exist are auto-created.\n","parameters":[{"$ref":"#/components/parameters/PersonExternalId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePersonRequest"}}}},"responses":{"200":{"description":"Person patched successfully.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"description":"Invalid request body or validation failure.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Person not found or internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}
```
