---
title: "Submit a port-in request"
method: POST
path: "/v1/port-ins"
tags: ["Port-Ins"]
---

# Submit a port-in request

`POST /v1/port-ins`

## Request

- Base URL: `https://api.telgea.com`
- URL: `https://api.telgea.com/v1/port-ins`
- Auth: API key in header `x-api-key`

Submits a number porting request to bring a phone number from another carrier into Telgea. The user must have an existing plan in INACTIVE or PORTING status.

**Important constraints:**
- The `executionDate` must be one of the type's `executionDate.dates` from `GET /v1/port-ins/fields/{countryCode}`, which hold until its `validUntil`. The date is checked once everything else passes: a date outside them is then refused with 400 BAD_REQUEST, and no port-in is created.
- Only **one port-in can be in progress** per phone number at a time. Submitting a port-in for an MSISDN that already has an active (non-completed, non-failed, non-rejected) port-in will be rejected.
- A number **already with Telgea** cannot be ported in: one on a Telgea line, or one whose plan ended within the last 14 days and can still be restored. It is refused with 409 CONFLICT.

**Recommended flow:**
1. Call `GET /v1/port-ins/fields/{countryCode}` to discover required fields for the country
2. Call `POST /v1/port-ins/validate` to verify the data before submission
3. Call this endpoint to submit the port-in

If provider-side validation fails, the response will have `status: "REJECTED"` with an `errors` array describing the issues. A successful submission returns `status: "CREATED"`.

The port-in will progress through states: CREATED → SUBMITTED → ACCEPTED → SUCCEEDED. Check the status with `GET /v1/port-ins/{portInId}`.

**Retrying a port-in that ended in REJECTED or FAILED:** read `failure.reason` and `failure.field` on the port-in, correct what they point at (`failure.text` explains it in words you can show your customer), then call this endpoint again with the same `msisdn`. The failed attempt is kept as history and stays readable at its own id — `GET /v1/port-ins/number/{numberId}` lists every attempt for the number, newest first. A retry sent while a port-in for that number is still in flight is refused with 409 CONFLICT — a number can only be ported once at a time anywhere. Wait for it to finish, then read `failure.reason` and submit again.

## Headers

- `idempotency-key` string: A value unique to this request, of 1 to 255 printable ASCII characters — a UUID is the usual choice. Retry with the same key within 24 hours and you get the original response back, even if it was a failure, and nothing is done twice. Send a new key whenever you change the request. Keys are private to your API key and organisation.

## Request body

- CreatePortInBody
  - `userId` string, uuid, required: UUID of the user to port a number for. The user must have an INACTIVE or PORTING plan.
  - `countryCode` string, required: ISO 3166-1 alpha-2 country code
  - `msisdn` string, required: Phone number to port in, in E.164 format
  - `executionDate` string, date, required: Requested porting date in YYYY-MM-DD format. Must be one of the type's `executionDate.dates` from `GET /v1/port-ins/fields/{countryCode}`, which hold until its `validUntil`.
  - `type` string, required: Port-in type as returned by the fields endpoint (e.g., "personal", "business")
  - `fields` object, required: Port-in fields as defined by the fields endpoint. Must include authorizationCode.

## Response `200`

Port-in request processed. Check the `status` field: "CREATED" means the port-in was accepted for processing; "REJECTED" means validation failed — see the `errors` array.

- CreatePortInResponse
  - `id` string, required: UUID of the created port-in
  - `status` 'CREATED' | 'REJECTED', required: Status of the port-in. CREATED means accepted for processing; REJECTED means validation failed.
  - `msisdn` string: The phone number being ported
  - `numberId` string: UUID of the associated number resource
  - `executionDate` string: Confirmed execution date
  - `errors` PortInValidationError[]: Validation errors when status is REJECTED
    - `message` string, required: Validation error description
    - `field` string: The field that caused the validation error
    - `code` 'REQUIRED' | 'FORMAT_INVALID' | 'LENGTH_INVALID' | 'NOT_ALLOWED' | 'DATE_NOT_ALLOWED' | 'CHECK_DIGIT_INVALID' | 'WRONG_CUSTOMER_TYPE', required: Why the value was refused, as a stable code to branch on. A code is never renamed or removed, but new ones can be added: show the `message` for a code you do not recognise.

## Other responses

- `400`: Request body failed schema validation, or business rule violation (e.g., user plan not in correct state, or, once everything else passes, an `executionDate` the market does not offer)
- `401`: Missing or invalid API key in the X-API-Key header
- `403`: Insufficient permissions to create port-ins, or the country is not available for your organization: it is not enabled, or it requires business verification your organization has not passed.
- `404`: No user with the given `userId` exists in your organization, so no port-in was created.
- `409`: No port-in was created: Telgea already holds this number, or a port-in for it is already in flight.
- `429`: The API key has used its request quota for the current window. `Retry-After` says how many seconds until it resets.
- `500`: Internal server error. Contact support if this persists.

---

[API](https://skmtc.dev/telgea/apis/telgea-api.md) - [All operations](https://skmtc.dev/telgea/apis/telgea-api/llms.txt) - [OpenAPI document](https://skmtc.dev/telgea/apis/telgea-api/revisions/4e8f8c04fe9e?raw)
