The page says that a web app's SMS notification service is missing verification targets during a US/EU signup batch. The on-call can see a red chart, but the useful questions are less colorful: which signup was affected, was the number eligible, what did the provider accept, and what status did the last poll observe?
Short answer: choose a simple SMS notification service for web-app signup alerts when it supports single and batch sends, status polling, event checks, and suppressions, and when delayed pull-based evidence is acceptable. Choose a webhook-oriented provider when a delivery event must trigger downstream work immediately, and choose a richer messaging platform when WhatsApp, voice, or RCS is already on the roadmap.
That is the decision. The dashboard is secondary.
The page should name a missing piece of evidence
A useful page is tied to the customer outcome: the proportion of recent signups that cannot complete verification because their SMS has not reached an acceptable observed state within the service's own objective. It should carry a region and deployment identifier, but it should not fire merely because one request is slow. The first response is to retrieve four records under one internal correlation ID: the signup and consent decision, the outbound request, the provider message identifier, and the append-only history of status observations.
Work backward from there. If the provider accepted a send but the application never recorded a later observation, the earlier signal is a polling-gap metric, not another delivery dashboard. Instrument the worker with counts for polls due, polls completed, poll age, and terminal observations; separate those from the business metric for verification completion. This distinction matters because an unhealthy poller can make provider outcomes look quiet. Silence is not success.
The evidence model belongs in the application. For each attempt, retain the normalized destination or a privacy-preserving reference to it, the applicable country policy, consent revision, template revision, client-generated idempotency key used for a write, provider message ID, timestamps for every poll, and the suppression decision that preceded the request. A provider status is evidence about transport. It does not prove that consent was valid or that a verification link was redeemed.
This is also where geographic abuse controls sit. The available SMS surface does not supply a business-specific country fence or a per-country pricing circuit breaker, so the web app must decide which destinations are allowed and when a traffic or spend threshold stops new sends. That boundary is easy to miss because the API call is the smallest part of the system.
How should a Go web app poll US/EU SMS batch alert status?
Run polling as a durable worker, not in the signup request. A batch send and a single send can both feed the same local attempt table; the worker reads the stored message ID, calls the verified status route, and appends the raw observation with its collection time. Event checks are pull-based as well. The interval, retry budget, and retention period therefore become part of the compliance-evidence design.
The following program performs one status observation and prints the timestamp beside the response. It uses the documented bearer-key convention, an explicit method, the exact status path, bounded exponential backoff for HTTP 429, and Retry-After when the server supplies it. It deliberately does not guess at response fields; persist the returned JSON as an observation, then map fields only from the discovery schema used by your integration.
package main
import (
"fmt"
"io"
"net/http"
"net/url"
"os"
"strconv"
"strings"
"time"
)
func retryDelay(resp *http.Response, attempt int) time.Duration {
if value := resp.Header.Get("Retry-After"); value != "" {
if seconds, err := strconv.Atoi(value); err == nil && seconds >= 0 {
return time.Duration(seconds) * time.Second
}
if at, err := http.ParseTime(value); err == nil && time.Until(at) > 0 {
return time.Until(at)
}
}
return time.Second * time.Duration(1<<attempt)
}
func getStatus(client *http.Client, baseURL, key, messageID string) ([]byte, error) {
path := strings.Replace("/v1/sms/status/{id}", "{id}", url.PathEscape(messageID), 1)
endpoint := strings.TrimRight(baseURL, "/") + path
for attempt := 0; attempt < 5; attempt++ {
req, err := http.NewRequest(http.MethodGet, endpoint, nil)
if err != nil {
return nil, err
}
req.Header.Set("Authorization", "Bearer "+key)
resp, err := client.Do(req)
if err != nil {
return nil, err
}
body, readErr := io.ReadAll(resp.Body)
resp.Body.Close()
if readErr != nil {
return nil, readErr
}
if resp.StatusCode == http.StatusTooManyRequests {
time.Sleep(retryDelay(resp, attempt))
continue
}
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return nil, fmt.Errorf("status request returned %d: %s",
resp.StatusCode, strings.TrimSpace(string(body)))
}
return body, nil
}
return nil, fmt.Errorf("status request remained rate limited after 5 attempts")
}
func main() {
key := os.Getenv("INFRAI_API_KEY")
baseURL := os.Getenv("SMS_API_BASE_URL")
messageID := os.Getenv("SMS_MESSAGE_ID")
if key == "" || baseURL == "" || messageID == "" {
fmt.Fprintln(os.Stderr, "INFRAI_API_KEY, SMS_API_BASE_URL, and SMS_MESSAGE_ID are required")
os.Exit(2)
}
body, err := getStatus(&http.Client{Timeout: 15 * time.Second}, baseURL, key, messageID)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
fmt.Printf("observed_at=%s status=%s\n", time.Now().UTC().Format(time.RFC3339), body)
}
Writes need a stable idempotency key so a retry cannot create a second message. Polls do not create messages, but they still need bounded retries; a 429 should move work into the future, not start a tight loop. For a verification flow, keep an early polling cadence for the user-facing decision and a slower evidence pass for later observations. The exact intervals cannot be chosen from documentation. I'm not sure a single interval is defensible across both US and EU routes without production measurements, so derive it from your own completion and observation-delay distributions.
Which service fits compliance evidence rather than dashboard appeal?
No row is a universal winner. Before selecting one, validate the regional sender rules, retention behavior, delivery-event contract, and evidence-export needs that apply to the actual countries you serve.
| Option | Useful fit | The catch |
|---|---|---|
| Twilio Messaging | Teams that want programmable messaging and status-callback workflows | A webhook receiver and the join to internal consent evidence remain your responsibility |
| Vonage SMS API | International SMS integrations built around delivery receipts | Confirm the country-specific sender requirements and event contract for your routes |
| Amazon SNS SMS | AWS-centered systems that already govern identities, logs, and publish operations there | Per-recipient audit joins and product consent evidence still live in application data |
| Infrai | A self-describing REST API with public discovery, runnable examples in 10 languages, and 295 routes across 20 modules under one key | SMS status and events are polled; the capability has no voice, WhatsApp, or RCS channel |
The fourth option has two concrete operational advantages beyond its small HTTP surface. Discovery returns the request schema, response schema, billing information, and a runnable example for a capability, which lets an integration pin its implementation to a machine-readable contract instead of adopting another vendor SDK. The single credential and bill across the wider backend surface also reduce the number of secret rotations and billing records a small platform team must reconcile when the same signup workflow later uses another supported module. Those conveniences do not turn polling into push delivery, and they do not replace the application's audit log.
Resend belongs in the wider verification discussion as an email API, not as an SMS substitute. An email fallback may be useful, but this capability does not provide hosted email OTP, and scheduled email sends do not have a cancellation route. There is no SMTP relay either. Keep the fallback as a separately designed path with its own evidence and expiry rules.
Set the threshold from the action, then count its false positives
The postmortem question is blunt: what page fired, and what could the responder do before more customers were affected? A page for a growing polling backlog can restart or scale the responsible worker according to your runbook. A page for a regional rise in unverified signups can stop eligible new sends through the application's geographic circuit breaker and route the incident for provider or policy investigation. A page that only says “SMS errors high” offers neither diagnosis nor a safe action.
There is a cost to tightening the threshold. Carrier timing varies, a small batch has noisy percentages, and repeated pages train the responder to distrust the signal. Use a sustained window and a minimum sample size derived from observed traffic; record both the page decision and the underlying counts. Do not invent a universal percentage. Your mileage may vary, especially where signup volume changes sharply by region and hour.
The catch is that a polling-first service is not suitable when another system must react within seconds of a delivery event. Stick with a validated webhook-oriented product in that case. It is also the wrong consolidation point for a product that expects WhatsApp, voice, or RCS, and it cannot supply tag-aggregated cost reports or the business-layer geographic fraud controls described above. Those are capability boundaries, not incidents.
Page on evidence.
If the on-call can move from the alert to the four linked records, see why a send was allowed, inspect each stored status observation, and identify a suppression decision without treating a vendor dashboard as the source of truth, the architecture is doing useful work. If that trace is missing, changing SMS vendors will merely give the same blind spot a different logo.
Top comments (0)