Skip to main content

Connect any SMS provider (generic HTTP provider)

MonoPbx sends and receives SMS through a provider. Twilio is built in. For any other provider that has an HTTP API you do not need code: you describe, in the admin console, the request that sends a message, how to read the provider's answer, and how to read its callbacks (inbound messages and delivery reports). Everything below is done in the web console; nothing needs the API.

You need the Owner role (or a custom role with the integrations:write permission). Sending also needs messaging:write.

:::info Credentials are write-only The API token and the callback secret you type here are sealed with your company's key when you save. They are never shown again, not even to you, and they never appear in the preview, the audit log or an error message. To change them you enter all of them again. :::

The example provider​

The tutorial uses a made-up provider, "ExampleSMS", with this API:

POST https://api.examplesms.com/v2/messages
Authorization: Bearer <token>
{"from": "+15550100199", "to": "+15550100100", "text": "hi", "ref": "<your id>"}
-> 200 {"data": {"id": "msg_91"}} accepted
-> 400 {"error": {"code": "INVALID_DEST"}} refused for good
-> 429 or 5xx try later
Callbacks (POST, header X-Signature: sha256=<hex hmac of the body>):
{"events": [{"kind": "mo", "id": "in_5", "from": "15550100100", "to": "15550100199", "text": "yes"},
{"kind": "dlr", "message": "msg_91", "state": "DELIVRD"}]}

1. Add the provider​

Open Admin console, SMS (the page is titled SMS providers) and choose New provider.

  1. Name: ExampleSMS.
  2. Kind: Generic HTTP provider. The request form opens.

2. Describe the request​

Under Request to the provider:

FieldValue
MethodPOST
URLhttps://api.examplesms.com/v2/messages
Header name and value (choose Add header)Authorization and Bearer {{secret.api_token}}
Body formatjson
Body template{"from":"{{from}}","to":"{{to}}","text":"{{body}}","ref":"{{message_id}}"}

Placeholders are written in double braces. You can use from, to, body, message_id, segments, timestamp, and secret.NAME for a credential. The scheme, host and port of the URL must be plain text (no placeholders), and the address must be public HTTPS: private and local addresses are always refused.

Each secret.NAME you use adds a password field under Credentials at the bottom of the form.

3. Describe the answer​

Under Reading the answer:

  1. Path of the provider's message id: $.data.id. This is how delivery reports find the message later.
  2. Choose Add rule, and set HTTP statuses to 400, Result to Refused for good, and Code path to $.error.code.

Without rules, a 2xx answer is accepted, 408, 425, 429 and 5xx are retried later, and anything else is refused.

4. Describe the callbacks​

Under Callbacks from the provider, tick The provider calls us back.

  1. Signature: Provider HMAC-SHA256. Set Signature header to X-Signature, Text before the signature to sha256=, and leave the encoding on hex.
  2. If the provider also sends a signed timestamp, enter its header in Timestamp header. While it is empty the form shows a warning: without a signed timestamp a captured callback can be replayed.
  3. Where the events are: $.events[*]. Event kind path: $.kind, with mo in Kinds that are inbound messages and dlr in Kinds that are delivery reports.
  4. Tick Read inbound messages and set the paths $.id, $.from, $.to and $.text.
  5. Tick Read delivery reports, set Message id path to $.message and Status path to $.state, then choose Add status and translate DELIVRD to Delivered. Add UNDELIV to Failed and ACCEPTD to Sent the same way.

5. Check it before you save​

The Preview section at the bottom is filled in by the server as you type. Nothing is sent and no credential is used.

  • It shows the exact request that would be sent, with credentials as placeholders such as <secret.api_token>.
  • Paste the provider's example answer into Sample answer body, for example {"data": {"id": "msg_91"}}, and the preview shows how it is read: accepted, with the provider's id msg_91.
  • Paste an example callback into Sample callback body to see the events it produces.
  • Mistakes come back as a list with the field name, for example send.url. A yellow box lists settings that are valid but probably not what you want, for example that the message id is not part of the request.

6. Enter the credentials and save​

Fill in the two password fields the form asks for:

  • Secret: api_token: your ExampleSMS API token.
  • Webhook signing secret: a secret of at least 16 characters that you also enter at the provider as the key that signs callbacks.

Choose Save. The provider appears in the list with its credentials marked Stored.

7. Add a number​

Open Numbers in the SMS tabs and choose Add number. Enter the number in international format (+15550100199), choose ExampleSMS as the provider, and optionally a label and the route new conversations take (a user, an extension, a queue or a ring group).

8. Point the provider at MonoPbx​

Back in Providers, copy the Callback address of ExampleSMS (https://<your address>/hooks/sms/...) into the provider's console as the callback URL, and set the same signing secret there. The address is secret and unguessable. If it leaks, choose New address on the provider: the old one stops working at once.

Your installation must be reachable over public HTTPS for the provider to call it.

9. Test​

Choose Test on the provider, pick one of its numbers as the sender, enter your own mobile number and choose Send test. The result shows what the provider said:

  • Accepted by the provider, with its message id;
  • Refused by the provider, with the code from your rules (for example INVALID_DEST);
  • Temporary error, which a real message would retry.

The test sends one real message. It creates no conversation, is recorded in the audit log without numbers or text, and is limited to 10 per minute for the company and 3 per recipient. Only the provider's own numbers can be the sender.

Then send a real message from SMS in the main navigation, and watch its delivery status change from Queued to Sent and Delivered.

Changing the settings later​

Open the provider with Edit. Credentials are not shown; leave all password fields empty to keep them.

If your change would send the stored credentials somewhere else (another URL, method, header, or a credential placed elsewhere in the request), the console refuses it and asks you to enter the credentials again, so that nobody who can edit the settings can read the credentials back by pointing the provider at a server of their own.

Usage​

Usage in the SMS tabs shows messages and segments per day, provider and direction. Providers bill by segment: 160 characters in the GSM alphabet (153 per part of a longer text), or 70 (67) when the text has other characters.