Skip to main content

SMPP API

SMPP endpoints exposed by the Devotel CPaaS API Base path: /api/v1/messaging/smpp Endpoint count: 15

title: “Worked request and response samples” description: “Worked samples for the bring-your-own-carrier bind lifecycle: register a carrier (201), list the live bind rows, delete to take it out of rotation (204), and the 404 for an unknown carrier id.”

Worked request and response samples

Copy a request as written, substitute your own ids, and compare the response envelope. Errors follow Devotel Orbit’s { error, ... } envelope with the error.code your client branches on. The chain a carrier/SMPP integrator runs: register → list the live bind → delete to retire it.

1. Register a carrier bind

POST /api/v1/messaging/smpp/carriers
Request
The created row registers a BYO upstream termination carrier your outbound messaging traffic routes through while status='active'. Devotel reads the routing fields (scope, priority — lower wins) and reconciles the SMPP bind within about 30 seconds; once live, GET on this row reports the reconciler-observed bindStatus (BOUND / UNBOUND / BIND_FAILED) and lastSeenAt. The password you sent is never on the wire again — reads redact it to remotePasswordSet: true. Most registrations on this platform connect to the inbound side (your SMSC binds to Orbit for MO and delivery receipts) — for that, create a credential (POST /api/v1/messaging/smpp/credentials) instead; a carrier is for outbound termination only.

2. List the live bind rows

GET /api/v1/messaging/smpp/carriers
Request
The list page returns data as an array of the full wire shape (see step 1 for every field). Rows come back in priority order, then newest-first within the same priority. There is no pagination envelope on this endpoint — the row set is a small per-tenant list. Filter status='active' client-side to find the routes currently eligible for outbound traffic.

3. Delete the carrier (204, hinted rebind)

DELETE /api/v1/messaging/smpp/carriers/{id}
Response: 204 No Content Delete is a soft delete — the row stays in your tenant for the audit chain with status='inactive', and routing stops sending through the carrier once the reconciler’s next ~30-second tick removes the underlying connector. Retired it by mistake? Re-activate with PATCH /api/v1/messaging/smpp/carriers/{id} and {"status": "active"} — a hinted rebind, no re-registration needed.

4. Unknown carrier id → 404

Reading, updating, testing, or deleting an id that is not a carrier in your tenant returns the 404 error envelope:
404

List SMPP carriers

GET /api/v1/messaging/smpp/carriers
List every BYO upstream termination carrier in the tenant, in priority order (lowest priority value first). A carrier is your own downstream SMSC — SMPP bind or HTTP API — that outbound MT traffic routes through when the row is active, and Devotel charges $0/message on those sends. Each item carries the full wire shape (id, label, type, connection block, scope, scopeFilter, priority, status, reconciler-observed bindStatus / lastSeenAt, timestamps) with credential material redacted to remotePasswordSet / httpCredentialsSet booleans. Use it to render a carrier table or confirm reconciliation state before a change.
string (enum: true|false)
Sandbox opt-in for Clerk-session-authenticated requests. Set to true to route the call through the test-mode pipeline: no real provider delivery, no credits deducted, response meta.test_mode: true. Ignored for live API keys (dv_live_sk_*) — server-to-server clients must use a test-prefixed key (dv_test_sk_*) to exercise sandbox. Test-prefixed keys unconditionally enable sandbox regardless of this header.

Get SMPP carrier

GET /api/v1/messaging/smpp/carriers/{id}
Fetch a single BYO upstream carrier by its id_smppcr_ id, returning the full configuration: label and carrier type (smpp or http), the connection block for that type (SMPP: remoteHost / remotePort / remoteSystemId / bindType / TLS flags; HTTP: httpUrl / httpAuthType), routing (scope, scopeFilter.mccs, priority), lifecycle status, and the reconciler-observed bindStatus / lastSeenAt. Credential material is redacted to remotePasswordSet / httpCredentialsSet booleans — never the value. Use it to hydrate a detail or edit view. Returns 404 when the id is not a carrier in this tenant.
string
required
—
string (enum: true|false)
Sandbox opt-in for Clerk-session-authenticated requests. Set to true to route the call through the test-mode pipeline: no real provider delivery, no credits deducted, response meta.test_mode: true. Ignored for live API keys (dv_live_sk_*) — server-to-server clients must use a test-prefixed key (dv_test_sk_*) to exercise sandbox. Test-prefixed keys unconditionally enable sandbox regardless of this header.

Get SMPP carrier route scores

GET /api/v1/messaging/smpp/carriers/route-scores
Read the reconciler’s per-carrier route-policy breakdown — the live LCR scoring inputs (cost, delivery quality, bind health, sticky affinity) with their weights and per-carrier totals — that the preflight gate uses to pick the optimal egress route and to fail over on degradation. Read-only; the ranking refresh follows the reconciler’s tick, so scores here are eventually consistent with the preflight gate’s view. Use it to explain WHY a carrier won or lost routing before retuning priority or scope on the carrier itself.
string (enum: true|false)
Sandbox opt-in for Clerk-session-authenticated requests. Set to true to route the call through the test-mode pipeline: no real provider delivery, no credits deducted, response meta.test_mode: true. Ignored for live API keys (dv_live_sk_*) — server-to-server clients must use a test-prefixed key (dv_test_sk_*) to exercise sandbox. Test-prefixed keys unconditionally enable sandbox regardless of this header.

List SMPP credentials

GET /api/v1/messaging/smpp/credentials
List every BYO-SMPP credential in the tenant, newest-first. A credential is the bind identity (systemId + password, generated at create) your SMSC uses to open an SMPP bind against Orbit for inbound (MO / delivery-receipt) traffic. The list view carries the full wire shape per credential (id, systemId, description, tpsLimit, allowedCidrs, dlrMode, dlrWebhookUrl, status, timestamps, bindCount, smppHost, smppPort, passwordRevealableUntil) — password material is never on the wire. Use it to hydrate a credentials table or to find a credential id before update / rotate / revoke.
string (enum: true|false)
Sandbox opt-in for Clerk-session-authenticated requests. Set to true to route the call through the test-mode pipeline: no real provider delivery, no credits deducted, response meta.test_mode: true. Ignored for live API keys (dv_live_sk_*) — server-to-server clients must use a test-prefixed key (dv_test_sk_*) to exercise sandbox. Test-prefixed keys unconditionally enable sandbox regardless of this header.

Get SMPP credential

GET /api/v1/messaging/smpp/credentials/{id}
Fetch a single BYO-SMPP credential by its smppcred_ id, returning the full configuration: bind identity (systemId), description, throughput cap (tpsLimit), CIDR allow-list, DLR delivery mode and webhook URL, lifecycle status, timestamps, bind count, and the smppHost / smppPort pair your SMSC binds to. passwordRevealableUntil tells you whether GET /:id/reveal can still return the plaintext. Use it to hydrate a detail or edit view. Returns 404 when the id is not a credential in this tenant.
string
required
—
string (enum: true|false)
Sandbox opt-in for Clerk-session-authenticated requests. Set to true to route the call through the test-mode pipeline: no real provider delivery, no credits deducted, response meta.test_mode: true. Ignored for live API keys (dv_live_sk_*) — server-to-server clients must use a test-prefixed key (dv_test_sk_*) to exercise sandbox. Test-prefixed keys unconditionally enable sandbox regardless of this header.

Reveal SMPP credential password

GET /api/v1/messaging/smpp/credentials/{id}/reveal
Return the plaintext bind password of an SMPP credential once, inside the short post-create (or post-rotate) reveal window — roughly 60 seconds from issuance. This is the ONLY read that ever returns password material, and it is gated to owner/admin only (developer / viewer roles are refused). After the window closes the secret is unrecoverable and the only recourse is POST /:id/rotate. Use it when the create / rotate response was not persisted. Returns 404 when the id is not a credential in this tenant and 410 when the reveal window has expired.
string
required
—
string (enum: true|false)
Sandbox opt-in for Clerk-session-authenticated requests. Set to true to route the call through the test-mode pipeline: no real provider delivery, no credits deducted, response meta.test_mode: true. Ignored for live API keys (dv_live_sk_*) — server-to-server clients must use a test-prefixed key (dv_test_sk_*) to exercise sandbox. Test-prefixed keys unconditionally enable sandbox regardless of this header.

Create SMPP or HTTP-API carrier

POST /api/v1/messaging/smpp/carriers
Register your own upstream termination carrier — an SMPP bind (type='smpp' with remoteHost, remotePort, remoteSystemId, remotePassword, optional bindType and TLS flags) or an HTTP API (type='http' with httpUrl, httpAuthType, httpCredentials) — that outbound MT traffic routes through while the row is active, at $0/message from Devotel. Routing fields pick what the carrier serves: scope='all' or scope='by_country_mcc' with a scopeFilter.mccs list (1–50 three-digit MCCs), plus a priority (lower wins). Submit status='inactive' to stage the row before flipping it live. The reconciler picks the row up on its next 30-second tick and opens the bind / installs the route. Owner / admin only, rate-limited to 20/hour per tenant; a missing connection block for the declared type is a 422.
string
Stripe-style idempotency token. Pass a stable, client-generated value (1-255 chars) to dedupe retries on transient timeouts. The same key+credential+path replays the original response for 24h on 2xx (5min on 4xx, 30s on 5xx). Returns 409 if a concurrent request with the same key is already in flight; replayed responses include the Idempotency-Replay: true response header.
string (enum: true|false)
Sandbox opt-in for Clerk-session-authenticated requests. Set to true to route the call through the test-mode pipeline: no real provider delivery, no credits deducted, response meta.test_mode: true. Ignored for live API keys (dv_live_sk_*) — server-to-server clients must use a test-prefixed key (dv_test_sk_*) to exercise sandbox. Test-prefixed keys unconditionally enable sandbox regardless of this header.
any
Human-readable name, 1–64 characters (required).
any
Carrier type: smpp (SMPP bind, default) or http (HTTP API).
any
SMPP: upstream host — hostname, IPv4 or IPv6 literal, no scheme or port (required for type='smpp').
any
SMPP: upstream port, 1–65535 (required for type='smpp').
any
SMPP: bind system_id, 1–15 characters per SMPP 3.4 (required for type='smpp').
any
SMPP: bind password, 1–8 characters (SMPP 3.4 C-Octet cap); encrypted at rest, never echoed back (required for type='smpp').
any
HTTP: upstream endpoint, HTTPS-only (required for type='http').
any
HTTP: auth scheme — basic, bearer or custom (required for type='http').
any
HTTP: opaque credential material the auth scheme consumes; encrypted at rest (required for type='http').
any
Routing scope: all (default) or by_country_mcc.
any
Routing filter { mccs: string[] } of 1–50 three-digit MCCs; required when scope='by_country_mcc'.
any
Route priority, 0–10000 (lower wins; default 100).
any
Initial lifecycle status — active, suspended or inactive; submit inactive to stage before going live.

Test SMPP carrier bind

POST /api/v1/messaging/smpp/carriers/{id}/test
Run a synchronous test bind against a BYO upstream carrier and return the outcome: ok, the observed bindStatus (BOUND / UNBOUND / BIND_FAILED), a failure reason when it did not bind, and the bind round-trip time in durationMs. Run it right after creating or updating a carrier — and again when the dashboard flags a degraded route — before routing live traffic through it. Owner / admin only, rate-limited to 6/minute per tenant so a stuck upstream cannot be hammered; returns 404 when the id is not a carrier in this tenant.
string
required
—
string
Stripe-style idempotency token. Pass a stable, client-generated value (1-255 chars) to dedupe retries on transient timeouts. The same key+credential+path replays the original response for 24h on 2xx (5min on 4xx, 30s on 5xx). Returns 409 if a concurrent request with the same key is already in flight; replayed responses include the Idempotency-Replay: true response header.
string (enum: true|false)
Sandbox opt-in for Clerk-session-authenticated requests. Set to true to route the call through the test-mode pipeline: no real provider delivery, no credits deducted, response meta.test_mode: true. Ignored for live API keys (dv_live_sk_*) — server-to-server clients must use a test-prefixed key (dv_test_sk_*) to exercise sandbox. Test-prefixed keys unconditionally enable sandbox regardless of this header.

Dry-run LCR route quote

POST /api/v1/messaging/smpp/carriers/route-quote
Simulate the least-cost-routing decision for a destination and estimate the cost you would be charged. Everything is computed against the same scoring engine + scope-match the preflight gate uses: decision='byo' names the carrier that would win (cost $0 — you pay your upstream directly); decision='devotel' returns a Devotel-termination cost estimate off the pricing resolver (unitPriceCents/totalCents), or an explicit devotelQuote: null when pricing couldn’t resolve. The request body is { destination, messageCount } (messageCount defaults to 1). Nothing is billed — the endpoint is read-only and never debits your wallet.
string
Stripe-style idempotency token. Pass a stable, client-generated value (1-255 chars) to dedupe retries on transient timeouts. The same key+credential+path replays the original response for 24h on 2xx (5min on 4xx, 30s on 5xx). Returns 409 if a concurrent request with the same key is already in flight; replayed responses include the Idempotency-Replay: true response header.
string (enum: true|false)
Sandbox opt-in for Clerk-session-authenticated requests. Set to true to route the call through the test-mode pipeline: no real provider delivery, no credits deducted, response meta.test_mode: true. Ignored for live API keys (dv_live_sk_*) — server-to-server clients must use a test-prefixed key (dv_test_sk_*) to exercise sandbox. Test-prefixed keys unconditionally enable sandbox regardless of this header.
string
required
The destination phone-number string (E.164 like +44... or the short-form you would actually send — the scope-match + price resolver interpret it exactly the way the live send does).
integer
How many messages to price (defaults to 1 so a single-send dry run reads a per-message unit price).

Create SMPP credential

POST /api/v1/messaging/smpp/credentials
Issue a new BYO-SMPP credential — the bind identity (systemId, smppcred_…) plus a generated password your SMSC uses to bind to Orbit for inbound (MO / delivery-receipt) traffic. All body fields are optional config: description, tpsLimit (1–1000, plan-tier-capped), allowedCidrs (up to 16 IPv4/IPv6 CIDRs that gate the bind source), dlrMode (bind delivers receipts on the SMPP bind, webhook POSTs them, both), and dlrWebhookUrl (HTTPS-only, SSRF-checked; required when dlrMode is webhook or both). THE PLAINTEXT PASSWORD IS RETURNED EXACTLY ONCE in this response together with the credential record — store it now. Within 60 seconds it remains re-fetchable via GET /:id/reveal; after that it is unrecoverable and you must call /rotate. Owner / admin only — an owner/admin dashboard session, or an API key scoped smpp:write — rate-limited to 10/hour per tenant.
string
Stripe-style idempotency token. Pass a stable, client-generated value (1-255 chars) to dedupe retries on transient timeouts. The same key+credential+path replays the original response for 24h on 2xx (5min on 4xx, 30s on 5xx). Returns 409 if a concurrent request with the same key is already in flight; replayed responses include the Idempotency-Replay: true response header.
string (enum: true|false)
Sandbox opt-in for Clerk-session-authenticated requests. Set to true to route the call through the test-mode pipeline: no real provider delivery, no credits deducted, response meta.test_mode: true. Ignored for live API keys (dv_live_sk_*) — server-to-server clients must use a test-prefixed key (dv_test_sk_*) to exercise sandbox. Test-prefixed keys unconditionally enable sandbox regardless of this header.
any
Human-readable label, 1–200 characters (optional).
any
Inbound throughput cap, 1–1000 messages/second; additionally plan-tier-capped service-side (optional).
any
Up to 16 IPv4/IPv6 CIDR strings that gate which source IPs may bind (optional; empty means any).
any
Delivery-receipt delivery mode: bind, webhook or both (optional, defaults to bind).
any
HTTPS webhook endpoint for DLRs; required when dlrMode is webhook or both (optional otherwise).

Rotate an SMPP credential’s password and return the new plaintext once

POST /api/v1/messaging/smpp/credentials/{id}/rotate
Issue a new SMPP bind password for an existing BYO-SMPP credential when the plaintext is lost (the 60-second reveal window expired), when the secret may be compromised, or on a scheduled rotation cycle. The credential’s systemId and every config field stay unchanged; only the password is replaced. The new plaintext is returned EXACTLY ONCE in this response — store it now. Owner / admin only — an owner/admin dashboard session, or an API key scoped smpp:write — rate-limited to 10 per hour per tenant. A 409 fires when the credential is revoked (create a new one instead), and 404 when no credential holds the id.
string
required
—
string
Stripe-style idempotency token. Pass a stable, client-generated value (1-255 chars) to dedupe retries on transient timeouts. The same key+credential+path replays the original response for 24h on 2xx (5min on 4xx, 30s on 5xx). Returns 409 if a concurrent request with the same key is already in flight; replayed responses include the Idempotency-Replay: true response header.
string (enum: true|false)
Sandbox opt-in for Clerk-session-authenticated requests. Set to true to route the call through the test-mode pipeline: no real provider delivery, no credits deducted, response meta.test_mode: true. Ignored for live API keys (dv_live_sk_*) — server-to-server clients must use a test-prefixed key (dv_test_sk_*) to exercise sandbox. Test-prefixed keys unconditionally enable sandbox regardless of this header.

Update SMPP carrier

PATCH /api/v1/messaging/smpp/carriers/{id}
Update mutable fields on a BYO upstream carrier in place — send only the fields you want to change (label, description, the type-specific connection block, routing scope / scopeFilter / priority, and/or status). Nullable fields (description, httpUrl, httpAuthType, scopeFilter) accept null to clear them; remotePassword rotation logs the field name but never the value. A status flip to active (back) reconciles the Jasmin connector on the next tick; inactive is the soft-deleted state. Use it to retune routing priority or rotate the upstream endpoint without dropping the row. Owner / admin only; returns 404 when the id is not a carrier in this tenant.
string
required
—
string (enum: true|false)
Sandbox opt-in for Clerk-session-authenticated requests. Set to true to route the call through the test-mode pipeline: no real provider delivery, no credits deducted, response meta.test_mode: true. Ignored for live API keys (dv_live_sk_*) — server-to-server clients must use a test-prefixed key (dv_test_sk_*) to exercise sandbox. Test-prefixed keys unconditionally enable sandbox regardless of this header.
any
New human-readable name, 1–64 characters.
any
New SMPP upstream host (hostname / IPv4 / IPv6 literal).
any
New SMPP upstream port, 1–65535.
any
New SMPP system_id, 1–15 characters.
any
New SMPP bind password, 1–8 characters; encrypted at rest.
any
New routing scope: all or by_country_mcc.
any
New { mccs: string[] } filter (1–50 three-digit MCCs), or null to clear.
any
New route priority, 0–10000 (lower wins).
any
New lifecycle status — active, suspended or inactive.

Update SMPP credential

PATCH /api/v1/messaging/smpp/credentials/{id}
Update mutable fields on an SMPP credential in place — send only the fields you want to change (description, tpsLimit, allowedCidrs, dlrMode, dlrWebhookUrl and/or status). Nullable fields (description, dlrWebhookUrl) accept null to clear them. A status flip is reconciler-routed: active enables the Jasmin user, suspended disables it, revoked removes it (soft delete). Use it to retune throughput, rotate the CIDR allow-list, move DLR delivery between bind and webhook, or suspend a credential without revoking it. Owner / admin only — an owner/admin dashboard session, or an API key scoped smpp:write; returns 404 when the id is not a credential in this tenant.
string
required
—
string (enum: true|false)
Sandbox opt-in for Clerk-session-authenticated requests. Set to true to route the call through the test-mode pipeline: no real provider delivery, no credits deducted, response meta.test_mode: true. Ignored for live API keys (dv_live_sk_*) — server-to-server clients must use a test-prefixed key (dv_test_sk_*) to exercise sandbox. Test-prefixed keys unconditionally enable sandbox regardless of this header.
any
New human-readable label (1–200 chars), or null to clear.
any
New inbound throughput cap, 1–1000 messages/second.
any
Replacement CIDR allow-list (up to 16 IPv4/IPv6 CIDR strings).
any
New delivery-receipt mode: bind, webhook or both.
any
HTTPS webhook endpoint for DLRs, or null to clear; required when dlrMode is webhook or both.
any
New lifecycle status — active, suspended or revoked; reconciler-routed to Jasmin.

Delete SMPP carrier

DELETE /api/v1/messaging/smpp/carriers/{id}
Soft-delete a BYO upstream carrier (sets status='inactive'). The row stays for the audit chain while the reconciler removes the Jasmin smppc connector and the mtrouter rule on its next ~30-second tick, which stops new sends routing through this carrier. Use it to take a carrier out of rotation; re-activate it via PATCH /:id with status='active' if you retired it by mistake. Owner / admin only; returns 404 when the id is not a carrier in this tenant and 204 No Content on success.
string
required
—
string (enum: true|false)
Sandbox opt-in for Clerk-session-authenticated requests. Set to true to route the call through the test-mode pipeline: no real provider delivery, no credits deducted, response meta.test_mode: true. Ignored for live API keys (dv_live_sk_*) — server-to-server clients must use a test-prefixed key (dv_test_sk_*) to exercise sandbox. Test-prefixed keys unconditionally enable sandbox regardless of this header.
Response: 204 No Content

Revoke SMPP credential

DELETE /api/v1/messaging/smpp/credentials/{id}
Revoke an SMPP credential — a soft delete: the row stays for the audit chain while the reconciler removes the Jasmin user on its next tick, so the credential’s existing binds drop and new binds are rejected. Use it to retire a bind identity; revocation is provider-side and cannot be undone through this endpoint (create a new credential instead). Owner / admin only — an owner/admin dashboard session, or an API key scoped smpp:write; returns 404 when the id is not a credential in this tenant and 204 No Content on success.
string
required
—
string (enum: true|false)
Sandbox opt-in for Clerk-session-authenticated requests. Set to true to route the call through the test-mode pipeline: no real provider delivery, no credits deducted, response meta.test_mode: true. Ignored for live API keys (dv_live_sk_*) — server-to-server clients must use a test-prefixed key (dv_test_sk_*) to exercise sandbox. Test-prefixed keys unconditionally enable sandbox regardless of this header.
Response: 204 No Content