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

# Write many contacts in one request

> Runs up to 1000 operations. Each operation answers for itself.

The status code describes the request, not the rows. A request that
Kai understands returns 200, even when every operation in it failed.
Read `summary` and `results` to see what happened.

Kai runs the operations in order. Two operations that name the same
person are applied one after the other.




## OpenAPI

````yaml /openapi.yaml post /contacts/batch
openapi: 3.1.0
info:
  title: Kai Contacts API
  version: 1.0.0
  description: |
    Push, update, assign and export the contacts of one Kai workspace.

    Every request needs an API key. Make a key in Kai, under
    **Settings → API**. Send the key in the `Authorization` header.

    The API works on one workspace. The key decides which workspace, so no
    request carries a workspace id.
  contact:
    name: Kai support
    url: https://kaisupport.com
servers:
  - url: https://kaisupport.com/api/v1
    description: Production
security:
  - bearerAuth: []
tags:
  - name: Contacts
    description: Customer profiles, their attributes and their account owners.
  - name: Attributes
    description: The attributes that the workspace keeps on every contact.
  - name: Members
    description: The teammates of the workspace. Read-only.
paths:
  /contacts/batch:
    post:
      tags:
        - Contacts
      summary: Write many contacts in one request
      description: |
        Runs up to 1000 operations. Each operation answers for itself.

        The status code describes the request, not the rows. A request that
        Kai understands returns 200, even when every operation in it failed.
        Read `summary` and `results` to see what happened.

        Kai runs the operations in order. Two operations that name the same
        person are applied one after the other.
      operationId: batchContacts
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - operations
              properties:
                operations:
                  type: array
                  minItems: 1
                  maxItems: 1000
                  items:
                    $ref: '#/components/schemas/BatchOperation'
            example:
              operations:
                - op: upsert
                  data:
                    external_id: DK-1042
                    name: Ayşe Yılmaz
                    attributes:
                      package: Tam Destek
                - op: assign
                  external_id: DK-1043
                  owner: baran@example.com
                - op: delete
                  id: 8b2f1c40-1f2e-4a9d-9d61-0c4f5a6b7c88
      responses:
        '200':
          description: The batch ran. Read the results for the outcome of each operation.
          content:
            application/json:
              schema:
                type: object
                required:
                  - summary
                  - results
                properties:
                  summary:
                    type: object
                    properties:
                      total:
                        type: integer
                      created:
                        type: integer
                      updated:
                        type: integer
                      deleted:
                        type: integer
                      assigned:
                        type: integer
                      errors:
                        type: integer
                  results:
                    type: array
                    items:
                      $ref: '#/components/schemas/BatchResult'
              example:
                summary:
                  total: 3
                  created: 1
                  updated: 0
                  deleted: 1
                  assigned: 1
                  errors: 0
                results:
                  - index: 0
                    op: upsert
                    status: created
                    id: 4f1d6f2a-6a1e-4a0b-9c53-2a9a1f0c77d1
                  - index: 1
                    op: assign
                    status: assigned
                    id: 7d2b8e11-3c4a-4f5b-8a9c-2e1d0f3a4b56
                  - index: 2
                    op: delete
                    status: deleted
                    id: 8b2f1c40-1f2e-4a9d-9d61-0c4f5a6b7c88
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
components:
  schemas:
    BatchOperation:
      type: object
      description: |
        `upsert` creates or updates. `update` refuses to create. `delete`
        removes the profile. `assign` sets the account owner.

        Name the contact with `id`, or with an identity such as `external_id`.
      properties:
        op:
          type: string
          enum:
            - upsert
            - update
            - delete
            - assign
          default: upsert
        id:
          type: string
          format: uuid
        external_id:
          type: string
        email:
          type: string
        phone:
          type: string
        owner:
          type:
            - string
            - 'null'
          description: For an `assign` operation.
        reassign_open_conversations:
          type: boolean
          default: false
        data:
          $ref: '#/components/schemas/ContactWrite'
    BatchResult:
      type: object
      properties:
        index:
          type: integer
          description: The position of this operation in the request.
        op:
          type: string
          enum:
            - upsert
            - update
            - delete
            - assign
        status:
          type: string
          enum:
            - created
            - updated
            - deleted
            - assigned
            - error
        id:
          type: string
          format: uuid
        contact:
          $ref: '#/components/schemas/Contact'
        error:
          $ref: '#/components/schemas/ErrorBody'
    ContactWrite:
      type: object
      description: |
        A key that you do not send keeps its stored value. A key set to `null`
        clears the value.
      properties:
        external_id:
          type:
            - string
            - 'null'
        name:
          type:
            - string
            - 'null'
        email:
          type:
            - string
            - 'null'
        phone:
          type:
            - string
            - 'null'
        note:
          type:
            - string
            - 'null'
        attributes:
          type: object
          description: |
            Values by API name. Kai refuses an unknown or archived key with a
            422 response, and names the key that it refused.
          additionalProperties:
            type:
              - string
              - number
              - boolean
              - 'null'
        owner:
          type:
            - string
            - 'null'
          description: A member id, the email of a member, or `null` to clear the owner.
        identities:
          type: array
          description: More handles that identify this person.
          items:
            $ref: '#/components/schemas/Identity'
    Contact:
      type: object
      required:
        - id
        - attributes
        - created_at
        - updated_at
      properties:
        id:
          type: string
          format: uuid
          description: The Kai contact id.
        external_id:
          type:
            - string
            - 'null'
          description: Your own id for this person. It is unique in the workspace.
        name:
          type:
            - string
            - 'null'
        email:
          type:
            - string
            - 'null'
        phone:
          type:
            - string
            - 'null'
        note:
          type:
            - string
            - 'null'
          description: A note for teammates. Kai does not send it to a customer.
        attributes:
          type: object
          description: The workspace attributes of this contact, by API name.
          additionalProperties:
            type:
              - string
              - number
              - boolean
              - 'null'
        owner:
          type:
            - object
            - 'null'
          description: The account owner, or `null`.
          properties:
            member_id:
              type: string
              format: uuid
            name:
              type:
                - string
                - 'null'
            email:
              type:
                - string
                - 'null'
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    ErrorBody:
      type: object
      properties:
        type:
          type: string
          description: A stable machine name for the error.
        message:
          type: string
          description: One sentence for a human reader.
        details:
          description: The attributes or the identities that caused the error.
    Error:
      type: object
      properties:
        error:
          $ref: '#/components/schemas/ErrorBody'
    Identity:
      type: object
      required:
        - kind
        - value
      properties:
        kind:
          type: string
          enum:
            - channel
            - email
            - phone
            - external
          description: |
            `channel` is a handle from a messaging channel, in the form
            `whatsapp_cloud:905321112233` or `intercom:5f3a...`.
        value:
          type: string
  responses:
    BadRequest:
      description: Kai could not read the request.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              type: invalid_request
              message: >-
                Send at least one of "external_id", "email", "phone" or
                "identities" so the contact can be matched.
    Unauthorized:
      description: The API key is missing or not valid.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              type: unauthorized
              message: That API key is not valid.
    Forbidden:
      description: The API key does not have the permission that this endpoint needs.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              type: forbidden
              message: This key does not have the "contacts:write" permission.
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: |
        Send your API key as `Authorization: Bearer kai_live_...`.

        Make and revoke keys in Kai, under **Settings → API**. Kai stores only
        a hash of the key, so the full key is shown one time.

````