Skip to content
Last updated

ContextSMS Teams Platform Integration Guide

The ContextSMS Teams Platform API connects Microsoft Teams with external messaging systems. It allows teams to send and receive text messages directly through Microsoft Teams, with full support for multiple customer organizations and CSP white-labeling.


Quick facts

  • Production base URL: https://context-sms.sabrhub.com/api/v2
  • Auth: Bearer JWT include Authorization: Bearer <ACCESS_TOKEN> in all protected requests.
  • Date format: createdDate / updateDate are epoch milliseconds (int64) unless otherwise noted.
  • Phone numbers: Use E.164 format (e.g. +15551234567).
  • Content-Type: application/json for JSON bodies.

Prerequisites

  • Sabrhub production account with Teams Platform access.
  • A CSP ID (if you are a CSP partner) — required for creating enterprises.
  • Production Teams identifiers (teamId/channelId) if mapping to Teams channels.
  • A secure place to store tokens (secrets manager / environment variables).
  • Postman collection & Redoc URL (see References).

1 Quick start zero → first mapping

Follow these steps to go from zero to a working phone→Teams mapping in production.

Step A Login and obtain access token

TOKEN=$(curl -s -X POST "https://context-sms.sabrhub.com/api/v2/auth/login"   -H "Content-Type: application/json"   -d '{"username":"you@company.com","password":"YourStrongPassword!"}'   | jq -r '.accessToken')

Step B Create enterprise under a CSP (replace CSP0000003 with your CSP ID)
Take note of returned enterpriseId (e.g. E0000090).

curl -s -X POST "https://context-sms.sabrhub.com/api/v2/enterprise/CSP0000003"   -H "Authorization: Bearer $TOKEN"   -H "Content-Type: application/json"   -d '{
    "name":"Sunshine Dental Clinic",
    "contact":"Dr. Maria Rodriguez",
    "number":"+15559876543",
    "email":"maria@sunshinedental.com"
  }' | jq

Step C Add mapping (replace E0000090 with the created enterpriseId)

curl -s -X POST "https://context-sms.sabrhub.com/api/v2/mapping/add/E0000090"   -H "Authorization: Bearer $TOKEN"   -H "Content-Type: application/json"   -d '{
    "phoneNumber":"+15559876543",
    "messagingAppType":"Teams",
    "messagingAppId":"teams-channel-id-12345",
    "name":"FrontDesk"
  }' | jq

Step D Verify mapping

curl -s -X GET "https://context-sms.sabrhub.com/api/v2/numbertomessageappmapping/enterprise/E0000090"   -H "Authorization: Bearer $TOKEN" | jq

If you do not have jq, the JSON will still print; jq is only for pretty-printing.


2 Field mapping & formats

FieldMeaningRequired / Notes
contactEnterprise contact namerequired for POST /enterprise/{cspId}
numberEnterprise phone number (E.164)required for POST /enterprise/{cspId}
emailEnterprise admin emailrequired for POST /enterprise/{cspId}
phoneNumberPhone number to map (E.164)required for mapping endpoints
messagingAppTypeMessaging platform type (e.g., Teams)required
messagingAppIdPlatform-specific identifier (e.g., Teams team/channel id)required
createdDate, updateDateepoch milliseconds (int64)convert client-side if needed

3 Authentication

3.1 Login obtain accessToken + refreshToken

POST /auth/login
URL: https://context-sms.sabrhub.com/api/v2/auth/login

Request

{
  "username": "you@company.com",
  "password": "YourStrongPassword!"
}

cURL

curl -X POST "https://context-sms.sabrhub.com/api/v2/auth/login"   -H "Content-Type: application/json"   -d '{"username":"you@company.com","password":"YourStrongPassword!"}'

JavaScript (fetch)

const res = await fetch('https://context-sms.sabrhub.com/api/v2/auth/login', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ username: 'you@company.com', password: 'YourStrongPassword!' })
});
const data = await res.json();
console.log(data); // contains accessToken + refreshToken

Python (requests)

import requests
resp = requests.post(
  'https://context-sms.sabrhub.com/api/v2/auth/login',
  json={'username':'you@company.com','password':'YourStrongPassword!'},
  headers={'Content-Type':'application/json'}
)
print(resp.json())

Success (200) (example)

{
  "username": "you@company.com",
  "accessToken": "eyJ...ACCESS...",
  "refreshToken": "eyJ...REFRESH...",
  "expirationTimeInUTC": "2025-01-01T12:00:00Z",
  "roles": ["CSP_BUSINESS"],
  "tenantId": "YourTenant",
  "services": ["Teams"]
}

Notes

  • Use Authorization: Bearer <accessToken> header for protected endpoints.
  • Securely store refreshToken to obtain new access tokens.

3.2 Refresh access token

POST /auth/getaccesstoken body:

{ "username": "you@company.com", "refreshToken": "<REFRESH_TOKEN>" }

4 CSP APIs

(Include only if you are a CSP partner)

4.1 Create CSP

POST /csp https://context-sms.sabrhub.com/api/v2/csp
Request (example):

{
  "email": "admin@csp.com",
  "name": "Example CSP",
  "carrier": "BANDWIDTH",
  "houseNumber": "700 S",
  "streetName": "1st ST",
  "city": "Austin",
  "stateCode": "TX",
  "zip": "78704",
  "country": "USA",
  "locationId": "844849",
  "subAccountId": "109733",
  "authorizingPersonName": "CSP Admin"
}

4.2 Get CSP config by phone

GET /csp/getcspconfig?phoneNumber={phoneNumber}

Example response:

{ "productName":"ContextSMS", "favicon":"favicon_url", "logo":"logo_url", "color":"#000000" }

5 Enterprise lifecycle

Important: POST /enterprise/{cspId} requires the CSP ID in the path.

5.1 Create enterprise

POST /enterprise/{cspId}
URL pattern: https://context-sms.sabrhub.com/api/v2/enterprise/{cspId}

Request (required):

{
  "name": "Sunshine Dental Clinic",
  "contact": "Dr. Maria Rodriguez",
  "number": "+15559876543",
  "email": "maria@sunshinedental.com"
}

cURL

curl -X POST "https://context-sms.sabrhub.com/api/v2/enterprise/CSP0000003"   -H "Authorization: Bearer YOUR_ACCESS_TOKEN"   -H "Content-Type: application/json"   -d '{ "name":"Sunshine Dental Clinic", "contact":"Dr. Maria Rodriguez", "number":"+15559876543", "email":"maria@sunshinedental.com" }'

Success (201) example:

{
  "enterpriseId": "E0000090",
  "name": "Sunshine Dental Clinic",
  "contact": "Dr. Maria Rodriguez",
  "number": "+15559876543",
  "email": "maria@sunshinedental.com",
  "deleted": false,
  "createdDate": 1698446777442,
  "updateDate": 1698446777443
}

Notes

  • createdDate / updateDate are epoch ms. Convert to ISO with new Date(ms) or Python conversion shown below.

Date conversion snippets

// JS
new Date(1698446777442).toISOString()
# Python
from datetime import datetime
datetime.utcfromtimestamp(1698446777442 / 1000).isoformat() + 'Z'

5.2 Get enterprise by ID

GET /enterprise/getenterprise/{enterpriseId}

5.3 List enterprises for CSP

GET /csp/enterprises/{cspId}

5.4 Delete enterprise

DELETE /enterprise/deleteenterprise/{enterpriseId} returns plain text Deleted enterprise {id}


6 Mapping lifecycle

6.1 Add mapping (create)

POST /mapping/add/{enterpriseId}
URL example: https://context-sms.sabrhub.com/api/v2/mapping/add/E0000027

Request (required):

{
  "phoneNumber": "+12223334444",
  "messagingAppType": "Teams",
  "messagingAppId": "teams-channel-id-12345",
  "name": "FrontDesk"
}

cURL

curl -X POST "https://context-sms.sabrhub.com/api/v2/mapping/add/E0000027"   -H "Authorization: Bearer YOUR_ACCESS_TOKEN"   -H "Content-Type: application/json"   -d '{ "phoneNumber":"+12223334444","messagingAppType":"Teams","messagingAppId":"teams-channel-id-12345","name":"FrontDesk" }'

JavaScript (fetch)

const res = await fetch('https://context-sms.sabrhub.com/api/v2/mapping/add/E0000027', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
  body: JSON.stringify({ phoneNumber: '+12223334444', messagingAppType: 'Teams', messagingAppId: 'teams-channel-id-12345', name: 'FrontDesk' })
});
console.log(await res.json());

Python (requests)

import requests
resp = requests.post(
  'https://context-sms.sabrhub.com/api/v2/mapping/add/E0000027',
  json={'phoneNumber': '+12223334444', 'messagingAppType': 'Teams', 'messagingAppId': 'teams-channel-id-12345', 'name': 'FrontDesk'},
  headers={'Authorization': f'Bearer {token}', 'Content-Type': 'application/json'}
)
print(resp.json())

Success (200):

{
  "numberToMessageAppMapId": "NTMAP0000123",
  "phoneNumber": "+12223334444",
  "messagingAppType": "Teams",
  "messagingAppId": "teams-channel-id-12345",
  "name": "FrontDesk"
}

6.2 Get mappings for enterprise

GET /numbertomessageappmapping/enterprise/{enterpriseId}

6.3 Get mappings for CSP

GET /mapping/csp/{cspId}

6.4 Update mapping

PUT /mapping/{numberToMessageAppMapId} partial fields allowed (example: messagingAppId, phoneNumber).

6.5 Delete mapping

DELETE /mapping/{numberToMessageAppMapId} returns Deleted mapping {id}

6.6 Lookup mapping by messagingAppId

POST /mapping/messagingAppId body: { "messagingAppId": "app789" } — returns mapping object if present.


7 Billing & Stripe

7.1 Check payment status

POST /stripe/check-payment body: { "email": "customer@example.com" }
Response (200):

{ "email": "customer@example.com", "paid": true, "subscriptionStatus": "active" }

7.2 Stripe webhook receiver

POST /stripe/webhook accept & validate Stripe events. Example payload (minimal):

{
  "id": "evt_1MqqbKLt4dXK03v5qaIbiNCC",
  "object": "event",
  "api_version": "2023-10-16",
  "type": "customer.subscription.updated",
  "data": { "object": { "id": "sub_xxx", "status": "active" } },
  "livemode": false
}

Success:

{ "status": "received", "processed": true }

**Webhook verification **

  1. Enable and store your Stripe webhook signing secret securely.
  2. Verify the Stripe-Signature header on each incoming request using Stripe SDK or HMAC SHA256 as Stripe docs instruct.
  3. Persist processed evt.id values to avoid replay.
  4. Respond with 2xx only after successful validation and processing.

8 Error payloads & troubleshooting

400 Bad Request

{ "error": "Missing required field 'phoneNumber'", "code": "BAD_REQUEST" }

Fix: Check required fields and JSON syntax.

401 Unauthorized

{ "error": "Invalid or expired access token", "code": "UNAUTHORIZED" }

Fix: Refresh token via /auth/getaccesstoken or re-login.

403 Forbidden

{ "error": "CSP does not have permission to create enterprises", "code": "PERMISSION_DENIED" }

Fix: Verify user roles and CSP privileges; contact support if needed.

404 Not Found

{ "error": "Enterprise not found", "code": "NOT_FOUND" }

Fix: Confirm enterpriseId / cspId is correct and active.

409 Conflict (duplicate mapping)

{ "error": "Phone number +15551234567 is already mapped to another enterprise", "code": "DUPLICATE_MAPPING" }

Fix: Query existing mappings, delete or update prior mapping before creating a new one.

500 Internal Server Error

{ "error": "Internal server error", "requestId": "req-abc123", "timestamp": "2025-10-14T12:34:56Z" }

Fix: Retry with exponential backoff and send details to support including requestId.


9 References & support

  • Full API Reference (Redoc): https://docs.sabrhub.com
  • OpenAPI spec (repo): specs/contextsms-teams.yaml
  • Postman collection (repo): tests/postman-collections/teams-collection.json
  • Support: support@sabrhub.com include full request URL, request body (no tokens), response body, and IDs (enterpriseId, numberToMessageAppMapId).