Create the account
Send company details and an administrator email.
Register an organisation, verify its administrator and create an isolated PBX with its own managed openwebpbx.com address.
Build onboarding into your own service, reseller portal or internal tools. Each tenant keeps its own PBX configuration while using the shared installation’s current application files.
https://call.openweb.co.za/api/v1One shared server, separate PBX services. The API creates a tenant’s PBX inside the hosted installation. It does not create a separate virtual machine, allocate a carrier number or activate a paid provider connection.
Debian 1.0.25 · Administration API v2
Compatibility: administration API v2 is live on hosted Debian 1.0.25. Public complete Debian and Windows downloads remain 1.0.23 and do not acquire these new endpoints automatically. Use API v1 for registration and onboarding.
Create an integration key in PBX → API Keys or Tenant Admin → API Keys. Choose its tenant, optional individual PBX, permissions and expiry. The full key appears once; revoke or replace it without changing phone passwords or QR codes.
curl --fail-with-body \
-H "Authorization: Bearer $OPENWEBPBX_API_KEY" \
https://call.openweb.co.za/api/v2/servicesAPI v2 covers users, SIP trunks, the single DID routing editor, office hours, ring groups, queues, call control, reports, voicemail and recordings, greetings, Call Me Back, hotel services, conferences, staff roles, phone recovery, provisioning, templates, resource packages and encrypted backups. Each key is checked against current ownership, permissions and tenant suspension on every request.
| Feature | Start here |
|---|---|
| PBX configuration and routing | /pbx/{domain_uuid}/users, /trunks, /dids and /actions/did-editor |
| Live calls and calling features | /pbx/{domain_uuid}/actions/live and named actions in the OpenAPI document |
| Templates and reseller packages | /templates, /services, /plans and /plans/assign |
| Tenant backup and restore | /tenants/{tenant_uuid}/backups, then verify, download or confirmed restore |
| Full server recovery | /instance/backups — instance administrator permission required |
| API key management | /keys — delegation stays within the calling key’s boundary and permissions |
Use Authorization: Bearer over HTTPS from your server. Keys allow 120 requests per minute and JSON up to 128 KiB. Separate binary backup import endpoints stream encrypted archives up to 2 GiB with an independently supplied backup password. Credentials and QR setup require explicit credential access; normal configuration reads remove passwords and server paths.
Hosted resources are controlled by the operator. Resellers define extension and concurrent call allowances, quote extra capacity and approve it after their billing process. This release provides resource orders and manual billing approval; it does not collect payments automatically. Self-hosted installations do not incur hosted resource charges.
API v2 requires Debian 1.0.25. API v1 registration and managed domain onboarding remain available separately. Windows support is qualified and released independently; a version number alone does not imply Windows feature parity.
Four steps
Send company details and an administrator email.
Redeem the one-use code and save your API token.
Create a service with a unique request key.
Poll readiness, then open the returned tenant URL.
Present the terms and privacy policy in your own onboarding flow before accepting registration. Choose a unique password of 12–72 UTF-8 bytes, including a letter and a number, and a short company label of 3–40 lower-case letters, numbers or hyphens.
curl --request POST 'https://call.openweb.co.za/api/v1/registrations' \
--header 'Content-Type: application/json' \
--data '{
"tenant_name": "Example Company",
"slug": "example-company",
"email": "owner@example.com",
"password": "replace-with-a-long-unique-password-42",
"accept_terms": true
}'A valid request returns 202 Accepted with status: "verification_required". This generic response protects existing accounts; it does not reveal whether an email or label already exists and does not prove inbox delivery.
The global outgoing-mail service sends a code valid for 30 minutes. Send it with the same password you chose at registration in a POST body. Opening an email or following a link alone never activates a tenant.
curl --request POST 'https://call.openweb.co.za/api/v1/registrations/verify' \
--header 'Content-Type: application/json' \
--data '{"token":"VERIFICATION_CODE_FROM_YOUR_EMAIL","password":"YOUR_ORIGINAL_REGISTRATION_PASSWORD"}'Successful verification returns 201 Created with the tenant, a new access_token, its expiry and token metadata. Store the token securely in your integration’s secret store. Subsequent read endpoints never reveal it.
Read GET /templates, then use a returned template UUID. Send a new UUID in Idempotency-Key. Keep that key for retries of the same intended operation.
curl --request POST 'https://call.openweb.co.za/api/v1/services' \
--header "Authorization: Bearer $OPENWEB_TOKEN" \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: 9b484c7d-4e6f-48b2-b9fd-c55260d8b563' \
--data '{
"template_uuid": "TEMPLATE_UUID_FROM_THE_LIST",
"service_name": "Main Office",
"slug": "main-office",
"subdomain": "example-company"
}'The response contains a new service and its subdomain status. Creation uses the current installed application files and the selected template’s current revision. Provider secrets are not exposed. Only shared published starter templates explicitly approved by the instance administrator are eligible, with no trunks, outbound rules or additional settings. If the list is empty, ask the instance administrator to publish an approved starter template. Configure your own provider after creating the PBX.
curl 'https://call.openweb.co.za/api/v1/services/SERVICE_UUID/subdomain' \
--header "Authorization: Bearer $OPENWEB_TOKEN"Wait for ready: true, then use the returned url and admin_url. The address guide explains pending DNS, certificates and collision handling. Set up a provider and test incoming and outgoing calls before moving live numbers.
Already verified? Send POST /auth/token with your owner email and password. Protected operations use Authorization: Bearer TOKEN. Browser sign-in cookies and phone passwords do not authenticate this API.
curl 'https://call.openweb.co.za/api/v1/me' \
--header "Authorization: Bearer $OPENWEB_TOKEN"Tokens start with owta_, followed by 64 hexadecimal characters. They expire after at most 90 days, with a default of 90 days. The server stores hashes, not usable token secrets. Each request checks that the owner and tenant remain active.
To change your account password, use POST /me/password with current_password and new_password. This revokes every previous owner API key, including the key making the request, and returns a replacement. Save that replacement before your next call. SIP, extension and phone-app passwords are unchanged.
Create a separate named token for each integration with POST /tokens, rotate it when needed and revoke it when no longer used. A tenant may have up to 10 active tokens. Rotation invalidates the old secret. A token-creation or rotation response is not saved for later secret recovery; if a response is lost, sign in again and review/revoke unused tokens.
Pass a single label such as example-company when creating the PBX, or use POST /services/{service_uuid}/subdomain for an existing owned service. Labels have 3–40 lower-case letters, numbers or hyphens and must start and end with a letter or number. Reserved names are refused. Omit subdomain during service creation to use the tenant slug.
GET /subdomains/availability?label=example-company is a local, advisory check. Its response has scope: "this_instance" and reservation_confirmed: false. It does not reserve global ownership or make a DNS request.
The central custodian confirms ownership and may assign a stable suffix for a label held elsewhere. Always use the final assigned hostname from status, rather than constructing it from your requested label. Once an address is queued or leased, it cannot be silently renamed. The initial custodian limit is 50 names per instance, including existing reserved names.
{
"subdomain": {
"service_uuid": "0d59d9f6-33a6-4328-8b31-dc63fe96d329",
"requested_label": "example-company",
"requested_hostname": "example-company.openwebpbx.com",
"hostname": null,
"url": null,
"admin_url": null,
"state": "pending_dns",
"ready": false,
"next_attempt": "2026-10-28T08:06:00+00:00",
"error_category": ""
}
}url and admin_url remain null until both the certificate and local transport are verified ready. Registration runs asynchronously through the signed domain worker. Your integration never receives DNS credentials, instance signing keys or a wildcard certificate key. Existing SIP realms and desk-phone credentials are preserved.
After readiness, users can use the tenant portal and administrators its /admin address. Phone setup remains under the tenant’s normal Users workflow, with QR codes or app passwords. API tokens are not Android connection credentials.
Self-installed servers and Webhotel.cloud images
Installing OpenWeb PBX on your own server? Open the setup wizard and use the code displayed by the installed server. Confirm your account email, choose a business address and keep the server running while its secure connection is prepared. Your PBX, database, calls and recordings stay on your own installation.
Debian 1.0.23 includes guided registration, the first-boot consumer and mandatory registration for fresh installations. See the Debian installation guide and the qualified release scope. Windows Server 1.0.23 uses the same guided registration flow on Windows Server 2025 x64 with Desktop Experience. Signed Windows 1.0.23 upgrades require installed Windows 1.0.22 or newer; see its qualification record for actual component and reused-recovery scope. Follow the Windows installation guide for local setup and registration.
Public pairing checks cover real custodian DNS, Let’s Encrypt certificates, signed authorization and verified tenant HTTPS readiness. The release report records exact installer, upgrade, restore and provider-image acceptance. Test verification mail was intercepted privately; these checks do not establish new inbox delivery, physical handset or carrier acceptance.
/api/v1/wizard API and its 20-operation specification. The image receives a private device credential; the owner’s password and bearer token stay out of the guest. No custom hostname or certificate is needed before pairing.Remote authorization creates no hosted /services row. A browser receives a connection link only after the actual tenant HTTPS proof and custodian ownership match. Always use the final assigned tenant hostname, including a collision suffix if one is assigned. Existing desk-phone domains, credentials and working connections are preserved.
Hosting integrations check global availability with POST /wizard/subdomains/availability, then reserve the chosen name for a verified owner before taking payment or creating a server. The reservation is bound to the installed server during claim. A separate encrypted cleanup credential stays in the provider backend and never enters the guest or browser.
To remove an instance, the provider first confirms its own virtual machine is stopped, then requests exact scoped cleanup through POST /wizard/servers/revoke. Only a fresh confirmed response permits address release. Conflicting ownership or uncertain DNS cleanup keeps those resources reserved for recovery. See the wizard specification for exact fields and retry rules.
/onboarding/email/request and /onboarding/email/verify./installations/challenge with canonical server hostname, public P256 key, local tenant/domain UUIDs and the chosen label.POST /installations; verify the signed receipt against the independently pinned public key before storing it.For exact signature bytes, provider-image preparation and local helper contracts, read the downloadable Webhotel and first-boot contract. The central API never receives a private instance key or exposes DNS provider credentials.
Expand an operation for its request, response and example. The OpenAPI file includes the machine-readable schemas. These examples use fictional data and never run API calls from this page.
17 of 24 endpoints shown.
No matching endpoints. Try “service”, “token” or “register”.
Read safe public API/version metadata. No account details or credentials are returned. A disabled or uninstalled API returns 503.
curl 'https://call.openweb.co.za/api/v1/health'{
"api": "OpenWeb PBX Tenant API",
"version": "1",
"software_version": "1.0.21",
"registration_enabled": true,
"documentation": "https://openwebpbx.com/api-docs"
}Other responses: 403, 405, 503. See errors and retry guidance.
Valid requests return a generic response without confirming whether an email or slug is already registered. No PBX, active owner or API token is created before email verification. The email code expires after 30 minutes. Public signup is enabled according to instance policy.
| Body field | Type | Presence | Rules |
|---|---|---|---|
tenant_name | string | Required | Maximum 120 UTF-8 bytes. Minimum 1 characters. Maximum 120 characters. |
slug | string | Required | 3–40 letters, numbers or hyphens; starts and ends with a letter or number. Reserved labels are refused. Minimum 3 characters. Maximum 40 characters. |
email | Required | Maximum 254 characters. | |
password | password | Required | 12–72 UTF-8 bytes, including a letter and a number. Never logged or returned. |
accept_terms | boolean | Required | Your client must present the project terms and privacy policy. Must be true. |
curl --request POST 'https://call.openweb.co.za/api/v1/registrations' \
--header 'Content-Type: application/json' \
--data '{
"tenant_name": "Example Company",
"slug": "example-company",
"email": "owner@example.com",
"password": "replace-with-a-long-unique-password-42",
"accept_terms": true
}'{
"status": "verification_required",
"message": "If these details can be registered, a verification code will be emailed. Check your inbox and spam folder."
}Other responses: 400, 403, 405, 413, 415, 429, 503. See errors and retry guidance.
Redeem the single-use email code together with the original registration password. Returns the active tenant and a new bearer token once. Use POST; opening a link or GET request never activates an account.
| Body field | Type | Presence | Rules |
|---|---|---|---|
token | string | Required | Single-use 30-minute verification code received by email. |
password | password | Required | The same password supplied when registering. Binds verification to your original registration. |
curl --request POST 'https://call.openweb.co.za/api/v1/registrations/verify' \
--header 'Content-Type: application/json' \
--data '{
"token": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"password": "original-registration-password-42"
}'{
"tenant": {
"tenant_uuid": "d8da1fce-51ac-4e1a-a53a-91a4971e0e3c",
"tenant_name": "Example Company",
"slug": "example-company",
"email": "owner@example.com",
"service_limit": 1,
"service_count": 0
},
"access_token": "owta_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"token_type": "Bearer",
"expires_at": "2027-01-26T08:00:00+00:00",
"token": {
"token_uuid": "17eae30b-1965-47ef-91bd-66e623b5ec99",
"name": "Tenant API",
"created_at": "2026-10-28T08:00:00+00:00",
"expires_at": "2027-01-26T08:00:00+00:00",
"revoked_at": null,
"last_used_at": null
}
}Other responses: 400, 401, 403, 405, 409, 413, 415, 429, 503. See errors and retry guidance.
A verified, enabled owner can obtain a fresh tenant-scoped token. Invalid credentials are reported generically. At most ten active tokens are allowed.
| Body field | Type | Presence | Rules |
|---|---|---|---|
email | Required | Maximum 254 characters. | |
password | password | Required |
curl --request POST 'https://call.openweb.co.za/api/v1/auth/token' \
--header 'Content-Type: application/json' \
--data '{
"email": "owner@example.com",
"password": "YOUR_ACCOUNT_PASSWORD"
}'{
"tenant": {
"tenant_uuid": "d8da1fce-51ac-4e1a-a53a-91a4971e0e3c",
"tenant_name": "Example Company",
"slug": "example-company",
"email": "owner@example.com",
"service_limit": 1,
"service_count": 0
},
"access_token": "owta_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"token_type": "Bearer",
"expires_at": "2027-01-26T08:00:00+00:00",
"token": {
"token_uuid": "17eae30b-1965-47ef-91bd-66e623b5ec99",
"name": "Tenant API",
"created_at": "2026-10-28T08:00:00+00:00",
"expires_at": "2027-01-26T08:00:00+00:00",
"revoked_at": null,
"last_used_at": null
}
}Other responses: 400, 401, 403, 405, 409, 413, 415, 429, 503. See errors and retry guidance.
Returns the current authenticated tenant and current token metadata. Token secrets are never returned by read endpoints.
curl 'https://call.openweb.co.za/api/v1/me' \
--header "Authorization: Bearer $OPENWEB_TOKEN"{
"tenant": {
"tenant_uuid": "d8da1fce-51ac-4e1a-a53a-91a4971e0e3c",
"tenant_name": "Example Company",
"slug": "example-company",
"email": "owner@example.com",
"service_limit": 1,
"service_count": 0
},
"token": {
"token_uuid": "17eae30b-1965-47ef-91bd-66e623b5ec99",
"name": "Tenant API",
"created_at": "2026-10-28T08:00:00+00:00",
"expires_at": "2027-01-26T08:00:00+00:00",
"revoked_at": null,
"last_used_at": null
}
}Other responses: 401, 403, 405, 429, 503. See errors and retry guidance.
Verify the current account password and choose a new 12–72-byte password with a letter and a number. All previous owner API keys, including the key making this request, are revoked. Store the returned replacement before making another request. Does not change SIP, extension or phone-app passwords. Limit five password-change attempts per owner per ten minutes.
| Body field | Type | Presence | Rules |
|---|---|---|---|
current_password | password | Required | Current account password; this additional verification is mandatory. |
new_password | password | Required | New account password: 12–72 UTF-8 bytes, including a letter and a number. Does not change SIP, extension or phone-app passwords. |
curl --request POST 'https://call.openweb.co.za/api/v1/me/password' \
--header "Authorization: Bearer $OPENWEB_TOKEN" \
--header 'Content-Type: application/json' \
--data '{
"current_password": "YOUR_CURRENT_ACCOUNT_PASSWORD",
"new_password": "replace-with-a-new-unique-password-73"
}'{
"access_token": "owta_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"token_type": "Bearer",
"expires_at": "2027-01-26T08:00:00+00:00",
"token": {
"token_uuid": "17eae30b-1965-47ef-91bd-66e623b5ec99",
"name": "Tenant API",
"created_at": "2026-10-28T08:00:00+00:00",
"expires_at": "2027-01-26T08:00:00+00:00",
"revoked_at": null,
"last_used_at": null
}
}Other responses: 400, 401, 403, 404, 405, 409, 413, 415, 429, 503. See errors and retry guidance.
Returns current revisions visible to this tenant, without credentials or encrypted payloads. Only shared, published starter templates explicitly approved by the instance administrator are available. They must have no trunks, outbound rules or additional settings. Configure your own provider after creating the PBX.
curl 'https://call.openweb.co.za/api/v1/templates' \
--header "Authorization: Bearer $OPENWEB_TOKEN"{
"templates": [
{
"template_uuid": "039b844b-7f52-40c6-a835-3db26a764d3c",
"template_name": "Starter PBX",
"description": "A starter office PBX.",
"version": 1,
"timezone": "Africa/Johannesburg",
"extension_start": 100,
"extension_count": 2,
"extension_limit": 100
}
]
}Other responses: 401, 403, 405, 429, 503. See errors and retry guidance.
Returns only this tenant's services. Each service is an isolated PBX on the shared instance, not a separate virtual machine.
curl 'https://call.openweb.co.za/api/v1/services' \
--header "Authorization: Bearer $OPENWEB_TOKEN"{
"services": [
{
"service_uuid": "0d59d9f6-33a6-4328-8b31-dc63fe96d329",
"tenant_uuid": "d8da1fce-51ac-4e1a-a53a-91a4971e0e3c",
"domain_uuid": "80d27531-dbb9-4ecb-8ed7-1c9295c2c6eb",
"service_name": "Main Office",
"template_uuid": "039b844b-7f52-40c6-a835-3db26a764d3c",
"template_name": "Starter PBX",
"template_version": 1,
"sip_domain": "main-office.example-company.call.openweb.co.za",
"software_version": "1.0.21",
"created_at": "2026-10-28T08:05:00+00:00"
}
]
}Other responses: 401, 403, 405, 429, 503. See errors and retry guidance.
Creates an isolated PBX from the selected current template and atomically queues its requested managed subdomain. New public tenants start with one service. No paid provider connection or carrier DID is automatically enabled. Retry the exact same request with the same Idempotency-Key after a timeout.
| Parameter | Location | Required | Meaning |
|---|---|---|---|
Idempotency-Key | header | Yes | A UUID unique to this intended operation. Retry the same JSON request with the same key. A changed request with a reused key is rejected. |
| Body field | Type | Presence | Rules |
|---|---|---|---|
template_uuid | uuid | Required | Choose a currently visible published starter template. |
service_name | string | Required | Maximum 120 UTF-8 bytes. Minimum 1 characters. Maximum 120 characters. |
slug | string | Required | Minimum 3 characters. Maximum 40 characters. |
subdomain | string | Optional | Optional single label. Defaults to your tenant slug. No scheme, dots, port or path. Minimum 3 characters. Maximum 40 characters. |
curl --request POST 'https://call.openweb.co.za/api/v1/services' \
--header "Authorization: Bearer $OPENWEB_TOKEN" \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: 9b484c7d-4e6f-48b2-b9fd-c55260d8b563' \
--data '{
"template_uuid": "039b844b-7f52-40c6-a835-3db26a764d3c",
"service_name": "Main Office",
"slug": "main-office",
"subdomain": "example-company"
}'{
"service": {
"service_uuid": "0d59d9f6-33a6-4328-8b31-dc63fe96d329",
"tenant_uuid": "d8da1fce-51ac-4e1a-a53a-91a4971e0e3c",
"domain_uuid": "80d27531-dbb9-4ecb-8ed7-1c9295c2c6eb",
"service_name": "Main Office",
"template_uuid": "039b844b-7f52-40c6-a835-3db26a764d3c",
"template_name": "Starter PBX",
"template_version": 1,
"sip_domain": "main-office.example-company.call.openweb.co.za",
"software_version": "1.0.21",
"created_at": "2026-10-28T08:05:00+00:00"
},
"subdomain": {
"service_uuid": "0d59d9f6-33a6-4328-8b31-dc63fe96d329",
"requested_label": "example-company",
"requested_hostname": "example-company.openwebpbx.com",
"hostname": null,
"url": null,
"admin_url": null,
"state": "pending_dns",
"ready": false,
"next_attempt": "2026-10-28T08:06:00+00:00",
"error_category": ""
}
}Other responses: 400, 401, 403, 404, 405, 409, 413, 415, 429, 503. See errors and retry guidance.
A valid UUID from another tenant is not disclosed. Existing service settings and the selected template revision remain attached to that service.
| Parameter | Location | Required | Meaning |
|---|---|---|---|
service_uuid | path | Yes | An owned service UUID. Foreign resources are not disclosed. |
curl 'https://call.openweb.co.za/api/v1/services/0d59d9f6-33a6-4328-8b31-dc63fe96d329' \
--header "Authorization: Bearer $OPENWEB_TOKEN"{
"service": {
"service_uuid": "0d59d9f6-33a6-4328-8b31-dc63fe96d329",
"tenant_uuid": "d8da1fce-51ac-4e1a-a53a-91a4971e0e3c",
"domain_uuid": "80d27531-dbb9-4ecb-8ed7-1c9295c2c6eb",
"service_name": "Main Office",
"template_uuid": "039b844b-7f52-40c6-a835-3db26a764d3c",
"template_name": "Starter PBX",
"template_version": 1,
"sip_domain": "main-office.example-company.call.openweb.co.za",
"software_version": "1.0.21",
"created_at": "2026-10-28T08:05:00+00:00"
}
}Other responses: 400, 401, 403, 404, 405, 429, 503. See errors and retry guidance.
Advisory local-instance check only. It does not reserve the name or query central DNS ownership. Reserved labels are refused. The custodian may assign a stable suffix when a requested name is held elsewhere; poll the owned service's actual status.
| Parameter | Location | Required | Meaning |
|---|---|---|---|
label | query | Yes | Single lower-case label, 3–40 letters, numbers or hyphens. |
curl 'https://call.openweb.co.za/api/v1/subdomains/availability?label=example-company' \
--header "Authorization: Bearer $OPENWEB_TOKEN"{
"label": "example-company",
"hostname": "example-company.openwebpbx.com",
"available": true,
"scope": "this_instance",
"reservation_confirmed": false
}Other responses: 400, 401, 403, 405, 429, 503. See errors and retry guidance.
DNS, trusted HTTPS and local transport preparation run in the background. url/admin_url remain null until the assigned name is verified ready. The requested name is not necessarily the final assigned hostname.
| Parameter | Location | Required | Meaning |
|---|---|---|---|
service_uuid | path | Yes | An owned service UUID. Foreign resources are not disclosed. |
curl 'https://call.openweb.co.za/api/v1/services/0d59d9f6-33a6-4328-8b31-dc63fe96d329/subdomain' \
--header "Authorization: Bearer $OPENWEB_TOKEN"{
"subdomain": {
"service_uuid": "0d59d9f6-33a6-4328-8b31-dc63fe96d329",
"requested_label": "example-company",
"requested_hostname": "example-company.openwebpbx.com",
"hostname": null,
"url": null,
"admin_url": null,
"state": "pending_dns",
"ready": false,
"next_attempt": "2026-10-28T08:06:00+00:00",
"error_category": ""
}
}Other responses: 400, 401, 403, 404, 405, 429, 503. See errors and retry guidance.
Queue a managed subdomain on an owned active PBX service. Use a single label. Once queued or leased, the label cannot be silently renamed; changing it returns a conflict. Existing SIP realms and phone credentials are preserved. The custodian supports fifty names per instance, including reserved existing names.
| Parameter | Location | Required | Meaning |
|---|---|---|---|
service_uuid | path | Yes | An owned service UUID. Foreign resources are not disclosed. |
Idempotency-Key | header | Yes | A UUID unique to this intended operation. Retry the same JSON request with the same key. A changed request with a reused key is rejected. |
| Body field | Type | Presence | Rules |
|---|---|---|---|
label | string | Required | Minimum 3 characters. Maximum 40 characters. |
curl --request POST 'https://call.openweb.co.za/api/v1/services/0d59d9f6-33a6-4328-8b31-dc63fe96d329/subdomain' \
--header "Authorization: Bearer $OPENWEB_TOKEN" \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: 9b484c7d-4e6f-48b2-b9fd-c55260d8b563' \
--data '{
"label": "example-company"
}'{
"subdomain": {
"service_uuid": "0d59d9f6-33a6-4328-8b31-dc63fe96d329",
"requested_label": "example-company",
"requested_hostname": "example-company.openwebpbx.com",
"hostname": null,
"url": null,
"admin_url": null,
"state": "pending_dns",
"ready": false,
"next_attempt": "2026-10-28T08:06:00+00:00",
"error_category": ""
}
}Other responses: 400, 401, 403, 404, 405, 409, 413, 415, 429, 503. See errors and retry guidance.
Returns up to the most recent 100 token metadata records, including revoked history, never raw token secrets. Use separate named keys for separate integrations.
curl 'https://call.openweb.co.za/api/v1/tokens' \
--header "Authorization: Bearer $OPENWEB_TOKEN"{
"tokens": [
{
"token_uuid": "17eae30b-1965-47ef-91bd-66e623b5ec99",
"name": "Tenant API",
"created_at": "2026-10-28T08:00:00+00:00",
"expires_at": "2027-01-26T08:00:00+00:00",
"revoked_at": null,
"last_used_at": null
}
]
}Other responses: 401, 403, 405, 429, 503. See errors and retry guidance.
Returns the new token secret once. The default and maximum lifetime are ninety days. At most ten active tokens are allowed per tenant. This operation does not retain a replayable copy of the token; avoid blindly retrying it.
| Body field | Type | Presence | Rules |
|---|---|---|---|
name | string | Required | Maximum 80 UTF-8 bytes. Minimum 1 characters. Maximum 80 characters. |
expires_in_days | integer | Optional | Minimum 1. Maximum 90. |
curl --request POST 'https://call.openweb.co.za/api/v1/tokens' \
--header "Authorization: Bearer $OPENWEB_TOKEN" \
--header 'Content-Type: application/json' \
--data '{
"name": "Billing integration",
"expires_in_days": 30
}'{
"access_token": "owta_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"token_type": "Bearer",
"expires_at": "2027-01-26T08:00:00+00:00",
"token": {
"token_uuid": "17eae30b-1965-47ef-91bd-66e623b5ec99",
"name": "Tenant API",
"created_at": "2026-10-28T08:00:00+00:00",
"expires_at": "2027-01-26T08:00:00+00:00",
"revoked_at": null,
"last_used_at": null
}
}Other responses: 400, 401, 403, 404, 405, 409, 413, 415, 429, 503. See errors and retry guidance.
Immediately invalidate the selected owned token. The response is 204 with no body. Revoking the current token also ends its ability to make subsequent requests.
| Parameter | Location | Required | Meaning |
|---|---|---|---|
token_uuid | path | Yes | A token belonging to this tenant. |
curl --request DELETE 'https://call.openweb.co.za/api/v1/tokens/17eae30b-1965-47ef-91bd-66e623b5ec99' \
--header "Authorization: Bearer $OPENWEB_TOKEN"(No response body)Other responses: 400, 401, 403, 404, 405, 429, 503. See errors and retry guidance.
Create a replacement secret and revoke the old secret atomically. Returns the replacement once; later read responses cannot recover it. Update the integration securely. Send an empty JSON object to use the default expiry.
| Parameter | Location | Required | Meaning |
|---|---|---|---|
token_uuid | path | Yes | A token belonging to this tenant. |
| Body field | Type | Presence | Rules |
|---|---|---|---|
expires_in_days | integer | Optional | Minimum 1. Maximum 90. |
curl --request POST 'https://call.openweb.co.za/api/v1/tokens/17eae30b-1965-47ef-91bd-66e623b5ec99/rotate' \
--header "Authorization: Bearer $OPENWEB_TOKEN" \
--header 'Content-Type: application/json' \
--data '{
"expires_in_days": 30
}'{
"access_token": "owta_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"token_type": "Bearer",
"expires_at": "2027-01-26T08:00:00+00:00",
"token": {
"token_uuid": "17eae30b-1965-47ef-91bd-66e623b5ec99",
"name": "Tenant API",
"created_at": "2026-10-28T08:00:00+00:00",
"expires_at": "2027-01-26T08:00:00+00:00",
"revoked_at": null,
"last_used_at": null
}
}Other responses: 400, 401, 403, 404, 405, 409, 413, 415, 429, 503. See errors and retry guidance.
Portable front controller: https://call.openweb.co.za/api/v1/index.php?route=/templates. Keep the same method, headers and body. Use &label=example-company when adding a query parameter to that form.
Public read-only metadata. Packages pin their own independent copy of this RSA3072 key; never replace that trust solely from an unauthenticated response.
Setup sequence · Full request/response schema · Public setup wizard
Invited owners may sign in normally, then confirm their current administrator email before authorizing a remote installation. Queues a one-use code through global outgoing mail; no installation is activated.
Body: {}.
Setup sequence · Full request/response schema · Public setup wizard
Requires the emailed code and current owner password. Keeps invitation/public-signup classification unchanged.
Required JSON fields: token, password.
Setup sequence · Full request/response schema · Public setup wizard
Requires an active, email-confirmed tenant owner. Binds canonical hostname, P256 public key, local tenant/domain UUIDs and desired label. Expires after five minutes. Does not create a hosted PBX service.
Required JSON fields: server_host, public_key, local_tenant_uuid, domain_uuid, label.
Setup sequence · Full request/response schema · Public setup wizard
Returns only this verified owner’s installation metadata, without private keys or another account’s grants.
Setup sequence · Full request/response schema · Public setup wizard
Verifies the exact challenge signature and fresh trusted canonical HTTPS nonce proof, then issues a signed one-year RSA authorization bound to owner/local IDs/key/hostname/label. The installed server independently verifies it before activation. Renewal increments generation and keeps bindings immutable. No central hosted PBX is created.
Required JSON fields: challenge_uuid, signature.
Setup sequence · Full request/response schema · Public setup wizard
Owner-scoped. The signed receipt is usable only by the exact local instance identity. Tenant address DNS and trusted HTTPS readiness are separate from authorization.
Setup sequence · Full request/response schema · Public setup wizard
PBX creation and subdomain registration require a UUID Idempotency-Key. Retrying the same JSON request with the same key returns its saved result and Idempotent-Replayed: true. Poll the subdomain resource for its current readiness; the original saved response can still show a pending state. Reusing that key with changed details returns 409. Use a new key only for a genuinely new intended operation.
New public tenants begin with one PBX service. The instance operator controls admission and quotas; the default public-signup cap is 25 tenants. This is not an offer of unlimited hosted capacity.
| Operation | Default limit |
|---|---|
| Register | 5 per source IP/hour; 3 per email/hour; 100 globally/day. |
| Verify | 30 per source IP/10 minutes. |
| Sign in | 20 per source IP/10 minutes; 8 per email/10 minutes. |
| Change account password | 5 attempts per owner/10 minutes. |
| Authenticated API | 120 requests per tenant per minute, shared by its tokens. |
On 429, honor Retry-After. On a timeout or temporary 503, use bounded exponential backoff and keep the original idempotency key for a write. Correct validation, authentication and conflict errors before retrying. Do not retry forever or repeatedly create new tokens after losing a response.
Use the HTTP status and error.code for application decisions. A request_id is safe to include in a support report; passwords and tokens are not.
{
"error": {
"code": "invalid_request",
"message": "Check the supplied details."
},
"request_id": "example-request-reference"
}| HTTP status | Meaning |
|---|---|
| 400 | Invalid request. |
| 401 | Missing, invalid, expired or revoked bearer token, or invalid owner sign-in. |
| 403 | Secure transport, request origin, account or tenant restriction. |
| 404 | Route or owned resource unavailable. |
| 405 | Incorrect method; inspect Allow. |
| 409 | Domain, quota, ownership or idempotency conflict. |
| 413 | Request body exceeds the supported size. |
| 415 | JSON body requires application/json. |
| 429 | Rate limit exceeded; honor Retry-After. |
| 503 | A required dependency is temporarily unavailable. |
Public self-service tenants use the modern Desktop and Tenant Services portals. Direct legacy administration pages remain unavailable to these accounts; existing invited tenants keep their current permissions.
Every protected operation is scoped to its verified tenant owner. Clients cannot choose arbitrary tenant identities, grant platform roles, supply DNS credentials, take another company’s name, read trunk passwords or execute operating-system commands. An unavailable or foreign-owned service is not disclosed.
Use a server-side integration and normal HTTPS certificate validation. Browser-cookie authentication and cross-origin browser requests are not supported. JSON request bodies are limited to 32 KiB and unknown fields are refused. Keep tokens in a secret store and send them only in the Authorization header, never in URLs.
There is no destructive tenant-installation or recording-deletion operation in this API. For account or personal-data removal, use the deletion procedure. Registering a tenant does not activate paid provider trunks or assign carrier numbers.
Verification uses the installation’s global outgoing-mail service. A queued message or SMTP acceptance does not prove inbox delivery. DNS and certificate readiness can take time; preserve a working connection while an address is pending.
For instance administrators: under Tenant Services → Templates, publish a shared starter and select Allow new tenants to use this starter template through the API. The template must have no trunks, outbound rules or additional settings. Tenant-owned templates and existing services are not changed.
For hosted account assistance, contact hello@openwebpbx.com. Include the route, approximate time and request reference. Remove tokens, passwords, verification codes, phone numbers and customer records before sharing a report.
The hosted API is a separately deployed service. Self-hosted public signup requires a build containing this API and operator enablement. API v1 is a separate contract from package versions. Debian is 1.0.23, Windows Server is 1.0.23 and Android remains 1.0.19; original published archives are unchanged. Hosted App, Core and updater1.0.24 separately provide callback-only SIP trunk selection, nine own-account speed dials and editable Keoma scripts with confirmed audio-preserving default reset. This hosted deployment is not a public1.0.24 installer or a new API contract. Its separate calling correction has user-confirmed Android outside-call sound both ways on the hosted instance; that does not qualify Windows carrier calling. Calling fix and validation. Hosted feature guide · Debian-to-Windows change ledger. Broader physical-phone, carrier and app-store acceptance are separate from this API’s provisioning scope.