Surge

Handle Failures

When a message can't be sent or delivered, the API returns a structured error object. Here's what each error means and what to do about it.

Error structure

All errors follow the same shape:

{
  "error": {
    "type": "opted_out",
    "message": "This contact has opted out of messages."
  }
}

Some errors include a detail object with field-level information:

{
  "error": {
    "type": "validation_error",
    "message": "Could not perform the request with the provided parameters.",
    "detail": {
      "body": ["can't be blank"]
    }
  }
}

Errors at send time

These errors come back synchronously when you call POST /accounts/:account_id/messages.

opted_out (422)

The recipient has previously replied STOP. Carriers require you to honour opt-outs. Do not attempt to send to this contact until they explicitly re-opt-in by texting START.

Fix: Check contact opt-out state before sending. Subscribe to contact.opted_out webhook events to update your database in real time.

demo_message_limit (403)

You've sent 25 messages from the demo number. The demo is for exploration — it's not for production use.

Fix: Register your business and purchase a phone number.

The message body contains more URLs than the campaign's registered includes allows, or the total URL content exceeds carrier limits.

Fix: Reduce the number of links in the message, or enable link shortening on your account.

no_phone_number (422)

No from number was specified and the account has no default phone number configured.

Fix: Either set a default phone number on the account in the dashboard, or always pass a from value.

phone_number_not_found (422)

The phone number ID passed as from doesn't exist or doesn't belong to this account.

Fix: Confirm the phone number ID is correct and belongs to the account you're sending from.

Errors at delivery (via webhooks)

These appear in message.failed webhook events after a message was initially accepted. The failure_reason field on the event contains the slug.

unreachable_destination

The recipient's number is disconnected, out of service, or unreachable on the carrier network.

What to do: Flag the contact as undeliverable in your system. Continued attempts to an unreachable number don't help and count against your volume.

Permanent undeliverability. When Surge receives unreachable_destination, invalid_mobile_number, or unreachable_carrier for a number, that number is permanently flagged as undeliverable in Surge's carrier database. All future sends to it — from any account — are cancelled immediately without hitting the carrier. If a number becomes reachable again (e.g., the subscriber reactivates their SIM), the flag clears when a successful delivery is recorded. This is why it's important to stop sending to failed numbers: it has no effect and your campaign volume quota is still consumed.

invalid_content_type

An MMS attachment's content type isn't supported by the recipient's carrier or handset.

What to do: Retry with a different format (prefer image/jpeg or image/png) or send the content as a link instead of an attachment.

message_filtered

The carrier's spam filter blocked the message. This can happen when message content matches spam patterns, when a campaign isn't fully approved, or when a number isn't attached to an active campaign.

What to do:

  1. Confirm the sending number is attached to an active, approved campaign
  2. Check that message content matches your registered campaign description and sample messages
  3. Avoid link shorteners that aren't trusted by carriers (use Surge's built-in link shortening instead)

Complete failure reason reference

All possible values for failure_reason in message.failed events:

ReasonMeaningRetryable?
account_archivedThe sending account has been archivedNo
account_lockedThe platform has been locked due to a policy violationNo — contact support
attachment_retrieval_errorSurge couldn't fetch the attachment URL when building the MMSYes — fix the URL or hosting
blockedThe number has been explicitly blocked at the carrier levelNo
carrier_errorA transient error from the carrier networkYes — Surge retries automatically
configuration_errorThe account's carrier credentials are misconfiguredNo — contact support
daily_message_cap_reachedThe campaign's daily T-Mobile volume cap was hitYes — automatically next day
geo_not_enabledThe destination country isn't in the platform's allowed regionsNo — contact support to enable the region
invalid_attachment_urlThe attachment URL is malformed or not publicly accessibleYes — fix the URL
invalid_content_typeMMS attachment type unsupported by the recipient's carrierYes — use a supported format
invalid_mobile_numberThe number is not a valid mobile number (e.g., a landline)No — permanently undeliverable
matching_sender_and_receiverThe from and to numbers are the sameNo — sending to yourself isn't supported
message_filteredBlocked by carrier spam filters or Surge's content policyInvestigate content before retrying
message_too_bigThe message body exceeds the 1,600-character limitYes — shorten the message
mms_not_supportedThe recipient's carrier or handset doesn't support MMSYes — Surge falls back to SMS automatically
opted_outThe contact has opted out of this conversationNo — wait for explicit opt-in
premium_rate_numberThe destination is a premium-rate numberNo
suspected_fraudSurge's fraud detection flagged the sendNo — contact support
unknown_destinationThe number doesn't exist on any carrier networkNo — permanently undeliverable
unknown_errorAn error occurred that Surge couldn't categoriseInvestigate with support
unreachable_carrierThe destination carrier network is unreachableNo — permanently undeliverable
unreachable_destinationThe number is disconnected or out of serviceNo
unregistered_numberThe sending number isn't registered with the carrier for this message typeNo — contact support
unsupported_routeNo valid carrier route exists for this number pairNo — contact support

Validation errors

validation_error (422)

A request field is missing or invalid. The detail map contains per-field errors.

{
  "error": {
    "type": "validation_error",
    "message": "Could not perform the request with the provided parameters.",
    "detail": {
      "to": ["is not a valid E.164 phone number"],
      "body": ["can't be blank"]
    }
  }
}

Fix: Correct the flagged fields. Phone numbers must include the country code with a + prefix (e.g. +18015551234, not 8015551234).

Full error reference

See the Error Reference for the complete list of error types, HTTP status codes, and additional context.