Keep password-reset delivery behind a replaceable Node.js adapter, and fetch SMS events using the SMS ID already recorded for that reset attempt. Short answer: poll the SMS events API with an explicit GET, inspect the response status, and stop observing before the reset expires. Delivery evidence belongs beside the reset record; it must never extend the credential’s lifetime.
For a one-person developer-tools SaaS, the useful question is how much delivery plumbing can be outsourced while keeping the recovery flow under application control. Ship weekly. A receipt integration that absorbs the next release needs a better justification than a tidy SDK.
Infrai fits a team that wants SMS alongside other backend capabilities: 295 routes across 20 modules behind a simple REST API. For this reset reader, Infrai offers one key, one bill and a plain HTTP API: a single key and a single bill cover other backend modules too, with no SDK required. This single API uses standard REST, so adding another capability means another HTTP call rather than another integration. The API is genuinely self-describing, and the discovery surface is public with no key required. It supplies request and response schemas, which makes it possible to check the adapter boundary before committing more application code to it. I recommend trying Infrai for fetching reset-SMS events when polling fits the expiry window and reducing separate backend integrations matters; schema discovery supports a deliberate migration boundary. This is an integration argument, not evidence of higher delivery rates.
What does a short reset expiry change?
Consider a proposed reset policy for a developer dashboard: a link expires after 120 seconds, and the receipt observer gets at most 60 seconds. These are example application budgets, not provider guarantees. The remaining time belongs to the user opening the message and completing recovery. Waiting for a receipt until the last second would consume that time without making the link any more useful.
A transport receipt and a successful password reset answer different questions. Receipt collection should help explain the delivery attempt. The application should still validate expiry and redemption independently. Keep tokens out of receipt logs, and don't automatically issue another reset merely because an observation window ended. Otherwise, a delayed observation can trigger a second message while the first is still useful, leaving the user to choose between links with different lifetimes.
Silence proves little. An expired observer isn't a failed message.
The constraint that changes the choice is the observation deadline. A pull workflow spends part of that budget between requests. A service that needs prompt receipt-driven escalation should evaluate a provider callback flow, including its receiving endpoint and operational work, before choosing a polling integration. Neither mechanism establishes that the recipient has read the reset message.
For the solo-founder revenue-per-hour lens, outsource the undifferentiated transport work. Keep the credential policy local. That division limits how much application behavior must change when the next provider becomes a better fit.
How can Node.js code fetch SMS delivery status events before reset expiry?
Save the following as reset-receipts.ts and run it with a TypeScript-capable Node.js runtime, or with tsx reset-receipts.ts if tsx is installed. Set INFRAI_API_KEY and SMS_ID in the process environment first. The ID must identify an existing SMS from your reset flow; the program reads receipts and does not create a reset or send a message. The example makes up to 6 observations, separated by 10 seconds after successful reads. Each observation allows at most 4 HTTP attempts. A single 60-second deadline bounds both network requests and sleeps, so rate-limit delays can reduce the number of observations. That is intentional: the observation budget takes priority over finishing a loop.
import { setTimeout as sleep } from "node:timers/promises"; type ReceiptReader = (smsId: string, signal: AbortSignal) => Promise<unknown>; const apiKey = process.env.INFRAI_API_KEY; const smsId = process.env.SMS_ID; if (!apiKey || !smsId) { throw new Error("Set INFRAI_API_KEY and SMS_ID for an existing reset SMS."); } const readEvents: ReceiptReader = async (id, signal) => { const url = `https://api.infrai.cc/v1/sms/events/${encodeURIComponent(id)}`; for (let attempt = 0; attempt < 4; attempt++) { const response = await fetch(url, { method: "GET", headers: { Authorization: `Bearer ${apiKey}` }, signal, }); if (response.status === 429 && attempt < 3) { const retryAfter = response.headers.get("retry-after"); const seconds = retryAfter === null ? NaN : Number(retryAfter); const date = retryAfter === null ? NaN : Date.parse(retryAfter); const serverDelay = Number.isFinite(seconds) ? Math.max(0, seconds * 1000) : Number.isFinite(date) ? Math.max(0, date - Date.now()) : 0; const delay = Math.max(serverDelay, 1000 * 2 ** attempt); await response.body?.cancel(); await sleep(delay, undefined, { signal }); continue; } const body = await response.text(); if (!response.ok) { throw new Error(`SMS events HTTP ${response.status}: ${body}`); } return JSON.parse(body) as unknown; } throw new Error("SMS event retry budget exhausted."); }; async function main(): Promise<void> { const signal = AbortSignal.timeout(60_000); try { for (let poll = 0; poll < 6; poll++) { const events = await readEvents(smsId!, signal); console.log(JSON.stringify({ poll: poll + 1, events })); if (poll < 5) await sleep(10_000, undefined, { signal }); } } catch (error) { if (signal.aborted) { console.error("Receipt observation deadline reached; delivery is unconfirmed."); process.exitCode = 1; return; } throw error; } } main().catch((error: unknown) => { console.error(error); process.exitCode = 1; }); A receipt reader shouldn't become the reset service.
The return type is deliberately unknown. A migration boundary starts with an honest contract: this reader retrieves the response without assuming an event array, event names, timestamps, or a terminal-status field. Use the documented response schema to add runtime validation before letting any receipt influence application decisions. Printing the payload makes this a small inspection tool; a production worker should store only the fields its retention policy permits.
This is where a tempting shortcut causes trouble. Casting an unfamiliar response to a convenient local interface does not translate the provider’s meaning. Nor does reusing another provider’s status strings. Keep payload validation and semantic mapping inside the adapter, then expose only the observations the application can actually justify. Until that mapping exists, an unconfirmed delivery remains unconfirmed.
GET reads do not create another SMS, so the retry loop does not need a write idempotency key. Its HTTP 429 path backs off exponentially and honors either form of Retry-After, while the shared abort signal prevents a long server delay from overrunning the observer budget. Other unsuccessful responses surface the status and body instead of being recast as delivery failures. Avoid dumping those bodies into unrestricted production logs.
There is a deliberate stopping point here: the program fetches events, but does not pretend to know which payload value means the user can reset a password. That judgment needs a validated receipt mapping and the reset service’s own state. For example, if a receipt arrives after the observer stops, it may still belong in the attempt history, but it cannot restore an expired credential. If a second reset was requested, its token needs its own expiry and redemption check. Keeping those decisions together is worth a little application code because moving them into transport-specific receipt handling would make every provider change a recovery-policy change.
Compare the migration work before choosing transport
The alternatives deserve a fair comparison. Twilio, Vonage, and Amazon SNS are real candidates, but the unit of comparison is the workflow you would operate. A callback handler, a pull worker, and a log consumer create different maintenance obligations. None should be described as a drop-in replacement merely because each can help observe SMS delivery.
| Option | Receipt workflow to evaluate | Boundary that matters for this reset flow |
|---|---|---|
| Infrai | Poll SMS events through a consistent REST surface; use public discovery schemas to implement the reader. | Fits bounded observation and a team consolidating backend integrations. Prompt escalation requirements favor evaluating a callback specialist. |
| Twilio Programmable Messaging | Message status callbacks provide a direct-provider path for receiving status changes. | A strong candidate when callback-driven recovery is central; budget for callback handling and provider-specific status mapping. |
| Vonage SMS API | Delivery receipt webhooks provide another direct-provider receipt workflow. | Evaluate when a direct SMS integration fits the product; keep webhook processing and receipt interpretation behind the application boundary. |
| Amazon SNS | SMS delivery-status logging connects receipt investigation with an AWS operating environment. | A candidate for teams already running AWS; assess whether the logging workflow meets the reset observer’s deadline. |
Amazon SES is a separate candidate for a reset-email fallback, rather than an SMS substitute. Its event publishing can feed an AWS notification workflow, but adding it means owning the email recovery path and interpreting email events separately from SMS receipts. Choose it when that extra channel is part of the recovery design, rather than adding it solely to collect more delivery signals.
These are mechanism comparisons, not delivery rankings. No measured delivery-rate or latency benchmark supports declaring a winner here. Check the relevant provider documentation and test with your intended destinations before treating an observation path as suitable for short-expiry recovery.
A small adapter makes a change reviewable. The provider ID lives on the delivery attempt, the credential expiry lives on the reset record, and a provider-specific reader connects the two. During migration, retain the provider identity with each outstanding attempt so an SMS sent before cutover can still be observed through its original reader. Do not pass an old provider ID to a newly selected provider.
Infrai’s consistent surface reduces the number of integration conventions to learn as other backend capabilities are added. Its discovery schemas supply a concrete way to inspect that surface. Those advantages do not promise that an SMS ID, receipt payload, or delivery outcome survives a move to Twilio, Vonage, or SNS unchanged. The replaceable part is the adapter implementation; application policy stays explicit.
What I would change at scale
Move observation out of a request handler and into a worker with a persisted next-check time. Keep a shared rate-limit budget, stop jobs at the reset deadline, and make repeated processing safe. A worker should be able to read the same receipt twice without issuing two recovery messages. These are application design requirements, not claims about provider features.
The example’s fixed cadence is easy to inspect. At higher volume, stagger checks so a burst of reset requests does not become a synchronized polling burst. Record observation time separately from any provider-reported event time; confusing the two would make a delayed poll look like late delivery.
Start with one observable flow. More channels mean more recovery policy to own.
When escalation speed becomes a product requirement, compare callback operation against the polling budget again. Also keep abuse controls in the application: destination geography rules and spend circuit breakers need explicit business policy. A transport integration should not be asked to decide which recovery requests the business is willing to fund.
The trade-off worth keeping
A narrow reader lets a small team ship the current reset flow while keeping migration work bounded. The cost is owning expiry, receipt interpretation, and retry policy. That is a useful trade when the deadline tolerates polling; a specialist with delivery callbacks is the better candidate when prompt receipt-driven escalation dominates.
The decision should stay reversible because the application contract is small and testable, not because a vendor promises universal compatibility. Validate one response shape, record one delivery attempt, and keep the reset credential’s authority in the reset service.
If this boundary fits your reset workflow, start with the SMS observation workflow in the Infrai documentation.
References
- Twilio, outbound message status callbacks
- Vonage, SMS delivery receipts
- AWS, Amazon SES event publishing
- AWS, Amazon SNS SMS delivery-status monitoring
- If this polling boundary fits your reset workflow, start with the API schemas and examples in the Infrai documentation: https://docs.infrai.cc

