Send KYC documents for a phone number order (pbx)
Send KYC documents for an order you already placed, typically because
POST /numbers/orders/check answered kyc_required_at_order: false and the
order was placed without them. Also use it to replace a document the carrier
rejected (kyc.provided[].status: rejected): send a new file under the same
documentType.
Must be called as multipart/form-data: one file part kyc[<documentType>] per
file document (PDF, JPEG or PNG, up to 10 MB each by
default), and a plain form field kyc[<documentType>]=<value> for identifier-only
types such as business_registration_number. At least one document is required.
The documentType values are the ones in kycRequirements from the check
endpoint; they may only contain letters, digits, underscores and hyphens.
The documents are forwarded to the carrier synchronously. On success the
response is the updated order (same shape as GET /numbers/orders/{id}), whose
kyc.provided now lists what you sent. The carrier then reviews them
asynchronously: you are told per document (kyc.document_accepted,
kyc.document_rejected) and once the whole KYC is signed off (kyc.validated)
through your webhook: see Webhooks in the Phone Number Orders introduction.
Documents already on file
For an order on a shared (deferred) carrier contract, documents your account
already holds for the order's address may be sent to the carrier for you,
once the address verification has been approved. Your order then shows them in
kyc.provided, and you may receive kyc.document_* webhook events without having
called this endpoint. Documents you upload through this API are sent to the carrier
only; they are not kept for later orders.
Errors
404: no such order in your PBX.409: the order has not been placed with the carrier yet (it has noorder_reference), so there is nothing to attach documents to.422: either the order cannot take documents any more (its KYC is already validated, or the order was canceled), a document failed validation (wrong file type, too large), or the carrier refused them; in the last caseerrorsnames the offendingkyc[<documentType>]parameters.502: the carrier could not be reached, so the documents may not have been delivered. CheckGET /numbers/orders/{id}(kyc.provided) before sending them again.
API key created on the Cockpit Integrations page (an "API key" integration).
It is a bearer token owned by the customer's PBX and limited to the scopes
selected when the key was created (e.g. phone-numbers, push-configuration).
Send it in the Authorization header:
Authorization: Bearer <api_key>
Manage keys (create / reveal / revoke) from Integrations → New integration → API key.
- HTTP Authorization Scheme
bearer
Request body · required · multipart/form-data
kyc*object
certificate.pdfbill.pdfpassport.jpgBE-12345Responses
550e8400-e29b-41d4-a716-446655440000po-2026-00042po-2026-0004201a0ae76-0000-4000-8000-000000000000ACME GmbHcreated requested submission_failed processing success success_kyc_required error processing_failed canceledrequestedaddressobject
Adenauerallee153113BonnDEAdenauerallee 1, 53113 Bonn, DE1+49228numbersarray<string>
phone_numbersarray<object>
550e8400-e29b-41d4-a716-446655440000+12125550100Customer Support1550e8400-e29b-41d4-a716-446655440100call_flowobject | null
kycobject
pending validated rejected nullpendingprovidedarray<object>
utility_billpending accepted rejected unknown nullaccepted2026-05-12T11:15:03+00:002026-05-13T08:02:41+00:00missingarray<object>
not_required pending retrying delivered failed cancelledAuthorization Token is missingerrorsobject
https://cockpit.voxbi.com/api/v1/numbers/orders/{id}/documents
curl -X POST 'https://cockpit.voxbi.com/api/v1/numbers/orders/{id}/documents' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-F 'kyc[business_registration_certificate]=@certificate.pdf' \
-F 'kyc[utility_bill]=@bill.pdf' \
-F 'kyc[id_document]=@passport.jpg' \
-F 'kyc[business_registration_number]=BE-12345'
const body = new FormData();
body.append('kyc[business_registration_certificate]', fileInput.files[0]); // certificate.pdf
body.append('kyc[utility_bill]', fileInput.files[0]); // bill.pdf
body.append('kyc[id_document]', fileInput.files[0]); // passport.jpg
body.append('kyc[business_registration_number]', 'BE-12345');
const response = await fetch('https://cockpit.voxbi.com/api/v1/numbers/orders/{id}/documents', {
method: 'POST',
headers: { Authorization: `Bearer ${YOUR_TOKEN}` },
body,
});
const data = await response.json();
console.log(data);
import requests
response = requests.post(
'https://cockpit.voxbi.com/api/v1/numbers/orders/{id}/documents',
headers={'Authorization': f'Bearer {YOUR_TOKEN}'},
data={
'kyc[business_registration_number]': 'BE-12345',
},
files={
'kyc[business_registration_certificate]': open('certificate.pdf', 'rb'),
'kyc[utility_bill]': open('bill.pdf', 'rb'),
'kyc[id_document]': open('passport.jpg', 'rb'),
},
)
response.raise_for_status()
data = response.json()
print(data)
<?php
$ch = curl_init('https://cockpit.voxbi.com/api/v1/numbers/orders/{id}/documents');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Authorization: Bearer YOUR_TOKEN']);
curl_setopt($ch, CURLOPT_POSTFIELDS, [
'kyc[business_registration_certificate]' => new CURLFile('certificate.pdf'),
'kyc[utility_bill]' => new CURLFile('bill.pdf'),
'kyc[id_document]' => new CURLFile('passport.jpg'),
'kyc[business_registration_number]' => 'BE-12345',
]);
$data = json_decode(curl_exec($ch), true);
print_r($data);
{ … }
"kyc": { … }
{ … }
"address": { … },
"numbers": [ … ],
"phone_numbers": [ … ],
{ … }
"kyc": { … },
"provided": [ … ],
{ … },
{ … }
{ … }
private, must-revalidatekeep-aliveapplication/jsonOrigin6057