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

# Attach Agent Phone Number

> Attach a workspace phone number to a DialNexa agent for inbound or outbound calls.

<span data-api-safety-label="changes-state"><Badge color="yellow" size="sm" shape="pill">Changes state - verify before retry</Badge></span>

Attach an agent phone number to route calls through that agent. Choose `inbound` so the number rings the agent, or `outbound` so the agent can call from it. The link belongs to the agent, not to a version: every version uses it, inbound calls run on the latest published version, and calls and batches pick the version they dial with.

## Before you begin

* Publish at least one version of the agent with [Update Agent](/docs/api-reference/v1/agents/update). An agent with no published version cannot take a number.
* Get the number's `phn_` ID from [List Phone Numbers](/docs/api-reference/v1/phone-numbers/list), [Buy Phone Number](/docs/api-reference/v1/phone-numbers/buy), or [Link SIP Trunk](/docs/api-reference/v1/phone-numbers/link-sip-trunk).
* Check [List Agent Phone Numbers](/docs/api-reference/v1/agents/list-phone-numbers). An agent can have at most three inbound and three outbound numbers.

## Limits

| Rule | Detail |
| - | - |
| Numbers per direction | Up to 3 inbound and 3 outbound numbers per agent. |
| One agent per direction | A number can ring one agent and be dialed from by one agent. The two can be different agents. |
| Default numbers | DialNexa's shared default number cannot be attached for inbound calls. |
| SIP trunk numbers | Not allowed on a Conversational Flow agent whose latest published version has a call transfer node. |

## Attach agent phone number request

```bash theme={null}
curl -X POST "https://api.dialnexa.com/v1/agents/agent_2g7Xy3tY53gRlp/phone-numbers" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "phone_number_id": "phn_abc123",
    "direction": "outbound"
  }'
```

## Verify the result

A `201` response returns the new link in `data`, with `linked_at` set and `unlinked_at` null. Call [List Agent Phone Numbers](/docs/api-reference/v1/agents/list-phone-numbers) to confirm the number appears under the chosen direction. Once an agent has two or more outbound numbers, [Create Call](/docs/api-reference/v1/calls/create) and [Create Batch Call](/docs/api-reference/v1/batches/create) need `phone_number_id` to choose one.

## Errors and recovery

Refusals carry a code in `data.code`.

| Status | Code | Cause and fix |
| - | - | - |
| `400` | `AGENT_NOT_PUBLISHED` | The agent has no published version. Publish one, then retry. |
| `400` | `PHONE_NUMBER_LIMIT_REACHED` | The agent already has 3 numbers in this direction (`data.limit`). Detach one first. |
| `400` | none | The body is invalid, or a SIP trunk number was sent for a Conversational Flow agent with a call transfer node. |
| `403` | `DEFAULT_NUMBER_NOT_ALLOWED_INBOUND` | DialNexa's shared default number was sent with `direction: "inbound"`. Use another number. |
| `404` | none | The agent or the phone number is not in this workspace. |
| `409` | `PHONE_NUMBER_ALREADY_LINKED` | The number is already linked to this agent in this direction. Nothing to do. |
| `409` | `PHONE_NUMBER_LINKED_TO_OTHER_AGENT` | Another agent holds the number in this direction (`data.agent_id`, `data.agent_title`). Detach it from that agent first, or send `move: true` after confirming that it should lose the number. |

If a request times out, list the agent's numbers before retrying. A repeat of a request that succeeded returns `409 PHONE_NUMBER_ALREADY_LINKED` and changes nothing.

## Move a number from another agent

Add `"move": true` to the attach request to move the number in the chosen direction. The old agent loses that direction and the new agent receives it in one transaction. The opposite direction stays unchanged. The old link is closed with `unlink_reason: "manual"`.

Live calls on the number block either direction with `409 PHONE_NUMBER_HAS_LIVE_CALLS`. For an outbound move, unfinished batches return `NUMBER_USED_BY_BATCH` and active workflows return `PHONE_NUMBER_USED_IN_ACTIVE_WORKFLOWS`. Change the affected batches' number or cancel them, pause the affected workflows, and wait for calls to finish before retrying. If the request times out, check both agents' number lists and link history before sending it again.

## Related endpoints

* [List Agent Phone Numbers](/docs/api-reference/v1/agents/list-phone-numbers)
* [Detach Agent Phone Number](/docs/api-reference/v1/agents/detach-phone-number)
* [Get Agent Phone Number History](/docs/api-reference/v1/agents/phone-number-history)
* [Create Call](/docs/api-reference/v1/calls/create)


## OpenAPI

````yaml POST /v1/agents/{agentId}/phone-numbers
openapi: 3.0.0
info:
  title: DialNexa API
  description: Public `/v1` REST API for the DialNexa voice AI platform.
  version: 1.0.0
servers:
  - url: https://api.dialnexa.com
    description: DialNexa production API
security:
  - bearer: []
tags:
  - name: Agents
  - name: Batch Calls
  - name: Calls
  - name: Knowledge Base
  - name: Languages
  - name: LLMs
  - name: Phone Numbers
  - name: Transcribers
  - name: Webhooks
  - name: Voices
  - name: Workflows
  - name: Workflow Leads
  - name: Authentication
  - name: Agent Builder
paths:
  /v1/agents/{agentId}/phone-numbers:
    post:
      tags:
        - Agents
      summary: Attach Agent Phone Number
      description: >-
        Links a workspace phone number to an agent for inbound or outbound
        calls. The agent needs a published version and can have at most 3
        numbers per direction. A number serves one agent per direction. Set move
        to true to detach it from its current agent and attach it here in one
        transaction; live calls, unfinished outbound batches, and active
        outbound workflows can block the move.
      operationId: attachAgentPhoneNumber
      parameters:
        - name: agentId
          in: path
          required: true
          schema:
            example: agent_2g7Xy3tY53gRlp
            type: string
          description: Agent ID from List Agents.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/LinkAgentPhoneNumberRequest'
            examples:
              request:
                value:
                  phone_number_id: phn_abc123
                  direction: outbound
      responses:
        '201':
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  error:
                    type: boolean
                  statusCode:
                    type: integer
                  message:
                    type: string
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                        description: Link record ID.
                      agent_id:
                        example: agent_2g7Xy3tY53gRlp
                        type: string
                      phone_number_id:
                        type: string
                        example: phn_abc123
                      direction:
                        type: string
                        enum:
                          - inbound
                          - outbound
                        description: >-
                          inbound: the number rings this agent. outbound: the
                          agent calls from it.
                      linked_at:
                        type: string
                        format: date-time
                      linked_by:
                        type: string
                        nullable: true
                        description: User who created the link, when known.
                      unlinked_at:
                        type: string
                        format: date-time
                        nullable: true
                        description: Null while the link is current.
                      unlinked_by:
                        type: string
                        nullable: true
                        description: User who ended the link, when known.
                      unlink_reason:
                        type: string
                        nullable: true
                        enum:
                          - manual
                          - agent_deleted
                          - number_deleted
                          - number_released
                        description: >-
                          Why the link ended: manual (detached), agent_deleted,
                          number_deleted, or number_released (the rental expired
                          or the number was withdrawn). Null while the link is
                          current.
                    required:
                      - id
                      - agent_id
                      - phone_number_id
                      - direction
                      - linked_at
                      - unlinked_at
                      - unlink_reason
                  timestamp:
                    type: string
                    format: date-time
                required:
                  - success
                  - error
                  - statusCode
                  - message
                  - data
                  - timestamp
              examples:
                success:
                  value:
                    success: true
                    error: false
                    statusCode: 201
                    message: Success
                    data:
                      id: k2m9q4wz1abcde
                      direction: outbound
                      linked_at: '2026-09-30T06:00:00.000Z'
                      linked_by: null
                      unlinked_at: null
                      unlinked_by: null
                      unlink_reason: null
                      agent_id: agent_2g7Xy3tY53gRlp
                      phone_number_id: phn_abc123
                    timestamp: '2026-09-07T06:00:00.000Z'
        '400':
          description: >-
            The agent has no published version, already has 3 numbers in this
            direction, or the body is invalid. A SIP trunk number is also
            refused for a Conversational Flow agent whose published version has
            a call transfer node.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CodedErrorResponse'
              examples:
                agentNotPublished:
                  value:
                    statusCode: 400
                    error: true
                    success: false
                    data:
                      code: AGENT_NOT_PUBLISHED
                    message: Publish the agent before attaching a phone number.
                    errors: []
                limitReached:
                  value:
                    statusCode: 400
                    error: true
                    success: false
                    data:
                      code: PHONE_NUMBER_LIMIT_REACHED
                      limit: 3
                    message: An agent can have at most 3 outbound numbers.
                    errors: []
                sipTrunkWithCallTransfer:
                  value:
                    statusCode: 400
                    error: true
                    success: false
                    data: []
                    message: >-
                      SIP trunk numbers cannot be used for conversational flow
                      agents that include a call transfer node.
                    errors:
                      - >-
                        SIP trunk numbers cannot be used for conversational flow
                        agents that include a call transfer node.
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                error:
                  value:
                    statusCode: 401
                    error: true
                    success: false
                    data: []
                    message: Invalid API key
                    errors: []
        '403':
          description: DialNexa's shared default number cannot answer inbound calls.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CodedErrorResponse'
              examples:
                defaultNumberInbound:
                  value:
                    statusCode: 403
                    error: true
                    success: false
                    data:
                      code: DEFAULT_NUMBER_NOT_ALLOWED_INBOUND
                    message: A default number cannot be used for inbound calls.
                    errors: []
        '404':
          description: The agent or the phone number is not in this workspace.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CodedErrorResponse'
              examples:
                agentNotFound:
                  value:
                    statusCode: 404
                    error: true
                    success: false
                    data: []
                    message: Agent agent_2g7Xy3tY53gRlp not found in your organization.
                    errors: []
                phoneNumberNotFound:
                  value:
                    statusCode: 404
                    error: true
                    success: false
                    data: []
                    message: Phone number phn_abc123 not found in your organization.
                    errors: []
        '409':
          description: >-
            The number is already linked, or moving it is blocked by calls,
            outbound batches, or outbound workflows.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CodedErrorResponse'
              examples:
                alreadyLinked:
                  value:
                    statusCode: 409
                    error: true
                    success: false
                    data:
                      code: PHONE_NUMBER_ALREADY_LINKED
                    message: >-
                      This number is already linked to this agent for outbound
                      calls.
                    errors: []
                linkedToOtherAgent:
                  value:
                    statusCode: 409
                    error: true
                    success: false
                    data:
                      code: PHONE_NUMBER_LINKED_TO_OTHER_AGENT
                      agent_id: agent_7h2Kq9Lm4Np3Rs
                      agent_title: Collections
                    message: >-
                      This number is linked to Collections for outbound calls.
                      Detach it there first, or send move: true to move it to
                      this agent.
                    errors: []
                usedByBatch:
                  value:
                    statusCode: 409
                    error: true
                    success: false
                    data:
                      code: NUMBER_USED_BY_BATCH
                      batches:
                        - id: batch_abc123
                          title: September renewals
                          status: paused
                      live_calls: 0
                    message: >-
                      1 unfinished batch(es) ("September renewals") and 0 live
                      call(s) use this number. Change the batches' number or
                      cancel them first.
                    errors: []
                liveCalls:
                  value:
                    statusCode: 409
                    error: true
                    success: false
                    data:
                      code: PHONE_NUMBER_HAS_LIVE_CALLS
                      live_calls: 2
                      batches: []
                    message: >-
                      2 call(s) are in progress on this number. Wait for them to
                      finish, then retry.
                    errors: []
                activeWorkflows:
                  value:
                    statusCode: 409
                    error: true
                    success: false
                    data:
                      code: PHONE_NUMBER_USED_IN_ACTIVE_WORKFLOWS
                      affected_workflows:
                        - id: Xy7Kp2mQ9rT4vB
                          title: Lead follow-up
                          status: active
                    message: >-
                      This phone number is used in 1 active workflow(s). Pause
                      those workflows first, then retry.
                    errors: []
      security:
        - bearer: []
components:
  schemas:
    LinkAgentPhoneNumberRequest:
      type: object
      properties:
        phone_number_id:
          type: string
          description: Organization phone number to attach
          example: phn_2g7Xy3tY53gRlp
        direction:
          type: string
          enum:
            - inbound
            - outbound
        move:
          type: boolean
          default: false
          description: >-
            Move the number here when another agent holds it in this direction.
            That agent loses it in the same request, under the same rules as
            detaching it there.
      required:
        - phone_number_id
        - direction
    CodedErrorResponse:
      type: object
      description: Error body for a coded refusal; data carries code and its details.
      properties:
        statusCode:
          type: integer
          example: 404
        error:
          type: boolean
          enum:
            - true
        success:
          type: boolean
          enum:
            - false
        data:
          oneOf:
            - type: object
              properties:
                code:
                  type: string
                  description: Machine-readable refusal code.
            - type: array
              items: {}
          description: >-
            For a coded refusal, an object with code and the details listed for
            that code. Otherwise an empty array.
        message:
          type: string
        errors:
          type: array
          items:
            type: string
          description: Validation messages for a 400. Empty for other errors.
      required:
        - statusCode
        - error
        - success
        - data
        - message
        - errors
    ErrorResponse:
      type: object
      description: Error body on endpoints without response filtering.
      properties:
        statusCode:
          type: integer
          example: 404
        error:
          type: boolean
          enum:
            - true
        success:
          type: boolean
          enum:
            - false
        data:
          oneOf:
            - type: object
              properties:
                code:
                  type: string
                  description: Machine-readable refusal code.
            - type: array
              items: {}
          description: >-
            For a coded refusal, an object with code and the details listed for
            that code. Otherwise an empty array.
        message:
          type: string
        errors:
          type: array
          items:
            type: string
          description: Validation messages for a 400. Empty for other errors.
      required:
        - statusCode
        - error
        - success
        - data
        - message
        - errors
  securitySchemes:
    bearer:
      scheme: bearer
      type: http

````

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