Direct customer-hosted messaging
Use this integration when you operate the app’s messaging service, including its inboxes, user authentication and carrier delivery. The SessionCloud portal supplies account configuration; the app contacts your HTTPS server directly to send and fetch text messages. SIP registration remains with your PBX.
Release requirement. This integration requires the portal’s Customer-hosted service option and an app release that supports its outgoing configuration. The implementation is prepared for release; it is not enabled in the live portal yet. Existing Custom HTTPS connections continue to use SessionCloud’s messaging API.
Choose the correct integration
| Custom HTTPS | Customer-hosted service | |
|---|---|---|
| Sending | App → SessionCloud → your gateway | App → your service |
| Receiving | Your gateway → SessionCloud webhook → app | Your service stores messages; the app fetches them directly |
| App inbox and access credentials | Managed by SessionCloud | Managed by your service |
| Carrier webhook | Forward messages to the portal’s Custom HTTPS webhook | Receive and verify callbacks on your own server |
| Notifications | SessionCloud requests notifications | Your service uses the scoped SessionTalk push API |
Both options support a bridge that delivers through VoIP Innovations or another carrier. Choose direct hosting only if your service also implements the app-facing API below. It supports text SMS; MMS and carrier delivery receipts are outside this integration.
Configure the portal
-
Open the BYO PBX project, go to Provisioning > Advanced > Messaging, enable SMS, and save the project.
-
Under Messaging providers, select Customer-hosted service.
-
Enter the service’s HTTPS URLs:
Portal field Example App request Incoming message fetch URL https://sms.example.com/inboxGET /inbox?after=cursorandGET /inbox/UUIDPush registration URL https://sms.example.com/devicesPUT /devicesOutgoing SMS URL https://sms.example.com/sendForm-encoded POST /send -
Check Advanced field mappings against your outgoing endpoint. Defaults are
username,password,dafor the destination,udfor the text, and success response prefixOK:. Clear the prefix if every HTTP 2xx response means accepted. -
Save the connection. No SessionCloud incoming webhook is generated for this mode.
URLs must use HTTPS and contain no embedded credentials, query strings or fragments. The app does not follow redirects. Enter final URLs with certificates trusted by the phone. Fetch and registration URLs receive the user’s service credentials.
Assign each user’s service account
Create the user and number assignment on your messaging server first. Your service must select an inbox and permitted sending number from the authenticated service account. A number or mailbox identifier supplied by a client is not authentication.
In the portal’s Assign a number form:
- Select the Customer-hosted service connection.
- Enter the messaging number in
+international format, the exact SIP username and the SIP domain, including its port where applicable. - Enter that user’s Service username and Service password. These are credentials for your SMS service, separate from SIP and carrier API credentials.
- Select incoming authentication: the service username/password using HTTP Basic, or an API token issued by your service. A service API token does not have the fixed 43-character requirement of a SessionCloud mailbox token.
- Assign the number and generate a new private account provisioning QR, or obtain updated authenticated external provisioning. Provision the matching account in a compatible app.
Outgoing SMS always sends the service username/password in the configured form fields. The incoming authentication selection applies to inbox fetches and push registration. Credentials are encrypted in the portal database and included only in authenticated provisioning for the matching account. Treat its QR as private; do not enter a carrier-wide API credential as a user’s service password.
The portal generates the routing identifier. The user does not register a second mailbox with SessionTalk or manually copy an identifier from your server. Your server associates the app’s device report with the inbox selected by authentication.
Changing an endpoint or service identity requires updated account provisioning. Disabling a portal assignment prevents future provisioning; it cannot revoke credentials already issued by your service. Revoke those credentials and remove device routes on your server when removing access. Your server controls message history and retention.
What the QR contains
The portal supplies byomessaging within the SIP account configuration. In this
mode it includes mode: "webservice", fetchurl, reporturl, service credentials,
an outgoing object and a routing identifier. apiurl equals the fetch URL.
Do not change only apiurl in a normal SessionCloud mailbox QR. Without the
webservice mode, the app expects the SessionCloud-compatible
/api/v1/byo-messaging base and /messages API. A different base path can be
rejected before the app contacts your server.
The following illustrates the generated account block; placeholders are not usable credentials. Generate the actual QR through authenticated portal provisioning.
{
"byomessaging": {
"mode": "webservice",
"provider": "custom",
"apiurl": "https://sms.example.com/inbox",
"fetchurl": "https://sms.example.com/inbox",
"reporturl": "https://sms.example.com/devices",
"mailboxid": "00000000-0000-4000-8000-000000000001",
"number": "+12025550123",
"authmode": "basic",
"authusername": "user-101",
"authpassword": "USER_SERVICE_PASSWORD",
"token": "",
"binding": { "username": "101", "domain": "pbx.example.com:5062" },
"outgoing": {
"url": "https://sms.example.com/send",
"username": "user-101",
"password": "USER_SERVICE_PASSWORD",
"usernameField": "username",
"passwordField": "password",
"destinationField": "da",
"messageField": "ud",
"successPrefix": "OK:"
}
}
}With incoming API-token authentication, authmode is bearer, token contains
the service token, and authusername/authpassword are empty. The outgoing form
credentials remain in outgoing.
Implement the service API
Fetch and registration requests carry Authorization: Basic ... or
Authorization: Bearer ..., according to the account configuration. Return JSON
and authenticate every request. Do not delete messages when fetched; multiple
devices maintain independent cursors.
Fetch messages
GET /inbox?after=0 returns:
{
"messages": [{
"id": "00000000-0000-4000-8000-000000000002",
"peer": "+12025550124",
"body": "Example incoming message",
"direction": "inbound",
"state": "received",
"created_at": "2026-01-01T12:00:00Z"
}],
"next": 1,
"more": false
}Message IDs must be stable UUIDs, including across retries. The cursor is a
monotonically increasing integer, or decimal string; it is not a UUID. Return
messages in sequence order, at most 100 per page. next is the last returned
sequence, or the requested cursor for an empty page. Set more when another
page is available. The app polls while foregrounded.
GET /inbox/UUID returns {"message": {...}} for that UUID, or HTTP 404 if absent.
The mobile app uses this endpoint to fetch the complete message after a push.
Use international numbers or supported alphanumeric sender IDs in peer and
UTF-8 text in body, up to 65,536 bytes.
Send a message
The app posts UTF-8 application/x-www-form-urlencoded directly to the outgoing
URL. With the default mappings the fields are username, password, da and
ud. The sending number comes from the authenticated service account.
Return HTTP 2xx and a body beginning with the configured success prefix after accepting a message. An empty prefix accepts any 2xx response. This confirms submission, not carrier delivery. HTTP 3xx/4xx rejects the send. Network failures, 5xx and an unexpected success body can leave submission uncertain; the app does not automatically repeat a potentially billable SMS.
Register notifications
The app sends PUT /devices with:
{
"deviceId": "example-device",
"profileId": 22,
"selector": "00000000-0000-4000-8000-000000000001",
"mailboxId": "00000000-0000-4000-8000-000000000001",
"number": "+12025550123",
"username": "user-101",
"pushUrl": "https://SELECTED_RELAY/byo/webservice/push",
"pushToken": "SCOPED_PUSH_GRANT",
"expiresAt": 1900000000
}The username is included with Basic authentication. Authenticate first, verify
that the number belongs to that service account, and upsert a route per
device/profile. selector and mailboxId are aliases; neither grants inbox
access. Return {"ok":true} and protect the stored push token.
After storing an incoming message, request a notification using the reported
push URL and Authorization: Bearer SCOPED_PUSH_GRANT, with this JSON body:
{
"messageId": "00000000-0000-4000-8000-000000000002",
"remoteNumber": "+12025550124",
"text": "Example incoming message"
}Allow only your approved SessionTalk relay hosts and the /byo/webservice/push
path. The app obtains the grant from its selected relay; your service does not
need a shared relay secret, the SIP password or the native APNs/FCM token.
Grants expire after seven days and are refreshed while the app is open. Private
push deployments need the matching webservice relay implementation.
Keep messages available for fetching if notifications fail. Retry notification network errors, HTTP 429 and 5xx with backoff and the same message UUID; HTTP 401 requires a refreshed device report. HTTP 200 acknowledges notification submission, not delivery or reading. A missing device report does not prevent foreground inbox fetching and has no bearing on SIP registration.
Verify the direct connection
Use a test service account and confirm these requests in your service’s sanitized logs: inbox GET, outgoing POST, and device PUT on a push-enabled mobile account. Do not log Authorization headers, service passwords, push tokens or message bodies. Check receiving while foregrounded, a reply, duplicate-message handling, offline recovery, and a locked-phone notification that opens the correct conversation.
The portal displays Check your service for last received SMS because SessionCloud does not store these messages. Verify receipt on your server and delivery in the app. An enabled assignment alone does not confirm that your service, carrier or notifications are working.