Skip to main content

Troubleshoot SMPP_BACKEND_UNAVAILABLE (503)

Issuing or rotating an SMPP credential can fail with 503 and code SMPP_BACKEND_UNAVAILABLE. This happens on the control plane — the credential create or rotate endpoint — before the credential ever reaches the SMPP edge. No bind was possible, so no wire-level error code could have returned. Keep the two failure classes separate:
  • Control-plane 503POST /messaging/smpp/credentials or POST /messaging/smpp/credentials/:id/rotate answered SMPP_BACKEND_UNAVAILABLE. Work this page’s dependency checklist.
  • Wire-level reject — the credential exists and the bind itself returned a non-zero command_status (ESME_RINVPASWD, ESME_RINVSYSID, ESME_RINVBNDFMT, …). That is a different class; decode it on the SMPP bind rejects and command_status codes page instead.
If you are reading a lookup, confirm which class it came from before changing anything.

The three control-plane dependencies

Issuance and rotation write the credential into your tenant schema, seal the password under your organization’s encryption envelope, and — for BYO Jasmin carriers — queue the related changes on the Jasmin reconciler. Three dependencies must all be available; a failure on any of them is folded into this 503. Check them in order: A request that names none of them explicitly still fails the same way — the three preconditions are checked unconditionally, so the wire format of the failure cannot tell you which dependency was down. Use the schedule of what you changed (org creation, rotation, a recent BYOK registration) to pick the first row to check.

Retry-safety

SMPP_BACKEND_UNAVAILABLE is in the transient 5xx class — it is safe to retry:
  • Wait, then retry the same issuance or rotation call with a short backoff. A retry hangs where it can; nothing is rolled back into a broken state.
  • If your client library sends or parses a Retry-After header on 5xx responses, honor it. The value names the platform’s expected recovery interval for the dependency it detected down.
  • Never delete partial state yourself. A failed issuance leaves no credential row behind, and a failed rotation keeps the previous password valid — do not issue a delete to “clean up,” because there is nothing to delete, and for rotation a delete would revoke credentials your ESME client still needs.
What must not be retried blindly: a 503 that persists for more than a few minutes is a dependency outage, and a tight loop only builds noise on an unavailable queue — prolong the backoff and escalate when the escalation thresholds below are reached.

When rotation is safe versus when the 503 implies an outage

Rotation of an existing credential is safe to attempt whenever the control-plane is healthy — the old password stays valid until a new one is issued, so an abortive rotate attempt breaks nothing. The 503 does imply one of the dependencies is unavailable now, so:
  • First issuance — if provisioning a brand-new org fails, suspect the tenant schema row: this matches the provisioning window the TENANT_SCHEMA_INCOMPLETE sibling covers, and a plain retry after seconds is the right move.
  • Rotation on a mature org — on an org that issued credentials before, a schema-related 503 is unusual; suspect the encryption-key or the reconciler queue row instead, and the escalate path below applies from the first failure.
  • Rotation under BYOK enforcement — if your org enforces a customer-managed key, the envelope depends on that key being decryptable; work the BYOK key unavailable runbook first.

When to escalate

Open a support ticket when one of these holds:
  • Retries of the same endpoint kept failing for 15 minutes on a mature org, or one hour on an org still inside the provisioning window.
  • Both issue and rotate fail with the same 503 — a schema cause that broad is never a per-call race.
  • Your org enforces BYOK and the GET /api/v1/compliance/byok read shows active + enforced, yet issuance still 503s on the encryption path.
Include your organization ID (Settings → Organization, or organizationId from GET /api/v1/me), the request ID from meta.request_id on one failing response, and whether the call was issuance or rotation.

See also