Skip to main content

BYO-SMPP Credentials API

Bring-your-own SMPP for organizations with existing carrier relationships. Orbit issues the credentials — when you create a credential set, Orbit generates the system_id and password (the password is shown once on create and via GET /{id}/reveal, and can be rotated). The SMPP host and port are platform-provided connection details returned on the credential, not values you supply. On create you only send optional settings (description, tpsLimit, allowedCidrs, dlrMode, dlrWebhookUrl); any other field is rejected. You bind to Orbit’s SMPP control plane (Jasmin) with the issued credentials, and Orbit reconciles them into its user store every 30 seconds and routes outbound SMS through your trunk. Base path: /api/v1/messaging Authentication: API key (X-API-Key) or session JWT.

Using the SDKs

Prefer the typed client, but this page’s endpoint has no helper yet — the generic request() keeps auth/retries and the { data, meta } envelope identical:
Python (same call via the SDK’s escape hatch):
The Python SDK is core-scope — it wraps the 8 core resources (messaging, voice, contacts, campaigns, verify, numbers) and reaches everything else through the generic client.request() escape hatch above. See the Python SDK. Raw curl in the body of this page works identically. Full SDK index at SDK quickstart.

Credentials

The Node tab of each example below uses the Node.js SDK helpers under orbit.messagingConfig.smppCredentials. The methods pass your input through as sent — the documented request fields are the ones the API accepts.

Issue a credential

POST /smpp/credentials returns the plaintext password in the response body. Save it on receipt — after the 60-second reveal window closes, the password is unrecoverable and rotation is the only way to get a new one.
201 Created:
The systemId, password, smppHost, and smppPort are platform-issued — use exactly these four values when you configure your SMPP client bind.

Reveal the password

Within the 60-second window after create or rotate (check passwordRevealableUntil), GET /{id}/reveal returns the password once. Every reveal is audit-logged. After the window closes the endpoint returns 410 Gone.

Rotate the password

POST /{id}/rotate generates a new password and returns it once, in the same shape as the create response. The old password stops working on the reconciler’s next 30-second pass — update your SMPP client immediately.
The response is the credential wire shape plus password and the same password_visible_once_warning as on create.

Update a credential

PATCH /{id} updates the mutable fields. Pass null for description or dlrWebhookUrl to clear them; set status to suspended to disable the bind or revoked to soft-delete it.
Deleting a credential (DELETE /{id}) is a soft delete — status flips to revoked and the endpoint returns 204 No Content.

Carriers

A carrier definition pairs a credential set with routing metadata — supported countries, quality, fallback order, billing rate. The Node tab of each example below uses the Node.js SDK helpers under orbit.messagingConfig.smppCarriers.

Add a carrier

For a type: "smpp" carrier you supply the upstream SMSC connection details — remoteHost, remotePort, remoteSystemId, and remotePassword are all required. The password never comes back on any response; SMPP 3.4 caps it at 8 usable characters, so a longer value is rejected at validation. A scope of by_country_mcc also requires a non-empty scopeFilter.mccs list of 3-digit MCCs.
201 Created:

Update a carrier

PATCH /{id} updates routing metadata and connection details. Pass scopeFilter: null to clear a MCC filter. Because PATCH is partial, updating a MCC-scoped carrier’s scope to by_country_mcc requires scopeFilter.mccs in the same request when none is stored yet.
The response is the full carrier wire shape, as on create. Deleting a carrier (DELETE /{id}) returns 204 No Content.

Test a carrier

POST /api/v1/messaging/smpp/carriers/{id}/test checks whether the carrier can bind to its SMSC. It does not submit an SMS — no test message is delivered and you are not billed for it. Use it to confirm host, port, system ID, and password before routing live traffic. The response reports the last bind state the platform has observed for the carrier:
A healthy carrier:
A failed bind reports the reason the SMSC rejected it:

Route scores (analytics)

GET /api/v1/messaging/smpp/carriers/route-scores returns the scoring breakdown Orbit uses to decide which of your carriers carries an outbound message. It re-runs the same cost × delivery-quality × bind-health × sticky-incumbent scoring as the live router, so you can see which carrier is winning right now, why, and whether Orbit has failed over away from a degraded bind. The call is read-only — it changes no routing and sends no traffic. The route-policy panel under Developer → SMPP in the dashboard reads this same endpoint. Only carriers with status: "active" and type: "smpp" are scored, matching the set the router chooses from. If Orbit cannot read your recent delivery history, the request still succeeds and every active carrier is scored on cost and bind health alone; those entries come back with delivered and failed at 0 and deliveryRate as null. Scores are smoothed, so quality will not match deliveryRate exactly on a low-volume carrier — a carrier with no traffic yet starts at a neutral quality rather than at zero.

Sender pools

Group multiple sender IDs / numbers into a pool that the router rotates across. Pools attach to carriers and are referenced by campaigns. The Node tab of each example below uses the Node.js SDK helpers under orbit.messagingConfig.senderPools. Pool members (sender_dids) mix E.164 long codes, numeric short codes, and alphanumeric sender IDs. strategy is one of sticky (default — same recipient keeps the same sender), round_robin, random, or geomatch (prefer a sender in the recipient’s country, falling back to sticky when none matches).

Create a pool

201 Created:
An empty sender_dids, more than 50 members, duplicates, or a member that is not a valid sender returns 422. Updating (PATCH /{id} with label, sender_dids, or strategy) returns the same shape; deleting (DELETE /{id}) returns 204 No Content.

Preview sender selection

GET /{id}/preview?recipient=<E.164> resolves which sender the pool would pick for a destination without persisting anything — no stickiness assignment is written and the round-robin cycle is not advanced, so you can probe freely. Use it to verify a pool’s behaviour before wiring it into a campaign.
For sticky pools the same recipient always previews to the same sender; for geomatch the preview shows the country-matched sender when the pool holds one for the recipient’s country.

See also