Skip to main content

Messaging Services API

Messaging Services endpoints exposed by the Devotel CPaaS API Base path: /api/v1/messaging Endpoint count: 14

title: “Errors worth branching on” description: “Per-endpoint failure templates matching the envelope — what actually fires, what to retry, what to surface to the operator.”

Errors worth branching on

These five failures cover the messaging-service create (POST /api/v1/messaging-services), which campaign provisioning flows through. Each block below is a full { error, meta } envelope as the API returns it, and the matrix at the bottom answers retry vs surface for the same five classes. For the platform-wide decision table these branches plug into, see the error handling guide.

401 — Unauthorized

A 401 on this page is the bearer key failing before the route ran — it never means the resource is wrong. Rotate the key or re-mint the scoped token; retrying the same request changes nothing.

403 — Forbidden

A 403 means the key authenticated but the operation is gated by scope — check the key’s scopes on the developer page; a 403 is never a data-not-found shape.

422 — Schema

A 422 means the payload did not match the request schema — branch on error.details.field and resend with an allowed service name (1-48 chars) instead of blind-retrying the same body.

429 — Rate

The Retry-After header and error.details.retry_after are both set on every 429 — resend the SAME request after the lower of the two.

409 — Conflict

Detach via the existing service first, then POST again — the sender mapping is single-owner.

60-second retry matrix


Get messaging data residency

GET /api/v1/messaging/data-residency
Read the messaging data plane’s residency posture for the tenant: the pinned storage region and whether it is enforced (projected from the org’s compliance data-residency pin), plus the API region this request was processed in and the region-pinned ingress endpoint. Use it to confirm — programmatically, next to sender pools and services — where SMS / MMS / chat bodies and metadata rest and are processed before onboarding a regulated buyer. Read-only; pin or enforce a region via PUT /v1/compliance/data-residency.
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 messaging services

GET /api/v1/messaging/services
List every messaging service configured in the tenant, newest-first. A messaging service is a Twilio-MessagingServiceSid-style container that bundles a sender pool, opt-out list, inbound webhook, throughput cap and sending flags under one id you reference from /v1/messages. Use it to populate a service picker or reconcile your configuration. Returns up to 500 services; an empty array means none are configured yet.
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 messaging service

GET /api/v1/messaging/services/{id}
Fetch a single messaging service by its Orbit id, returning its full configuration — sender pool, per-country pool overrides, opt-out list, inbound/fallback/status-callback URLs, sending flags, validity period, throughput cap, external id and feature flags. Use it to hydrate a detail/edit view. Returns 404 when the id is not a messaging service 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.

List messaging service phone numbers

GET /api/v1/messaging/services/{id}/phone-numbers
List every tenant-owned phone number (DID) attached to a messaging service, joined with each number’s E.164, country code and capabilities for display, newest-attached first. Use it to render the service’s sender-number table. Returns 404 when the id is not a messaging service in this tenant; an empty array means no numbers are attached yet.
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 messaging service throughput cap

GET /api/v1/messaging/services/{id}/throughput
Read the per-service outbound throughput cap (messages per second) plus the min/max bounds the dashboard renders the control against. mps_cap is null when the service is uncapped (inherits only the tenant/provider limits). Use it to hydrate the throughput slider before an operator raises or clears the cap. Returns 404 when the id is not a messaging service 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 messaging service throughput stats

GET /api/v1/messaging/services/{id}/throughput-stats
Read live throughput telemetry for one messaging service, derived from the Redis token bucket the send path enforces: current send rate, token-bucket utilization against the configured cap, over-cap queue depth and recently observed throttle (429) events, joined with the service label. Use it to drive a per-service throughput gauge or alert on sustained throttling. Returns 404 when the id is not a messaging service 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.

Look up messaging service by external id

GET /api/v1/messaging/services/lookup
Resolve a messaging service by its external id — a Twilio MessagingServiceSid (MGxxx) or any opaque vendor id you stored on the service — and return the matching Orbit resource with its full configuration. Pass the id as the external_id query parameter. Used by the Twilio migrator import flow and the dashboard’s “I came from Twilio” wizard to map a foreign id onto the Orbit resource. Returns 404 when no service in this tenant carries that external id, so the caller can branch into a create-new flow without parsing a 200 body.
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 account messaging throughput stats

GET /api/v1/messaging/services/throughput-stats
Read a tenant-wide throughput rollup across every messaging service, derived from the Redis token buckets the send path enforces. Reads each service’s live sample concurrently and sums the totals — current send rate, configured cap, over-cap queue depth and recently observed throttle (429) events — alongside a per-service breakdown and the count of capped services. Use it to drive an account-level throughput dashboard or alert on sustained throttling. Returns an empty services array when no messaging services are configured yet.
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 messaging service

POST /api/v1/messaging/services
Create a messaging service — the container /v1/messages resolves once at send time to copy sender pool, opt-out list, inbound webhook, sending flags and throughput cap onto the message. Only label is required; attach a sender_pool_id (or per-country country_sender_pools), an opt_out_list_id, inbound/fallback/status-callback URLs, an mps_cap, and an external_id (Twilio MGxxx) so the migrator can reconcile an imported service. Use it when standing up a new sending profile. Owner / admin only; a duplicate external_id returns 409.
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
Human-readable name (1–200 chars, required).
string
Default sender pool the send path resolves from through.
string
—
string
—
string (enum: POST|GET)
—
integer
Optional throughput cap (messages/sec).
string
Twilio MGxxx / opaque vendor id for migrator import.

Attach phone number to messaging service

POST /api/v1/messaging/services/{id}/phone-numbers
Attach a tenant-owned phone number (DID) to a messaging service so it becomes a candidate sender for outbound SMS through that service. The number must belong to this tenant and be SMS-capable (a voice/fax/MMS-only DID is rejected with 422). Re-attaching the same number is idempotent — it returns the existing binding rather than erroring. Body: { phone_number_id }. Owner / admin only; returns 404 when the service or number is not found 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.
string
Id of a tenant-owned, SMS-capable DID to attach (required).

Update messaging service

PATCH /api/v1/messaging/services/{id}
Update mutable fields on a messaging service in place — send only the fields you want to change (at least one is required). Nullable fields (sender_pool_id, opt_out_list_id, the webhook URLs, validity_period_seconds, mps_cap, external_id) accept null to clear them; pass country_sender_pools: {} to remove all per-country overrides. Changes bust the per-service send cache so the next send reads them within seconds. Owner / admin only; returns 404 when the id is not a messaging service 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.
string
—
string | null
—
string | null
—
integer | null
—
boolean
—

Update messaging service throughput cap

PATCH /api/v1/messaging/services/{id}/throughput
Set or clear the per-service outbound throughput cap (messages per second, 1–1000). Send a numeric mps_cap to throttle sends that reference this service through the shared token-bucket limiter; send null to remove the cap and inherit only the tenant/provider limits. Use it to protect downstream carriers or a bursty campaign from starving the tenant pool. Owner / admin only; returns 404 when the id is not a messaging service 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.
integer | null
Messages-per-second cap (1–1000), or null to clear the cap.

Delete messaging service

DELETE /api/v1/messaging/services/{id}
Permanently delete a messaging service and clean up its phone-number bindings. New /v1/messages calls referencing the id fail to resolve immediately; messages already sent are unaffected. Use it to retire a sending profile you no longer need. Owner / admin only; returns 404 when the id is not a messaging service 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

Detach phone number from messaging service

DELETE /api/v1/messaging/services/{id}/phone-numbers/{numberId}
Remove a phone number (DID) binding from a messaging service so it is no longer a candidate sender for that service. The DID itself is not released — only the association is dropped. Use it to prune a number from a sending profile. Owner / admin only; returns 404 when the binding (service or number) does not exist in this tenant and 204 No Content on success.
string
required
—
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