Number Porting
Number porting lets you transfer existing phone numbers from another carrier to DialStack. This guide walks through the full port-in workflow: checking eligibility, creating a port order, approving the order, and tracking it through completion.
Overview
Porting follows a draft-based workflow:
- Check eligibility — verify numbers can be ported
- Create a draft — provide subscriber details and your requested date and time
- Approve — customer approves the port order with their electronic signature
- Submit — send the order to the carrier for processing
- Track status — monitor until the port completes
draft → approved → submitted → foc (scheduled) → complete
→ exception → (fix + resubmit) → submitted
Prerequisites
- DialStack API key (
sk_live_*) - Phone numbers currently active with another US carrier
- Subscriber details matching the losing carrier's records (name, service address, account number, and PIN as listed on the current carrier's records)
Step 1: Check Eligibility
Before creating a port order, verify that the numbers can be ported. This endpoint is platform-scoped — no DialStack-Account header is needed.
curl -X POST https://api.dialstack.ai/v1/port-in-eligibility \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone_numbers": ["+12025551234", "+12025555678"]
}'
Response:
{
"portable_numbers": [
{
"phone_number": "+12025551234",
"losing_carrier_name": "Verizon Wireless",
"losing_carrier_spid": "6006",
"is_wireless": true,
"account_number_required": true
}
],
"non_portable_numbers": [
{
"phone_number": "+12025555678",
"rate_center": "WASHINGT DC",
"city": "Washington",
"state": "DC"
}
]
}
Only numbers listed in portable_numbers can be included in a port order. Check account_number_required — when true, you'll need to include the subscriber's account_number and pin in the port order.
Step 2: Create a Draft Port Order
Create a draft with the subscriber details, phone numbers, and your requested porting date and time. You can control exactly when your numbers transfer by setting requested_foc_date and optionally requested_foc_time (Eastern Time, between 08:00 and 20:00). The date must be at least 5 business days and no more than 30 calendar days from today.
Once the carrier confirms the order, the port will complete at the date and time you requested — so you can plan your cutover with confidence.
curl -X POST https://api.dialstack.ai/v1/port-orders \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41" \
-H "Content-Type: application/json" \
-d '{
"phone_numbers": ["+12025551234"],
"subscriber": {
"btn": "+12025551234",
"business_name": "Smith Consulting",
"approver_name": "Jane Smith",
"account_number": "123456789",
"pin": "1234",
"address": {
"house_number": "123",
"street_name": "Main St",
"city": "Washington",
"state": "DC",
"zip": "20001"
}
},
"requested_foc_date": "2026-03-15",
"requested_foc_time": "10:00"
}'
Response:
{
"id": "port_01jkx...",
"status": "draft",
"details": {
"phone_numbers": ["+12025551234"],
"subscriber": {
"btn": "+12025551234",
"business_name": "Smith Consulting",
"approver_name": "Jane Smith",
"account_number": "123456789",
"pin": "1234",
"address": {
"house_number": "123",
"street_name": "Main St",
"city": "Washington",
"state": "DC",
"zip": "20001"
}
},
"requested_foc_date": "2026-03-15",
"requested_foc_time": "10:00"
},
"submitted_at": null,
"created_at": "2026-02-11T14:00:00Z",
"updated_at": "2026-02-11T14:00:00Z"
}
All subscriber fields must match the records on file with the losing carrier. Mismatches are the most common reason for port rejections.
- BTN (Billing Telephone Number) — the main number on the account
- Approver name — the name of the person authorized to approve the port
- Service address — split into
house_numberandstreet_nameto match the carrier's format - Account number and PIN — required for wireless ports (check
account_number_requiredin the eligibility response)
Step 3: Approve the Port Order
Have the customer approve the port order by providing their electronic signature and IP address. This authorizes the transfer of their phone numbers.
curl -X POST https://api.dialstack.ai/v1/port-orders/port_01jkx.../approve \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41" \
-H "Content-Type: application/json" \
-d '{
"signature": "Jane Smith",
"ip": "203.0.113.42"
}'
Response:
{
"id": "port_01jkx...",
"status": "approved",
"details": {
"phone_numbers": ["+12025551234"],
"subscriber": { "...": "..." },
"approval": {
"signature": "Jane Smith",
"ip": "203.0.113.42",
"timestamp": "2026-02-11T14:02:00Z"
},
"requested_foc_date": "2026-03-15",
"requested_foc_time": "10:00"
},
"submitted_at": null,
"created_at": "2026-02-11T14:00:00Z",
"updated_at": "2026-02-11T14:02:00Z"
}
The status transitions from draft to approved. If the order details are updated after approval, the approval is cleared and the status reverts to draft — the customer must approve again.
Step 4: Submit the Order
Once the order is approved, submit it to begin the porting process:
curl -X POST https://api.dialstack.ai/v1/port-orders/port_01jkx.../submit \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41"
Response:
{
"id": "port_01jkx...",
"status": "submitted",
"details": { "...": "..." },
"submitted_at": "2026-02-11T14:05:00Z",
"created_at": "2026-02-11T14:00:00Z",
"updated_at": "2026-02-11T14:05:00Z"
}
The status transitions from approved to submitted. The necessary authorization documents are generated and forwarded to the carrier automatically.
Step 5: Track the Order
Poll the order to check its status. Non-terminal orders are automatically refreshed from the carrier:
curl https://api.dialstack.ai/v1/port-orders/port_01jkx... \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41"
You can also list all port orders, optionally filtering by status:
curl "https://api.dialstack.ai/v1/port-orders?status=submitted" \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41"
Status Reference
| Status | Description |
|---|---|
draft | Order created, not yet approved |
approved | Customer has approved the order, ready to submit |
submitted | Sent to the carrier, awaiting processing |
exception | Rejected by the carrier — can be corrected and resubmitted |
foc | Scheduled — the carrier has confirmed a completion date and time (in telecom, this confirmation is called a Firm Order Commitment, abbreviated FOC). Your numbers will port at the confirmed date and time. |
complete | Numbers successfully ported and active in DialStack |
cancelled | Order was cancelled |
Viewing the Audit Trail
Every status change is recorded. View the full history:
curl https://api.dialstack.ai/v1/port-orders/port_01jkx.../events \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41"
Handling Rejections
If the carrier rejects the port (status becomes exception), the rejection details appear in the order:
{
"status": "exception",
"details": {
"rejection": {
"code": "address_mismatch",
"message": "Service address mismatch"
}
}
}
To fix and resubmit, update the order with corrected information:
curl -X POST https://api.dialstack.ai/v1/port-orders/port_01jkx... \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41" \
-H "Content-Type: application/json" \
-d '{
"subscriber": {
"btn": "+12025551234",
"business_name": "Smith Consulting",
"approver_name": "Jane Smith",
"address": {
"house_number": "456",
"street_name": "Oak Ave",
"city": "Washington",
"state": "DC",
"zip": "20002"
}
}
}'
Changing the Port Date
For an order in submitted or foc, send only the new port date and time:
curl -X POST https://api.dialstack.ai/v1/port-orders/port_01jkx... \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41" \
-H "Content-Type: application/json" \
-d '{
"requested_foc_date": "2026-09-02",
"requested_foc_time": "08:00"
}'
The order keeps its current status. Other fields cannot be changed at this stage
and result in a 409 response with code: port_order_invalid_state.
Cancelling an Order
Cancel a port order that hasn't reached a terminal state:
curl -X POST https://api.dialstack.ai/v1/port-orders/port_01jkx.../cancel \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "DialStack-Account: acct_01h2xcejqtf2nbrexx3vqjhp41"
Orders in complete or cancelled status cannot be cancelled.
Common Rejection Reasons
| Code | Reason | How to Fix |
|---|---|---|
address_mismatch | Service address mismatch | Update the address to match the losing carrier's records |
account_number_invalid | Account number required | Contact the losing carrier for your account number |
name_mismatch | Approver name mismatch | Use the exact name on file with the losing carrier |
business_name_mismatch | Business name mismatch | Use the business name from the carrier's Customer Service Record (CSR), which may differ from the name on the bill |
btn_mismatch | BTN mismatch | Verify the billing telephone number with the losing carrier |
pin_required | PIN required | Contact the losing carrier to get the PIN or passcode for the account, then include it in the pin field |
pin_invalid | PIN invalid | The PIN provided doesn't match the carrier's records — contact the losing carrier to verify the correct PIN and update the order |
Error Handling
| Status | Error | Description |
|---|---|---|
| 400 | Validation errors | Invalid phone numbers, bad date format, etc. |
| 404 | Port order not found | Order doesn't exist or belongs to a different account |
| 409 | Invalid state | Operation not allowed in the order's current status |
| 409 | Number limit reached | The port would take the account past its phone number limit — see below |
| 422 | Approval required | Must approve the order before submitting |
Phone number limit
Each account has a cap on how many phone numbers it can hold, set by the platform
administrator (max_phone_numbers on the account's config, default 25). Porting
counts against it just as buying numbers does, so creating a port order — or
editing one to add numbers — returns 409 Conflict when the resulting total would
exceed the cap. The response says how many numbers the account holds, what the cap
is, and how many the request tried to add.
The count includes numbers reserved by port orders already in flight, so two concurrent ports draw on the same allowance. Released numbers don't count. To clear the rejection, either have the platform administrator raise the account's limit, or release numbers the account no longer needs — the count is evaluated live at the time of the request.
This response carries "code": "phone_number_limit_exceeded", so you can tell it
apart from the other 409s without reading the message — see
Error codes.
Related Resources
- API Reference — Number Porting — Complete endpoint documentation
- Phone Numbers — Managing active phone numbers