Basic External Provisioning and Web Service Contacts¶
This guide describes a minimal deployment of Acrobits external provisioning and Web Service Contacts using the example PHP scripts from the integration-snippets repository.
The example service:
- Authenticates a user against a CSV file and returns Account XML.
- Authenticates the same user and returns the other CSV users as Web Service Contacts.
The examples use form-encoded POST requests so credentials do not appear in request URLs or ordinary access logs. Use this implementation as a starting point or proof of concept. Review the production notes before exposing it to end users.
Source Files¶
Download or copy these files from the snippet repository:
helpers.phpacrobits_prov.phpacrobits_contacts.phpexample-data/extProv/SAMPLE.xmlexample-data/users/SAMPLE.csv
Server Requirements¶
The server needs:
- PHP 7.4 or newer.
- A web server with PHP support, such as Apache or Nginx with PHP-FPM.
- HTTPS enabled.
- Read access from the PHP process to
/srv/data/provisioning/.
HTTPS is required because the provisioning and contacts endpoints receive user credentials.
Deploy the PHP Files¶
Place the PHP files together in a public web directory:
The public URLs will look like this:
https://customer-domain.example/provisioning/acrobits_prov.php
https://customer-domain.example/provisioning/acrobits_contacts.php
Prepare the Data Directory¶
Store customer data outside the public web root. The example scripts use this layout:
The filename must match the Cloud ID. For example, use SAMPLE.csv and SAMPLE.xml for cloud_id=SAMPLE.
The scripts convert the Cloud ID to uppercase and strip a trailing *, so the editable SAMPLE* version and live SAMPLE version use the same files. For safe filesystem access, Cloud IDs may contain only letters, digits, _, and -.
For local testing, you can set the ACROBITS_PROVISIONING_DATA_DIR environment variable to use a different data directory.
Create the User CSV¶
Place the user CSV file at:
The sample CSV uses this structure:
cloud_username,cloud_password,username,password,display_name,first_name,last_name,avatar,phone_number1
user001,SAMPLE_PASSWORD,1001,ACCOUNT_PASSWORD_1001,Example User One,Example,User One,https://example.com/avatar-user001.png,Mobile:+12025550101
user002,bcrypt:<bcrypt_hash_for_user002>,1002,ACCOUNT_PASSWORD_1002,Example User Two,Example,User Two,https://example.com/avatar-user002.png,Mobile:+12025550102
The columns have these purposes:
cloud_usernameandcloud_passwordauthenticate both endpoint requests.usernameandpasswordare the SIP account credentials returned in Account XML.display_name,first_name,last_name, andavatardescribe the contact.phone_number1throughphone_number5may contain either a number orlabel:number, such asMobile:+12025550101.
The cloud_password value may be:
- Plain text, only for a quick local test.
- A bcrypt hash prefixed with
bcrypt:, recommended for real deployments.
Generate a compatible value with:
The placeholder hashes in the sample CSV are not usable passwords. Replace them, along with every sample password and SIP credential, before deployment.
The values used as username, or cloud_username when username is empty, must be unique because Web Service Contacts requires a stable, unique contactId.
Create the Account XML Template¶
Place the external provisioning template at:
Replace customer-domain.example with the deployment hostname. Use the following complete template:
<account>
<title>{display_name}</title>
<acrobitsDisplayName>{display_name}</acrobitsDisplayName>
<cloud_id>{cloud_id}</cloud_id>
<cloud_username>{cloud_username}</cloud_username>
<cloud_password>{cloud_password}</cloud_password>
<username>{username}</username>
<password>{password}</password>
<wsContactsUrl>https://customer-domain.example/provisioning/acrobits_contacts.php</wsContactsUrl>
<wsContactsMethod>POST</wsContactsMethod>
<wsContactsContentType>application/x-www-form-urlencoded</wsContactsContentType>
<wsContactsPostData>cloud_id=%account[cloud_id]%&cloud_username=%account[cloud_username]%&cloud_password=%account[cloud_password]%</wsContactsPostData>
<wsContactsRefresh>180</wsContactsRefresh>
</account>
Placeholders matching CSV column names are replaced with values from the authenticated row. The script also supplies {cloud_id}.
{cloud_password} is replaced with the password submitted by the app after authentication, not with the stored CSV value. This prevents a stored bcrypt hash from being returned to the app and lets the contacts endpoint authenticate subsequent requests.
The & sequences in wsContactsPostData are XML-escaped ampersands. The resulting HTTP request body contains ordinary & separators.
For additional Web Service Contacts options, see Web Service Contacts.
Configure Initial External Provisioning¶
In the Cloud Softphone portal, configure initial external provisioning with these values:
InitialProvisioningUrl = https://customer-domain.example/provisioning/acrobits_prov.php
InitialProvisioningMethod = POST
InitialProvisioningPostData = cloud_id=%fullcode%&cloud_username=%username%&cloud_password=%password%
The placeholders are expanded by the app:
%fullcode%is the Cloud ID.%username%is the username entered by the user.%password%is the password entered by the user.
The PHP script authenticates these values against the CSV row and returns the completed XML template. For more information about the request and response contract, see External Provisioning.
Test the Deployment¶
Test external provisioning:
curl --fail-with-body \
--data-urlencode 'cloud_id=SAMPLE' \
--data-urlencode 'cloud_username=user001' \
--data-urlencode 'cloud_password=SAMPLE_PASSWORD' \
https://customer-domain.example/provisioning/acrobits_prov.php
Expected result: an XML response with exactly one <account> root node.
Test Web Service Contacts:
curl --fail-with-body \
--data-urlencode 'cloud_id=SAMPLE' \
--data-urlencode 'cloud_username=user001' \
--data-urlencode 'cloud_password=SAMPLE_PASSWORD' \
https://customer-domain.example/provisioning/acrobits_contacts.php
The requesting user is omitted. The response contains the remaining contacts, including separate SIP and mobile entries:
{
"contacts": [
{
"fname": "Example",
"lname": "User Two",
"displayName": "Example User Two",
"contactId": "1002",
"contactEntries": [
{
"entryId": "tel:sip",
"label": "SIP extension",
"type": "tel",
"uri": "1002"
},
{
"entryId": "tel:phone1",
"label": "Mobile",
"type": "tel",
"uri": "+12025550102"
}
],
"cloudUsername": "user002",
"networkId": "SAMPLE",
"avatar": "https://example.com/avatar-user002.png",
"largeAvatar": "https://example.com/avatar-user002.png"
}
]
}
Both endpoints return:
400when required parameters or the Cloud ID are invalid.403when the username or password is rejected.405for unsupported HTTP methods.500when the configured CSV or XML data is unavailable.
Provisioning errors use the XML <error><message>...</message></error> format. Contacts errors use JSON.
Production Notes¶
- Keep
/srv/data/provisioning/outside the public directory and restrict file access to the required service account. - Use bcrypt hashes for activation passwords and HTTPS for every request.
- Do not enable wildcard CORS unless browser clients genuinely require it and the exposure is acceptable.
- Add rate limiting and monitoring at the web-server or application layer.
- The example contacts script does not implement
Last-Modifiedor304 Not Modified. Add caching for large contact lists because clients may refresh every 180 seconds. - Replace the CSV backend with an appropriate authenticated data store when the deployment requires concurrent administration or substantial scale.
- The provisioning script escapes replacement values for XML. Apply equivalent validation and escaping to any custom processing you add.