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

# Update Contact

> Change the attributes of an existing contact. Values are overwritten unless a row sends replace: false. Fails with 404 if the number is not a contact.

> [!NOTE]
>
> Changes the attributes of a contact that is already in your [CRM](https://docs.callkaro.ai/crm/introduction.md), for example when a lead's status changes in your own system.

## Quick Example

```bash theme={null}
curl -X POST "https://api.callkaro.ai/contact/update" \
  -H "Content-Type: application/json" \
  -H "X-API-KEY: YOUR_API_KEY" \
  -d '{
    "to_number": "+919876543210",
    "attributes": [
      { "key": "city", "value": "Mumbai" },
      { "key": "first_name", "value": "Rahul K", "replace": false }
    ]
  }'
```

The contact must already exist. To add a new one, use [Create Contact](https://docs.callkaro.ai/api-reference/contact-create.md).

## Use Cases

* **Status changes**: update a lead stage or payment status when it changes in your CRM or billing system
* **Enrichment**: fill in details you learn later, such as city, company or plan
* **Keeping two systems in step**: copy changes from your own database so agents and workflows see current values

## Where to find the values

| Field | Where it comes from |
| - | - |
| `X-API-KEY` | **API Key** in the dashboard sidebar. Use the key of the account the contact belongs to. |
| `to_number` | The contact's phone number. `+919876543210`, `919876543210` and `9876543210` all find the same contact. |
| `attributes[].key` | The name of an attribute in **CRM → Attributes**. See [Attributes](https://docs.callkaro.ai/crm/attributes.md). |

## How attributes are saved

Each row in `attributes` is a `key`, a `value` and an optional `replace`.

* **`replace: true`** (the default here) overwrites the value the contact already has.
* **`replace: false`** only fills an attribute that is empty. An existing value is kept and listed under `kept_existing`.
* **Edits made by hand win**: a value someone typed into the CRM is never overwritten through the API, even with `replace: true`. It is listed under `kept_existing`.
* **Matching names**: `key` is matched ignoring case, spaces, underscores and hyphens, so `"First Name"` matches `first_name`.
* **Types**: the value is checked against the attribute's type. A number attribute needs a number, a date needs a date, and an enum value must be one of its options.
* **Leaving a value out** changes nothing: attributes you do not send keep their values, and a blank value is skipped rather than clearing the attribute.

> [!WARNING]
>
> Only attributes that already exist in **CRM → Attributes** are saved. A key with no matching attribute is listed under `ignored`.

The response reports what happened to every row:

```json theme={null}
"attributes": {
  "updated": ["city"],
  "kept_existing": ["first_name"],
  "ignored": [],
  "invalid": []
}
```

## Errors worth handling

> **404 Contact not found**
>
> The number is not a contact on the account this key belongs to. Create it with [Create Contact](https://docs.callkaro.ai/api-reference/contact-create.md), or check the number and the key.

> **401 Invalid API key**
>
> The `X-API-KEY` header is missing or does not belong to any account.

> **403 Account is inactive**
>
> The account the key belongs to has been deactivated. Contact support.

> **400 Missing to\_number, or a problem with attributes**
>
> The body has no phone number, `attributes` is not a list, or a row has no `key`, a non-boolean `replace`, an object or list as its `value`, or a value longer than 1000 characters.


## OpenAPI

````yaml POST /contact/update
openapi: 3.1.0
info:
  title: CallKaro AI API
  description: Campaign and outbound call management API for CallKaro AI voice agents
  version: 1.0.0
  contact:
    name: CallKaro AI Support
    email: support@callkaro.ai
    url: https://callkaro.ai
servers:
  - url: https://api.callkaro.ai
    description: Production server
security:
  - ApiKeyAuth: []
paths:
  /contact/update:
    post:
      tags:
        - Endpoints
      summary: Update Contact
      description: >-
        Change the attributes of an existing contact. Values are overwritten
        unless a row sends replace: false. Fails with 404 if the number is not a
        contact.
      operationId: updateContact
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ContactWriteRequest'
            example:
              to_number: '+919876543210'
              attributes:
                - key: city
                  value: Mumbai
                - key: first_name
                  value: Rahul K
                  replace: false
      responses:
        '200':
          description: Contact updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ContactWriteResponse'
              example:
                status: done
                message: Contact updated
                contact:
                  to_number: '919876543210'
                  channels: []
                  attributes:
                    first_name: Rahul
                    city: Mumbai
                  created_at: '2026-10-27 11:42:05.118'
                  updated_at: '2026-10-27 12:03:51.402'
                  last_message_at: null
                attributes:
                  updated:
                    - city
                  kept_existing:
                    - first_name
                  ignored: []
                  invalid: []
        '400':
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                status: error
                message: attributes must be a list of { key, value, replace }
        '401':
          description: Missing or unknown X-API-KEY
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                status: error
                message: Invalid API key
        '403':
          description: The account this key belongs to is inactive
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                status: error
                message: Account is inactive
        '404':
          description: The number is not a contact on this account
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                status: error
                message: Contact not found
components:
  schemas:
    ContactWriteRequest:
      type: object
      required:
        - to_number
      properties:
        to_number:
          type: string
          description: >-
            Phone number with country code. A 10-digit number is read as Indian
            (+91). Spaces, dashes and + are ignored.
          example: '+919876543210'
        attributes:
          type: array
          maxItems: 50
          items:
            $ref: '#/components/schemas/ContactAttribute'
          description: >-
            CRM attributes to save on the contact. Only attributes that already
            exist in CRM > Attributes are saved.
    ContactWriteResponse:
      type: object
      properties:
        status:
          type: string
          example: done
        message:
          type: string
          example: Contact created
        contact:
          $ref: '#/components/schemas/Contact'
        attributes:
          $ref: '#/components/schemas/ContactAttributeReport'
    ErrorResponse:
      type: object
      properties:
        status:
          type: string
          example: error
        message:
          type: string
          description: Error description
          example: 'Missing required field: to_number'
    ContactAttribute:
      type: object
      required:
        - key
        - value
      properties:
        key:
          type: string
          description: >-
            Name of an attribute in CRM > Attributes. Matched ignoring case,
            spaces, underscores and hyphens.
          example: first_name
        value:
          description: >-
            A string, number or boolean, at most 1000 characters. Checked
            against the attribute's type.
          oneOf:
            - type: string
            - type: number
            - type: boolean
          example: Rahul
        replace:
          type: boolean
          description: >-
            Overwrite a value the contact already has. Defaults to false on
            create and true on update.
    Contact:
      type: object
      properties:
        to_number:
          type: string
          description: 'Phone number as stored: digits only, with country code'
          example: '919876543210'
        channels:
          type: array
          items:
            type: string
          description: Channels this contact has been reached on
          example:
            - whatsapp
        attributes:
          type: object
          additionalProperties: true
          description: Attribute name to value
          example:
            first_name: Rahul
            city: Pune
        created_at:
          type: string
          description: IST, YYYY-MM-DD HH:mm:ss.SSS
          example: '2026-10-27 11:42:05.118'
        updated_at:
          type: string
          description: IST, YYYY-MM-DD HH:mm:ss.SSS
          example: '2026-10-27 11:42:05.118'
        last_message_at:
          type: string
          nullable: true
          description: IST time of the last WhatsApp message, or null
          example: null
    ContactAttributeReport:
      type: object
      description: What happened to every row of `attributes`
      properties:
        updated:
          type: array
          items:
            type: string
          description: Attributes saved
        kept_existing:
          type: array
          items:
            type: string
          description: >-
            Attributes left as they were: replace was false and a value existed,
            or the value was set by hand in the CRM
        ignored:
          type: array
          items:
            type: string
          description: Keys with no matching attribute in CRM > Attributes
        invalid:
          type: array
          items:
            type: object
            properties:
              key:
                type: string
              reason:
                type: string
          description: Values that did not fit the attribute's type or options
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-KEY
      description: API key from https://callkaro.ai/dashboard/api-key

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.