Skip to main content

Troubleshoot sender-ownership 422s

Numeric senders pass through a hard pre-send ownership gate. When the E.164 number you named in from belongs to a different organization on the platform, the send is refused before it ever reaches a carrier — the Devotel softswitch trusts the originator field, so without this fence a recipient would see (and attribute the message to) the true owner’s number. The gate returns 422 SENDER_NOT_OWNED, and when it cannot confirm ownership because of a transient database or cache fault it refuses the send with 503 SENDER_OWNERSHIP_CHECK_UNAVAILABLE instead. Both are pre-send rejects: no message is submitted and no message charge is taken.

Match the code to its meaning

The distinction drives the fix: SENDER_NOT_OWNED is a sender fix — retrying the identical payload returns the same 422 forever. The 503 sibling is a transient platform state — retry the same request after a short backoff (about 30 seconds, with jitter). SENDER_NOT_OWNED fires only on cross-organization collisions. Sending from a fully custom number that your organization does not own and that no other organization holds produces a different flow. The deliberate trigger list:
  • Cross-org number — hard reject.
  • Stale tenant number — your org once held the number, then released it and another organization claimed it. Released inventory stays selectable in older dashboards or hard-coded apps, so sends from it start failing here.
  • Softphone direct number — an extension’s assigned caller ID that is no longer in your inventory is rejected on the same code when an agent texts from that extension.

Fix the 422 — pick a sender you own

The gate accepts any sender identity your organization legitimately controls. Apply one of these once, then retry the send:
  1. Send from a number you own. List active inventory with GET /api/v1/numbers and pass one of those E.164 numbers in from. A number you purchased or ported in passes with no extra step.
  2. Verify an external number through the register → confirm flow. If your own handset or landline must appear as the sender, enrol it once and the gate accepts it afterwards:
    • Register — POST /api/v1/voice/caller-ids/verify with the E.164 phone_number and the channel ("sms" or "voice"). Orbit sends a one-time code to that handset (a text on SMS, spoken readback on voice).
    • Confirm — POST /api/v1/voice/caller-ids/confirm with the verification_id and the code. A correct code flips the row to verified and opens the number as an outbound sender.
    • A wrong code or an elapsed TTL leaves the row expired; re-arm it with POST /api/v1/voice/caller-ids/:id/resend and confirm again. The full endpoint contract is in Manage outbound caller IDs, and the same journey runs from the dashboard under Voice → Caller IDs.
  3. Use the platform default. Omit from (or omit the pool) and the resolution chain falls back to the shared (Devotel) sender — see Sender resolution. Alphanumeric sender IDs registered to your organization skip the numeric ownership lookup entirely, subject to destination-country alpha rules (US/Canada carriers reject alphanumeric senders outright — send to those destinations from a number).
Replacing a sender on an automated pipeline: update the one place that supplies it — the campaign’s sender field, the sender pool members, or the extension’s default caller ID — rather than editing every send body.

Why the 503 fails closed

An ownership check that errors rather than answering has a choice: pass the send along without an ownership verdict, or refuse it. The gate refuses it. Passing along would let a momentary datastore or cache outage quietly disable the only control that stops one organization from sending under another organization’s number — recipients would see the wrong number, and carrier complaints would land on the true owner. A brief 503 that a retry clears is cheaper than that, so the gate treats “cannot confirm ownership” the same as “ownership denied”: the send is refused until the check works again. If 503s persist beyond a few minutes: check status.orbit.devotel.io, then retry through your normal idempotent retry path. The 503 is safe to retry — the send was never submitted, and re-sending with the same idempotency key cannot duplicate a message.

Sample error envelopes to paste into a ticket

Cross-org numeric sender, POST /api/v1/messages/sms:
Transient ownership-check failure (same request):
When you open a support ticket, paste the full error object, the endpoint, and the timestamp — the sender and channel fields in details are what support needs to trace the gate decision.