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

# Upsert Clients

> Creates or updates clients using your firm's client identifiers. Submit 1 to 10,000 clients per request.

### Permissions

Requires **Client matters admin** (`write:client_matters`).

### Matching and results

A live or soft-deleted client with the same trimmed `client_id` is updated or restored. Matched clients appear in `updated`, even when their fields do not change. New clients appear in `created`.

HTTP 200 can include row failures in `errors`; valid rows still succeed. A repeated identifier in the batch produces `duplicate_client_id` for the later row.

See the [Client Matters guide](/guides/client_matters) for examples and migration steps.


## OpenAPI

````yaml /client_matters_api.json post /api/v2/clients
openapi: 3.0.1
info:
  title: Harvey Client Matter API
  description: >-
    Create and update clients and matters by your firm identifiers. Retrieve and
    delete client matters through the v1 endpoints.
  version: 1.0.0
  contact:
    email: support@harvey.ai
servers:
  - url: https://api.harvey.ai
    description: Harvey API server
security: []
paths:
  /api/v2/clients:
    post:
      tags:
        - Upsert
      summary: Upsert Clients
      description: >-
        Creates or updates clients using your firm's client identifiers. Submit
        1 to 10,000 clients per request.
      operationId: upsertClients
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpsertClientsRequest'
            example:
              clients:
                - client_id: '10022421'
                  client_name: Acme Corp
      responses:
        '200':
          description: Per-row results for the submitted clients.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UpsertClientsResponse'
              examples:
                created:
                  summary: Created row
                  value:
                    created:
                      - client_id: '10022421'
                        client_name: Acme Corp
                    updated: []
                    errors: []
                updated:
                  summary: Existing row, including a repeated request
                  value:
                    created: []
                    updated:
                      - client_id: '10022421'
                        client_name: Acme Corp
                    errors: []
                partialSuccess:
                  summary: Valid row succeeds while another row fails
                  value:
                    created:
                      - client_id: '10022421'
                        client_name: Acme Corp
                    updated: []
                    errors:
                      - client_id: ' '
                        error: invalid_client_id
                        detail: Client identifier must not be empty
        '400':
          description: The request was rejected as a whole.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClientMatterBatchError'
              example:
                error: invalid_request
                detail: Invalid request body
                validation_errors:
                  - loc:
                      - clients
                    type: too_short
        '401':
          description: >-
            Missing, invalid, or expired API token, or missing
            write:client_matters permission.
        '403':
          description: Forbidden.
        '429':
          description: >-
            Rate limit exceeded. These endpoints share the client matter rate
            limit, which defaults to 150 requests per minute per workspace.
        '500':
          description: Internal server error.
      security:
        - bearerAuth: []
components:
  schemas:
    UpsertClientsRequest:
      type: object
      required:
        - clients
      properties:
        clients:
          type: array
          minItems: 1
          maxItems: 10000
          items:
            $ref: '#/components/schemas/UpsertClientInput'
    UpsertClientsResponse:
      type: object
      required:
        - created
        - updated
        - errors
      properties:
        created:
          type: array
          items:
            $ref: '#/components/schemas/ClientResult'
        updated:
          type: array
          description: >-
            Includes restored clients and matched clients whose fields did not
            change.
          items:
            $ref: '#/components/schemas/ClientResult'
        errors:
          type: array
          items:
            $ref: '#/components/schemas/ClientError'
    ClientMatterBatchError:
      type: object
      description: Body of a 400 response from `/api/v2/clients` and `/api/v2/matters`.
      required:
        - error
        - detail
      properties:
        error:
          $ref: '#/components/schemas/ClientMatterBatchErrorCode'
        detail:
          type: string
          description: Human-readable explanation.
        validation_errors:
          type: array
          description: Present for `invalid_request`. Field values are never echoed.
          items:
            $ref: '#/components/schemas/ClientMatterFieldError'
    UpsertClientInput:
      type: object
      description: >-
        One client keyed on the firm's client identifier. Omit `client_name` to
        leave the stored label unchanged. Send null or a blank string to clear
        it. Values are stripped.
      required:
        - client_id
      properties:
        client_id:
          type: string
          description: >-
            The firm's client identifier, the upsert key within the workspace.
            Not the Harvey client UUID that `GET /api/v1/client_matters` returns
            in its own `client_id` field. Empty after stripping, or over 128
            characters, fails per row with `invalid_client_id`.
        client_name:
          type: string
          nullable: true
          description: >-
            Friendly label for the client. Over 256 characters fails per row
            with `invalid_client_name`.
    ClientResult:
      type: object
      required:
        - client_id
        - client_name
      properties:
        client_id:
          type: string
          description: The stored, stripped firm client identifier.
        client_name:
          type: string
          nullable: true
          description: The stored label after this request.
    ClientError:
      type: object
      required:
        - client_id
        - error
        - detail
      properties:
        client_id:
          type: string
          description: Echoes the raw request value.
        error:
          $ref: '#/components/schemas/ClientErrorCode'
        detail:
          type: string
          description: Human-readable explanation.
    ClientMatterBatchErrorCode:
      type: string
      description: >-
        Stable code for a rejected request. too_many_items: more than 10,000
        rows. invalid_request: invalid request shape, empty batch, missing
        required field, wrong type, allowed set to null, or a token user that
        cannot be found. delimiter_required: POST /api/v2/matters requires an
        explicit delimiter for the active workspace, but none is configured.
        Other workspaces use `.` when no delimiter is configured. POST
        /api/v2/clients does not emit delimiter_required. Duplicate identifiers
        and length limits on text fields produce per-row errors instead.
      enum:
        - too_many_items
        - invalid_request
        - delimiter_required
    ClientMatterFieldError:
      type: object
      required:
        - loc
        - type
      properties:
        loc:
          type: array
          description: >-
            Path to the offending field. Each entry is a string naming a field
            or an integer indexing an array.
          items: {}
        type:
          type: string
          description: The validation failure kind, for example `missing` or `string_type`.
    ClientErrorCode:
      type: string
      description: >-
        Stable code for a client row that was not stored. `invalid_client_id`:
        `client_id` is empty after stripping or over 128 characters.
        `invalid_client_name`: `client_name` is over 256 characters.
        `duplicate_client_id`: a later entry repeats an earlier `client_id`
        after stripping; the first entry wins.
      enum:
        - invalid_client_id
        - invalid_client_name
        - duplicate_client_id
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: Token

````

## Related topics

- [Upsert Matters](/api-reference/upsert/upsert-matters.md)
- [Get Client Matters](/api-reference/retrieve/get-client-matters.md)
- [Audit Logs](/guides/audit_logs.md)
