Skip to main content

Stand Alone Non-NANP Port-Ins (BETA)

Bandwidth supports Stand Alone Non-NANP Port-Ins for numbers in the following countries:

  • United Kingdom (GBR)
  • Germany (DEU)
  • France (FRA)
  • Italy (ITA)
  • Spain (ESP)
  • Belgium (BEL)
  • Ireland (IRL)
  • Portugal (PRT)

This article will cover the process for submitting a Stand Alone Non-NANP Port-In request.

Overview

The /portins API is used to create and manage a single port-in order for a set of telephone numbers that are portable and can be ported together.

In general, numbers can be ported together if they meet the following criteria:

  • They are located in the same country
  • They are hosted by the same losing carrier
  • They are all the same type of number (geographic, national, mobile, etc.)

High Level Steps

To create and manage a port-in, these are the basic steps:

Prerequisites

  1. Create a Requirements Package for the port-in. This may or may not be required, depending on the country and the type of numbers being ported.
  2. Create a Voice Configuration Package for the port-in. Voice Configuration Packages are a bundle of voice features that will be provisioned when the port-in completes. Voice Configuration Packages are required if your account has the Voice Configurations feature.
  3. Create an address for the port-in. This is the address of the end-user or business.
  4. Find your losing carrier by referring to the using the losing carriers API.
  5. Find your porting document requirements by referring to the porting document requirements API.

Submitting the Port-in

  1. Create the port-in order, possibly in DRAFT state.
  2. Upload one or more porting documents.
  3. Submit the port-in order.
  4. Monitor the port-in order status.
  5. Optionally add notes to the order to communicate with Bandwidth.

The remainder of this document provides more detailed information for creating and managing port-ins.

Creating a Requirements Package

Many telecom regulators require that the end user of a phone number is verified, typically with proof of ID and/or proof of address, before services on the number can be activated. If the country you are porting in has KYC (Know Your Customer) requirements for the types of numbers you are porting, you are required to attach a Requirements Package to the port-in order. The Requirements Package will contain the proof (of address and ID) documents that are required to activate services on the numbers being ported. During the port-in process, a Verified Requirements Package is linked to the numbers being ported. Therefore, a verified Requirements Package is a prerequisite for porting numbers in countries that require KYC.

The /api/v2/accounts/{accountId}/compliance/requirements endpoint can be used query KYC requirements for a specific country, number, and subscriber / end-user type.

If a Requirements Package is required, it must be created before the non-draft port-in order can be created. The Requirements Package is created using the /api/v2/accounts/{accountId}/compliance/requirementsPackages API.

Before the port-in can be submitted to a porting specialists, the Requirements Package must be Verified. Port-in orders submitted with an unverified Requirements Package will be remain in a Missing Requirements state until the Requirements Package is verified.

A Requirements Package can be attached at port-in creation time by specifying the Requirements Package ID in the LnpOrder payload as RequirementsPackageId.

Creating a Voice Configuration Package

Voice Configuration Packages are a bundle of voice features that will be provisioned when the port-in completes. Voice features like Automatic Call Routing (ACR), Caller Name Delivery (CNAM), and Stir/Shaken are examples of features that can be included in a Voice Configuration Package.

Voice features available in a Voice Configuration Package are dependent on the country and number type of the numbers being ported. If a Voice Configuration Package is attached to a port-in order containing incompatible numbers, the port-in order will transition to the Missing Requirements state until corrected by the user. Incompatible changes to the Voice Configuration Package made after the port-in has reached Submitted or FOC can lead to delays getting your port-in order processed and provisioned.

Voice Configuration Packages can be created and retreived using the /api/v2/accounts/{accountId}/voiceConfigs API.

A Voice Configuration Package can be attached at port-in creation time by specifying the Voice Configuration Package ID in the LnpOrder payload as VoiceConfigurationPackageId.

Creating an Address

The address of the end-user or business needs to be created before port-in order can be created. The address is used to validate the port-in order and to provide the address to the losing carrier, if necessary. In the past, the address was supplied with the port-in order, but for non-NANP port-ins, the address is now a separate resource managed by /api/v2/accounts/{accountId}/addresses.

Once the address is created, note the addressId returned in the response. This will be used when creating the port-in order.

Keep in mind, you can reuse an existing address. An address can be attached at port-in creation time by passing the Address ID in the LnpOrder.Subscriber payload as AddressId.

Planning Your Port-In

Prior to creating a port-in order, you'll need to know the number type and country of the numbers being ported. You'll need to know the losing carrier of the numbers being ported. Finally, you should be familiar with the porting document requirements, which is based on country and number type.

Bandwidth provides two API tools to provide this information, once you know the country and number type:

You may submit up to 500 telephone numbers in a stand-alone non-NANP port-in. The numbers must belong to the same country, losing carrier, and have the same number type.

To request the earliest possible FOC date, you may omit the RequestedFocDate from the /accounts/\{accountId\}/portins payload.

Creating a Draft Port-in

Bandwidth provides the ability for you to create a port-in order in DRAFT state. This allows you to manipulate the order with minimal validation checking prior to submitting the port-in. In DRAFT state, a port-in order can exist without all of the mandatory elements, while you gather the necessary information from your customer or back-office systems. Then, when you are ready, you can submit the port-in and all of the validations will be run to ensure that the port-in can be successfully sent to our porting vendor for processing.

To create a DRAFT port-in, you must include the ProcessingStatus element with a value of DRAFT when you create the port-in using POST /accounts/{accountId}/portins.

Then you can use PUT /accounts/{accountId}/portins/{orderId} to add or change your port-in order.

When you are ready to submit the draft port-in order, simply execute PUT on the order with the ProcessingStatus value changed to SUBMITTED.

Be aware that draft port-in orders are automatically removed from the system if they remain in the draft state and sit idle (i.e. no PUT updates) for 48 hours since the last update.

Creating a Regular Port-in

Use POST /accounts/{accountId}/portins to create a port-in order for regular (non toll free/) telephone numbers. This API is asynchronous, meaning the POST will create an order with a unique order-id that you will use to check status as it progresses. Please see Order Model for more information.

When you POST to /accounts/{accountId}/portins, some validation is performed to ensure that your request is properly formed. If errors are detected during this validation, you will receive a 4xx response that includes one or more Errors objects, containing an error code and description. These errors must be corrected before resubmitting the POST operation.

If your request passes the initial round of validation, you will receive a 201 response, including an OrderId element with a unique string that you will use to refer to the port-in order in subsequent requests. Additional validation is performed at this point, and if errors are detected, the 201 response will include one or more Errors objects and the ProcessingStatus will be set to Exception. In this case, the order is created and you must use PUT /accounts/{accountId}/portins/{orderId} to correct the errors.

Port-in orders will activate update to 24 hours before the Actual FOC Date.

Fetching Port-in Status

Anytime you need an update on the status of a port-in order, you should use GET /accounts/{accountId}/portins/{orderId}. This will return the latest information about the port-in. You should do this even if you receive a notification about an order state change, because the GET response contains more information than the notification.

As we've mentioned in other places, port-in orders can take days to complete. While waiting for completion, you may poll the port-in order, or you may subscribe to port-in order status change and notes events.

The key items to look for in the 200 response to GET /accounts/{accountId}/portins/{orderId} are:

  • ProcessingStatus - this is the current port-in order state. The values may be:
    • DRAFT - The regular port-in order is in draft state and has not been submitted
    • MISSING_REQUIREMENTS - The port-in order requires one or more requirements to be satisfied before it can be submitted to a porting specialist.
    • PENDING_CARRIER_APPROVAL - The port-in order has been submitted to the losing carrier and is awaiting approval.
    • SUBMITTED - The port-in order has been submitted to a porting specialist.
    • EXCEPTION - The port-in order has a problem that requires intervention. The order will include error information describing the problem.
    • REQUESTED_SUPP - A request to update the order has been submitted.
    • FOC - A firm order commitment date has been agreed upon. The date appears in the order as ActualFocDate.
    • REQUESTED_CANCEL - A request to cancel the order has been submitted.
    • CANCELLED - The order is cancelled. This could be because someone cancelled it (no errors will be present), or because the order incurred an error that could not be corrected.
    • COMPLETE - The order is complete.
  • The presence of Errors objects.

More About Missing Requirements

Missing Requirements is a new processing status introduced for Non-NANP port-in orders. Non-NANP port-in orders now have one or more requirements that need to be satisfied before it can begin processing by a porting specialist. Those requirements are:

  • One or more porting documents must be uploaded. The types of documents vary by porting country and number type.
  • If KYC is required, the port-in order must have a verified Requirements Package attached. Port-ins submitted with Requirements Package that is not verified will remain in the Missing Requirements state until the Requirements Package is verified. Verification is a process that may take sometime to complete. Once the Requirements Package is verified, this requirement will be satisfied.
  • If a Requirements Package is attached to the port-in order, the Requirements Package must be compatible with the numbers being ported. If not, the port-in order will remain in the Missing Requirements state until the Requirements Package is corrected by the user.
  • If a Voice Configuration Package is attached to the port-in order, the Voice Configuration Package must be compatible with the numbers being ported. If not, the port-in order will remain in the Missing Requirements state until the Voice Configuration Package is corrected by the user.

Our system periodically evaluates the port-in order to determine if the requirements have been satisfied. If the requirements are satisfied, the port-in order will automatically transition to the SUBMITTED state.

The details of the requirements that need to be satisfied can be found in the MissingRequirements object in the port-in order response when executing a GET on the port-in order. For example:

<LnpOrderResponse>
...
<ProcessingStatus>MISSING_REQUIREMENTS</ProcessingStatus>
...
<MissingRequirements>
<MissingRequirement>
<Requirement>PORTING_DOCUMENTS</Requirement>
<Description>A Copy of Bill (COB) is required</Description>
</MissingRequirement>
<MissingRequirement>
<Requirement>REQUIREMENTS_PACKAGE</Requirement>
<Description>The selected Requirements Package is not yet verified</Description>
</MissingRequirement>
<MissingRequirement>
<Requirement>VOICE_REQUIREMENTS_PACKAGE</Requirement>
<Description>The selected Voice Configuration Package is not compatible with the phone numbers being ported</Description>
</MissingRequirement>
</MissingRequirements>
</LnpOrderResponse>

Updating a Port-in

A port-in order can be updated using PUT /accounts/{accountId}/portins/{orderId}. The rules about what can be changed vary depending on whether the order is in a draft state, and the port type.

When a port-in order is in one of the draft states (DRAFT or MISSING_REQUIREMENTS), all elements may be updated using the PUT operation.

After an order has been submitted, the fields you are allowed to change vary depending on the port-type.

  • SiteId
  • SippeerId
  • LosingCarrierName
  • RequestedFocDate
  • CustomerOrderId
  • SubscriberType
  • AddressId
  • FirstName
  • LastName
  • BusinessName
  • VatNumber
  • VoiceConfigurationPackageId
  • RequirementsPackageId

If a port-in order already has a FOC date assigned, there are limits on how near to the FOC date and activation time you may update the port-in order. Generally, you cannot update a port-in if the FOC date and activation time are less than 24 hours in the future.

Adding Documents to a Port-in

Any time a port-in is requested, one or more porting documents may be required by the carrier or account from which the telephone number is being ported. These can include a letter of authorization (LOA), copy of bill (COB), or an invoice.

Porting documents must be uploaded prior to submission of the port-in. The port-in will remain in the MISSING_REQUIREMENTS state until all required documents have been uploaded.

Document sizes are restricted to 20 megabytes.

Once a porting document is uploaded, it's initial status will be "Pending Validation". The document will be reviewed by Bandwidth and the status will be updated to "Valid" or "Invalid". If the document is invalid, the reason will be included in the order notes

Documents and metadata are uploaded using POST /api/v2/accounts/{accountId}/porting/portinOrders/{orderId}/documents API. The port-in order must be created prior to uploading documents. The 201 response will assign a unique file identifier that is used to delete, update, or attach metadata to the document.

Documents may be removed from a port-in order using DELETE /api/v2/accounts/{accountId}/porting/portinOrders/{orderId}/documents/{documentId}. Documents can only be removed if the order is in the DRAFT state.

Documents and metadata may be replaced using PUT /api/v2/accounts/{accountId}/porting/portinOrders/{orderId}/documents/{documentId}. Documents can only be replaced if the order in the DRAFT state or the document is INVALID.

See the list of porting documents you have uploaded for a port-in order using GET /api/v2/accounts/{accountId}/porting/portinOrders/{orderId}/documents.

Supported Formats

Bandwidth supports document uploads in the following formats.

Document TypeContent Header
JPG/JPEGimage/jpeg
PDFapplication/pdf
XLSapplication/vnd.ms-excel
XLSXapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheet

Port-in Order Notes

The port-in notes capability provides a means to communicate with Bandwidth regarding a specific port-in order. When you add a note to a port-in order, a Zendesk ticket is automatically created and sent to our LNP team. The LNP team can also use notes to communicate back to you. If you are subscribed to port-in order status notifications, you will also be notified if Bandwidth adds a note to your order.

This capability is very useful for the following type of exchange:

You: Hey, I submitted this order 3 days ago and I have not received FOC.  Can you tell me what's going on?

This creates a Zendesk ticket that will be assigned to someone on our LNP team to address.

Bandwidth: I've checked with the porting vendor and they are having difficulty getting a response from the losing carrier.  I'll continue to follow up.

This will show up in the order history on the Bandwidth App's Port-in Order Details page. And, if you are subscribed to port-in order status notifications, will notify you via email or webhook, depending on your notification preferences.

Order notes increase productivity by making it easy to ask about an order without you having to cut and paste all of the order context information (e.g. order-id or PON, order state, what you've tried, etc.) into a separate ticketing system.

A note may be created using POST /accounts/{accountId}/portins/{orderId}/notes. The 201 response will assign a unique note identifier allowing you to update the note, if necessary.

You may fetch all of the notes for a port-in order using GET /accounts/{accountId}/portins/{orderId}/notes.

You can update an existing order note using PUT /accounts/{accountId}/portins/{orderId}/notes/{noteId}.

Port-in Order History

Each time a port-in order is created or changes state, a history entry is created showing the order status, a note indicating what happened, the date and time of the change, and what was changed if the order was modified. This order history is retained by Bandwidth as a history of the port-in order.

You can fetch the port-in order history using GET /accounts/{accountId}/portins/{orderId}/history.

Note that it occasionally takes a minute or two to update the order history. So if you perform an operation and immediately fetch the order history, the operation may not yet be reflected.

Finding a Port-in Order

Bandwidth's GET /accounts/{accountId}/portins API provides a way to search for port-in orders using a number of filters. This can be useful if you do not have the port-in order-id for an order, or if you need to find out if a port-in was created for a particular telephone number, etc.

Because this API has the potential to match a large number of port-in orders, the results are paginated. The pagination is controlled by two mandatory query parameters called page and size. Generally you start by setting page to 1, and size to the number of entries you want per page.

If more results exist than the number specified by “size”, you will have to fetch the next page. This can be done by using the Links element in the response payload.

The following query parameters can be used to filter the results. They are all logically ANDed together, such that the results will match all of the query parameters that are present in your query.

  • status - only orders in the specified state
  • startdate - the earliest last-modified date to include
  • enddate - the latest last-modified date to include
  • orderTn - one of the TNs being ported
  • customerOrderId - orders matching this customer order id
  • pon - orders having this PON
  • date - only orders modified on this date
  • phoneNumberType - only orders for this type of number
  • countryCodeA3 - only orders for this country

These query parameters are defined in the API reference.

The response will include the pagination links mentioned above, plus a TotalCount element indicating how many results there are in total, which might be greater than the value you supplied for “size”. The results will also contain an object for each order that matched all of your query parameters (limited to “size” entries). This object differs slightly from the data you would receive if you queried the specific order-id using GET /accounts/{accountId}/portins/{orderId}, but includes the main port-in fields, including the order-id.

Cancelling a Port-in

You may cancel a stand-alone port-in using DELETE /accounts/{accountId}/portins/{orderId}.

If the port-in order is in DRAFT state, cancelling the order will remove it from the system entirely.

If the port-in order has already been submitted, the port-in order will transition to the REQUESTED_CANCEL.

If a port-in order already has a FOC date assigned, there are limits on how near to the FOC date and activation time you may cancel the port-in order. Generally, you cannot cancel a port-in if the FOC date and activation time are less than 24 hours in the future.

The CANCELLED state is a terminal state, so you cannot do anything further with the order once it has reached this state.

If you've submitted an order that should not, or cannot complete, it is important that you cancel the order so that the telephone numbers in the order will not be prevented from appearing in subsequent orders.

Example - Porting a number in the United Kingdom (GBR, +44)

Let's walk through an example of creating a port-in order for a single telephone number. I will be porting a UK number, +442012345555 from BT to Bandwidth.

Voice Configuration Package

Let's start by finding a suitable Voice Configuration Package.

Our request:

GET /api/v2/accounts/1234567/voiceConfigs
Host: dashboard.bandwidth.com
Authorization: {Authorization}

The response:

{
"data": [
{
"voiceConfigId": "b1bf9c8c-2c68-474f-ad58-70d1d36628e3",
"accountId": 1234567,
"name": "Voice Config for FRA Toll-Free Numbers",
"description": "Voice Config for FRA Toll-Free Numbers",
"originationRoutePlan": null,
"stirShakenBehavior": {
"verstat": "NONE",
"identity": false
},
"cnam": {
"enabled": false
},
"httpVoiceV2ApplicationId": null
},
{
"voiceConfigId": "cb1265d8-1f11-4012-9f92-487d757392eb",
"accountId": 1234567,
"name": "Voice Config for UK Geographic Numbers",
"description": "Voice Config With All Enabled and Multiple Routes",
"originationRoutePlan": {
"routes": [
{
"name": "PRIMARY ROUTE",
"priority": 1,
"endpoints": [
{
"endpoint": "domain.com:1234",
"type": "FQDN",
"weight": 100
}
]
}
]
},
"stirShakenBehavior": {
"verstat": "NONE",
"identity": false
},
"cnam": {
"enabled": false
},
"httpVoiceV2ApplicationId": null
}
],
"links": [],
"errors": [],
"page": null
}

The voiceConfigId for UK Geographic Numbers is cb1265d8-1f11-4012-9f92-487d757392eb. We'll use this value for VoiceConfigurationPackageId for our port-in. More information about creating and configuring Voice Configuration Packages will be provided at a later date.

Requirements Package

Next, lets determine if we need to create a Requirements Package for the port-in. We can use the compliance requirements API to find this information.

Our request:

GET /api/v2/accounts/1234567/compliance/requirements?countryCodeA3[eq]=GBR&endUserType[eq]=BUSINESS&phoneNumberType[eq]=GEOGRAPHIC
Host: dashboard.bandwidth.com
Authorization: {Authorization}

Note: Depending on your API client, [ and ] may need to be URL encoded as %5B and %5D.

Our response:

  "links": [
{
"href": "https://dashboard.bandwidth.com/api/v2/accounts/1234567/compliance/requirementsPackages",
"rel": "create-requirements-package",
"method": "GET"
},
{
"href": "https://dashboard.bandwidth.com/api/v2/accounts/1234567/compliance/requirements",
"rel": "self",
"method": "GET"
}
],
"data": [],
"errors": []
}

The data object is empty, so we do not need to create and attach a Requirements Package for this port-in.

Address

Next, lets create an address for the port-in.

Our request:

POST /api/v2/accounts/1234567/addresses
Host: dashboard.bandwidth.com
Authorization: {Authorization}
Content-Type: application/json

{
"addressLine1": "221 Brooklyn Square",
"city": "Nottingham",
"countryCodeA3": "GBR",
"customReference": "home_office",
"postalCode": "WC1B 3JA"
}

The response:

{
"links": [
{
"href": "https://dashboard.bandwidth.com/api/v2/accounts/1234567/addresses/4b860f0d-efe8-4f0a-9472-3d276c221c93",
"rel": "get-address",
"method": "GET"
}
],
"data": {
"address": {
"city": "Nottingham",
"postalCode": "WC1B 3JA",
"createdDateTime": "2024-01-29T15:33:14.335191654Z",
"addressId": "4b860f0d-efe8-4f0a-9472-3d276c221c93",
"updatedDateTime": "2024-01-29T15:33:14.335191654Z",
"customReference": "home_office",
"countryCodeA3": "GBR",
"addressLine1": "221 Brooklyn Square"
}
},
"errors": []
}

Make note of the addressId in the response. We will use this when we create the port-in order.

Losing Carrier & Required Porting Documents

We are porting a Geographic number in the UK. We can use this information to look identify the losing carrier and the porting document requirements.

We should already know the losing carrier, but we should verify that we can find it in using the losing carriers API, querying by country and number type.

Our request:

GET /api/v2/porting/losingCarriers?countryCodeA3=GBR&phoneNumberType=GEOGRAPHIC
Host: dashboard.bandwidth.com
Authorization: {Authorization}

The response:

{
"links": [
{
"href": "/porting/losingCarriers",
"rel": "self",
"method": "GET"
}
],
"data": [
{
"name": "Affinity"
},
{
"name": "BT"
},
{
"name": "Gamma"
}
]
}

BT is a valid losing carrier for our port-in.

Next, we need to know the porting document requirements for the port-in. We can use the porting document requirements API to find this information.

Our request:

GET /api/v2/porting/referenceDocuments?countryCodeA3=GBR&phoneNumberType=GEOGRAPHIC
Host: dashboard.bandwidth.com
Authorization: {Authorization}

Response

{
"links": [
{
"href": "/porting/referenceDocuments",
"rel": "self",
"method": "GET"
}
],
"data": {
"referenceDocuments": [
{
"countryCodeA3": "GBR",
"phoneNumberType": "GEOGRAPHIC",
"residential": [
{
"type": "LOA",
"description": "Letter of Authorization",
"requiredDocument": true,
"supportedFileTypes": [
"pdf",
"xls",
"xlsx",
"jpg",
"jpeg"
]
},
{
"type": "COB",
"description": "Copy of Bill",
"requiredDocument": true,
"supportedFileTypes": [
"pdf",
"xls",
"xlsx",
"jpg",
"jpeg"
]
}
]
}
]
}
}

For this port, we need to upload a letter of authorization (LOA) and a copy of the bill (COB). Our end user type is residential.

Create Draft Port-in Order

Now we can create the port-in order. We will create the order in DRAFT state, so that we can add the porting documents before submitting the order.

Our request

POST /api/v2/accounts/1234567/portins
Content-Type: application/xml
Authorization: {Authorization}

<LnpOrder>
<SiteId>100</SiteId>
<PeerId>3000</PeerId>
<LosingCarrierName>BT</LosingCarrierName>
<ListOfPhoneNumbers>
<PhoneNumber>+442012345555</PhoneNumber>
</ListOfPhoneNumbers>
<CustomerOrderId>custom-order-id</CustomerOrderId>
<RequestedFocDate>2024-04-25</RequestedFocDate>
<Subscriber>
<SubscriberType>RESIDENTIAL</SubscriberType>
<FirstName>Jody</FirstName>
<LastName>Smith</LastName>
<AddressId>4b860f0d-efe8-4f0a-9472-3d276c221c93</AddressId>
</Subscriber>
<VoiceConfigurationPackageId>cb1265d8-1f11-4012-9f92-487d757392eb</VoiceConfigurationPackageId>
</LnpOrder>

The response:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<LnpOrderResponse>
<OrderId>9c84fcec-79f2-4a80-9784-3d4cd75b820d</OrderId>
<Status>
<Code>201</Code>
<Description>Order request received. Please use the order id to check the status of your order later.
</Description>
</Status>
<ProcessingStatus>DRAFT</ProcessingStatus>
<RequestedFocDate>2024-04-25</RequestedFocDate>
<Subscriber>
<SubscriberType>RESIDENTIAL</SubscriberType>
<FirstName>Jody</FirstName>
<LastName>Smith</LastName>
<AddressId>4b860f0d-efe8-4f0a-9472-3d276c221c93</AddressId>
</Subscriber>
<ListOfPhoneNumbers>
<PhoneNumber>+442012345555</PhoneNumber>
</ListOfPhoneNumbers>
<SiteId>100</SiteId>
<PeerId>3000</PeerId>
<LosingCarrierName>BT</LosingCarrierName>
<CustomerOrderId>custom-order-id</CustomerOrderId>
<PartialPort>false</PartialPort>
</LnpOrderResponse>

Note the OrderId in the response. We will use this to add the porting documents and submit the order.

Upload Porting Documents

Now we can upload the porting documents. First, we'll upload the LOA.

Our request:

POST /api/v2/accounts/1234567/porting/portinOrders/9c84fcec-79f2-4a80-9784-3d4cd75b820d/documents
Host: dashboard.bandwidth.com
Authorization: {Authorization}
Content-Type: multipart/form-data; boundary=boundary

--boundary
Content-Disposition: form-data; name="documentContent"; filename="loa.pdf"
Content-Type: application/pdf

<LOA PDF>

--boundary
Content-Disposition: form-data; name="metadata"
Content-Type: application/json

{
"contentType": "application/pdf",
"type": "LOA",
"customReference": "loa-001"
}
--boundary--

The response:

{
"data": {
"id": "6c4cb5e2-b6dc-4730-b644-e4e593ea2766",
"type": "LOA",
"customReference": "loa-001.pdf",
"status": "PENDING_VALIDATION",
"contentType": "application/pdf",
"createdDateTime": "2024-01-30T20:31:08.985Z",
"updatedDateTime": "2024-01-30T20:31:08.985Z"
},
"errors": [],
"links": [
{
"href": "https://dashboard.bandwidth.com/api/v2/accounts/1234567/porting/portinOrders/9c84fcec-79f2-4a80-9784-3d4cd75b820d/documents",
"rel": "self",
"method": "GET"
}
]
}

Next, we'll upload the COB.

Our request:

POST /api/v2/accounts/1234567/porting/portinOrders/9c84fcec-79f2-4a80-9784-3d4cd75b820d/documents
Host: dashboard.bandwidth.com
Authorization: {Authorization}
Content-Type: multipart/form-data; boundary=boundary

--boundary
Content-Disposition: form-data; name="documentContent"; filename="cob.pdf"
Content-Type: application/pdf

<COB PDF>

--boundary
Content-Disposition: form-data; name="metadata"
Content-Type: application/json

{
"contentType": "application/pdf",
"type": "COB",
"customReference": "cob-001"
}
--boundary--

The response:

{
"data": {
"id": "f4467d98-1b70-4b3c-9f32-8d8a9d1ae061",
"type": "COB",
"customReference": "cob-001.pdf",
"status": "PENDING_VALIDATION",
"contentType": "application/pdf",
"createdDateTime": "2024-01-30T20:31:08.985Z",
"updatedDateTime": "2024-01-30T20:31:08.985Z"
},
"errors": [],
"links": [
{
"href": "https://dashboard.bandwidth.com/api/v2/accounts/1234567/porting/portinOrders/9c84fcec-79f2-4a80-9784-3d4cd75b820d/documents",
"rel": "self",
"method": "GET"
}
]
}

Submit Port-in Order

Now we can submit the port-in order.

Our request:

PUT /api/v2/accounts/1234567/portins/9c84fcec-79f2-4a80-9784-3d4cd75b820d
Host: dashboard.bandwidth.com
Authorization: {Authorization}
Content-Type: application/xml

<LnpOrder>
<ProcessingStatus>SUBMITTED</ProcessingStatus>
</LnpOrder>

The response:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<LnpOrderResponse>
<OrderId>9c84fcec-79f2-4a80-9784-3d4cd75b820d</OrderId>
<Status>
<Code>200</Code>
<Description>Supp request received. Please use the order id to check the status of your order later.
</Description>
</Status>
<ProcessingStatus>MISSING_REQUIREMENTS</ProcessingStatus>
</LnpOrderResponse>

Now we can check the status of the port-in order.

Our request:

GET /api/v2/accounts/1234567/portins/9c84fcec-79f2-4a80-9784-3d4cd75b820d
Host: dashboard.bandwidth.com
Authorization: {Authorization}

The response:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<LnpOrderResponse>
<ProcessingStatus>SUBMITTED</ProcessingStatus>
<RequestedFocDate>2024-04-25T00:00:00Z</RequestedFocDate>
<EarliestEstimate>2024-04-25T00:00:00Z</EarliestEstimate>
<Subscriber>
<SubscriberType>RESIDENTIAL</SubscriberType>
<FirstName>Jody</FirstName>
<LastName>Smith</LastName>
<AddressId>4b860f0d-efe8-4f0a-9472-3d276c221c93</AddressId>
</Subscriber>
<ListOfPhoneNumbers>
<PhoneNumber>+442012345555</PhoneNumber>
</ListOfPhoneNumbers>
<PON>979E024026CB035C</PON>
<AccountId>1234567</AccountId>
<SiteId>100</SiteId>
<PeerId>3000</PeerId>
<LosingCarrierName>BT</LosingCarrierName>
<VendorName>International porting vendor</VendorName>
<OrderCreateDate>2024-04-25T00:39:51.456Z</OrderCreateDate>
<LastModifiedDate>2024-04-25T19:17:20.783Z</LastModifiedDate>
<userId>portingUser</userId>
<LastModifiedBy>portingUser</LastModifiedBy>
<CustomerOrderId>custom-order-id</CustomerOrderId>
<BillingType>PORTIN</BillingType>
<PortType>MANUAL</PortType>
<AutoActivation>true</AutoActivation>
<CountryCodeA3>GBR</CountryCodeA3>
<PhoneNumberType>GEOGRAPHIC</PhoneNumberType>
<VoiceConfigurationPackageId>cb1265d8-1f11-4012-9f92-487d757392eb</VoiceConfigurationPackageId>
</LnpOrderResponse>

Our port-in has been submitted. It will be validated and move to the FOC state upon successful validation.

Example - Porting a number in France (FRA, +33)

Let's walk through an example of creating a port-in order for a single telephone number. We will be porting a French geographic number, +33160520520 from Waycom Retail to Bandwidth.

Create Address

Let's start by creating an address for the port-in and to use with a Requirements Package.

Our request:

POST /api/v2/accounts/1234567/addresses
Host: dashboard.bandwidth.com
Authorization: {Authorization}
Content-Type: application/json

{
"addressLine1": "13 Rue Sainte-Croix",
"city": "Provins",
"countryCodeA3": "FRA",
"customReference": "front_desk",
"postalCode": "77160"
}

The response:

{
"links": [
{
"href": "https://dashboard.bandwidth.com/api/v2/accounts/1234567/addresses/96065e99-db47-4d5f-94cd-95f096acf45a",
"rel": "get-address",
"method": "GET"
}
],
"data": {
"address": {
"addressId": "96065e99-db47-4d5f-94cd-95f096acf45a",
"addressLine1": "13 Rue Sainte-Croix",
"city": "Provins",
"countryCodeA3": "FRA",
"customReference": "front_desk",
"postalCode": "77160",
"createdDateTime": "2024-04-24T17:37:31.269938279Z",
"updatedDateTime": "2024-04-24T17:37:31.269938279Z"
}
},
"errors": []
}

Make note of the addressId in the response. We will use this when we create the port-in order.

Voice Configuration Package

Next, lets find a suitable Voice Configuration Package ID. Creating a new Voice Configuration Package will be covered in a future guide.

Our request:

GET /api/v2/accounts/1234567/voiceConfigs
Host: dashboard.bandwidth.com
Authorization: {Authorization}

The response:

{
"data": [
{
"voiceConfigId": "b1bf9c8c-2c68-474f-ad58-70d1d36628e3",
"accountId": 1234567,
"name": "Voice Config for FRA Numbers",
"description": "Voice Config for FRA Numbers",
"originationRoutePlan": null,
"stirShakenBehavior": {
"verstat": "NONE",
"identity": false
},
"cnam": {
"enabled": false
},
"httpVoiceV2ApplicationId": null
},
{
"voiceConfigId": "cb1265d8-1f11-4012-9f92-487d757392eb",
"accountId": 1234567,
"name": "Voice Config for UK Geographic Numbers",
"description": "Voice Config With All Enabled and Multiple Routes",
"originationRoutePlan": {
"routes": [
{
"name": "PRIMARY ROUTE",
"priority": 1,
"endpoints": [
{
"endpoint": "domain.com:1234",
"type": "FQDN",
"weight": 100
}
]
}
]
},
"stirShakenBehavior": {
"verstat": "NONE",
"identity": false
},
"cnam": {
"enabled": false
},
"httpVoiceV2ApplicationId": null
}
],
"links": [],
"errors": [],
"page": null
}

The voiceConfigId for French Numbers is b1bf9c8c-2c68-474f-ad58-70d1d36628e3. We'll use this value for VoiceConfigurationPackageId for our port-in. More information about creating and configuring Voice Configuration Packages will be provided when available.

Requirements Package

Next, lets determine if we need to create a Requirements Package for the port-in. We can use the Requirements Packages API to find this information.

Our request:

GET /api/v2/accounts/1234567/compliance/requirements?countryCodeA3[eq]=FRA&endUserType[eq]=BUSINESS&phoneNumberType[eq]=GEOGRAPHIC
Host: dashboard.bandwidth.com
Authorization: {Authorization}

Our response:

  "links": [
{
"href": "https://dashboard.bandwidth.com/api/v2/accounts/1234567/compliance/requirementsPackages",
"rel": "create-requirements-package",
"method": "GET"
},
{
"href": "https://dashboard.bandwidth.com/api/v2/accounts/1234567/compliance/requirements",
"rel": "self",
"method": "GET"
}
],
"data": [
{
"countryCodeA3": "FRA",
"phoneNumberType": "GEOGRAPHIC",
"endUserType": "BUSINESS",
"requirement": {
"endUser": {
"type": "BUSINESS",
"fields": [
{
"friendlyName": "Business name",
"fieldName": "businessName",
"type": "String",
"maxLength": 100,
"required": true
},
{
"friendlyName": "Business description",
"fieldName": "businessDescription",
"type": "String",
"maxLength": 3000,
"required": true
}
]
},
"address": {
"location": "NATIONAL"
},
"supportingDocuments": [
{
"name": "Some Business Proof",
"description": "Valid proof dated last two months",
"type": "OTHER",
"acceptedDocuments": [
{
"type": "balanceSheet",
"deleteFileOnApproval": false,
"friendlyName": "Balance sheet"
}
]
},
{
"name": "Local proof of address",
"description": "Some description",
"type": "ADDRESS",
"acceptedDocuments": [
{
"type": "utilityBill",
"deleteFileOnApproval": false,
"friendlyName": "Utility bill",
"fields": [
{
"friendlyName": "Business name",
"fieldName": "businessName",
"type": "String",
"maxLength": 100,
"required": true
},
{
"friendlyName": "Address ID",
"fieldName": "addressId",
"type": "String",
"maxLength": 36,
"required": true
}
]
},
{
"type": "tvBill",
"deleteFileOnApproval": false,
"friendlyName": "TV bill",
"fields": [
{
"friendlyName": "Address ID",
"fieldName": "addressId",
"type": "String",
"maxLength": 36,
"required": true
},
{
"friendlyName": "Business name",
"fieldName": "businessName",
"type": "String",
"maxLength": 100,
"required": true
}
]
}
]
},
{
"name": "ID PROOF of business representative",
"description": "Valid ID Proof worldwide",
"type": "IDENTITY",
"acceptedDocuments": [
{
"type": "passport",
"deleteFileOnApproval": false,
"friendlyName": "Passport",
"fields": [
{
"friendlyName": "Last name",
"fieldName": "lastName",
"type": "String",
"maxLength": 50,
"required": true
},
{
"friendlyName": "First name",
"fieldName": "firstName",
"type": "String",
"maxLength": 50,
"required": true
}
]
},
{
"type": "driversLicense",
"deleteFileOnApproval": false,
"friendlyName": "Drivers license",
"fields": [
{
"friendlyName": "Last name",
"fieldName": "lastName",
"type": "String",
"maxLength": 50,
"required": true
},
{
"friendlyName": "First name",
"fieldName": "firstName",
"type": "String",
"maxLength": 50,
"required": true
}
]
}
]
}
]
}
}
],
"errors": []
}

Creating Requirements Package

We need to create a Requirements Package with the following assets:

  • Business name
  • Business description
  • Proof of business (ex. balance sheet)
  • Proof of address (ex. utility bill)
  • Proof of identity of the business representative (ex. passport)

Let's create the Requirements Package.

Our request:

POST /api/v2/accounts/1234567/compliance/requirementsPackages
Host: dashboard.bandwidth.com
Authorization: {Authorization}
Content-Type: application/json

{
"callback": "https://domain.com/callback",
"countryCodeA3": "FRA",
"customReference": "Le Cesar Hotel - Provins",
"email": "lecesar-provins@foobar.com",
"endUserType": "BUSINESS",
"phoneNumberType": "GEOGRAPHIC"
}

Our response:

{
"data": {
"acknowledgements": {
"allDetailsAccurate": true
},
"callback": "https://domain.com/callback",
"countryCodeA3": "FRA",
"createdDateTime": "2015-03-11T04:09:25.399Z",
"customReference": "Le Cesar Hotel - Provins",
"email": "lecesar-provins@foobar.com",
"endUserType": "BUSINESS",
"phoneNumberType": "GEOGRAPHIC",
"remarks": "Remarks provided by Admin",
"requirementsPackageId": "93ac73e8-20a7-95ec-bd32-4e8270e66c31",
"status": "SUBMITTED",
"updatedDateTime": "2015-03-11T04:09:25.399Z"
},
"errors": [],
"links": [
{
"href": "https://dashboard.bandwidth.com/api/v2/accounts/1234567/compliance/requirementsPackages/93ac73e8-20a7-95ec-bd32-4e8270e66c31",
"rel": "get-requirements-package",
"type": "GET"
}
]
}

Make note of the requirementsPackageId in the response. We will use this when attaching assets and during port-in order creation.

Attaching End User Information

Let's add end user information to our Requirements Package, starting with our business information:

POST /api/v2/compliance/endUsers
Host: dashboard.bandwidth.com
Authorization: {Authorization}
Content-Type: application/json

{
"customReference": "Le Cesar Hotel - Provins",
"fields": {
"businessName": "Les Cesar Hotel",
"businessDescription": "Hospitality and hoteling"
},
"type": "BUSINESS"
}

Our response:

{
"links": [
{
"href": "https://dashboard.bandwidth.com/api/v2/accounts/1234567/compliance/endUsers/6ab5e6ee-a1c3-4e33-879a-275e3997bae6",
"rel": "get-endUser",
"method": "GET"
}
],
"data": {
"type": "BUSINESS",
"customReference": "Le Cesar Hotel - Provins",
"fields": {
"businessName": "Les Cesar Hotel",
"businessDescription": "Hospitality and hoteling"
},
"endUserId": "6ab5e6ee-a1c3-4e33-879a-275e3997bae6",
"status": "DRAFT",
"createdDateTime": "2024-04-25T17:27:47.828Z",
"updatedDateTime": "2024-04-25T17:27:47.828Z"
},
"errors": []
}

Let's attach our end user to our Requirements Package.

Our request:

POST /api/v2/accounts/1234567/compliance/requirementsPackages/93ac73e8-20a7-95ec-bd32-4e8270e66c31/assets
Host: dashboard.bandwidth.com
Authorization: {Authorization}
Content-Type: application/json

{
"assetReferenceId": "6ab5e6ee-a1c3-4e33-879a-275e3997bae6",
"assetType": "END_USER"
}

Our response:

{
"links": [
{
"href": "https://dashboard.bandwidth.com/api/v2/accounts/1234567/requirementsPackages/93ac73e8-20a7-95ec-bd32-4e8270e66c31/assets",
"rel": "self",
"method": "GET"
}
],
"data": {
"assetId": "91e3d4fa-2bfd-407c-bd83-c8a20885cd29",
"assetReferenceId": "6ab5e6ee-a1c3-4e33-879a-275e3997bae6",
"assetType": "END_USER",
"createdDateTime": "2024-04-25T17:37:05.478Z",
"updatedDateTime": "2024-04-25T17:37:05.478Z"
},
"errors": []
}

Attaching Assets

We need to create and attach three assets:

  1. Proof of business, balance sheet
  2. Proof of address, utility bill
  3. Proof ID of the business representative, passport

Creating & Attaching Balance Sheet

Our request:

POST /api/v2/accounts/1234567/compliance/documents
Host: dashboard.bandwidth.com
Authorization: {Authorization}
Content-Type: multipart/form-data; boundary=boundary

--boundary
Content-Disposition: form-data; name="file"; filename="balance_sheet.pdf"
Content-Type: application/pdf

<BALANCE SHEET file contents>

--boundary
Content-Disposition: form-data; name="metadata"
Content-Type: application/json

{
"customReference": "Provins Balance Sheet",
"type": "balanceSheet",
"fields": {}
}
--boundary--

Our response:

{
"links": [
{
"href": "https://dashboard.bandwidth.com/api/v2/accounts/1234567/compliance/documents/0c0dca4e-f25d-4bbe-9bef-83066c24d75a",
"rel": "get-document",
"method": "GET"
}
],
"data": {
"type": "balanceSheet",
"customReference": "Provins Balance Sheet",
"fileName": "balance_sheet.pdf",
"fields": {},
"documentId": "0c0dca4e-f25d-4bbe-9bef-83066c24d75a",
"status": "DRAFT",
"createdDateTime": "2024-04-25T17:37:04.880Z",
"updatedDateTime": "2024-04-25T17:37:04.880Z",
"fileContentExists": true
},
"errors": []
}

Now it's time to attach the asset to the Requirements Package.

Our request:

POST /api/v2/accounts/1234567/compliance/requirementsPackages/93ac73e8-20a7-95ec-bd32-4e8270e66c31/asset
Host: dashboard.bandwidth.com
Authorization: {Authorization}
Content-Type: application/json

{
"assetReferenceId": "0c0dca4e-f25d-4bbe-9bef-83066c24d75a",
"assetType": "DOCUMENT"
}

Our response:

{
"links": [
{
"href": "https://dashboard.bandwidth.com/api/v2/accounts/1234567/requirementsPackages/93ac73e8-20a7-95ec-bd32-4e8270e66c31/assets",
"rel": "self",
"method": "GET"
}
],
"data": {
"assetId": "91e3d4fa-2bfd-407c-bd83-c8a20885cd29",
"assetReferenceId": "0c0dca4e-f25d-4bbe-9bef-83066c24d75a",
"assetType": "DOCUMENT",
"assetReferenceData": {
"type": "balanceSheet",
"customReference": "Provins Balance Sheet",
"fileName": "loa_in.pdf",
"fields": {},
"documentId": "0c0dca4e-f25d-4bbe-9bef-83066c24d75a",
"status": "DRAFT",
"createdDateTime": "2024-04-25T17:37:04.880Z",
"updatedDateTime": "2024-04-25T17:37:05.491Z",
"fileContentExists": true
},
"createdDateTime": "2024-04-25T17:37:05.478Z",
"updatedDateTime": "2024-04-25T17:37:05.478Z"
},
"errors": []
}

Creating & Attaching Utility Bill

Our request:

POST /api/v2/accounts/1234567/compliance/documents
Host: dashboard.bandwidth.com
Authorization: {Authorization}
Content-Type: multipart/form-data; boundary=boundary

--boundary
Content-Disposition: form-data; name="file"; filename="utilityBill.pdf"
Content-Type: application/pdf

<UTILITY BILL file contents>

--boundary
Content-Disposition: form-data; name="metadata"
Content-Type: application/json

{
"customReference": "Provins Utility Bill",
"type": "utilityBill",
"fields":{
"businessName":"Les Cesar Hotel",
"addressId":"96065e99-db47-4d5f-94cd-95f096acf45a"
}
}
--boundary--

Note: we need to pass additional fields like businessName and addressId for the utility bill asset. These fields are defined in our initial /requirements API response.

Our response:

{
"links": [
{
"href": "https://eng.dashboard.bandwidth.com/api/v2/accounts/9902989/requirementsPackages/8b268f61-a229-439d-b76f-b424f4570043/assets",
"rel": "self",
"method": "GET"
}
],
"data": {
"assetId": "1279e833-6ce2-450e-a1de-fc0de144dc1b",
"assetReferenceId": "71dfdd50-79eb-4e4b-9a97-4ef6e5c3bca2",
"assetType": "DOCUMENT",
"assetReferenceData": {
"type": "utilityBill",
"customReference": "Provins Utility Bill",
"fileName": "utilityBill.pdf",
"fields": {
"businessName": "Les Cesar Hotel",
"addressId": "96065e99-db47-4d5f-94cd-95f096acf45a"
},
"documentId": "71dfdd50-79eb-4e4b-9a97-4ef6e5c3bca2",
"status": "DRAFT",
"createdDateTime": "2024-04-29T19:27:10.342Z",
"updatedDateTime": "2024-04-29T19:27:37.173Z",
"fileContentExists": true
},
"createdDateTime": "2024-04-29T19:27:37.159Z",
"updatedDateTime": "2024-04-29T19:27:37.159Z"
},
"errors": []
}

Now it's time to attach the asset to the Requirements Package.

Our request:

POST /api/v2/accounts/1234567/compliance/requirementsPackages/93ac73e8-20a7-95ec-bd32-4e8270e66c31/asset
Host: dashboard.bandwidth.com
Authorization: {Authorization}
Content-Type: application/json

{
"assetReferenceId": "71dfdd50-79eb-4e4b-9a97-4ef6e5c3bca2",
"assetType": "DOCUMENT"
}

Our response:

{
"links": [
{
"href": "https://dashboard.bandwidth.com/api/v2/accounts/1234567/requirementsPackages/93ac73e8-20a7-95ec-bd32-4e8270e66c31/assets",
"rel": "self",
"method": "GET"
}
],
"data": {
"assetId": "91e3d4fa-2bfd-407c-bd83-c8a20885cd29",
"assetReferenceId": "71dfdd50-79eb-4e4b-9a97-4ef6e5c3bca2",
"assetType": "DOCUMENT",
"assetReferenceData": {
"type": "utilityBill",
"customReference": "Provins Utility Bill",
"fileName": "utilityBill.pdf",
"fields": {
"businessName": "Les Cesar Hotel",
"addressId": "96065e99-db47-4d5f-94cd-95f096acf45a"
},
"documentId": "71dfdd50-79eb-4e4b-9a97-4ef6e5c3bca2",
"status": "DRAFT",
"createdDateTime": "2024-04-29T19:27:10.342Z",
"updatedDateTime": "2024-04-29T19:27:37.173Z",
"fileContentExists": true
},
"createdDateTime": "2024-04-25T17:37:05.478Z",
"updatedDateTime": "2024-04-25T17:37:05.478Z"
},
"errors": []
}

Creating & Attaching a Passport

Our request:

POST /api/v2/accounts/1234567/compliance/documents
Host: dashboard.bandwidth.com
Authorization: {Authorization}
Content-Type: multipart/form-data; boundary=boundary

--boundary
Content-Disposition: form-data; name="file"; filename="passport.pdf"
Content-Type: application/pdf

<PASSPORT file contents>

--boundary
Content-Disposition: form-data; name="metadata"
Content-Type: application/json

{
"customReference": "Jacque Doe Passport",
"type": "passport",
"fields": {
"firstName": "Jacque",
"lastName": "Doe"
}
}
--boundary--

Note: we need to pass additional fields like firstName and lastName for the passport asset. These fields are defined in our initial /requirements API response.

Our response:

{
"links": [
{
"href": "https://eng.dashboard.bandwidth.com/api/v2/accounts/9902989/compliance/documents/0f3e10d8-2cfc-4886-88b1-0eced06292db",
"rel": "get-document",
"method": "GET"
}
],
"data": {
"type": "passport",
"customReference": "Jacque Doe Passport",
"fileName": "passport.pdf",
"fields": {
"firstName": "Jacque",
"lastName": "Doe"
},
"documentId": "0f3e10d8-2cfc-4886-88b1-0eced06292db",
"status": "DRAFT",
"createdDateTime": "2024-04-29T19:27:42.288Z",
"updatedDateTime": "2024-04-29T19:27:42.288Z",
"fileContentExists": true
},
"errors": []
}

Now it's time to attach the asset to the Requirements Package.

Our request:

POST /api/v2/accounts/1234567/compliance/requirementsPackages/93ac73e8-20a7-95ec-bd32-4e8270e66c31/asset
Host: dashboard.bandwidth.com
Authorization: {Authorization}
Content-Type: application/json

{
"assetReferenceId": "0f3e10d8-2cfc-4886-88b1-0eced06292db",
"assetType": "DOCUMENT"
}

Our response:

{
"links": [
{
"href": "https://dashboard.bandwidth.com/api/v2/accounts/1234567/requirementsPackages/93ac73e8-20a7-95ec-bd32-4e8270e66c31/assets",
"rel": "self",
"method": "GET"
}
],
"data": {
"assetId": "91e3d4fa-2bfd-407c-bd83-c8a20885cd29",
"assetReferenceId": "0f3e10d8-2cfc-4886-88b1-0eced06292db",
"assetType": "DOCUMENT",
"assetReferenceData": {
"type": "passport",
"customReference": "Jacque Doe Passport",
"fileName": "passport.pdf",
"fields": {
"firstName": "Jacque",
"lastName": "Doe"
},
"documentId": "0f3e10d8-2cfc-4886-88b1-0eced06292db",
"status": "DRAFT",
"createdDateTime": "2024-04-29T19:27:42.288Z",
"updatedDateTime": "2024-04-29T19:27:42.288Z",
"fileContentExists": true
},
"createdDateTime": "2024-04-25T17:37:05.478Z",
"updatedDateTime": "2024-04-25T17:37:05.478Z"
},
"errors": []
}

Submiting the Requirements Package

Finally, submit the Requirements Package.

Our request:

PATCH /api/v2/accounts/1234567/compliance/requirementsPackages/93ac73e8-20a7-95ec-bd32-4e8270e66c31
Host: dashboard.bandwidth.com
Authorization: {Authorization}
Content-Type: application/json

{
"status": "SUBMITTED",
"acknowledgements": {
"allDetailsAccurate": true
}
}

Our response:

{
"links": [
{
"href": "https://dashboard.bandwidth.com/api/v2/accounts/1234567/compliance/requirementsPackages/93ac73e8-20a7-95ec-bd32-4e8270e66c31",
"rel": "get-requirements-package",
"method": "GET"
}
],
"data": {
"requirementsPackageId": "93ac73e8-20a7-95ec-bd32-4e8270e66c31",
"phoneNumberType": "GEOGRAPHIC",
"customReference": "Le Cesar Hotel - Provins",
"countryCodeA3": "FRA",
"endUserType": "BUSINESS",
"status": "SUBMITTED",
"createdDateTime": "2024-04-25T17:27:17Z",
"updatedDateTime": "2024-04-25T17:47:02.823Z",
"acknowledgements": {
"allDetailsAccurate": true
}
},
"errors": []
}

From here, the passport gets verified by our compliance team. We can submit a port-in with this Requirements Package, however, it the port-in will remain in "Missing Requirements" until all porting requirements are resolved, including a verified Requirements Package.

Retrieving Losing Carrier & Porting Documents Requirements

We are porting a Geographic number in France. We can use this information to look identify the losing carrier and the porting document requirements.

We should already know the losing carrier, but we should verify that we can find it in using the losing carriers API, querying by country and number type.

Our request:

GET /api/v2/porting/losingCarriers?countryCodeA3=FRA&phoneNumberType=GEOGRAPHIC
Host: dashboard.bandwidth.com
Authorization: {Authorization}

The response:

{
"links": [
{
"href": "/porting/losingCarriers",
"rel": "self",
"method": "GET"
}
],
"data": [
{
"name": "Verizon"
},
{
"name": "Voxbone"
},
{
"name": "Waycom Retail"
}
]
}

Waycom Retail is a valid losing carrier for our port-in.

Next, we need to know the porting document requirements for the port-in. We can use the porting document requirements API to find this information.

Our request:

GET /api/v2/porting/referenceDocuments?countryCodeA3=FRA&phoneNumberType=GEOGRAPHIC
Host: dashboard.bandwidth.com
Authorization: {Authorization}

Response

{
"links": [
{
"href": "/porting/referenceDocuments",
"rel": "self",
"method": "GET"
}
],
"data": {
"referenceDocuments": [
{
"countryCodeA3": "FRA",
"phoneNumberType": "GEOGRAPHIC",
"business": [
{
"type": "LOA",
"description": "Letter of Authorization",
"requiredDocument": true,
"supportedFileTypes": [
"pdf",
"xls",
"xlsx",
"jpg",
"jpeg"
]
},
{
"type": "COB",
"description": "Copy of Bill",
"requiredDocument": true,
"supportedFileTypes": [
"pdf",
"xls",
"xlsx",
"jpg",
"jpeg"
]
}
]
}
]
}
}

For this port, we need to upload a letter of authorization (LOA) and a copy of the bill (COB). Our end user type is business.

Create Draft Port-in Order

Now we can create the port-in order. We will create the order in DRAFT state, so that we can add the porting documents before submitting the order.

Our request

POST /api/v2/accounts/1234567/portins
Content-Type: application/xml
Authorization: {Authorization}

<LnpOrder>
<SiteId>100</SiteId>
<PeerId>3000</PeerId>
<LosingCarrierName>Waycom Retail</LosingCarrierName>
<ListOfPhoneNumbers>
<PhoneNumber>+33160520520</PhoneNumber>
</ListOfPhoneNumbers>
<CustomerOrderId>custom-order-id</CustomerOrderId>
<RequestedFocDate>2024-04-25</RequestedFocDate>
<Subscriber>
<SubscriberType>BUSINESS</SubscriberType>
<BusinessName>Le Cesar Hotel</BusinessName>
<VatNumber>FR12345678901</VatNumber>
<AddressId>96065e99-db47-4d5f-94cd-95f096acf45a</AddressId>
</Subscriber>
<RequirementsPackageId>93ac73e8-20a7-95ec-bd32-4e8270e66c31<RequirementsPackageId>
<VoiceConfigurationPackageId>b1bf9c8c-2c68-474f-ad58-70d1d36628e3</VoiceConfigurationPackageId>
</LnpOrder>

The response:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<LnpOrderResponse>
<OrderId>9c84fcec-79f2-4a80-9784-3d4cd75b820d</OrderId>
<Status>
<Code>201</Code>
<Description>Order request received. Please use the order id to check the status of your order later.
</Description>
</Status>
<ProcessingStatus>DRAFT</ProcessingStatus>
<RequestedFocDate>2024-04-25</RequestedFocDate>
<Subscriber>
<SubscriberType>BUSINESS</SubscriberType>
<BusinessName>Le Cesar Hotel</BusinessName>
<AddressId>96065e99-db47-4d5f-94cd-95f096acf45a</AddressId>
</Subscriber>
<ListOfPhoneNumbers>
<PhoneNumber>+442012345555</PhoneNumber>
</ListOfPhoneNumbers>
<SiteId>100</SiteId>
<PeerId>3000</PeerId>
<LosingCarrierName>Waycom Retail</LosingCarrierName>
<CustomerOrderId>custom-order-id</CustomerOrderId>
<PartialPort>false</PartialPort>
<RequirementsPackageId>93ac73e8-20a7-95ec-bd32-4e8270e66c31<RequirementsPackageId>
<VoiceConfigurationPackageId>b1bf9c8c-2c68-474f-ad58-70d1d36628e3</VoiceConfigurationPackageId>
</LnpOrderResponse>

Note the OrderId in the response. We will use this to add the porting documents and submit the order.

Upload Porting Documents

Now we can upload the porting documents. First, we'll upload the LOA.

Our request:

POST /api/v2/accounts/1234567/porting/portinOrders/9c84fcec-79f2-4a80-9784-3d4cd75b820d/documents
Host: dashboard.bandwidth.com
Authorization: {Authorization}
Content-Type: multipart/form-data; boundary=boundary

--boundary
Content-Disposition: form-data; name="documentContent"; filename="loa.pdf"
Content-Type: application/pdf

<LOA PDF>

--boundary
Content-Disposition: form-data; name="metadata"
Content-Type: application/json

{
"contentType": "application/pdf",
"type": "LOA",
"customReference": "loa-001"
}
--boundary--

The response:

{
"data": {
"id": "6c4cb5e2-b6dc-4730-b644-e4e593ea2766",
"type": "LOA",
"customReference": "loa-001.pdf",
"status": "PENDING_VALIDATION",
"contentType": "application/pdf",
"createdDateTime": "2024-01-30T20:31:08.985Z",
"updatedDateTime": "2024-01-30T20:31:08.985Z"
},
"errors": [],
"links": [
{
"href": "https://dashboard.bandwidth.com/api/v2/accounts/1234567/porting/portinOrders/9c84fcec-79f2-4a80-9784-3d4cd75b820d/documents",
"rel": "self",
"method": "GET"
}
]
}

Next, we'll upload the COB.

Our request:

POST /api/v2/accounts/1234567/porting/portinOrders/9c84fcec-79f2-4a80-9784-3d4cd75b820d/documents
Host: dashboard.bandwidth.com
Authorization: {Authorization}
Content-Type: multipart/form-data; boundary=boundary

--boundary
Content-Disposition: form-data; name="documentContent"; filename="cob.pdf"
Content-Type: application/pdf

<COB PDF>

--boundary
Content-Disposition: form-data; name="metadata"
Content-Type: application/json

{
"contentType": "application/pdf",
"type": "COB",
"customReference": "cob-001"
}
--boundary--

The response:

{
"data": {
"id": "f4467d98-1b70-4b3c-9f32-8d8a9d1ae061",
"type": "COB",
"customReference": "cob-001.pdf",
"status": "PENDING_VALIDATION",
"contentType": "application/pdf",
"createdDateTime": "2024-01-30T20:31:08.985Z",
"updatedDateTime": "2024-01-30T20:31:08.985Z"
},
"errors": [],
"links": [
{
"href": "https://dashboard.bandwidth.com/api/v2/accounts/1234567/porting/portinOrders/9c84fcec-79f2-4a80-9784-3d4cd75b820d/documents",
"rel": "self",
"method": "GET"
}
]
}

Submit Port-in Order

Now we can submit the port-in order.

Our request:

PUT /api/v2/accounts/1234567/portins/9c84fcec-79f2-4a80-9784-3d4cd75b820d
Host: dashboard.bandwidth.com
Authorization: {Authorization}
Content-Type: application/xml

<LnpOrder>
<ProcessingStatus>SUBMITTED</ProcessingStatus>
</LnpOrder>

The response:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<LnpOrderResponse>
<OrderId>9c84fcec-79f2-4a80-9784-3d4cd75b820d</OrderId>
<Status>
<Code>200</Code>
<Description>Supp request received. Please use the order id to check the status of your order later.
</Description>
</Status>
<ProcessingStatus>MISSING_REQUIREMENTS</ProcessingStatus>
</LnpOrderResponse>

Now we can check the status of the port-in order.

Our request:

GET /api/v2/accounts/1234567/portins/9c84fcec-79f2-4a80-9784-3d4cd75b820d
Host: dashboard.bandwidth.com
Authorization: {Authorization}

The response:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<LnpOrderResponse>
<ProcessingStatus>SUBMITTED</ProcessingStatus>
<RequestedFocDate>2024-04-25T00:00:00Z</RequestedFocDate>
<EarliestEstimate>2024-04-25T00:00:00Z</EarliestEstimate>
<Subscriber>
<SubscriberType>BUSINESS</SubscriberType>
<VatNumber>FR12345678901</VatNumber>
<BusinessName>Le Cesar Hotel</BusinessName>
<AddressId>96065e99-db47-4d5f-94cd-95f096acf45a</AddressId>
</Subscriber>
<ListOfPhoneNumbers>
<PhoneNumber>+33160520520</PhoneNumber>
</ListOfPhoneNumbers>
<PON>979E024DERG035C</PON>
<AccountId>1234567</AccountId>
<SiteId>100</SiteId>
<PeerId>3000</PeerId>
<LosingCarrierName>Waycom Retail</LosingCarrierName>
<VendorName>International porting vendor</VendorName>
<OrderCreateDate>2024-04-25T00:39:51.456Z</OrderCreateDate>
<LastModifiedDate>2024-04-25T19:17:20.783Z</LastModifiedDate>
<userId>portingUser</userId>
<LastModifiedBy>portingUser</LastModifiedBy>
<CustomerOrderId>custom-order-id</CustomerOrderId>
<BillingType>PORTIN</BillingType>
<PortType>MANUAL</PortType>
<AutoActivation>true</AutoActivation>
<CountryCodeA3>FRA</CountryCodeA3>
<PhoneNumberType>GEOGRAPHIC</PhoneNumberType>
<RequirementsPackageId>93ac73e8-20a7-95ec-bd32-4e8270e66c31<RequirementsPackageId>
<VoiceConfigurationPackageId>b1bf9c8c-2c68-474f-ad58-70d1d36628e3</VoiceConfigurationPackageId>
</LnpOrderResponse>

Our port-in has been submitted. It will be validated and move to the FOC state upon successful validation.