Backpressure in A2P SMS: How to Design Queues That Protect Delivery During Spikes, Limits, and Degradation
An operational guide to separating A2P SMS acceptance from sending, limiting pressure by destination and route, and managing delays, expiry, and retries without worsening an incident.

What Backpressure Means in A2P SMS
Backpressure in A2P SMS is the set of controls that prevents incoming requests from consistently exceeding actual processing and sending capacity. Its purpose is not to accept the highest possible number of requests, but to preserve useful traffic behavior when there are spikes, rate limits, congestion, or route degradation.
A positive API response does not prove that a message has reached the handset. In SMPP, submit_sm submits a message to the Message Center for later delivery; requesting a delivery receipt is configured separately through registered_delivery. Similarly, a platform may accept and queue a message before sending it to an upstream operator.
If the system accepts more work than it can drain, queue depth and message age increase. For time-sensitive traffic, the result can be worse than an explicit rejection: an OTP may be sent too late, a transactional notification may lose its value, and retries may multiply messages or worsen saturation.
- Treat acceptance as an admission state, not as evidence of delivery.
- Measure effective outbound capacity by the relevant scope, not only API inbound capacity.
- Apply upstream pressure before accumulated work exceeds the message's useful time window.
- Keep internal queue states separate from statuses reported by the network or operator.

Separate Admission, Queuing, Scheduling, and Status Confirmation
An operable design divides the lifecycle into layers with distinct responsibilities. This separation makes it possible to decide where to apply limits and prevents a delivery issue from being hidden behind an API that appears healthy.
The admission layer validates the request, checks its idempotency key, applies quotas, and decides whether to accept, defer, or reject it. The queue retains admitted work with enough metadata to prioritize it, expire messages, and prevent duplicates. The scheduler chooses which message can be sent based on available capacity. The status layer records both internal transitions and later responses and DLRs.
DLRs should not be used as the primary real-time control signal. Events generated by operators may arrive long after sending; immediate health should therefore rely mainly on admission, queue, session, and dispatch signals.
- Admission: authentication, validation, classification, deduplication, and the decision to accept or reject.
- Queue: persistence, priority, creation time, useful time window, destination, intended route, and idempotency identifier.
- Scheduling: message selection subject to hierarchical limits and observed capacity.
- Confirmation: recording acceptance, queuing, outbound attempt, technical response, expiry, and DLR where available.

Detect Pressure Before the Queue Becomes an Incident
A growing queue is the most obvious indicator, but it is not enough. A queue may remain stable while still being unacceptable if messages age too much, if one destination consumes most of the capacity, or if retries displace new traffic.
Define thresholds by traffic class and control scope. A useful threshold for OTP traffic may not be suitable for a non-urgent transactional notification, and an issue limited to one destination or route should not require all traffic to stop.
Acceptance latency also deserves monitoring. If the API starts taking longer to respond, it may be accumulating work before responding or depending on components that are already degraded. Explicit, bounded admission is preferable to growing and unpredictable response times.
- Total queue depth and queue depth by account, application, destination, route, session, and traffic class.
- Maximum age and message-age percentiles for messages not yet sent.
- Admission rate versus effective dispatch rate.
- Temporary rejections, session errors, response times, and SMPP reconnections.
- Number of messages that expire internally, are suppressed, or are rejected by policy.
- Percentage of capacity consumed by retries versus first attempts.
Classify Traffic Before Queuing It
Priority should be assigned before a message enters a shared queue. It is not enough to label everything as transactional: some messages have strict time limits, others have declining value, and others can wait or should not be sent during degradation.
A practical classification distinguishes OTP, time-sensitive transactional, consented marketing, and non-priority traffic. AWS distinguishes transactional messages, which are critical or time-sensitive, from promotional messages, which are not. That distinction is useful as a starting point, but each organization must document its own legitimate priorities, obligations, and time limits.
Classification must not become a mechanism for bypassing route, consent, or sender rules. Priority is an internal operational decision for using limited capacity consistently with the message's legitimate purpose.
- OTP: one-time messages with brief usefulness; they should have a short waiting budget and strict expiry.
- Time-sensitive transactional: alerts, status changes, or operational notifications that lose value after a defined period.
- Consented marketing: traffic that should normally be able to be deferred, limited, or paused without compromising a critical operation.
- Non-priority: low-urgency traffic that should be reduced or rejected first under pressure.
Define Waiting Budgets and Expiry Without Confusing States
Each message class needs a waiting budget: the maximum time it can remain within your own platform before attempting to send it no longer makes sense. That budget must be less than or equal to the business usefulness window and should be reviewed against available outbound capacity.
Internal expiry is a decision made by your system: for example, suppressing an OTP that has waited longer than allowed before assigning it a route. It should not be reported as an operator DLR. Maintain an explicit status such as “expired internally” or an equivalent, and retain the reason for the decision.
When SMPP is used, validity_period expresses the expiry time at the SMSC, after which the message must be discarded if it has not been delivered. This validity period is different from the prior wait within your own queue and also different from confirmation of delivery to the handset. In messaging services, TTL controls how long an SMS is attempted for delivery, not a guarantee that a final DLR will be received.
- Store for each message: creation time, internal deadline, requested validity period, and expiry reason if it occurs.
- Do not schedule outbound sending for messages whose internal budget has already been exhausted.
- Expose separately: expired before sending, expired during the delivery attempt, and DLR received where applicable.
- Do not interpret expiry or an acceptance status as confirmation of receipt on the handset.
Apply Hierarchical Limits and Control Bursts
Capacity is not a single number. A system may have enough aggregate capacity while still being limited for an account, application, destination, route, SMPP session, or provider. Limits must be composable: a message is sent only if it has budget in all applicable scopes.
A token bucket model is useful for enforcing a sustained rate and limiting bursts after a backlog has built up. The rate limits continuous dispatch; burst size limits how quickly an accumulated queue can be drained. This prevents recovery after a short outage from causing new congestion.
Apply the same dispatch limit to first attempts and retries. If retries remain uncontrolled, they consume capacity that should be reserved for new or priority traffic.
- Limit by account, campaign, or application to protect quotas and customer isolation.
- Limit by destination to prevent a numbering range, network, or country from consuming shared capacity.
- Limit by route and provider to respect applicable capacity or restrictions.
- Limit by SMPP session to avoid overloading a connection or its operating window.
- Reserve or weight capacity by traffic class to protect OTP and other time-sensitive flows.
- Control bursts to recover gradually after a pause or degradation.
Choose an Explicit Admission Strategy
When sufficient capacity is unavailable, there are four legitimate outcomes: accept, defer, reject, or ask the sender to reduce its rate. The choice should depend on the useful time window, documented priority, ability to retry safely, and whether the capacity shortage is global or localized.
Accepting means the message enters the queue within a realistic waiting budget. Deferring means retaining it for a later window only if it will still be useful. Rejecting is appropriate when there is no reasonable prospect of meeting the deadline or when policy does not allow more work to accumulate. Requesting rate reduction is especially useful for integrations that can adapt their production rate.
In HTTP, a temporary overload can be communicated with 503 and Retry-After. It is preferable for the client to receive an explicit, actionable signal rather than accepting requests indefinitely that will probably expire. To make that integration safe, clearly document retry semantics and idempotency keys.
- Accept only if the queue and capacity indicate that the message can be sent within its budget.
- Defer wait-tolerant traffic, with a deadline that prevents late sending.
- Reject OTP or messages whose deadline has expired or is not feasible, with a reason readable by both machines and operations teams.
- Return an indication of temporary rate reduction when the interface allows it.
- Do not turn an admission rejection into a silent acceptance that ends in an unbounded queue.
Schedule Queues With Fairness and Documented Priorities
Scheduling must prevent a single customer, campaign, or destination from consuming all available capacity. At the same time, it must not obscure legitimate business priorities, such as protecting OTP traffic over consented marketing during a restriction.
A reasonable approach is to use queues by traffic class and apply tenant, destination, and route limits before selecting the next message. Within the same class, a fair-sharing policy can prevent a highly active source from monopolizing dispatch.
Strict arrival order is not always the right order. When deadlines are present, it may be preferable to prioritize messages close to expiry within a class, provided the policy prevents other messages from being starved. Any exception should be explicit, auditable, and consistent with the purpose of the traffic.
- Avoid a single global queue without priority, destination, and deadline metadata.
- Isolate degraded destinations or routes so they do not block healthy traffic.
- Use quotas or fair sharing within equivalent categories.
- Protect documented priorities without improperly labeling non-urgent traffic as critical.
- Periodically review whether any messages never receive a dispatch opportunity.
Frequently asked questions
Does accepting an SMS through an API mean it has already been delivered?
No. Acceptance indicates that the request was admitted or queued. In SMPP, submit_sm submits the message for later delivery. Delivery and delivery receipts are separate stages, and a DLR, when received, should not be confused with a universal and immediate guarantee.
When should an OTP be rejected instead of queued?
It should be explicitly rejected when available capacity and queue age indicate that it cannot be sent within its useful time window. Sending an OTP late may be less useful than informing the sender so it can apply its recovery flow or generate a new code.
Should retries have a separate rate limit?
They should be subject to the same dispatch control as first attempts and should also have limits on the number of attempts and elapsed time. If they are excluded from the limit, they can consume available capacity and prolong congestion.
Does an SMPP validity_period replace internal expiry?
No. validity_period defines expiry at the SMSC, after which the message must be discarded if it has not been delivered. The platform still needs an internal waiting budget to prevent messages that have lost their usefulness from reaching the SMSC late.
Should DLRs be used to detect real-time degradation?
Not as the only signal. Events from operators can arrive with significant delay. For immediate operational control, monitor admission, queue depth and age, dispatch, technical errors, session health, and behavior by destination or route.
How can duplicates be avoided when a client retries an HTTP request?
Use a persistent idempotency key or an equivalent mechanism that can recognize a request that has already been applied. Automatic retries of non-idempotent operations are unsafe if the sender cannot determine whether the original request was processed.
Sources consulted
- SMPP Protocol Specification v3.4, Issue 1.2SMPP Developers Forum
- RFC 9110: HTTP SemanticsIETF
- Cloud Tasks: Configure queue routing, limits, and retriesGoogle Cloud
- Cloud Tasks v2 API reference: RateLimitsGoogle Cloud
- AWS End User Messaging SMS: How SMS worksAmazon Web Services
- AWS End User Messaging SMS: Event types for SMS, MMS, and voiceAmazon Web Services
- AWS End User Messaging SMS: Example of sending an SMS or voice messageAmazon Web Services
- Messages resourceTwilio
- Outbound Message Status in Status CallbacksTwilio
- 30036: Validity Period ExpiredTwilio
- 30001: Queue overflowTwilio