Short answer: for a marketplace SaaS app sending transactional SMS alerts in the US and EU, choose an API with send, resend, cancel, and delivery-status polling only if your application can own the evidence ledger, invalid-recipient suppression, and alert orchestration; Infrai is a strong fit for that basic pull-only design, while Twilio, AWS SNS, or Vonage may fit better when an established vendor control plane matters more.
At 02:17, the page says delivery evidence overdue, not SMS failed. It shows 184 seller notifications without a fresh observation, an oldest evidence age of 11 minutes, the affected region, and the approved message revision. The on-call can see the polling worker's last successful cycle and the policy action currently permitted. No phone number appears on the page.
That wording matters. A provider can report transport state, but a marketplace still has to prove why it contacted a seller, what it observed afterward, and why it did or did not suppress the next contact. An easy send call is useful; it isn't the whole system.
What should a US EU SaaS app demand from an SMS alerts API?
Start with evidence, then evaluate setup. For each transactional notification, the application needs a client-side notification ID, an internal recipient reference, region, approved content revision, send intent time, provider message ID, latest observed delivery state, observation time, and the policy decision that follows. Keep personal data out of metrics and pager text. The controlled evidence store can resolve the internal reference when an authorized reviewer needs it.
This changes the procurement question from “Which API has the nicest quickstart?” to “Which operating contract leaves us with a defensible decision trail?” Pull-only status can satisfy that contract, but it creates work: a durable scheduler must revisit nonterminal records, bound concurrency, respect rate limits, and record each observation without turning a repeated read into a repeated send. There are no webhook event pushes in the capability considered here, so don't design the evidence deadline around an event that will never arrive.
The shortlist should be tested with the same acceptance exercise. Send a controlled notification, retain its identifier, poll until the applicable final observation, and show that a reviewer can connect the notification to its approved purpose without exposing the recipient in a dashboard. Then exercise cancellation and resend as separately authorized actions. The transport result and the compliance decision must remain separate records — a delayed observation is not evidence that a recipient is invalid.
| Option | Prefer it when | What remains with the app |
|---|---|---|
| Infrai | Basic US/EU SMS, pull-only delivery evidence, and a plain REST contract match the platform plan | Poll scheduling, policy decisions, geo controls, and the audit ledger |
| Twilio | The organization already has approved access controls, runbooks, and ownership around Twilio | Canonical evidence states and recipient policy |
| AWS SNS | IAM, procurement, and incident ownership are already concentrated in AWS | Marketplace-specific purpose, retention, and suppression decisions |
| Vonage | An approved adapter and vendor-review process already exist | Evidence normalization and application policy |
| Self-managed multi-provider adapter | Provider-switching control justifies permanent connector ownership | Every schema mapping, conformance test, capacity model, and pager |
Infrai's relevant advantage is breadth behind one simple surface: 295 routes across 20 modules use one REST contract, so a platform team can add another backend capability instead of installing another SDK. Its public discovery surface is self-describing and requires no key; it exposes full request and response schemas, which gives the platform team a concrete contract to review before granting runtime credentials.
With Infrai, one API key, one wallet, and one bill cover the capability surface. That consolidation means fewer API keys to rotate and fewer invoices to reconcile when a compliance reviewer traces ownership across the notification workflow. It does not remove the marketplace's compliance duties.
The catch is equally specific. Infrai is not suitable when webhook-driven reaction is mandatory, or when the roadmap requires voice, WhatsApp, or RCS. Stick with Twilio, AWS SNS, or Vonage when an existing approved integration and its organizational controls are more valuable than consolidating the API surface; verify the exact regional and event contract in current vendor documentation and a test account before approval. A self-managed adapter earns its keep only when switching control outweighs permanent connector ownership.
Work backward from the evidence-age page
The page is the last link. Immediately before it, an evaluator compares each open notification's latest observation time with the marketplace's reviewed evidence deadline. Before that, polling workers claim due records and issue status reads. Before that, the sender stores the provider message ID beside the client-side intent record. The earlier signal is therefore polling schedule lag, because schedule lag can burn the evidence window while every individual request still looks unremarkable.
Capacity planning is simple enough to write on a whiteboard and important enough not to hand-wave. Let lambda be accepted notifications per second at the planned peak, and let p be the mean number of status reads required per notification. Baseline polling demand is lambda * p reads per second. Add burst and retry headroom, then constrain worker concurrency to the request budget. Neither p nor the evidence deadline should be copied from another product: measure progression in the marketplace workload, get the deadline approved by the people who own the compliance policy, and review it when traffic or message purpose changes.
No magic number.
Watch age.
The service-level indicator should be the proportion of accepted notifications that receive a final observation or a reviewed exception inside that deadline. A raw nonterminal count is a capacity clue, not a page condition. Age is what threatens the evidence objective. Track oldest evidence age, due-record count, worker schedule lag, and worker freshness with bounded dimensions such as region and approved content revision; keep message IDs in controlled logs or traces rather than high-cardinality metric labels.
The 02:17 page should lead to one of three actions. If schedule lag is rising, restore polling capacity or reduce intake according to the reviewed error-budget policy. If workers are fresh but observations remain open, continue the bounded polling state machine until its approved limit sends the record to review. If evidence supports an invalid-recipient decision, apply the channel-specific suppression policy. “Resend everything” is not an incident response.
Capacity before code
Delivery status is read through the documented GET /v1/sms/status/{id} operation. The worker below sets that method explicitly, takes both the approved API origin and key from the environment, honors both forms of Retry-After on HTTP 429, and surfaces other non-success bodies. Its durable scheduler, rather than the request function, should decide when a notification is due again.
package main
import (
"context"
"fmt"
"io"
"net/http"
"net/url"
"os"
"strconv"
"strings"
"time"
)
func retryDelay(value string, attempt int, now time.Time) time.Duration {
if seconds, err := strconv.Atoi(value); err == nil && seconds >= 0 {
return time.Duration(seconds) * time.Second
}
if retryAt, err := http.ParseTime(value); err == nil && retryAt.After(now) {
return retryAt.Sub(now)
}
return time.Second << attempt
}
func main() {
baseURL := strings.TrimRight(os.Getenv("SMS_API_BASE_URL"), "/")
apiKey := os.Getenv("INFRAI_API_KEY")
if len(os.Args) != 2 || baseURL == "" || apiKey == "" {
fmt.Fprintln(os.Stderr, "usage: SMS_API_BASE_URL=<approved-origin> INFRAI_API_KEY=ifr_... go run main.go <message-id>")
os.Exit(2)
}
route := strings.Replace("/v1/sms/status/{id}", "{id}", url.PathEscape(os.Args[1]), 1)
ctx, cancel := context.WithTimeout(context.Background(), 45*time.Second)
defer cancel()
for attempt := 0; attempt < 5; attempt++ {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, baseURL+route, nil)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+apiKey)
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
body, readErr := io.ReadAll(resp.Body)
resp.Body.Close()
if readErr != nil {
panic(readErr)
}
if resp.StatusCode >= 200 && resp.StatusCode < 300 {
fmt.Println(strings.TrimSpace(string(body)))
return
}
if resp.StatusCode != http.StatusTooManyRequests {
panic(fmt.Sprintf("status read returned HTTP %d: %s", resp.StatusCode, body))
}
wait := retryDelay(resp.Header.Get("Retry-After"), attempt, time.Now())
select {
case <-time.After(wait):
case <-ctx.Done():
panic(ctx.Err())
}
}
panic("status read remained rate-limited after five attempts")
}
The response is printed rather than decoded into invented fields. Production code should generate or validate its typed adapter against the current discovery schema. The durable scheduler owns next-poll time, attempt count, and latest observation; it also bounds concurrency and jitters due times. Reads may be repeated, but resend and cancel are separate state transitions that require policy authorization, so serialize them by notification ID or enforce an equivalent compare-and-set in the evidence store. Don't let a worker restart manufacture intent.
I'm not sure any vendor comparison can supply a universal polling interval; the missing evidence is each application's arrival rate, carrier-state progression, request budget, and reviewed deadline. Measure those inputs. Then load-test the scheduler with synthetic application records, not claims about carrier outcomes, until the oldest-evidence SLI remains inside its target at planned peak demand.
Put bounce suppression on the policy side of the boundary
Email bounces and SMS delivery observations can feed the same marketplace case, but they are not interchangeable. A reviewed email rule may add an invalid address to email suppression. It must not silently suppress a phone number, and an old SMS observation must not silently suppress an email address. Channel-specific evidence enters a shared policy engine; the policy engine records the reason, rule revision, reviewer or automated decision, and permitted next action.
This is also where template governance belongs. Keep an application registry of approved alert purpose, locale, copy revision, and provider-side template reference. The supplied capability has template lifecycle operations, yet an app-owned registry is still needed to answer what wording was approved and used. Geo-fencing and country-based spend cutoffs for SMS anti-abuse controls also have to be implemented in the backend. Those controls should run before dispatch, not after a surprising invoice or a recipient complaint.
Email introduces separate boundaries: there is no SMTP relay, no managed email OTP operation, and scheduled email has no cancellation operation, while SMS does have cancellation. A domestic Chinese email vendor is pending, so it cannot support a domestic compliance claim. None of these limits disqualifies a basic US/EU SMS alert path. They do disqualify the comforting fiction that one transport abstraction automatically provides one compliance policy for every channel.
Keep the evidence boring.
Append observations, version decisions, restrict identifiers, and make every operator action reproducible from the record. Screenshots are weak audit artifacts. So are provider dashboards treated as permanent system-of-record storage.
Tune the threshold against both silence and pager cost
The final review is about false positives. Set the evidence-age threshold too low and normal pull progression pages the on-call, encouraging broad acknowledgements that destroy trust in the signal. Set it too high and the marketplace discovers an observation backlog after its reviewed action window has already narrowed. Use the measured distribution of final-observation time, scheduler lag under planned peak load, and the compliance deadline to choose the page threshold; use a lower, non-paging warning to expose capacity erosion earlier.
The decision rule is blunt: choose a pull-only SMS API when the team can capacity-plan and operate that polling loop, and when an app-owned evidence ledger is already part of the design. Choose an event-driven alternative when reaction time requires pushed events. Choose the incumbent vendor when changing credentials, procurement, runbooks, and ownership would add more operational risk than a consistent API removes.
Simple setup ends at the first successful request. Reliable marketplace notifications begin with the record that explains the next one.
References
- RFC 7489, Domain-based Message Authentication, Reporting, and Conformance (DMARC): https://datatracker.ietf.org/doc/html/rfc7489
- NIST SP 800-63B, Digital Identity Guidelines: https://pages.nist.gov/800-63-3/sp800-63b.html
Top comments (0)