KKeepMyNumber
Get started

Port-in orders

A port-in order transfers numbers from their current carrier onto the platform. Orders are asynchronous: after submission, progress depends on the losing carrier and can take from hours (US FastPort-style) to weeks (international/local processes).

Lifecycle

draft ──submit──▶ submitted ──▶ in_process ──▶ foc_scheduled ──▶ activating ──▶ completed
                     │               │                                          completed_partial
                     └── exception ◀─┘    fix requirements, resubmit ──▶ submitted
Status Meaning
draft Created; fulfill requirements and end-user info, then submit
submitted Sent to the provider; being validated
in_process The losing carrier is processing the port
exception Something was rejected — check requirements and comments, fix, resubmit
foc_scheduled The port date (FOC — Firm Order Commitment) is confirmed; see foc_actual
activating Numbers are being activated on the platform
completed / completed_partial Done — numbers are live (partial: some numbers failed)
cancel_pending Cancellation requested, awaiting provider confirmation
cancelled / rejected Terminal

Every transition emits a porting_order.status_changed webhook.

Order splitting

One POST /v2/porting_orders may return several orders. Numbers are grouped by country and number type, and providers may split further (e.g. by losing carrier). All orders from one request share a batch_id, and a porting_order.split event tells you it happened. Each order is fulfilled and submitted independently — always iterate over the response array.

Requirements

Each order carries requirements — the documents and data legally required for its country, number type, and provider. Check them before ordering:

curl "https://api.example.com/v2/porting/requirements?country_code=GB&number_type=mobile" \
  -H "Authorization: Bearer pk_live_YOUR_KEY"

Requirement statuses: requirement-info-pending → you must act; requirement-info-under-review → we are validating; requirement-info-exception → rejected, see exception_reason, resubmit; approved → done.

To fulfill a textual requirement, PATCH the value; for a document requirement, upload the file first and pass its id:

# upload
curl -X POST https://api.example.com/v2/documents \
  -H "Authorization: Bearer pk_live_YOUR_KEY" \
  -F "file=@invoice.pdf" -F "document_date=2026-08-01T00:00:00Z"

# attach
curl -X PATCH https://api.example.com/v2/porting_orders/{order_id}/requirements/{req_id} \
  -H "Authorization: Bearer pk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"field_value": "DOCUMENT_ID"}'

Invoices and LOAs must usually be fresher than 30 days — we validate this at submit time so you fail fast instead of waiting days for a carrier rejection.

The LOA (Letter of Authorization)

Do not write your own LOA. Download the pre-filled one — it already contains the numbers, account holder, and service address from your order, which eliminates the typos that cause most rejections:

curl https://api.example.com/v2/porting_orders/{order_id}/loa \
  -H "Authorization: Bearer pk_live_YOUR_KEY" -o loa.pdf

Have the account holder sign it, upload the signed PDF via POST /v2/documents, and attach it to the loa requirement.

End-user data

end_user must match the losing carrier's records exactly — mismatches are the second most common rejection cause. Provide entity_name (businesses) or auth_person_name (individuals), the account_number at the losing carrier, and the service location.

Exceptions

If the order hits exception:

  1. GET /v2/porting_orders/{id}/requirements — look for requirement-info-exception and its exception_reason.
  2. GET /v2/porting_orders/{id}/comments — our operations team and the provider leave details here. You can reply via POST …/comments.
  3. Fix the data or documents, then POST …/submit again.

Cancellation

POST /v2/porting_orders/{id}/cancel. A draft cancels instantly. After submission the order enters cancel_pending — cancellation is not guaranteed once the losing carrier has confirmed the port; watch for the final cancelled (or a return to in_process) via webhook.

Duplicates and idempotency

  • A number that is already active or in an active port on the platform is refused with 409 and the existing order ids.
  • Send Idempotency-Key on creation: retries with the same key and body return the original response instead of creating duplicate orders.