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

# Import a historical conversation

> Create one historical conversation and all supplied messages atomically. Requires cxm:conversations.write. References an existing contact (or anonymous) and optional existing organization, without updating either. No messages, AI turns, routing or notifications are activated during import. Waits for one search-indexing attempt after commit. Indexing failure returns 201 with the created ID and IndexingFailed; an existing projection returns IndexingConflict without replacing it. A known disabled indexer rejects with 503 before creation. There is no append, merge, upsert or transcript continuation. Import shares the conversation-write rate group. Search may retain only the latest 500 messages and public history applies size/redaction limits, so neither is a lossless export verifier. Requires the matching tenant API-key write scope or broader scope. Maximum JSON request body: 1 MiB, subject to a lower configured gateway limit. Unknown fields are rejected. Each accepted request executes; no idempotency or replay guarantee. A timeout may occur after commit.



## OpenAPI

````yaml /api-reference/openapi-v1.json post /api/v1/cxm/tenants/{tenantId}/conversations/import
openapi: 3.1.0
info:
  title: Crescendo CXP API
  version: 1.0.0
  description: >-
    Use the Customer Experience Platform API from trusted server-side
    applications to create Contacts and Organizations, import historical
    Conversations, create live Conversations, read projected detail and stored
    history, update operational fields, assign work, and add internal notes.
    Writes execute independently; repeating a write may repeat its effects.
servers:
  - url: https://platform.crescendo.ai
    description: Production
security: []
tags:
  - name: Conversations
    description: Create, import, continue, and manage customer conversations.
  - name: Contacts
    description: Create contacts for backend integrations and historical imports.
  - name: Organizations
    description: Create organizations for historical conversation references.
paths:
  /api/v1/cxm/tenants/{tenantId}/conversations/import:
    post:
      tags:
        - Conversations
      summary: Import a historical conversation
      description: >-
        Create one historical conversation and all supplied messages atomically.
        Requires cxm:conversations.write. References an existing contact (or
        anonymous) and optional existing organization, without updating either.
        No messages, AI turns, routing or notifications are activated during
        import. Waits for one search-indexing attempt after commit. Indexing
        failure returns 201 with the created ID and IndexingFailed; an existing
        projection returns IndexingConflict without replacing it. A known
        disabled indexer rejects with 503 before creation. There is no append,
        merge, upsert or transcript continuation. Import shares the
        conversation-write rate group. Search may retain only the latest 500
        messages and public history applies size/redaction limits, so neither is
        a lossless export verifier. Requires the matching tenant API-key write
        scope or broader scope. Maximum JSON request body: 1 MiB, subject to a
        lower configured gateway limit. Unknown fields are rejected. Each
        accepted request executes; no idempotency or replay guarantee. A timeout
        may occur after commit.
      operationId: importConversation
      parameters:
        - name: tenantId
          in: path
          required: true
          description: Tenant authorized for the API key and every referenced resource.
          schema:
            type: string
            minLength: 1
            maxLength: 255
          example: tenant_demo
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ImportConversationRequest'
            example:
              contact:
                contactId: external-contact-123
              organization:
                organizationId: external-org-123
              conversation:
                id: external-conversation-456
                subject: Replacement received
                status: closed
                created_at: '2026-10-18T10:00:00Z'
                closed_at: '2026-10-20T14:00:00Z'
                channel: email
                messages:
                  - channel: email
                    role: user
                    content: The replacement arrived. Thank you.
                    created_at: '2026-10-20T12:00:00Z'
                    author_id: external-contact-123
                    author_name: Jane Doe
                  - channel: email
                    role: agent
                    content: Glad to hear it arrived.
                    created_at: '2026-10-20T13:00:00Z'
                    author_id: former-agent-7
                    author_name: Sam
      responses:
        '201':
          description: >-
            Conversation and all supplied messages created. Optional warnings
            report unsuccessful search indexing after the successful commit.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ImportConversationResponse'
              examples:
                created:
                  value:
                    conversation:
                      conversationId: external-conversation-456
                      result: created
                      contactId: external-contact-123
                      status: closed
                      messageCount: 2
                indexingFailed:
                  value:
                    conversation:
                      conversationId: external-conversation-456
                      result: created
                      contactId: external-contact-123
                      status: closed
                      messageCount: 2
                    warnings:
                      - code: IndexingFailed
                        message: Conversation was created, but search indexing failed
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthenticated'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          description: >-
            A referenced resource is absent or ineligible in the authorized
            tenant.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                contact:
                  value:
                    code: ContactNotFound
                    message: Contact not found
                organization:
                  value:
                    code: OrganizationNotFound
                    message: Organization not found
                team:
                  value:
                    code: TeamNotFound
                    message: Team not found
        '409':
          description: A supplied ID or identity conflicts with existing tenant data.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                id:
                  value:
                    code: ConversationIdConflict
                    message: Conversation ID already exists
                    existingConversationId: external-conversation-456
                contactReadOnly:
                  value:
                    code: ContactReadOnly
                    message: Contact is read-only
                team:
                  value:
                    code: TeamAmbiguous
                    message: Team name is ambiguous
        '413':
          $ref: '#/components/responses/PayloadTooLarge'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'
        '502':
          $ref: '#/components/responses/BadGateway'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
        '504':
          $ref: '#/components/responses/GatewayTimeout'
      security:
        - BearerApiKey: []
components:
  schemas:
    ImportConversationRequest:
      type: object
      additionalProperties: false
      required:
        - contact
        - conversation
      properties:
        contact:
          $ref: '#/components/schemas/ImportContactReference'
        organization:
          allOf:
            - $ref: '#/components/schemas/ImportOrganizationReference'
          description: >-
            Omission inherits the contact organization, or no organization for
            anonymous.
        conversation:
          $ref: '#/components/schemas/ImportConversationInput'
    ImportConversationResponse:
      type: object
      additionalProperties: false
      required:
        - conversation
      properties:
        conversation:
          type: object
          additionalProperties: false
          required:
            - conversationId
            - result
            - contactId
            - status
            - messageCount
          properties:
            conversationId:
              type: string
              minLength: 1
              maxLength: 255
            result:
              type: string
              const: created
            contactId:
              type: string
              minLength: 1
              maxLength: 255
            status:
              type: string
              enum:
                - open
                - pending
                - resolved
                - closed
            messageCount:
              type: integer
              minimum: 0
              maximum: 1000
        warnings:
          type: array
          items:
            $ref: '#/components/schemas/ImportConversationWarning'
    Error:
      type: object
      additionalProperties: false
      required:
        - code
        - message
      properties:
        code:
          type: string
          enum:
            - BadRequest
            - InvalidCustomField
            - Unauthenticated
            - PermissionDenied
            - EmailChannelNotFound
            - AssigneeNotFound
            - NotFound
            - EmailChannelDisabled
            - ContactIdentityConflict
            - OrganizationAmbiguous
            - AssigneeAmbiguous
            - Conflict
            - PayloadTooLarge
            - RateLimitExceeded
            - BadGateway
            - ServiceUnavailable
            - GatewayTimeout
            - ContactIdConflict
            - OrganizationIdConflict
            - ConversationIdConflict
            - ContactNotFound
            - OrganizationNotFound
            - ContactReadOnly
            - TeamNotFound
            - TeamAmbiguous
        message:
          type: string
        existingContactId:
          type: string
          minLength: 1
          maxLength: 255
          description: >-
            One blocking record ID in a corresponding create/import conflict
            response. It does not establish that an earlier request had the same
            payload.
        existingOrganizationId:
          type: string
          minLength: 1
          maxLength: 255
          description: >-
            One blocking record ID in a corresponding create/import conflict
            response. It does not establish that an earlier request had the same
            payload.
        existingConversationId:
          type: string
          minLength: 1
          maxLength: 255
          description: >-
            One blocking record ID in a corresponding create/import conflict
            response. It does not establish that an earlier request had the same
            payload.
    ImportContactReference:
      type: object
      additionalProperties: false
      required:
        - contactId
      properties:
        contactId:
          type: string
          minLength: 1
          maxLength: 255
          description: >-
            Existing tenant contact ID, or literal anonymous. No contact updates
            are applied.
    ImportOrganizationReference:
      type: object
      additionalProperties: false
      required:
        - organizationId
      properties:
        organizationId:
          type: string
          minLength: 1
          maxLength: 255
          description: >-
            Existing tenant organization ID. Import does not create an
            organization or change the contact association.
    ImportConversationInput:
      type: object
      additionalProperties: false
      required:
        - created_at
        - messages
      properties:
        id:
          type: string
          minLength: 1
          maxLength: 255
          description: >-
            Optional external ID, up to 255 characters before normalization.
            Every ASCII colon (:) is removed; for example, external:123 becomes
            external123. The supplied value cannot contain whitespace, control
            characters, /, backslash, %, ? or #. After colon removal the ID must
            be nonempty, cannot equal `.` or `..`, and cannot be uppercase CX or
            AA followed only by decimal digits (including zero/leading-zero
            forms). Use the returned normalized ID for subsequent requests and
            source-to-CXP mappings. IDs differing only by colons conflict with
            the same existing ID. Omission allocates a native CX ID. External
            IDs do not support native Agent Assist child IDs. Contact and
            Organization IDs are not normalized this way.
          pattern: ^(?!\.{1,2}$)[^\s\u0000-\u001F\u007F-\u009F/\\%?#]+$
          not:
            pattern: ^(?:CX|AA)[0-9]+$
        subject:
          type: string
          minLength: 1
          maxLength: 255
          description: >-
            Omission defaults to Message from followed by contact email, phone,
            display name or Anonymous, in that order.
        assignee:
          allOf:
            - $ref: '#/components/schemas/AssigneeInput'
          description: >-
            Current eligible agent or team assignment. Omission leaves
            unassigned. Historical message authors are independent; import does
            not activate routing or AI.
        team:
          allOf:
            - $ref: '#/components/schemas/ImportTeamInput'
          description: >-
            Current eligible team. Defaults to team assignee ID, otherwise
            unset. An explicit team must agree with a team assignee; an agent
            can have a separate team association.
        priority:
          type: string
          enum:
            - low
            - normal
            - high
            - urgent
          default: normal
        tags:
          type: array
          maxItems: 50
          items:
            type: string
            minLength: 1
            maxLength: 100
          description: Case-insensitive deduplication; whitespace-only values are invalid.
        customFields:
          type: object
          maxProperties: 100
          additionalProperties: true
          description: >-
            Configured conversation custom field values, validated and committed
            with the conversation and messages.
        status:
          type: string
          enum:
            - open
            - pending
            - resolved
            - closed
          default: closed
          description: >-
            Pending reason/time fields are not accepted. Later activity can
            reuse non-closed conversations; closed conversations may be
            explicitly reopened.
        created_at:
          type: string
          format: date-time
          description: >-
            RFC 3339 timestamp with explicit timezone, no later than now.
            Normalized to UTC at millisecond precision.
        updated_at:
          type: string
          format: date-time
          description: >-
            RFC 3339 timestamp with explicit timezone, no later than now.
            Normalized to UTC at millisecond precision. Defaults to the latest
            creation, lifecycle or message time; an explicit value must be at
            least all those times.
        resolved_at:
          type: string
          format: date-time
          description: >-
            RFC 3339 timestamp with explicit timezone, no later than now.
            Normalized to UTC at millisecond precision. Optional known history,
            no earlier than creation. Omission remains unknown even for resolved
            status.
        closed_at:
          type: string
          format: date-time
          description: >-
            RFC 3339 timestamp with explicit timezone, no later than now.
            Normalized to UTC at millisecond precision. Optional known history,
            no earlier than creation. Omission remains unknown even for closed
            status. No universal order relative to resolved_at is required.
        channel:
          type: string
          enum:
            - chat
            - voice
            - email
            - sms
            - web_chat
            - phone_call
            - web_audio
            - social
            - whatsapp
            - in_app
            - api
            - unknown
          description: >-
            Historical label only; omission leaves unset. Does not create a
            provider delivery connection.
        messages:
          type: array
          maxItems: 1000
          items:
            $ref: '#/components/schemas/ImportMessageInput'
          description: >-
            Required, possibly empty transcript. All messages commit together,
            with stable timestamp/input ordering in stored history. The whole
            request must fit 1 MiB; there is no continuation upload.
    ImportConversationWarning:
      type: object
      additionalProperties: false
      required:
        - code
        - message
      properties:
        code:
          type: string
          enum:
            - IndexingFailed
            - IndexingConflict
        message:
          type: string
      description: >-
        The conversation is already created. Search/detail may remain missing or
        stale. Record the warning for indexing repair; do not retry the import
        merely to repair indexing.
    AssigneeInput:
      type: object
      additionalProperties: false
      required:
        - type
      oneOf:
        - required:
            - id
          not:
            required:
              - name
        - required:
            - name
          not:
            required:
              - id
      properties:
        type:
          type: string
          enum:
            - agent
            - team
        id:
          type: string
          minLength: 1
          maxLength: 255
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: Exact normalized active agent or team name.
    ImportTeamInput:
      type: object
      additionalProperties: false
      properties:
        teamId:
          type: string
          minLength: 1
          maxLength: 255
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: Exact normalized eligible team name.
      oneOf:
        - required:
            - teamId
          not:
            required:
              - name
        - required:
            - name
          not:
            required:
              - teamId
    ImportMessageInput:
      type: object
      additionalProperties: false
      required:
        - content
        - created_at
        - role
      properties:
        content:
          type: string
          minLength: 1
          maxLength: 100000
          description: Required nonblank plain text, preserved after validation.
        created_at:
          type: string
          format: date-time
          description: >-
            RFC 3339 timestamp with explicit timezone, no later than now.
            Normalized to UTC at millisecond precision. Must not precede
            conversation.created_at.
        role:
          type: string
          enum:
            - user
            - agent
            - assistant
            - system
        channel:
          type: string
          enum:
            - chat
            - voice
            - email
            - sms
            - web_chat
            - phone_call
            - web_audio
            - social
            - whatsapp
            - in_app
            - api
            - unknown
          default: chat
          description: Defaults independently of the parent conversation channel.
        media:
          type: string
          enum:
            - chat
            - email
            - voice
          description: >-
            Defaults to email for email; voice for voice, phone_call or
            web_audio; chat otherwise. Historical voice content is
            transcript-only.
        author_id:
          type: string
          minLength: 1
          maxLength: 255
          description: Opaque historical author ID; no current-user lookup.
        author_name:
          type: string
          minLength: 1
          maxLength: 255
          description: Historical author display-name snapshot.
        visibility:
          type: string
          enum:
            - public
            - internal
          default: public
          description: >-
            Internal hides the message from customers, but does not exclude
            authorized history readers or AI processing.
      description: >-
        Each array entry creates a distinct message, including identical
        entries. Source message IDs, arbitrary metadata, attachments and
        provider interactions are not accepted.
  responses:
    BadRequest:
      description: The body, a field, an unknown property, or a custom field is invalid.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: BadRequest
            message: message.text is required
    Unauthenticated:
      description: The API key is missing, invalid, or expired.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: Unauthenticated
            message: Authentication required
    PermissionDenied:
      description: The API key does not authorize the tenant or required scope.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: PermissionDenied
            message: API key does not allow this operation
    PayloadTooLarge:
      description: >-
        The request exceeds the endpoint body limit or a lower configured
        gateway limit.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: PayloadTooLarge
            message: CXM API request body must not exceed 1048576 bytes
    RateLimitExceeded:
      description: The tenant/API-key/route limit was exceeded.
      headers:
        Retry-After:
          description: Seconds to wait before another request.
          schema:
            type: integer
            minimum: 1
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: RateLimitExceeded
            message: CXM API rate limit exceeded
    BadGateway:
      description: >-
        The gateway could not complete downstream transport. The durable
        mutation outcome may be unknown.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: BadGateway
            message: CXM API downstream request failed
    ServiceUnavailable:
      description: A required service or durable/configuration dependency is unavailable.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: ServiceUnavailable
            message: CXM API is temporarily unavailable
    GatewayTimeout:
      description: >-
        The gateway timed out. The durable mutation outcome may be unknown, and
        retrying can duplicate effects.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: GatewayTimeout
            message: CXM API downstream request timed out
  securitySchemes:
    BearerApiKey:
      type: http
      scheme: bearer
      description: >-
        Tenant API key with the operation's scope: `cxm:conversations.read`,
        `cxm:conversations.write`, `cxm:contacts.write`, or
        `cxm:organizations.write`. Corresponding resource wildcards and broader
        `cxm:read`, `cxm:write`, or `cxm:*` scopes apply. Keep it in a trusted
        backend; do not expose it in browser code.

````

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