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

# Create a contact

> Creates a person from a CPF or a company from a CNPJ. QX looks up the CPF or the CNPJ after the creation, and the `lookup_status` shows the progress of the lookup. The creation counts toward the paid write limit of the key.



## OpenAPI

````yaml /en/openapi.yaml post /contacts
openapi: 3.1.0
info:
  title: QX API
  version: 1.0.0
  description: >-
    The QX API creates and reads the contacts, the collections and the documents
    of the organization, and it lists the packs.

    Each call carries the API key of the organization.


    The API sends each error in the RFC 9457 format
    (`application/problem+json`), with a stable `code`.

    In addition to the errors of each endpoint, any path under `/api/v1` can
    return these errors:


    - `404` with `route_not_found`: the API does not have the path, or the path
    does not accept the HTTP method.

    - `405` with `method_not_allowed`: the API does not recognize the HTTP
    method.

    - `406` with `not_acceptable`: the API does not recognize the `Content-Type`
    or the `Accept` of the call.

    - another `4xx` status with `request_refused`: the API could not complete
    the call.

    - a `5xx` status with `internal_error`: QX had an internal error.
servers:
  - url: https://app.useqx.com/api/v1
    description: Production
security:
  - bearerAuth: []
tags:
  - name: Collections
    description: >-
      The collections of the organization. A collection asks the contact for the
      documents of a pack.
  - name: Contacts
    description: >-
      The people and the companies of the organization. A person has a CPF, and
      a company has a CNPJ.
  - name: Documents
    description: >-
      The documents of the organization. A document sent without a collection
      goes to Triage. A document sent with a collection fills the slot of its
      type.
  - name: Packs
    description: The packs of the organization and the requirements of each pack.
paths:
  /contacts:
    post:
      tags:
        - Contacts
      summary: Create a contact
      description: >-
        Creates a person from a CPF or a company from a CNPJ. QX looks up the
        CPF or the CNPJ after the creation, and the `lookup_status` shows the
        progress of the lookup. The creation counts toward the paid write limit
        of the key.
      operationId: createContact
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ContactInput'
            examples:
              company:
                summary: A company from a CNPJ
                value:
                  tax_id: 12.345.678/0001-95
                  email: fiscal@importadora.com.br
                  name: Importadora Exemplo Ltda
              person:
                summary: A person from a CPF, without a name
                value:
                  tax_id: 529.982.247-25
                  email: maria.souza@exemplo.com.br
      responses:
        '201':
          description: The new contact.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Contact'
              examples:
                company:
                  summary: The new company, with the CNPJ lookup in progress
                  value:
                    id: com_12
                    type: company
                    name: Importadora Exemplo Ltda
                    trade_name: null
                    email: fiscal@importadora.com.br
                    tax_id: '12345678000195'
                    lookup_status: pending
                    discarded: false
                    origin: contact
                    created_at: '2026-09-25T10:30:00.000-03:00'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '402':
          $ref: '#/components/responses/PaymentRequired'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          description: >-
            The organization already has a contact with this CPF or CNPJ, and
            the `contact` field contains that contact. The contact can be
            archived, or it can be a shareholder that the CNPJ lookup created.
            The API also returns `409` when another call with the same
            `Idempotency-Key` is still in progress.
          content:
            application/problem+json:
              schema:
                anyOf:
                  - $ref: '#/components/schemas/ContactExistsProblem'
                  - $ref: '#/components/schemas/IdempotencyKeyInUseProblem'
              examples:
                contact_exists:
                  summary: The organization already has a contact with this CNPJ
                  value:
                    type: about:blank
                    title: Conflict
                    status: 409
                    detail: >-
                      The organization already has a contact with this CPF or
                      CNPJ. The contact field contains that contact.
                    code: contact_exists
                    contact:
                      id: com_12
                      type: company
                      name: Importadora Exemplo Ltda
                      trade_name: Exemplo
                      email: fiscal@importadora.com.br
                      tax_id: '12345678000195'
                      lookup_status: completed
                      discarded: false
                      origin: contact
                      created_at: '2026-09-25T10:30:00.000-03:00'
                idempotency_key_in_use:
                  $ref: '#/components/examples/IdempotencyKeyInUse'
        '422':
          description: >-
            A field has an error, and the `errors` list gives the error of each
            field. The API also returns `422` when the `Idempotency-Key` already
            served a call with different content.
          content:
            application/problem+json:
              schema:
                anyOf:
                  - $ref: '#/components/schemas/ValidationProblem'
                  - $ref: '#/components/schemas/IdempotencyKeyReusedProblem'
              examples:
                validation_failed:
                  summary: The CPF or the CNPJ is not valid
                  value:
                    type: about:blank
                    title: Unprocessable Content
                    status: 422
                    detail: >-
                      One or more fields have an error. The errors list gives
                      the error of each field.
                    code: validation_failed
                    errors:
                      - field: tax_id
                        code: invalid
                        message: The value is not a valid CPF and not a valid CNPJ.
                idempotency_key_reused:
                  $ref: '#/components/examples/IdempotencyKeyReused'
        '429':
          $ref: '#/components/responses/TooManyRequests'
components:
  parameters:
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: false
      description: >-
        A unique value that your system creates for each write, such as a UUID.
        A repeated call with the same value and the same content gets the first
        response, and the API writes nothing new. The API keeps the response for
        24 hours.
      schema:
        type: string
        minLength: 1
        maxLength: 255
      example: 5f0c7e8a-3a1b-4d2e-9c61-2b7f4e0d9a13
  schemas:
    ContactInput:
      type: object
      additionalProperties: false
      required:
        - tax_id
        - email
      properties:
        tax_id:
          type: string
          description: >-
            The CPF of the person or the CNPJ of the company, with or without
            punctuation. A CNPJ can have letters in the first twelve positions.
            The value decides the type of the contact.
          examples:
            - 12.345.678/0001-95
        email:
          type: string
          format: email
          description: The email of the contact.
          examples:
            - fiscal@importadora.com.br
        name:
          type: string
          description: >-
            The name of the contact. Without a name, the contact gets the name
            that the CPF or CNPJ lookup returns.
          examples:
            - Importadora Exemplo Ltda
    Contact:
      type: object
      additionalProperties: false
      required:
        - id
        - type
        - name
        - trade_name
        - email
        - tax_id
        - lookup_status
        - discarded
        - origin
        - created_at
      properties:
        id:
          type: string
          pattern: ^(per|com)_[1-9][0-9]*$
          description: >-
            The id of the contact. A person id starts with `per_`, and a company
            id starts with `com_`.
          examples:
            - com_12
        type:
          type: string
          enum:
            - person
            - company
          description: '`person` for a person and `company` for a company.'
        name:
          type:
            - string
            - 'null'
          description: >-
            The name of the contact. The value is `null` until the CPF or CNPJ
            lookup returns the name.
          examples:
            - Importadora Exemplo Ltda
        trade_name:
          type:
            - string
            - 'null'
          description: The trade name of the company. On a person, the value is `null`.
          examples:
            - Exemplo
        email:
          type:
            - string
            - 'null'
          description: The email of the contact, in lowercase.
          examples:
            - fiscal@importadora.com.br
        tax_id:
          type:
            - string
            - 'null'
          description: >-
            The CPF of the person or the CNPJ of the company, without
            punctuation and with uppercase letters. The value is `null` on a
            person who waits for the CPF confirmation.
          examples:
            - '12345678000195'
        lookup_status:
          type: string
          enum:
            - not_enqueued
            - pending
            - completed
            - failed
            - stale
            - needs_review
          description: >-
            The progress of the CPF or CNPJ lookup. `not_enqueued`: the lookup
            did not start. `pending`: the lookup is in progress. `completed`:
            the lookup ended. `failed`: the lookup failed. `stale`: the lookup
            data is old. `needs_review`: the person waits for the CPF
            confirmation.
        discarded:
          type: boolean
          description: With `true`, the contact is archived.
        origin:
          type: string
          enum:
            - contact
            - shareholder
          description: >-
            `contact` for a contact that the organization created. `shareholder`
            for a shareholder that the CNPJ lookup created.
        created_at:
          type: string
          format: date-time
          description: >-
            The date and the time of the creation, in the time zone of the
            organization.
          examples:
            - '2026-09-25T10:30:00.000-03:00'
    ContactExistsProblem:
      description: The organization already has a contact with this CPF or CNPJ.
      allOf:
        - $ref: '#/components/schemas/Problem'
        - type: object
          required:
            - contact
          properties:
            code:
              enum:
                - contact_exists
            contact:
              $ref: '#/components/schemas/Contact'
    IdempotencyKeyInUseProblem:
      description: Another call with the same `Idempotency-Key` is still in progress.
      allOf:
        - $ref: '#/components/schemas/Problem'
        - type: object
          properties:
            code:
              enum:
                - idempotency_key_in_use
    ValidationProblem:
      description: A validation error. The `errors` list gives the error of each field.
      allOf:
        - $ref: '#/components/schemas/Problem'
        - type: object
          required:
            - errors
          properties:
            code:
              enum:
                - validation_failed
            errors:
              type: array
              items:
                $ref: '#/components/schemas/FieldError'
    IdempotencyKeyReusedProblem:
      description: The `Idempotency-Key` already served a call with different content.
      allOf:
        - $ref: '#/components/schemas/Problem'
        - type: object
          properties:
            code:
              enum:
                - idempotency_key_reused
    Problem:
      type: object
      description: An error in the RFC 9457 format.
      required:
        - type
        - title
        - status
        - detail
        - code
      properties:
        type:
          type: string
          const: about:blank
          description: Always `about:blank`.
        title:
          type: string
          description: The phrase of the HTTP status, in English.
          examples:
            - Unauthorized
        status:
          type: integer
          description: The HTTP status.
          examples:
            - 401
        detail:
          type: string
          description: >-
            The explanation of the error, in the language of the organization.
            An answer that leaves before the key identifies the organization
            stays in Portuguese.
        code:
          type: string
          description: >-
            The error code, in English. The code does not change between
            versions of v1.
    FieldError:
      type: object
      additionalProperties: false
      required:
        - field
        - code
        - message
      properties:
        field:
          type: string
          description: The name of the field with the error.
        code:
          type: string
          description: The error code of the field, in English.
        message:
          type: string
          description: >-
            The explanation of the field error, in the language of the
            organization.
  responses:
    BadRequest:
      description: >-
        The API refused the call. The `code` gives the reason:


        - `invalid_parameter`: a parameter is missing or has an invalid value.

        - `malformed_request`: the API could not read the call. Examples of
        causes:
          - the path or the query has an invalid encoding;
          - the query repeats a parameter in different forms, such as `limit=1&limit[]=2`;
          - the body is not valid JSON;
          - the address in the `Client-IP` header is not in the `X-Forwarded-For` header.
      content:
        application/problem+json:
          schema:
            allOf:
              - $ref: '#/components/schemas/Problem'
              - type: object
                properties:
                  code:
                    enum:
                      - invalid_parameter
                      - malformed_request
          examples:
            invalid_parameter:
              summary: The limit is above 100
              value:
                type: about:blank
                title: Bad Request
                status: 400
                detail: The limit parameter has an invalid value.
                code: invalid_parameter
            malformed_request:
              $ref: '#/components/examples/MalformedRequest'
    Unauthorized:
      description: The key is missing, does not exist or is revoked.
      headers:
        WWW-Authenticate:
          $ref: '#/components/headers/WwwAuthenticate'
      content:
        application/problem+json:
          schema:
            allOf:
              - $ref: '#/components/schemas/Problem'
              - type: object
                properties:
                  code:
                    enum:
                      - unauthorized
          examples:
            unauthorized:
              summary: The key is missing or not valid
              value:
                type: about:blank
                title: Unauthorized
                status: 401
                detail: >-
                  The call did not include a valid API key. Send the key in the
                  Authorization header, in the format Bearer <key>.
                code: unauthorized
    PaymentRequired:
      description: The subscription of the organization is blocked.
      content:
        application/problem+json:
          schema:
            allOf:
              - $ref: '#/components/schemas/Problem'
              - type: object
                properties:
                  code:
                    enum:
                      - subscription_blocked
          examples:
            subscription_blocked:
              summary: The subscription is blocked
              value:
                type: about:blank
                title: Payment Required
                status: 402
                detail: >-
                  The subscription of the organization is blocked. Settle the
                  payment in QX to use the API.
                code: subscription_blocked
    Forbidden:
      description: >-
        The organization is archived, or the plan of the organization does not
        include the API.
      content:
        application/problem+json:
          schema:
            allOf:
              - $ref: '#/components/schemas/Problem'
              - type: object
                properties:
                  code:
                    enum:
                      - organization_archived
                      - plan_required
          examples:
            plan_required:
              summary: The free plan does not include the API
              value:
                type: about:blank
                title: Forbidden
                status: 403
                detail: >-
                  The free plan does not include the API. Subscribe to a paid
                  plan in QX to use the API.
                code: plan_required
    TooManyRequests:
      description: The key or the IP address went over a limit.
      headers:
        Retry-After:
          $ref: '#/components/headers/RetryAfter'
      content:
        application/problem+json:
          schema:
            allOf:
              - $ref: '#/components/schemas/Problem'
              - type: object
                properties:
                  code:
                    enum:
                      - rate_limited
                      - daily_limit_reached
                      - too_many_invalid_keys
          examples:
            rate_limited:
              summary: The key went over the per-minute limit
              value:
                type: about:blank
                title: Too Many Requests
                status: 429
                detail: >-
                  The key went over a per-minute limit. Wait for the seconds in
                  the Retry-After header and call again.
                code: rate_limited
  examples:
    IdempotencyKeyInUse:
      summary: Another call with the same Idempotency-Key is in progress
      value:
        type: about:blank
        title: Conflict
        status: 409
        detail: >-
          Another call with this Idempotency-Key is still in progress. Wait for
          that call to end and call again.
        code: idempotency_key_in_use
    IdempotencyKeyReused:
      summary: The Idempotency-Key already served another call
      value:
        type: about:blank
        title: Unprocessable Content
        status: 422
        detail: >-
          This Idempotency-Key already served a call with different content. Use
          a new value for the new call.
        code: idempotency_key_reused
    MalformedRequest:
      summary: The API could not read the call
      value:
        type: about:blank
        title: Bad Request
        status: 400
        detail: >-
          The API could not read the call. Check the shape and the encoding of
          the path and the query, the JSON of the body and the headers.
        code: malformed_request
  headers:
    WwwAuthenticate:
      description: The authentication scheme that the API expects.
      required: true
      schema:
        type: string
      example: Bearer realm="QX API"
    RetryAfter:
      description: The seconds to wait before the next call.
      required: true
      schema:
        type: integer
        minimum: 1
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        The API key of the organization, in the `Authorization: Bearer <key>`
        header. The key starts with `qx_`.

````