Quickstart Number Porting

Workflow Steps:

In this guide, you'll learn how to create and submit a port request using Porting V2 API commands. Just follow these simple steps:

  1. Check portability of your telephone numbers
  2. Create a draft Porting Order
  3. View allowable FOC dates
  4. Submit relevant supporting documents
  5. Update your Porting Order
  6. Confirm and submit your Porting Order

Miscellaneous:

This guide will also show you some of the other capabilities of the Porting V2 API, including:

  • Document links
  • Setup webhook URL for eligible port-in events
  • Documentation Requirements for International Porting Orders
  • Retrieving phone numbers of a particular Porting Order
  • Cancelling a Porting Order

Step 1: Check Portability

First, use the following command to check whether your numbers are portable into Telnyx.

curl --location --request POST 'https://api.telnyx.com/v2/portability_checks' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer [REDACTED]' \
--data-raw '{
    "phone_numbers": [
        "+13125552486",
        "+12125558724"
    ]
}'

Response:

{
    "data": [
        {
            "fast_portable": true,
            "not_portable_reason": null,
            "phone_number": "+12125558724",
            "portable": true,
            "record_type": "portability_check_result"
        },
        {
            "fast_portable": true,
            "not_portable_reason": null,
            "phone_number": "+13125552486",
            "portable": true,
            "record_type": "portability_check_result"
        }
    ]
}

In the response, you will get back a list of portable and nonportable numbers. Proceeding to Step 2 with nonportable numbers will result in 4xx errors.

Step 2: Create a Draft Porting Order

Next, you can create your draft port order using the following command.

curl --location --request POST 'https://api.telnyx.com/v2/porting_orders' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer [REDACTED]' \
--data-raw '{
"phone_numbers": [
        "+16785554405"
    ]
}'

If you create a draft port order with multiple numbers, it is possible that the numbers will be split into multiple port orders. If this occurs, you will need to update and submit each draft port order individually. Numbers are split based on the following criteria:

  • Country
  • Number type
  • SPID (for US/CA numbers)
  • If the number is eligible for FastPort

Step 3: View Allowable FOC Dates

Using the following command, you will be able to see the allowed FOC dates for your port order. You will later be asked to submit one of these dates using the foc_datetime_requested field when completing your Porting Order.

curl --location --request GET 'https://api.telnyx.com/v2/porting_orders/d25fed86-1f15-4f29-a0c0-ec923b18ee46/allowed_foc_windows' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer [REDACTED]'

Step 4: Submit Relevant Supporting Documents

At a minimum, you will need to attach a Letter of Authorization (LOA) and Invoice to your Porting Order. Before doing so, you first need to upload those documents and retrieve their document id.

You can easily upload your documents as a multipart, as shown below

curl --location --request POST 'https://api.telnyx.com/v2/documents' \
--header 'Content-Type: multipart/form-data' \
--header 'Authorization: Bearer [REDACTED]' \
--form '[email protected]/Users/xd/Downloads/threads-bugs.pdf'

Step 5: Update your Porting Order

At this point, you should have all the necessary info you need to complete a Porting Order. To simplify things, we are going to break this down into two steps.

Part 1

First, you can update your Port Order with the required general information.

curl --location --request PATCH 'https://api.telnyx.com/v2/porting_orders/d25fed86-1f15-4f29-a0c0-ec923b18ee46' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer [REDACTED]' \
--data-raw '{
    "misc": {
        "type": "full",
        "remaining_numbers_action": null,
        "new_billing_phone_number": null
    },
    "end_user": {
        "admin": {
            "entity_name": "Telnyx",
            "auth_person_name": "John Doe",
            "billing_phone_number": "+1 I am not valid",
            "account_number": "1",
            "tax_identifier": "",
            "pin_passcode": "",
            "business_identifier": ""
        },
        "location": {
            "street_address": "311 W Superior St",
            "extended_address": "Suite 504",
            "locality": "Chicago",
            "administrative_area": "IL",
            "postal_code": "60654",
            "country_code": "US"
        }
    },
    "activation_settings": {
        "foc_datetime_requested": "2021-04-25T13:39:42Z"
    },
    "phone_number_configuration": {
        "connection_id": "",
        "message_profile_id": "",
        "emergency_address_id": "",
        "tags": [
            "culpa quis",
            "consectetur"
        ]
    },
    "user_feedback": {
        "user_rating": 60324306,
        "user_comment": "aliqua eu cillum ea"
    },
    "webhook_url": "https://example.com/9c4ac3ce-43d8-4a3f-bcdc-2831747c7105",
    "user_reference": "test"
}'

Part 2

Second, you can attach those documents that you submitted earlier in Step 4

curl --location --request PATCH 'https://api.telnyx.com/v2/porting_orders/d25fed86-1f15-4f29-a0c0-ec923b18ee46' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer [REDACTED]' \
--data-raw '{
    "documents": {
        "loa": "64ffb720-04c7-455b-92d6-20fcca92e935",
        "invoice": "ce74b771-d23d-4960-81ec-8741b3862146"
    }
}'

If during either of these steps any fields you submit are invalid, the PATCH request will not be successful. In the example below, the API responds with 422

curl --location --request PATCH 'https://api.telnyx.com/v2/porting_orders/e0fcd703-efec-48cb-b5ed-a6dbd56354e9' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer [REDACTED]' \
--data-raw '{
    "misc": {
        "type": "full",
        "remaining_numbers_action": null,
        "new_billing_phone_number": null
    },
    "end_user": {
        "admin": {
            "entity_name": "Telnyx",
            "auth_person_name": "X.D. Zhai",
            "billing_phone_number": "+1 I am not valid",
            "account_number": "1",
            "tax_identifier": "",
            "pin_passcode": "",
            "business_identifier": ""
        },
        "location": {
            "street_address": "311 W Superior St",
            "extended_address": "Suite 504",
            "locality": "Chicago",
            "administrative_area": "IL",
            "postal_code": "60654",
            "country_code": "US"
        }
    },
    "activation_settings": {
        "foc_datetime_requested": "2020-11-06T13:39:42Z"
    },
    "phone_number_configuration": {
        "connection_id": "",
        "message_profile_id": "",
        "emergency_address_id": "",
        "tags": [
            "culpa quis",
            "consectetur"
        ]
    },
    "documents": {
        "loa": "64ffb720-04c7-455b-92d6-20fcca92e935",
        "invoice": "ce74b771-d23d-4960-81ec-8741b3862146"
    },
    "user_feedback": {
        "user_rating": "",
        "user_comment": ""
    },
    "webhook_url": "https://example.com/4f141040-3bab-410b-8cec-9551a8195882",
    "customer_reference": "1-alpha-2-bravo-3-charlie"
}'

Response:

{
    "errors": [
        {
            "detail": "The 'billing_phone_number' parameter must be valid.",
            "source": {
                "pointer": "/billing_phone_number"
            },
            "title": "Invalid billing_phone_number"
        }
}

Step 6: Confirm and Submit your Porting Order

If you are satisfied with your porting order, you can execute the command below to submit it. If successful, the porting order will transition from a "draft" status to an "in-process" status

curl --location --request POST 'https://api.telnyx.com/v2/porting_orders/d25fed86-1f15-4f29-a0c0-ec923b18ee46/actions/confirm' \
--header 'Authorization: Bearer [REDACTED]'

And that's it! You just successfully submitted a port request!


Documents have owners and you can see what particular resource owns the a document

curl --location --request GET 'https://api.telnyx.com/v2/document_links?page[number]=1&page[size]=20&filter[document_id]=65573c68-2913-42a1-b7d7-cba0385bdde0' \
--header 'Authorization: Bearer [REDACTED]'

Response:

{
    "data": [
        {
            "created_at": "2020-10-27T16:04:33Z",
            "document_id": "65573c68-2913-42a1-b7d7-cba0385bdde0",
            "id": "a7b42a18-b33b-43fc-8e50-362032854f4c",
            "linked_record_type": "porting_order",
            "linked_resource_id": "a158957f-3a28-4348-ba62-f70d13f68dae",
            "record_type": "document_link",
            "updated_at": "2021-03-27T16:04:33Z"
        }
    ],
    "meta": {
        "page_number": 1,
        "page_size": 20,
        "total_pages": 1,
        "total_results": 1
    }
}

You also have options to filter documents by the owning resource ID

curl --location -g --request GET 'https://api.telnyx.com/v2/document_links?filter[linked_resource_id]=becb019f-af6a-48c1-980a-f0a856e84db7' \
--header 'Authorization: Bearer [REDACTED]'

Response:

{
    "data": [
        {
            "created_at": "2020-12-28T21:04:42Z",
            "document_id": "8c643671-62f8-4445-8e1e-5348b2165468",
            "id": "308da510-74d8-4a11-9ab4-ebddf5aa2e26",
            "linked_record_type": "porting_order",
            "linked_resource_id": "becb019f-af6a-48c1-980a-f0a856e84db7",
            "record_type": "document_link",
            "updated_at": "2021-03-28T21:04:42Z"
        },
        {
            "created_at": "2020-12-28T21:04:42Z",
            "document_id": "8c643671-62f8-4445-8e1e-5348b2165468",
            "id": "779b2570-0bc3-4ad3-beef-14a0f5a610cc",
            "linked_record_type": "porting_order",
            "linked_resource_id": "becb019f-af6a-48c1-980a-f0a856e84db7",
            "record_type": "document_link",
            "updated_at": "2021-03-28T21:04:42Z"
        }
    ],
    "meta": {
        "page_number": 1,
        "page_size": 20,
        "total_pages": 1,
        "total_results": 2
    }
}

Misc: Setup Webhook URL for Eligible Port-In Events

Users can add a webhook url as the field value for the "webhook_url" parameter in the port order form. In doing so, the user will be opting in to receive port in notifications on their order. This will include notifications for port order status changes, new comments, and porting order splits. In the following section, examples of webhooks for all possible events are shown.

Transition to "submitted" status

{
  "data": {
    "event_type": "porting_order.status_changed",
    "id": "12ae614e-ed37-4a19-9fe3-2b69bf33d429",
    "occurred_at": "2021-01-19T19:52:13.874635Z",
    "payload": {
      "customer_reference": "1-alpha-2-bravo-3-charlie",
      "id": "3594c6c3-51a7-4306-b715-ca3765f13464",
      "status": {
        "details": [],
        "value": "submitted"
      },
      "support_key": "sr_98f022",
      "updated_at": "2021-03-19T19:52:13+00:00",
      "webhook_url": "https://example.com/porting_webhooks"
    },
    "record_type": "event"
  },
  "meta": {
    "attempt": 1,
    "delivered_to": "https://example.com/porting_webhooks"
  }
}

Transition to "exception" status

A Porting Order can have multiple underlying Exception reasons. When resolved, Porting Order re-enters Submitted state. The webhook will be the same as the previous section.

{
  "data": {
    "event_type": "porting_order.status_changed",
    "id": "72322cb3-b6c6-46a4-a571-21a759c02da0",
    "occurred_at": "2021-01-19T19:51:37.844234Z",
    "payload": {
      "customer_reference": "1-alpha-2-bravo-3-charlie",
      "id": "3594c6c3-51a7-4306-b715-ca3765f13464",
      "status": {
        "details": [
          {
            "code": "ACCOUNT_NUMBER_MISMATCH",
            "description": "Account number does not match that on the CSR"
          },
          {
            "code": "PORTING_ORDER_SPLIT_REQUIRED",
            "description": "The OSP requires this Porting Order to be split map_exception_detail and submitted as separate orders"
          },
          {
            "code": "LOA_ILLEGIBLE",
            "description": "The LOA is illegible"
          }
        ],
        "value": "exception"
      },
      "support_key": "sr_98f022",
      "updated_at": "2021-03-19T19:51:37+00:00",
      "webhook_url": "https://example.com/porting_webhooks"
    },
    "record_type": "event"
  },
  "meta": {
    "attempt": 1,
    "delivered_to": "https://example.com/porting_webhooks"
  }
}

Transition to "foc-date-confirmed" status

{
  "data": {
    "event_type": "porting_order.status_changed",
    "id": "80227461-b684-4e89-a1a9-5055a2b4d8ef",
    "occurred_at": "2021-03-19T19:48:58.261079Z",
    "payload": {
      "customer_reference": "1-alpha-2-bravo-3-charlie",
      "id": "3594c6c3-51a7-4306-b715-ca3765f13464",
      "status": {
        "details": [],
        "value": "foc-date-confirmed"
      },
      "support_key": "sr_98f022",
      "updated_at": "2021-03-19T19:48:57+00:00",
      "webhook_url": "https://example.com/porting_webhooks"
    },
    "record_type": "event"
  },
  "meta": {
    "attempt": 1,
    "delivered_to": "https://example.com/porting_webhooks"
  }
}

Transition to "ported" status

{
  "data": {
    "event_type": "porting_order.status_changed",
    "id": "334e12a2-a016-489e-a2b6-7abb46637327",
    "occurred_at": "2021-03-19T19:48:58.261079Z",
    "payload": {
      "customer_reference": "1-alpha-2-bravo-3-charlie",
      "id": "3594c6c3-51a7-4306-b715-ca3765f13464",
      "status": {
        "details": [],
        "value": "ported"
      },
      "support_key": "sr_98f022",
      "updated_at": "2021-03-19T19:48:57+00:00",
      "webhook_url": "https://example.com/porting_webhooks"
    },
    "record_type": "event"
  },
  "meta": {
    "attempt": 1,
    "delivered_to": "https://example.com/porting_webhooks"
  }
}

Transition to "cancel-pending" status

{
  "data": {
    "event_type": "porting_order.status_changed",
    "id": "4f0c225d-3892-4e0e-9524-7625dfc20b19",
    "occurred_at": "2022-04-11T15:50:53.869432Z",
    "payload": {
      "customer_reference": "Test1234",
      "id": "f17074cb-72ee-48b4-bb45-64894e756f01",
      "status": {
        "details": [],
        "value": "cancel-pending"
      },
      "support_key": "sr_602ae7",
      "updated_at": "2022-04-11T15:50:52+00:00",
      "webhook_url": "https://example.com/porting_webhooks"
    },
    "record_type": "event"
  },
  "meta": {
    "attempt": 1,
    "delivered_to": "https://example.com/porting_webhooks"
  }
}

Transition to "cancelled"

{
  "data": {
    "event_type": "porting_order.status_changed",
    "id": "6cac3a83-dc30-45a9-ab51-32e1882f4d04",
    "occurred_at": "2022-04-11T15:52:52.596025Z",
    "payload": {
      "customer_reference": "Test1234",
      "id": "f17074cb-72ee-48b4-bb45-64894e756f01",
      "status": {
        "details": [],
        "value": "cancelled"
      },
      "support_key": "sr_602ae7",
      "updated_at": "2022-04-11T15:52:47+00:00",
      "webhook_url": "https://example.com/porting_webhooks"
    },
    "record_type": "event"
  },
  "meta": {
    "attempt": 1,
    "delivered_to": "https://example.com/porting_webhooks"
  }
}

New Comment

{
  "data": {
    "event_type": "porting_order.new_comment",
    "id": "6cafaed2-05f4-4791-9bcf-2392a0c912ef",
    "occurred_at": "2021-11-04T17:37:43.145988Z",
    "payload": {
      "comment": {
        "body": "Testing Webhooks 123",
        "id": "ca4b9cf6-d840-4ba9-ba38-95f4bc971164",
        "inserted_at": "2021-11-04T17:37:42Z",
        "user_id": null,
        "user_type": "admin"
      },
      "porting_order_id": "b3d55519-25c8-4af4-a50a-c92a9ddf7da4",
      "support_key": "sr_acdabe"
    },
    "record_type": "event"
  },
  "meta": {
    "attempt": 1,
    "delivered_to": "https://example.com/porting_webhooks"
  }
}

Split port order event notification. You will receive one webhook for each number that is split from one port order and added to another. For example, if you originally submitted a port order with 5 numbers, and 3 numbers were split away from the original port order, then you would receive 3 split port order event notifications.

{
  "data": {
    "event_type": "porting_order.split",
    "id": "a98be460-2d1e-42b7-8c0d-d516c352efd2",
    "occurred_at": "2021-11-15T19:37:37.131727Z",
    "payload": {
      "from": {
        "id": "a6efe074-0a3a-4522-8512-d0e004cf6c7d"
      },
      "to": {
        "id": "ef245340-da3d-4212-8769-1fa7672a675f"
      }
    },
    "record_type": "event"
  },
  "meta": {
    "attempt": 1,
    "delivered_to": "https://example.com/porting_webhooks"
  }
}

Misc: Documentation Requirement for International Porting Orders

For international porting orders, please note the field requirements

{
   "requirements": [
       {
          "field_type": "document",
          "field_value": null,
          "record_type": "porting_requirement",
          "requirement_id": "53970723-fbff-4f46-a975-f62be6c1a585" 
       },
       {  
          "field_type": "document",
          "field_value": null,
          "record_type": "porting_requirement",
          "requirement_type_id": "9b32e1a4-df3a-4462-9a90-5bb40de34c24"
       }
    ],

}

The requirement can be obtained by

curl --location --request GET
'https://api.telnyx.com/v2/requirement_types/53970723-fbff-4f46-a975-f62be6c1a585' \
--header 'Authorization: Bearer [Redacted]' \

Response:

{
    "data": {
        "acceptance_criteria": {
            "locality_limit": null,
            "time_limit": "90 days"
        },
        "created_at": "2021-05-03T13:23:37Z",
        "description": "A copy of the latest phone bill from the current provider",
        "example": "Most recent phone bill",
        "id": "53970723-fbff-4f46-a975-f62be6c1a585",
        "name": "Latest Invoice",
        "record_type": "requirement_type",
        "type": "document",
        "updated_at": "2021-05-26T10:20:15Z"
    }
}

To associate a submitted document to a requirement, issue the following command specifying the document ID as the field_value.

curl --location --request PATCH 'https://api.telnyx.com/v2/porting_orders/53970723-fbff-4f46-a975-f62be6c1a585' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer [REDACTED]' \
--data-raw '{
    "requirements": [
      {   
          "requirement_type_id": "53970723-fbff-4f46-a975-f62be6c1a585",
          "field_value": "64ffb720-04c7-455b-92d6-20fcca92e935"
      },
      {   
          "requirement_type_id": "88bba197-6d2a-4f7a-ac6a-54976585b79e",
          "field_value": "9b32e1a4-df3a-4462-9a90-5bb40de34c24"
       }
    ],
}'

Misc: Retrieving Phone Numbers for a Specific Porting Order

Use the /porting_phone_numbers endpoint to retrieve all of the phone numbers in a Porting Order.

curl --location --request GET 'https://api.telnyx.com/v2/porting_phone_numbers?page[number]=1&page[size]=20&filter[porting_order_id]=a158957f-3a28-4348-ba62-f70d13f68dae' \
--header 'Authorization: Bearer [REDACTED]'
{
    "data": [
        {
            "activation_status": null,
            "phone_number": "+13129457420",
            "portability_status": "confirmed",
            "porting_order_id": "a158957f-3a28-4348-ba62-f70d13f68dae"
        }
    ],
    "meta": {
        "page_number": 1,
        "page_size": 20,
        "total_pages": 1,
        "total_results": 1
    }
}

Misc: Cancelling a Porting Order

If you decide that you want to cancel your port order, then you can use the following command to do so. This will transition the port order into a "cancel-pending" status

curl --location --request POST 'https://api.telnyx.com/v2/porting_orders/[porting_order_id]/actions/cancel' \
--header 'Authorization: Bearer [REDACTED]'

Afterwards, you can expect the following webhook:

{
  "data": {
    "event_type": "porting_order.status_changed",
    "id": "73f31498-030a-44a2-9331-0d4cb3a7a766",
    "occurred_at": "2021-03-19T19:49:19.406853Z",
    "payload": {
      "customer_reference": "1-alpha-2-bravo-3-charlie",
      "id": "3594c6c3-51a7-4306-b715-ca3765f13464",
      "status": {
        "details": [],
        "value": "cancel-pending"
      },
      "support_key": "sr_98f022",
      "updated_at": "2021-01-19T19:49:18+00:00",
      "webhook_url": "https://example.com/c49bf044-2ab6-46ee-a148-f8eb40afbd78"
    },
    "record_type": "event"
  },
  "meta": {
    "attempt": 1,
    "delivered_to": "https://example.com/c49bf044-2ab6-46ee-a148-f8eb40afbd78"
  }
}

The Porting Order will remain in a "cancel-pending" status until Porting Ops reviews and cancels the order. When that happens, the Porting Order will transition into a "cancelled" status and you will receive the following webhook:

{
  "data": {
    "event_type": "porting_order.status_changed",
    "id": "f0700172-d201-41f7-8be0-f3c08019432f",
    "occurred_at": "2021-03-19T19:55:54.357004Z",
    "payload": {
      "customer_reference": "1-alpha-2-bravo-3-charlie",
      "id": "3594c6c3-51a7-4306-b715-ca3765f13464",
      "status": {
        "details": [],
        "value": "cancelled"
      },
      "support_key": "sr_98f022",
      "updated_at": "2021-03-19T19:55:53+00:00",
      "webhook_url": "https://example.com/c49bf044-2ab6-46ee-a148-f8eb40afbd78"
    },
    "record_type": "event"
  },
  "meta": {
    "attempt": 1,
    "delivered_to": "https://example.com/c49bf044-2ab6-46ee-a148-f8eb40afbd78"
  }
}
Was this page helpful?