Sign inGet Started

File a number's ownership paperwork

Some countries ask who holds a number before it can carry traffic. Until that paperwork is accepted and the number's registration completes, the number is allocated to you and billed, but its status is pending_ownership_registration: it carries no incoming or outgoing voice calls and sends no SMS. The number carries traffic once its status is active and its ownership.blocked_at is null. You file the paperwork from the dashboard or with the API, and both paths use the same requirements, review rules, and registration process. The number's ownership.next names each step, including when to file a new submission.

The answers you file are a legal representation made in your business's name. Once accepted, they are passed on to the carrier or regulator for that country under the name of the business they describe, so confirm them with whoever is responsible for them before you file, and do not let an automated job file answers nobody has checked.

Before you start

  • To file from the dashboard, your workspace role must allow editing compliance details. Without it, the number shows its ownership status but no button to file.
  • To file through the standalone compliance endpoints, an API key with the compliance scope at write level. A key with read level can check requirements and review progress but not file. Reading the number also needs the numbers scope at read level. In the dashboard key picker, compliance is under Compliance.
  • The number's nda_ identifier, from GET /v1/numbers. Find a number in your list shows how to look it up.

The API examples read your key from BIRD_API_KEY, its regional host from BIRD_API_URL, and the number's identifier from NUMBER_ID. Each later step names the variable it sets. The jq commands extract one field from a response; read the field by hand if you do not use jq.

Check whether a number needs paperwork

Read the number with GET /v1/numbers/{number_id}:

Code example
curl "$BIRD_API_URL/v1/numbers/$NUMBER_ID" \
  --header "Authorization: Bearer $BIRD_API_KEY"

Keep the number's country_code as COUNTRY_CODE; the requirements read and the submission both take it:

Code example
COUNTRY_CODE=$(curl -s "$BIRD_API_URL/v1/numbers/$NUMBER_ID" \
  --header "Authorization: Bearer $BIRD_API_KEY" | jq -r .country_code)

ownership is null when the number's country asks for no paperwork. It is also null when we could not read the paperwork's progress and no block is recorded on the number; read the number again. Otherwise it carries:

  • status: needs_input means answers are missing or need correcting, under_review means your answers are being reviewed, approval_pending means the paperwork is accepted and registration is still pending; calls and outgoing SMS stay blocked while blocked_at is set. approved means registration is approved, though calls and outgoing SMS stay blocked while blocked_at is set. not_required means nothing more is asked. rejected means the submission was closed, or a correction deadline passed, and it takes no more corrections. Contact support to have it reopened. unknown means the status could not be read; read the number again.
  • next: the steps that move the paperwork forward, in order. A wait step means nothing is asked of you now. Read it again after each change.
  • submission_id: the most recent submission for the number, once one exists.
  • blocked_at: when the ownership block began, or null once it is clear. The block stops incoming and outgoing voice calls and outgoing SMS.

The status of an allocated number explains how ownership relates to the number's own status.

File from the dashboard

  1. Open the number from the Numbers page. Its Ownership row shows the paperwork's status and the next steps.
  2. When the status is Details needed, select Update ownership details. The Prove ownership of this number form opens.
  3. Choose the business that holds the number, or describe a new one, then answer each item and upload the documents it asks for. Items that offer a blank form link it for you to download, complete, and upload back.
  4. Select Submit answers.

The Ownership row moves to Under review. If a reviewer rejects an answer, the row returns to Details needed: select Update ownership details again, correct the answers the form shows, then select Update ownership details at the end of the form to send them.

If the number's country has no form yet, the form page says Ownership form unavailable. Contact support to ask for that country.

File with the API

To file with the API, read what the country asks for, upload each document, submit every answer at once, then read the number to follow the review.

Read what the country asks for

Read the requirements for the number with GET /v1/compliance/requirements. Set subject_kind to number, subject_id to the number's nda_ identifier, and country_code to the number's own COUNTRY_CODE:

Code example
curl "$BIRD_API_URL/v1/compliance/requirements?subject_kind=number&subject_id=$NUMBER_ID&country_code=$COUNTRY_CODE" \
  --header "Authorization: Bearer $BIRD_API_KEY"

The response names the program the number registers under, which follows its number type; keep it as PROGRAM. It lists each item to answer in fields, in the order to present them. For each field:

  • key is what you send the answer under.
  • data_type says how to answer it. A document field takes an uploaded file; every other type takes a string, so a number goes as "1500" and a yes-or-no as "true". An enum field accepts one of its options.
  • required says whether approval waits on it, and help_text says what a good answer looks like.
  • max_items is set on a field that takes more than one answer.
  • template_url links a blank form to download, complete, and upload back, where the field has one.
  • state is where the item stands: not_supplied before you answer, then supplied, in_review, approved, or rejected, with the reviewer's reason on a rejected item. An accepted answer can later read expired and needs supplying again, and not_applicable marks an item that does not apply to you.

submission_id is null until you file. needs_input is true while any item waits on you.

A 422 with E19001 means we have no ownership form for that country yet. Contact support to ask for it.

Upload each document

Upload each file a document field asks for with POST /v1/compliance/attachments, as a multipart/form-data body with the bytes in a file part. Keep the id from the response, the attachment's tca_ identifier, as ATTACHMENT_ID:

Code example
curl --request POST "$BIRD_API_URL/v1/compliance/attachments" \
  --header "Authorization: Bearer $BIRD_API_KEY" \
  --form "file=@registration-certificate.pdf"

PNG, JPEG, and PDF files up to 10 MB are accepted, and the type is read from the file's contents. A 201 response returns the new attachment. Uploading the same file again returns the first attachment with 200, so retrying an upload does not create a duplicate. An attachment no submission cites expires after seven days.

The attachment's download_url is a signed link valid for 24 hours from when you fetched the attachment. List your attachments with GET /v1/compliance/attachments for a fresh one, or download the bytes directly with GET /v1/compliance/attachments/{attachment_id}.

Submit every answer

File the answers with POST /v1/compliance/submissions. Send subject_kind and subject_id, the program the requirements read reported, and the number's country_code. In answers, send one entry for every field whose required is true, and one for each optional field you have a real answer for; leave an optional field out rather than invent a value for it. A typed field takes value, a document field takes attachment_id, and a field with max_items takes values or attachment_ids. Save the body as submission.json, with your values in place of <NUMBER_ID>, <PROGRAM>, <COUNTRY_CODE>, and <ATTACHMENT_ID>. The example shows three of the answers a form asks for:

Code example
{
  "subject_kind": "number",
  "subject_id": "<NUMBER_ID>",
  "program": "<PROGRAM>",
  "country_code": "<COUNTRY_CODE>",
  "answers": [
    { "key": "legal_entity_name", "value": "Goldcrest Communications Inc" },
    { "key": "business_registration_number", "value": "90012768" },
    { "key": "business_registration_certificate", "attachment_id": "<ATTACHMENT_ID>" }
  ]
}

Send it with an Idempotency-Key. Reuse the key only to retry the same body: a rejection can be retained and replayed, so after a 422 correct the body and send it under a new key. Idempotency explains what is retained.

Code example
curl --request POST "$BIRD_API_URL/v1/compliance/submissions" \
  --header "Authorization: Bearer $BIRD_API_KEY" \
  --header "Content-Type: application/json" \
  --header "Idempotency-Key: ownership-$NUMBER_ID" \
  --data-binary @submission.json

There are no drafts: this request files the answers for review, so it must carry every required answer. A required field you leave out, or an answer the form refuses, comes back as a 422 with E01001 and one entry in details per field, named in param, and nothing is filed. A 201 response returns the submission with every answer on it. Keep its id, the submission's csb_ identifier, as SUBMISSION_ID.

A business your workspace describes is an identity. Create one in the dashboard's Identity Center or with POST /v1/compliance/identities, sending its display name. A number submission can also carry an inline identity instead of an identity_id. The submission response's identity_id names the new identity, which POST /v1/compliance/identities returns as id; reuse it for later numbers rather than creating another one. To file for an identity, add its identity_id, and the answers it holds fill in the ones you leave out. GET /v1/compliance/identities lists the business identities. The single-value answers you file are written back onto the identity whatever the review decides, so the next submission that names it starts from them; documents and multi-value answers are asked again each time. Use one identity per business: if you file for several end customers, give each its own identity, or one customer's approved answers fill in another's.

Follow ownership.next rather than filing again. A number has one submission per version of its country's form, so filing again while that submission is open answers 409 with E19009: correct it instead, as Correct a rejected answer shows. When we reopen a closed submission after the form changes, next asks for a new submission to POST /v1/compliance/submissions.

Follow the review

Each answer is reviewed on its own. Read the number again and check ownership.status and ownership.next, as in Check whether a number needs paperwork. To see how each answer was judged, read the submission with GET /v1/compliance/submissions/{submission_id}, or read the requirements again: each field carries its state and, when it is rejected, its reason.

When a review completes, we email the result to your organization's owners and the last recorded person who filed or corrected the submission, when one exists. A first filing by API key goes to the owners. A later API-key correction keeps the previously recorded person as a recipient. Your integration learns the result by reading ownership.status.

Correct a rejected answer

Send the replacement answers to POST /v1/compliance/submissions/{submission_id}/resupply. Include only the answers you are replacing; the others stay as they are. Take the submission_id from the number's ownership or from the requirements read:

Code example
curl --request POST "$BIRD_API_URL/v1/compliance/submissions/$SUBMISSION_ID/resupply" \
  --header "Authorization: Bearer $BIRD_API_KEY" \
  --header "Content-Type: application/json" \
  --header "Idempotency-Key: ownership-fix-1-$NUMBER_ID" \
  --data '{"answers": [{"key": "business_registration_number", "value": "90012769"}]}'

A 200 response returns the submission with your replacements, which go back to review. Once no required answer is still rejected, expired, or missing, the number's ownership.status returns to under_review. Replace answers whose state is rejected, expired, or not_supplied. When we ask for a correction after accepting your answers, an answer whose editable_for_verifier_repair is true can also be replaced until that correction closes. An answer in any other state, such as one still under review or accepted outside a correction we requested, answers 422 with E19003. A replacement document is a new upload: upload it first and send its attachment_id.

File the paperwork with the order

If you know the answers when you buy the number, send them in the order's compliance block on POST /v1/numbers/orders, in the same answers shape the submission takes. To read what the country asks for before you hold the number, call the requirements read without subject_id, with COUNTRY_CODE and NUMBER_TYPE set to the country_code and number_type of the number in GET /v1/numbers/available:

Code example
curl "$BIRD_API_URL/v1/compliance/requirements?subject_kind=number&country_code=$COUNTRY_CODE&program=$NUMBER_TYPE" \
  --header "Authorization: Bearer $BIRD_API_KEY"

An order with a compliance block uses the order's existing numbers scope at write level.

Once the order is accepted, it completes either way: if the filing in the compliance block is refused, the number is still yours, and you file with POST /v1/compliance/submissions as in Submit every answer. When the answers are filed, the new number reads under_review with its submission_id. Buy and release a number covers the order itself.

Reuse a business identity

Use GET /v1/compliance/identities/{identity_id} to read the business and its saved answers. Saved answers can include a review state, reason, and decided_at; a value with no review decision can omit its state. Rename the business with PATCH /v1/compliance/identities/{identity_id}, or remove it with DELETE /v1/compliance/identities/{identity_id}. Reads need compliance:read; creation, renaming, and deletion need compliance:write.

To verify the business itself, create the identity first. Read requirements with subject_kind=identity, its cid_ identifier as subject_id, program=business, and country_code=ZZ. File against that same identity. An inline identity on a number submission does not replace this identity-verification flow.

The review uses your submitted business details, declared contacts, and verification evidence. Filing through an API key or the dashboard does not establish a different business relationship. Keep contact details accurate and provide the evidence requested by the form.

File for an SMS sender instead

An SMS sender's paperwork uses the same requirements, attachments, submission and correction requests, with the sender's registration as the subject. Register an SMS sender over the API covers getting that registration and checking its price first.

When a request is refused

ResponseWhat it meansWhat to do
403 with E02035For a standalone compliance write, the key lacks the compliance scope or holds it at read level only.Use a key with compliance at write level.
422 with E19001We have no ownership form for the number's country yet.Contact support to ask for that country.
422 with E19013The requirements read had no subject_id and no program.Send the number's nda_ identifier, or program when you read before buying.
422 with E01001The submission leaves out a required field or has an invalid answer.Fix each field named in details and send the whole submission again under a new idempotency key.
409 with E19009The number already has a submission for its current form.Replace the answers that need it with the resupply request.
409 with E01009The resupply targets a closed submission.Contact support. If we reopen it, file what ownership.next names.
422 with E19003A replacement targets an answer that is under review, or accepted outside a correction we requested.Replace only answers whose state is rejected, expired, or not_supplied.
404 with E01008The number is not in this workspace, or country_code is not the number's country.Send the country_code that GET /v1/numbers/{number_id} reports.

Errors explains the error body and its remediation.

Next steps

Continue with the documentation, guides and examples for this topic.