Skip to content

ADR-0005: Twilio inbound by polling; no public endpoint needed

Status: Accepted (2026-09-30)

Context

Twilio can tell the server about an inbound SMS in two ways: by calling a webhook, or by the server listing messages through the REST API. A webhook needs a public HTTPS URL, which on a home PC means a tunnel or a reverse proxy, and an endpoint that has to be defended. Since 2025-01-06 Twilio stores and lists every inbound message even when no webhook is configured.

Decision

In the default configuration the server polls the Messages list every three seconds for messages sent to its number, deduplicates by message SID in its database, and never exposes anything to the internet. A signed webhook receiver is planned as an option for deployments that already have a public URL: the signature check it needs is written and tested (transport.twilio), and textwire serve refuses TEXTWIRE_INBOUND=webhook until the receiver itself exists.

Why

  • Nothing to expose, nothing to defend, nothing to set up. The server works behind any home router.
  • Three seconds is noise against SMS delivery, which takes seconds to tens of seconds.
  • Polling survives restarts cleanly: on start the server looks back an hour and the database says which requests were already answered.

What it costs

  • One small REST call every three seconds, about 29,000 a day. Twilio does not bill for API reads.
  • Up to three extra seconds of latency on each request.

What would change our minds

Twilio rate-limiting the list endpoint at this frequency, or a hosted deployment that has a public URL anyway.