---
title: "Submit KYC"
method: POST
path: "/v1/whatsapp/phone-numbers/kyc"
tags: ["WhatsApp Phone Numbers"]
deprecated: true
---

# Submit KYC

`POST /v1/whatsapp/phone-numbers/kyc`

## Request

- Base URL: `https://zernio.com/api`
- URL: `https://zernio.com/api/v1/whatsapp/phone-numbers/kyc`
- Auth: HTTP bearer

> **Deprecated.**

Deprecated alias of `/v1/phone-numbers/kyc`; same contract. New
integrations should use that path.

Submit the end customer's KYC (textual values, uploaded documents,
address) for a Tier 3/4 country. Documents are streamed straight to the
number provider and are not stored by Zernio. Builds + submits a
regulatory requirement group and claims a pending_regulatory slot; the
number is ordered + activated once the provider approves (asynchronous).
A customer may hold several same-country numbers in review at once; a
double-submit of the SAME attempt is deduped via `submissionId`.

For an ID-card document requirement, carriers commonly require BOTH sides:
combine the front and back into a single file before uploading (the
dashboard does this automatically). A one-sided ID is a common decline
reason; fix it via POST /v1/whatsapp/phone-numbers/{id}/remediate.

Before submitting, call GET /v1/whatsapp/phone-numbers/availability to
check the country has deliverable inventory and, for geographic-match
countries, which area the address must be in. Otherwise the submission
can pass review yet never be assignable a number.

## Request body

- object
  - `profileId` string, required
  - `country` string, required
  - `submissionId` string: Idempotency token for this submission attempt. Once the number has been ordered, a retry with the same token returns that same number instead of ordering another. A submission that fails before the number is ordered releases the token, so you can correct your details and re-submit with it. Omit it and every call provisions a new number.
  - `quantity` integer: Provision several same-country numbers from one submission (1-5). The single verification covers all of them; each number is billed only when it activates. Numbers that fail to order are skipped (best-effort). With `areaCode`, a quantity above that area's live stock is rejected with a 400.
  - `reuse` boolean: Reuse a prior approved verification for this country (skips document/field collection; places the order immediately).
  - `reuseOptionId` string: Which reusable verification to use (GET reusable.options[].id). The unambiguous selection key. Omitted = the approved default. No match = 409.
  - `reuseFrom` string: Legacy fallback for `reuseOptionId`: the source phone number (GET reusable.options[].fromPhoneNumber). Ambiguous when a number labels two verifications, so prefer `reuseOptionId`. Omitted = the approved default. No match = 409.
  - `areaCode` string: Area code (NDC) the number must be in. Hard constraint: an empty area pool fails with 409 code AREA_CODE_UNAVAILABLE instead of ordering from another area. Omit for any area. Options come from GET /v1/phone-numbers/availability (areaOptions); the purchase 202 kycUrl echoes the areaCode picked at purchase time so it can be passed here.
  - `preOrder` boolean: With areaCode: pre-order that area when it has no stock (an area listed in soldOutAreas with preOrderable true) instead of failing with AREA_CODE_UNAVAILABLE. The carrier sources a number in that area. Without areaCode it accepts the pre-order a previous submit offered with 409 code area_pre_order_available (a geographic-match country whose address area has no stock): resend the same body with preOrder true and the order is placed for that area. A whole pair with no stock is pre-ordered without either flag.
  - `endUserFirstName` string: End user's legal first name. Required when the country has an action/ID-verification (Onfido) requirement.
  - `endUserLastName` string: End user's legal last name. Same condition as endUserFirstName.
  - `values` object: requirementId → textual value
  - `documents` union[]: One per document requirement. Each is EITHER inline base64 OR a `documentId` returned by POST /v1/whatsapp/phone-numbers/kyc/upload-document (use the upload endpoint for large files to stay under the request-size limit).
    - union
      - object
        - `requirementId` string, required
        - `filename` string, required
        - `base64` string, required
      - object
        - `requirementId` string, required
        - `documentId` string, required: Id from POST /v1/whatsapp/phone-numbers/kyc/upload-document.
  - `address` object
    - `requirementId` string
    - `country_code` string
    - `business_name` string
    - `first_name` string
    - `last_name` string
    - `street_address` string
    - `extended_address` string: Address complement: apartment, suite, unit, or the quadra/lote used in some countries. Optional. Does not substitute for a building number on street_address.
    - `locality` string
    - `administrative_area` string
    - `postal_code` string

## Response `200`

KYC submitted (or already submitted); number pending review.

- object
  - `status` 'kyc_submitted' | 'kyc_reused' | 'kyc_already_submitted'
  - `preOrder` boolean: True when this submission placed a pre-order instead of an order from stock: the country and type had nothing deliverable, the picked areaCode was sold out (preOrder: true sent), or the country requires the number's area to cover the registered address, that area has no stock, and the caller accepted the offer (preOrder true after a 409 area_pre_order_available; the carrier is then asked for a number in exactly that area). The number stays `pending_regulatory` until we get it, from regular stock the moment it returns or sourced by the carrier (usually 2 to 4 weeks, never guaranteed), and is not billed until active. Releasing it (DELETE /v1/phone-numbers/{id}) cancels the pre-order. A pre-order is one number: `quantity` above 1 is rejected with 400.
  - `phoneNumber` object: The first/primary number, kept at the top level for backward compatibility. See `numbers` for the full set when `quantity` > 1.
    - `id` string
    - `status` string
    - `country` string
  - `numbers` object[]: Every number provisioned from this submission. Length equals the requested `quantity` on full success (fewer if some orders failed; best-effort). The first element mirrors `phoneNumber`.
    - `id` string
    - `status` string
    - `phoneNumber` string
    - `country` string

## Other responses

- `400`: Validation error (e.g. address not in-country, file too large)
- `401`: Missing or invalid API key. `code` is `missing_credentials` when no Authorization header was sent and `invalid_credentials` when the key is unknown, revoked or expired.
- `409`: code area_pre_order_available: the country requires the number to cover the registered address and that area has no stock, but the carrier can source one. Nothing was created; details carries { areaCode, areaName, estimatedWeeks: "2-4", billedWhenActive: true }. Show it to the customer and, once they agree, resend the same body with preOrder true (optionally with details.areaCode as areaCode). Otherwise: reuse was requested but no prior approved verification exists for this country; or the requested areaCode (or, in a geographic-match country, the area covering the registered address) has no deliverable inventory and cannot be pre-ordered (code: area_code_unavailable; pick another area, or a registered address in an area with stock); or the whole country and type pool has nothing deliverable and cannot be pre-ordered (code: country_out_of_stock; choose an area with stock or set a stock watch). When the only numbers the carrier lists failed WhatsApp registration recently and are held back, the message names the date the first one clears and details.undeliverableUntil carries it as an ISO timestamp.
- `503`: An upstream service or database is temporarily unavailable. Retry after the indicated delay. A timed-out write may have completed upstream; check its outcome before resubmitting.

## Changes

- **2026-10-14** `c9d54f4783af`: 1 info
  - added the non-success response with the status `503`
- **2026-10-06** `f8c8f34fb41a`: 1 warning
  - added the new `account` enum value to the `details/budgetScope` response property for the response status `401`
- **2026-10-02** `d556591af3f6`: 7 info
  - added the optional property `code` to the response with the `401` status
  - added the optional property `details` to the response with the `401` status
  - added the optional property `docUrl` to the response with the `401` status
  - added the optional property `param` to the response with the `401` status
  - …3 more
- **2026-09-15** `0dba7d004d75`: 1 info
  - added the new optional request property `preOrder`
- **2026-09-10** `e70ed06e7150`: 1 info
  - added the optional property `preOrder` to the response with the `200` status

[Operation history](https://skmtc.dev/zernio/apis/zernio-api/changes/v1/whatsapp/phone-numbers/kyc/post.md)

---

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