> ## Documentation Index
> Fetch the complete documentation index at: https://docs.keebai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# PATCH /v1/crm/customers/:id

> Partially update a customer. Omitted fields keep their current value.

Updates a customer in place. Only the fields you send are written; everything else is left alone. There is no full-replacement variant.

`external_ids` cannot be changed here — it is set at creation time.

## Endpoint

```
PATCH https://api.keebai.com/v1/crm/customers/{id}
```

## Required scope

`crm:customers:write`

## Headers

| Header          | Required | Value                    |
| --------------- | -------- | ------------------------ |
| `Authorization` | Yes      | `Bearer kbai_pk_<token>` |
| `Content-Type`  | Yes      | `application/json`       |

## Path parameters

| Field | Type     | Required | Description                 |
| ----- | -------- | -------- | --------------------------- |
| `id`  | `string` | Yes      | `ObjectId` of the customer. |

## Body

All fields optional. Send only what changes.

| Field                    | Type       | Description                               |
| ------------------------ | ---------- | ----------------------------------------- |
| `name`                   | `string`   | First name or company name.               |
| `last_name`              | `string`   | Last name.                                |
| `email`                  | `string`   | Valid email address.                      |
| `phone`                  | `string`   | Phone number.                             |
| `identification_number`  | `string`   | National id. Unique within your company.  |
| `identification_type`    | `string`   | One of `rut`, `dni`, `passport`, `other`. |
| `identification_country` | `string`   | ISO 3166-1 alpha-2 country code.          |
| `custom_fields`          | `object`   | Replaces the whole custom fields object.  |
| `tags`                   | `string[]` | Replaces the whole tag list.              |
| `accepts_marketing`      | `boolean`  | Marketing consent flag.                   |

## Example request

<CodeGroup>
  ```bash curl theme={null}
  curl -X PATCH https://api.keebai.com/v1/crm/customers/65a1f2b3c4d5e6f7a8b9c0d1 \
    -H "Authorization: Bearer kbai_pk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
    -H "Content-Type: application/json" \
    -d '{
      "phone": "+56987654321",
      "accepts_marketing": false
    }'
  ```

  ```js JavaScript theme={null}
  const response = await fetch(
    `https://api.keebai.com/v1/crm/customers/${customerId}`,
    {
      method: "PATCH",
      headers: {
        Authorization: `Bearer ${process.env.KEEBAI_API_TOKEN}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ phone: "+56987654321", accepts_marketing: false }),
    },
  );
  const { customer } = await response.json();
  ```

  ```python Python theme={null}
  import os, requests

  resp = requests.patch(
      f"https://api.keebai.com/v1/crm/customers/{customer_id}",
      headers={"Authorization": f"Bearer {os.environ['KEEBAI_API_TOKEN']}"},
      json={"phone": "+56987654321", "accepts_marketing": False},
      timeout=10,
  )
  resp.raise_for_status()
  customer = resp.json()["customer"]
  ```
</CodeGroup>

## Response

### 200 OK

Returns the updated customer, same shape as [`GET /v1/crm/customers/:id`](/dev/endpoints/crm-customer-get).

### 400 Bad Request

Malformed `email`, an `identification_type` outside the allowed set, or a property the endpoint does not accept.

### 401 Unauthorized

Missing, invalid, revoked, or expired token.

### 403 Forbidden

The token does not have the `crm:customers:write` scope.

### 404 Not Found

No customer with that id, or the customer belongs to a different company.

### 502 Bad Gateway

The CRM service could not complete the write. The most common cause is an `identification_number` that another customer in your company already uses — that collision surfaces as a `502`, not a `409`.

## Operational notes

* **`custom_fields` and `tags` replace, not merge.** Sending `{"tags": ["65a…"]}` drops every other tag on the record. Read the customer first if you only mean to add one.
* Sending `{"email": ""}` is rejected as a malformed address. To clear a field, coordinate with your Keebai contact — the public API has no explicit null-out semantics yet.


## OpenAPI

````yaml PATCH /v1/crm/customers/{id}
openapi: 3.0.0
info:
  title: Keebai Public API
  description: Superficie pública REST autenticada con Personal Access Tokens (PAT).
  version: 1.0.0
  contact: {}
servers:
  - url: https://api.keebai.com
    description: Production
security: []
tags: []
paths:
  /v1/crm/customers/{id}:
    patch:
      tags:
        - crm-customers
      summary: Actualizar un cliente
      operationId: PublicCustomersController_update
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PublicCustomerUpdateDto'
      responses:
        '200':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicCustomerEnvelopeDto'
      security:
        - PAT: []
components:
  schemas:
    PublicCustomerUpdateDto:
      type: object
      properties:
        name:
          type: string
        last_name:
          type: string
        email:
          type: string
        phone:
          type: string
        identification_number:
          type: string
        identification_type:
          type: string
          enum:
            - rut
            - dni
            - passport
            - other
        identification_country:
          type: string
        custom_fields:
          type: object
        tags:
          description: Reemplaza la lista completa de tags
          type: array
          items:
            type: string
        accepts_marketing:
          type: boolean
    PublicCustomerEnvelopeDto:
      type: object
      properties:
        customer:
          $ref: '#/components/schemas/PublicCustomerResponseDto'
      required:
        - customer
    PublicCustomerResponseDto:
      type: object
      properties:
        _id:
          type: string
          description: ObjectId del cliente
        name:
          type: string
        last_name:
          type: string
        email:
          type: string
        phone:
          type: string
        identification_number:
          type: string
        identification_type:
          type: string
          enum:
            - rut
            - dni
            - passport
            - other
        identification_country:
          type: string
          description: Código de país ISO 3166-1 alpha-2
        external_ids:
          type: array
          items:
            $ref: '#/components/schemas/PublicCustomerExternalIdResponseDto'
        custom_fields:
          type: object
          description: Campos personalizados de la company
        tags:
          description: Ids de tags del CRM
          type: array
          items:
            type: string
        accepts_marketing:
          type: boolean
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required:
        - _id
        - name
        - external_ids
        - custom_fields
        - tags
        - accepts_marketing
        - created_at
        - updated_at
    PublicCustomerExternalIdResponseDto:
      type: object
      properties:
        provider:
          type: string
          description: Sistema externo dueño del identificador
        external_id:
          type: string
          description: Identificador del cliente en ese sistema
      required:
        - provider
        - external_id
  securitySchemes:
    PAT:
      scheme: bearer
      bearerFormat: kbai_pk_<hex>
      type: http
      description: >-
        Personal Access Token con prefijo `kbai_pk_`. Generar desde el portal
        con permiso `developer.manage_tokens`.

````