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

# Start Phone Pairing

> Start linking a WhatsApp number by phone pairing code.



## OpenAPI

````yaml post /whatsapp_accounts/phone_pairing
openapi: 3.0.3
info:
  title: Timelines Public API
  description: >
    # Timelines Public API


    _Some API calls may utilize message sending quota or be subject to message
    sending rate limits as described below._


    ### Credit Utilization 
      - Sending a message via API consumes 1 credit from message sending quota.
      - Sending a message with non-empty text and attachment consumes 2 credits from message sending quota.
      - If a message cannot be sent (invalid or not connected to WhatsApp number, WhatsApp server error), message sending quota will be restored (usually within a couple of hours).
    ### Message sending rate
      - Messages will be sent with random delay of about 2 seconds between each two messages (to avoid WhatsApp spam detection mechanisms). Contact support@timelines.ai if you want to modify delay for your workspace (available on Business plan only).
      - If you exceed message sending frequency, messages be queued and sent out with delay. Each queued message will consume a message sending credit, so the number of queued messages cannot exceed the available quota.
      
    ### Authorization:
      - Copy API token from [Public API page](https://app.timelines.ai/integrations/api/) in your TimelinesAI account.
      - Put the token in *Authorization* header of request as follows:
      ```
      Authorization: Bearer 4d2d0239-e28c-4f4a-8a4d-3a3ca40056b8
      ```
            
    ### Message formatting:
      - use "\n" for line breaks

    ### Input strings:
      - String fields must not contain the NUL character (U+0000).
  version: 1.3.0
servers:
  - url: https://app.timelines.ai/integrations/api
    description: Public API root URL
security:
  - bearerAuth: []
paths:
  /whatsapp_accounts/phone_pairing:
    post:
      summary: Start linking a WhatsApp number by phone pairing code.
      description: >
        Starts linking a WhatsApp number to a workspace member with a pairing
        code instead of a QR scan. The response comes back before WhatsApp
        issues the code, usually in state `starting`; poll `GET
        /whatsapp_accounts/phone_pairing/{id}` until the state is
        `awaiting_code`, then the member enters `pairing_code` in WhatsApp
        (Linked devices → Link with phone number). Requires the `accounts:write`
        scope.


        **Who the link is for**


        - User-scoped token: `user_id` is optional. Omitted, or equal to the
        token's user, the link belongs to that user. A caller whose role can
        manage members may pass another member's `user_id`, and the link belongs
        to that member; a caller without that permission gets `403`
        `permission_denied`.

        - Legacy workspace token: `user_id` is required, and the link belongs to
        that active member.

        - The member's role must be able to connect WhatsApp accounts, as in the
        web app; a collaborator gets `403` `permission_denied`.


        **Repeated calls**


        While the member's link for the same `phone`, started with this call, is
        still `starting` or `awaiting_code` and less than a day old, another
        call returns that link (same `id`, current state and code) instead of
        starting a new one, so the call is safe to retry. If that link reads
        `code_unavailable`, the call ends it and starts a new link with a new
        `id`, and the old `id` keeps reading `code_unavailable`. A link a day
        old, which the status read no longer finds, is replaced the same way.
        Such a link for a different `phone` is replaced too, so a stuck link
        never blocks the member. A link the member started from the web app is
        not returned: the call is refused with
        `member_has_phone_link_in_progress` until that link ends.


        A WABA account on the same phone does not block the link: WABA and QR
        numbers each need their own free seat, and the same phone may be both.


        **Errors**


        `message` is the `error_code` with spaces instead of underscores. Checks
        run in this order and the first one that fails is returned:


        | Order | `error_code` | HTTP | `message` | When |

        |---|---|---|---|---|

        | 1 | `validation_error` | 400 | `validation error` | `user_id` is not
        an integer |

        | 2 | `user_id_required` | 400 | `user id required` | Legacy workspace
        token without `user_id` |

        | 3 | `permission_denied` | 403 | `permission denied` | Another member's
        `user_id` from a caller who cannot manage members |

        | 4 | `member_not_found` | 404 | `member not found` | `user_id` is not
        an active member of this workspace |

        | 5 | `permission_denied` | 403 | `permission denied` | The member's
        role cannot connect WhatsApp accounts |

        | 6 | `validation_error` | 400 | `validation error` | `phone` is missing
        or not a valid phone number |

        | 7 | `account_already_connected` | 400 | `account already connected` |
        A WhatsApp (QR) account in this workspace is already connected on this
        phone |

        | 8 | `member_has_connected_account` | 400 | `member has connected
        account` | The member already has a different connected number |

        | 9 | `member_has_phone_link_in_progress` | 400 | `member has phone link
        in progress` | The member is already linking a different phone (a link
        still `starting` or `awaiting_code`), or this phone from the web app |

        | 10 | `number_pairing_in_progress` | 403 | `number pairing in progress`
        | Another member is already linking this phone |

        | 11 | `member_has_qr_connection_in_progress` | 400 | `member has qr
        connection in progress` | The member has a QR connection in progress |

        | 12 | `number_not_allowed` | 403 | `number not allowed` | This phone is
        not allowed to be linked with TimelinesAI |

        | 13 | `connected_accounts_limit_reached` | 403 | `connected accounts
        limit reached` | Connected accounts and links in progress fill the
        workspace seats |


        A link the member already started with this call for the same `phone` is
        returned before checks 7–13. A new link that replaces one goes through
        every check, with the old link's seat counted as free; a refused call
        leaves the old link as it was.


        Some refusals can only be made once the phone has accepted the code.
        Such a link reads `failed`, and its `message` says why; see
        `PhoneLinkStatus.message`.
      requestBody:
        description: The phone to link and, optionally, the member it is for.
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PhonePairingRequest'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PhonePairingResponse'
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '403':
          $ref: '#/components/responses/AccessDenied'
        '404':
          $ref: '#/components/responses/NotFound'
components:
  schemas:
    PhonePairingRequest:
      type: object
      required:
        - phone
      properties:
        phone:
          type: string
          description: The WhatsApp phone number to link, in international format.
          example: '+972501234567'
        user_id:
          type: integer
          description: >
            The member the link is for: the integer `user_id` from GET
            /workspace/teammates, the same id as DELETE
            /workspace/invitations/{user_id}. Optional on a user-scoped token,
            required on a legacy workspace token.
          example: 42
    PhonePairingResponse:
      type: object
      required:
        - status
        - data
      properties:
        status:
          type: string
          example: ok
          enum:
            - ok
            - error
        data:
          $ref: '#/components/schemas/PhoneLinkStatus'
    PhoneLinkStatus:
      type: object
      required:
        - id
        - phone
        - state
        - pairing_code
        - whatsapp_account_id
        - message
      properties:
        id:
          type: integer
          description: The link id, used to read its status.
          example: 1234
        phone:
          type: string
          description: The phone being linked.
          example: '+972501234567'
        state:
          $ref: '#/components/schemas/PhoneLinkState'
        pairing_code:
          type: string
          description: >
            The code to enter in WhatsApp: 8 characters, no hyphen, may contain
            letters. The same code is returned on every read. Empty string
            outside `awaiting_code`.
          example: K7Q2M9XA
        whatsapp_account_id:
          type: string
          description: >
            The linked account, in the same WID form as `id` on GET
            /whatsapp_accounts. Empty string unless the state is `connected`.
          example: 972501234567@s.whatsapp.net
        message:
          type: string
          description: >
            Why the link failed, when the state is `failed`: `banned`, `logged
            out from another device`, `logged out from Timelines`, or `other`
            for any reason not named. After the phone accepted the code, the
            link may still be refused: `number_not_allowed` (the phone is not
            allowed to be linked with TimelinesAI),
            `number_used_by_another_trial` (the phone was linked to another
            trial workspace), or `connected_accounts_limit_reached` (the
            workspace seats filled up meanwhile). Empty string in every other
            state.
          example: ''
    ErrorResponse:
      required:
        - message
        - status
      type: object
      properties:
        message:
          type: string
        status:
          type: string
          example: error
          enum:
            - ok
            - error
        error_code:
          type: string
          description: >-
            Stable, machine-readable error code. Use this for branching in
            client integrations.
          example: validation_error
          enum:
            - missing_credentials
            - invalid_token
            - member_not_found
            - permission_denied
            - insufficient_scope
            - plan_feature_unavailable
            - quota_exceeded
            - rate_limit_exceeded
            - validation_error
            - not_found
            - account_inactive
            - template_not_approved
            - template_wrong_waba
            - template_variables_mismatch
            - service_window_closed
            - not_supported
            - internal_error
            - account_already_connected
            - member_has_connected_account
            - member_has_phone_link_in_progress
            - number_pairing_in_progress
            - member_has_qr_connection_in_progress
            - connected_accounts_limit_reached
            - user_id_required
            - number_not_allowed
        errors:
          type: array
          description: >-
            Per-field validation diagnostics for request-schema (body/params)
            validation failures. Present only when the request failed schema
            validation; absent on business-rule `validation_error` rejections
            (which carry `message` and `error_code` only) and on
            auth/authorization/quota errors.
          items:
            $ref: '#/components/schemas/ValidationError'
    PhoneLinkState:
      type: string
      enum:
        - starting
        - awaiting_code
        - connected
        - expired
        - code_unavailable
        - failed
      description: >
        `starting` — WhatsApp has not issued the code yet; read the status
        again. `awaiting_code` — the member enters `pairing_code` in WhatsApp;
        right after the code is entered, while the connection completes,
        `pairing_code` is empty. `connected` — the number is linked, see
        `whatsapp_account_id`. `expired` — the code was issued but not entered
        in time; offer a new code with a new POST
        /whatsapp_accounts/phone_pairing. `code_unavailable` — WhatsApp never
        issued a code; start again with a new POST
        /whatsapp_accounts/phone_pairing. The member has nothing to fix.
        `failed` — WhatsApp refused the attempt, the link did not connect, or a
        link that connected was later logged out or banned; `message` says why.
        Do not retry automatically.
      example: awaiting_code
    ValidationError:
      type: object
      required:
        - fields
        - msg
      properties:
        fields:
          type: array
          items:
            type: string
          description: >-
            Path of the offending field, as a list of keys/indexes from the
            request root.
          example:
            - url
        msg:
          type: string
          description: Validator message for that field.
          example: must be a valid http(s) URL
  responses:
    BadRequestError:
      description: Invalid parameters
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    UnauthorizedError:
      description: Access token is missing or invalid
    AccessDenied:
      description: Access denied
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    NotFound:
      description: Specified entities not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer

````

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