Three steps to a first request
Create a key
In the portal, Settings → API Keys. Name it, pick an expiry and copy it: the key is shown once and stored only as a hash.
Call an endpoint
Send the key as a bearer token. GET /api/v1/me answers with your organization, the scopes the key holds and its rate limit, so it is the call to make first.
Subscribe to events
Settings → Webhooks: add an https address on a host your organization has approved, tick the events you want, from call.completed to survey.responded, and keep the signing secret it shows once.
Start from a working request
No package to install: the API is plain HTTPS and JSON, so these samples work as they are.
OpenAPI 3.1
openapi.jsonGET /api/v1/openapi.jsonGenerated from the schemas the API validates against, and readable without a key.
Open the speccurl
shellcurl https://api.inboundcx.com/api/v1/me \ -H "Authorization: Bearer $API_KEY"Checks the key: the organization, its scopes and the rate limit come back.
JavaScript
fetchconst res = await fetch("https://api.inboundcx.com/api/v1/contacts?includeAutoCreated=false&limit=50", { headers: { Authorization: `Bearer ${process.env.API_KEY}` }, }); if (!res.ok) throw new Error(`${res.status} ${await res.text()}`); const { contacts, nextCursor } = await res.json();Lists the contacts a person entered, 50 at a time, with a cursor for the next page.
Python
requestsimport os import requests r = requests.post( "https://api.inboundcx.com/api/v1/messages", headers={"Authorization": f"Bearer {os.environ['API_KEY']}"}, json={"to": "+15145550142", "body": "Your technician arrives between 9 and 11."}, timeout=10, ) r.raise_for_status() message = r.json()["message"]Sends a text as the organization, billed at its carrier rate.
Webhook signatures
HMAC-SHA256import crypto from "node:crypto"; // Deprecated names with the same values: x-ringfully-timestamp, x-ringfully-signature. const timestamp = req.get("x-inboundcx-timestamp") ?? ""; const signature = req.get("x-inboundcx-signature") ?? ""; const expected = crypto .createHmac("sha256", process.env.INBOUNDCX_WEBHOOK_SECRET) .update(`${timestamp}.${rawBody}`) .digest("hex"); const valid = expected.length === signature.length && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature)) && Math.abs(Date.now() - Number(timestamp)) < 5 * 60 * 1000;Reads
x-inboundcx-timestampandx-inboundcx-signature;x-ringfully-timestampandx-ringfully-signatureDeprecated still arrive with the same values.API keys
Pro and BusinessAuthorization: Bearer rk_live_…Created in Settings → API Keys. Revoke one there and it stops working on its next request.
Open API Keys in the portal
What you can build with it today
Every call logged in your own system
Receive call.completed when a call ends, or page back through the history, and file each call against the right customer.
GET /api/v1/callsOne contact list, kept up to date
Create, rename and remove contacts from the software you already use. A number your team has already called is named, not duplicated.
POST /api/v1/contactsTexts sent from your own tools
Send a reminder or a job update from your booking or dispatch software, and read the replies conversation by conversation.
POST /api/v1/messages
Questions about the API
Ask about a scope, a limit or an endpoint through the contact form.
Contact usService status
Whether our servers, the web app and the phone network are working right now, checked live, with the incidents we have written up.
Check the service status