Regulatory Requirements
Fulfill regulatory requirements for phone number purchases in certain countries
Some phone numbers require regulatory information before they can be used: an address, an identity or business document, or text such as a business name. Which numbers do is decided per number by the carrier, not by a fixed list of countries, and the purchase checks it for the exact number you buy, before anything is charged.
Overview
To buy a number with regulatory requirements:
- Check requirements for the number you want to buy
- Create addresses for any
addressrequirement - Upload documents for any
documentrequirement - Purchase the number with its
type, passing every requirement asregulatoryRequirements - Wait for review: the number is yours immediately with
regulatoryStatus: pending_review, and can send messages and place calls once it isapproved - Assign it to a sender, before or after approval
The information is kept for your project under the number's country and type. A later purchase in the same country and type may omit regulatoryRequirements, as long as what is kept still covers that number's requirements.
Checking Requirements
Before purchasing, check what requirements apply. Pass phoneNumber with a number from GET /v1/phone-numbers/available to get the requirements for that exact number, which is what the purchase checks. Encode its + as %2B. countryCode and type give the requirements for a country instead:
terminalcurl "https://api.zavu.dev/v1/phone-numbers/requirements?phoneNumber=%2B4930123456" \ -H "Authorization: Bearer $ZAVUDEV_API_KEY"
An empty items array means the number needs nothing: buy it normally. When the number's own requirements cannot be resolved, the list for its country and type is returned instead, and the purchase checks the same list. If the requirements cannot be retrieved at all, the API answers 502 with code requirements_unavailable instead of an empty list: retry rather than purchasing without them. For US and Canadian numbers a purchase does not wait on this lookup: they are sold as numbers without requirements.
The SDKs below take countryCode and type; they have no per-number variant yet:
const requirements = await zavu.phoneNumbers.requirements({
countryCode: "DE",
type: "local",
});
for (const req of requirements.items) {
console.log("Requirement:", req.id);
for (const type of req.requirementTypes) {
console.log(" -", type.name, `(${type.type})`);
console.log(" ", type.description);
}
}
Requirement Types
| Type | Description |
|---|---|
address | An address: create one and pass its id |
document | An identity or business document: upload one and pass its id |
textual | Text (e.g. a business name): pass the text itself |
action | An instruction to follow; send no entry for it |
Response
JSON{ "items": [ { "id": "+4930123456", "countryCode": "DE", "phoneNumberType": "local", "action": "ordering", "requirementTypes": [ { "id": "8c5b1a2e-0f3d-4f5b-9a61-2c7e4d9b1f10", "name": "Address", "description": "An address within Germany", "type": "address" }, { "id": "3f9e2d41-7b6a-4c1e-8d52-9a0b1c2d3e4f", "name": "Identity Document", "description": "Government-issued ID", "type": "document" } ] } ] }
For a phoneNumber request, id is that phone number. For a country request it identifies the requirement group. acceptanceCriteria, when present, carries allowedValues on a phoneNumber request, and minLength, maxLength and allowedValues on a country request.
Creating Addresses
If an address requirement exists, create an address first:
const created = await zavu.addresses.create({
firstName: "John",
lastName: "Doe",
streetAddress: "Unter den Linden 77",
locality: "Berlin",
administrativeArea: "Berlin",
postalCode: "10117",
countryCode: "DE",
});
console.log("Address ID:", created.address.id);
console.log("Status:", created.address.status);
Address Fields
| Field | Type | Required | Description |
|---|---|---|---|
firstName | string | Yes | First name of the person the address is registered to |
lastName | string | Yes | Last name of the person the address is registered to |
businessName | string | No | Business name, for a business address. Defaults to the person's full name |
streetAddress | string | Yes | Street address line 1 |
extendedAddress | string | No | Street address line 2 (apartment, suite, etc.) |
locality | string | Yes | City or town |
administrativeArea | string | No | State, province, or region |
postalCode | string | Yes | Postal or ZIP code |
countryCode | string | Yes | Two-letter ISO country code |
Address Status
A new address is returned with status: pending and stays that way. You can use its id in a purchase right away, in the same project it was created in. Review happens on the purchase, not on the address: follow it with the number's regulatoryStatus. An address marked rejected is refused in a purchase.
Uploading Documents
If a document requirement exists, upload the required document:
// Step 1: Get upload URL
const { uploadUrl } = await zavu.regulatoryDocuments.uploadURL();
// Step 2: Upload the file to the returned URL
const uploadResponse = await fetch(uploadUrl, {
method: "POST",
headers: { "Content-Type": "image/jpeg" },
body: fileBuffer,
});
const { storageId } = await uploadResponse.json();
// Step 3: Create document record with the storageId
const created = await zavu.regulatoryDocuments.create({
name: "John Doe Passport",
documentType: "passport",
storageId: storageId,
mimeType: "image/jpeg",
fileSize: fileBuffer.byteLength,
});
console.log("Document ID:", created.document.id);
console.log("Status:", created.document.status);
Supported Document Types
| Type | Description |
|---|---|
passport | Government-issued passport |
national_id | National identity card |
drivers_license | Driver's license |
utility_bill | Utility bill (for proof of address) |
tax_id | Tax identification document |
business_registration | Business registration certificate |
proof_of_address | Bank statement or official letter |
other | Other document type |
File Requirements
The API does not check the file's format or size; the dashboard uploader accepts the following, so stay within it:
- Formats: JPEG, PNG, or PDF
- Max size: 10MB
- Quality: Clear, readable scan or photo
- Validity: Document must not be expired
Document Status
A new document is returned with status: uploaded and stays that way. You can use its id in a purchase right away, in the project it was uploaded to. Review happens on the purchase, not on the document: follow it with the number's regulatoryStatus. A document marked rejected is refused in a purchase.
Purchasing with Requirements
Pass one entry per requirement except action ones: requirementType is the requirementTypes[].id from the requirements response, and fieldValue is the address id, the document id, or the text. type is required alongside, the type you searched the number under.
Every required id must be present, once, no unknown id may be sent, and addresses and documents must belong to the project making the purchase and must not be rejected. Otherwise the purchase is refused with 400 invalid_request, naming the requirement, before anything is charged. The same happens if an address or document cannot be registered for review.
cURLcurl -X POST https://api.zavu.dev/v1/phone-numbers \ -H "Authorization: Bearer $ZAVUDEV_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "phoneNumber": "+4930123456", "name": "Germany Line", "type": "local", "regulatoryRequirements": [ { "requirementType": "8c5b1a2e-0f3d-4f5b-9a61-2c7e4d9b1f10", "fieldValue": "<address id>" }, { "requirementType": "3f9e2d41-7b6a-4c1e-8d52-9a0b1c2d3e4f", "fieldValue": "<document id>" } ] }'
The response is the purchased number. It is billed from purchase, and cannot send messages or place calls until review approves it:
JSON{ "phoneNumber": { "id": "pn_abc123", "phoneNumber": "+4930123456", "status": "active", "regulatoryStatus": "pending_review" } }
The status is re-checked every 6 hours. Poll GET /v1/phone-numbers/{phoneNumberId} until regulatoryStatus is approved or rejected.
Assigning a Sender
Assign the number to a sender to use it, before or after approval:
cURLcurl -X PATCH https://api.zavu.dev/v1/phone-numbers/pn_abc123 \ -H "Authorization: Bearer $ZAVUDEV_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "senderId": "snd_abc123" }'
Assigned while pending_review, the number is recorded on the sender and connected when it is approved; if that connection fails it is retried until it succeeds. A sender created over the API is set up for SMS as part of the assignment. A rejected number cannot be assigned: the call answers 400. A number that stays pending_review for long may be waiting on information the API cannot supply: contact support.
Reusing Submitted Information
If the number needs regulatory information and the request carries none, the purchase reuses what your project submitted before for the same country and type, but only when it still covers every requirement of the new number and every address and document in it belongs to the project. Otherwise it is refused with 400 regulatory_compliance_required, listing the missing requirements in details.missingRequirements, and nothing is charged.
Managing Addresses
List Addresses
const result = await zavu.addresses.list();
for (const address of result.items) {
console.log(address.id, address.streetAddress, address.status);
}
Delete Address
await zavu.addresses.delete("addr_abc123");
Managing Documents
List Documents
const result = await zavu.regulatoryDocuments.list();
for (const doc of result.items) {
console.log(doc.id, doc.name, doc.status);
}
Delete Document
await zavu.regulatoryDocuments.delete("doc_xyz789");
Country-Specific Requirements
Requirements differ by country and number type, and change with regulation. The requirements endpoint is the source of truth: query it for the number you are about to buy rather than relying on a fixed list.
Best Practices
Create addresses and upload documents before the purchase call, so it carries every requirement.
A regulated number is billed from purchase but usable only once regulatoryStatus is approved.
Ensure documents are not expired and information is up to date.
Query requirements during your planning phase to avoid purchase delays.
Error Handling
| Status | Code | Description |
|---|---|---|
400 | regulatory_compliance_required | The number needs regulatory information and none was provided or reusable. details.missingRequirements lists what to send |
400 | invalid_request | Malformed request, a missing, unknown or repeated requirement id, an address or document from another project or rejected in review, one that could not be registered for review, type missing with regulatoryRequirements, or requirements that cannot be looked up for this input |
400 | number_unavailable | The number is no longer available, or is not listed under the type sent |
502 | requirements_unavailable | The requirements lookup failed. Retry; it does not mean nothing is required. A purchase refused this way is not charged. A purchase of a US or Canadian number does not return it, because it goes ahead as a number without requirements; this endpoint returns it for any country |