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

# Redeem handoff link

> Consumes a handoff link and returns the contact it was issued for, so the
caller can attach the new conversation to that existing contact instead of
creating a duplicate.

Single-use is enforced atomically: the second call on the same token fails,
even if it arrives concurrently with the first. Expired links fail the same
way — the check is on the stored expiry, not on MongoDB's TTL sweep, which
lags by up to a minute.

Like `ReadSupportTokenController`, this accepts any identity
`useOperatorAuth` recognizes rather than requiring tenant membership: the
usual caller is Talqui Core reacting to an inbound message, authenticating
as a plugin with no operator session of its own.



## OpenAPI

````yaml /api/services-api.yaml post /v1/tenants/{tenantID}/handoff-links/{handoffLinkToken}/redeem
openapi: 3.0.3
info:
  description: >-
    Talqui is an omnichannel customer service platform that unifies
    conversations from WhatsApp, Instagram, Telegram, and many other channels
    into a single attendant panel, alongside a broader ecosystem of plugins and
    integrations. This API gives developers programmatic access to Talqui's
    services layer, exposing the operations needed to read and manage tenants,
    conversations, plugins, and related resources that power that platform.


    Authentication is available on behalf of an Operator (the default for this
    API), a Plugin Connection, or a Plugin — see the [Talqui authentication
    guide](https://docs.talqui.chat/guides/introduction/authentication/) for how
    each token is obtained and when to use it.


    Need help or have questions not covered here? Reach out to
    support@talqui.com.
  license:
    name: ISC
    url: https://opensource.org/license/isc-license-txt
  title: Talqui - Services API
  version: 0.65.0
servers:
  - description: Production
    url: https://services-api.talqui.chat
security: []
tags:
  - name: Tenants
  - name: Settings
  - name: Analytics
  - name: Campaigns
  - name: Campaigns models
  - name: Contacts
  - name: Handoff links
  - name: Inboxes
  - name: Messages
  - name: Notifications
  - name: Sessions
  - name: Operators
  - name: Plugins
  - name: Setup
  - name: Uploads
paths:
  /v1/tenants/{tenantID}/handoff-links/{handoffLinkToken}/redeem:
    post:
      tags:
        - Handoff links
      summary: Redeem handoff link
      description: >-
        Consumes a handoff link and returns the contact it was issued for, so
        the

        caller can attach the new conversation to that existing contact instead
        of

        creating a duplicate.


        Single-use is enforced atomically: the second call on the same token
        fails,

        even if it arrives concurrently with the first. Expired links fail the
        same

        way — the check is on the stored expiry, not on MongoDB's TTL sweep,
        which

        lags by up to a minute.


        Like `ReadSupportTokenController`, this accepts any identity

        `useOperatorAuth` recognizes rather than requiring tenant membership:
        the

        usual caller is Talqui Core reacting to an inbound message,
        authenticating

        as a plugin with no operator session of its own.
      operationId: RedeemHandoffLinkController
      parameters:
        - in: path
          name: tenantID
          required: true
          schema:
            description: The tenant that owns the handoff link.
            format: uuid
            pattern: >-
              ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
            type: string
        - in: path
          name: handoffLinkToken
          required: true
          schema:
            description: The single-use token carried by the link.
            minLength: 1
            type: string
      requestBody:
        content:
          application/json:
            schema:
              properties:
                usedByContactID:
                  description: Contact the destination channel resolved.
                  minLength: 1
                  nullable: true
                  type: string
                usedSessionID:
                  description: Session opened on the destination channel.
                  minLength: 1
                  nullable: true
                  type: string
              type: object
        required: true
      responses:
        '200':
          content:
            application/json:
              schema:
                additionalProperties: false
                properties:
                  handoffLink:
                    additionalProperties: false
                    properties:
                      contactID:
                        description: >-
                          The contact this link re-identifies on the destination
                          channel.
                        type: string
                      createdAt:
                        description: When the link was issued.
                        format: date-time
                        type: string
                      expiresAt:
                        description: >-
                          Instant after which the link can no longer be
                          redeemed.
                        format: date-time
                        type: string
                      handoffLinkID:
                        description: Unique identifier for this handoff link (UUIDv7).
                        type: string
                      handoffLinkToken:
                        description: Single-use bearer token carried by the generated URL.
                        type: string
                      handoffLinkURL:
                        description: >-
                          The channel-specific URL the contact opens to continue
                          elsewhere.
                        type: string
                      sourceChannel:
                        description: Channel URN the contact is currently talking on.
                        nullable: true
                        type: string
                      sourceSessionID:
                        description: The session the handoff was generated from.
                        type: string
                      status:
                        description: PENDING until redeemed; USED is terminal.
                        enum:
                          - PENDING
                          - USED
                        type: string
                      targetChannel:
                        description: Channel URN the contact is being sent to.
                        type: string
                      targetPluginConnectionID:
                        description: The destination plugin connection the link points at.
                        type: string
                      tenantID:
                        description: The tenant this link belongs to.
                        type: string
                      updatedAt:
                        description: When the link was last modified.
                        format: date-time
                        type: string
                      usedAt:
                        description: When the link was redeemed, if it was.
                        format: date-time
                        nullable: true
                        type: string
                      usedByContactID:
                        description: Contact the destination channel saw at redemption.
                        nullable: true
                        type: string
                      usedSessionID:
                        description: >-
                          Session created on the destination channel at
                          redemption.
                        nullable: true
                        type: string
                    required:
                      - handoffLinkID
                      - handoffLinkToken
                      - handoffLinkURL
                      - tenantID
                      - contactID
                      - sourceSessionID
                      - sourceChannel
                      - targetChannel
                      - targetPluginConnectionID
                      - status
                      - usedAt
                      - usedSessionID
                      - usedByContactID
                      - expiresAt
                      - createdAt
                      - updatedAt
                    type: object
                required:
                  - handoffLink
                type: object
          description: Response for status 200.
        '400':
          content:
            application/json:
              schema:
                properties:
                  errors:
                    items:
                      oneOf:
                        - $ref: '#/components/schemas/MissingTenantIDError'
                        - $ref: '#/components/schemas/RequestValidationError'
                    maxItems: 1
                    minItems: 1
                    type: array
                required:
                  - errors
                type: object
          description: >-
            MissingTenantIDError (error_code 1001): tenantID absent from the
            URL. | RequestValidationError (error_code 1002): params or body fail
            schema validation.
        '401':
          content:
            application/json:
              schema:
                properties:
                  errors:
                    items:
                      $ref: '#/components/schemas/UnauthorizedError'
                    maxItems: 1
                    minItems: 1
                    type: array
                required:
                  - errors
                type: object
          description: >-
            UnauthorizedError (error_code 1003): missing/invalid operator or
            plugin token.
        '403':
          content:
            application/json:
              schema:
                properties:
                  errors:
                    items:
                      $ref: '#/components/schemas/ForbiddenError'
                    maxItems: 1
                    minItems: 1
                    type: array
                required:
                  - errors
                type: object
          description: 'ForbiddenError (error_code 1004): token rejected upstream.'
        '409':
          content:
            application/json:
              schema:
                properties:
                  errors:
                    items:
                      $ref: '#/components/schemas/HandoffLinkNotRedeemableError'
                    maxItems: 1
                    minItems: 1
                    type: array
                required:
                  - errors
                type: object
          description: >-
            HandoffLinkNotRedeemableError (error_code 1601): token unknown,
            already redeemed, or expired.
        '500':
          content:
            application/json:
              schema:
                properties:
                  errors:
                    items:
                      $ref: '#/components/schemas/UnknownError'
                    maxItems: 1
                    minItems: 1
                    type: array
                required:
                  - errors
                type: object
          description: >-
            UnknownError (error_code 5999): Unexpected internal error not
            otherwise documented for this endpoint.
components:
  schemas:
    MissingTenantIDError:
      additionalProperties: false
      properties:
        error:
          enum:
            - MissingTenantIDError
          type: string
        error_code:
          enum:
            - 1001
          type: number
        message:
          example: tenantID is required.
          type: string
        statusCode:
          enum:
            - 400
          type: number
      required:
        - statusCode
        - error
        - error_code
        - message
      type: object
    RequestValidationError:
      additionalProperties: false
      properties:
        error:
          enum:
            - RequestValidationError
          type: string
        error_code:
          enum:
            - 1002
          type: number
        fields:
          items:
            additionalProperties: false
            properties:
              allowed:
                type: string
              field:
                type: string
              received:
                type: string
            required:
              - field
              - received
              - allowed
            type: object
          type: array
        message:
          example: Invalid request data.
          type: string
        statusCode:
          enum:
            - 400
          type: number
      required:
        - statusCode
        - error
        - error_code
        - message
        - fields
      type: object
    UnauthorizedError:
      additionalProperties: false
      properties:
        error:
          enum:
            - UnauthorizedError
          type: string
        error_code:
          enum:
            - 1003
          type: number
        message:
          example: You are not authorized to perform this request.
          type: string
        statusCode:
          enum:
            - 401
          type: number
      required:
        - statusCode
        - error
        - error_code
        - message
      type: object
    ForbiddenError:
      additionalProperties: false
      properties:
        error:
          enum:
            - ForbiddenError
          type: string
        error_code:
          enum:
            - 1004
          type: number
        message:
          example: You do not have access to this resource.
          type: string
        statusCode:
          enum:
            - 403
          type: number
      required:
        - statusCode
        - error
        - error_code
        - message
      type: object
    HandoffLinkNotRedeemableError:
      additionalProperties: false
      properties:
        error:
          enum:
            - HandoffLinkNotRedeemableError
          type: string
        error_code:
          enum:
            - 1601
          type: number
        message:
          example: This handoff link has already been used or has expired.
          type: string
        statusCode:
          enum:
            - 409
          type: number
      required:
        - statusCode
        - error
        - error_code
        - message
      type: object
    UnknownError:
      additionalProperties: false
      properties:
        error:
          enum:
            - UnknownError
          type: string
        error_code:
          enum:
            - 5999
          type: number
        message:
          example: For some unknown reason your request has not succeeded.
          type: string
        statusCode:
          enum:
            - 500
          type: number
      required:
        - statusCode
        - error
        - error_code
        - message
      type: object

````

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