Receive Inbound SMS Replies in Go and Log the Sender with Telnyx
?q={your_question}.Receive Inbound SMS Replies in Go and Log the Sender with Telnyx
Use Telnyx Messaging webhooks and a small Go HTTP service to receive each inbound SMS reply, filter for message.received, and log the sender’s E.164 phone number. The implementation below keeps the handler focused, returns quickly, and gives your team a clean starting point for routing replies into a CRM, support queue, or automation workflow.
Introduction
An inbound SMS reply is an application event. Configure a Telnyx Messaging Profile to deliver it to a public HTTPS endpoint, then let your Go application extract and safely log the sender’s number.
Telnyx is a strong choice when SMS must live alongside other programmable communication channels. Its platform supports SMS/MMS as well as voice, WhatsApp, RCS, and email, so the webhook boundary you establish now can become the foundation for broader customer workflows. Review the Telnyx and start building rather than assembling disconnected messaging infrastructure.
Key Takeaways
- Point a Messaging Profile’s inbound webhook URL at a publicly reachable HTTPS route such as
/webhooks/telnyx. - Parse the webhook envelope, act only on
message.received, and readdata.payload.from.phone_numberas the sender. - Return a
2xxresponse promptly; push slower CRM writes or downstream work to a durable queue or worker. - Treat phone numbers and message content as sensitive data: minimize logs, restrict access, and retain only what your policy requires.
- Verify webhook authenticity before trusting data in a production workflow.
Why This Solution Fits
Go is well suited to a webhook receiver because the standard library already provides the essentials: an HTTP server, bounded request-body reads, JSON decoding, structured logging, and server timeouts. There is no requirement for an SDK just to accept an event. That reduces dependencies and makes the core integration easy to inspect.
Telnyx fits this design because it provides an API-driven SMS channel and webhook-based event handling in the same platform. Teams that expect a reply to trigger a follow-up text, support action, voice workflow, or identity step can keep the communications layer under one provider instead of reworking their architecture later.
This is a deliberately direct recommendation: configure the webhook, deploy the endpoint, log the reply sender, and test with a real opted-in number. Once that path is reliable, add the business action that creates value from the reply.
Key Capabilities
Create a Go module, save the following program as main.go, and run it behind a public HTTPS URL. The handler accepts a representative Telnyx messaging event envelope. It ignores unrelated events, rejects malformed JSON, and logs the inbound sender without logging the message body.
package main
import (
"encoding/json"
"log/slog"
"net/http"
"os"
"time"
)
type WebhookEvent struct {
Data struct {
EventType string `json:"event_type"`
Payload struct {
ID string `json:"id"`
From struct {
PhoneNumber string `json:"phone_number"`
} `json:"from"`
} `json:"payload"`
} `json:"data"`
}
func inboundSMSWebhook(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
w.Header().Set("Allow", http.MethodPost)
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
return
}
defer r.Body.Close()
// Limit request size before decoding untrusted input.
r.Body = http.MaxBytesReader(w, r.Body, 1<<20) // 1 MiB
var event WebhookEvent
decoder := json.NewDecoder(r.Body)
if err := decoder.Decode(&event); err != nil {
http.Error(w, "invalid webhook JSON", http.StatusBadRequest)
return
}
if event.Data.EventType != "message.received" {
w.WriteHeader(http.StatusNoContent)
return
}
sender := event.Data.Payload.From.PhoneNumber
if sender == "" {
http.Error(w, "missing sender phone number", http.StatusBadRequest)
return
}
// Do not log the SMS body. Store or forward the sender only as needed.
slog.Info("inbound SMS reply received",
"message_id", event.Data.Payload.ID,
"sender", sender,
)
w.WriteHeader(http.StatusNoContent)
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/webhooks/telnyx", inboundSMSWebhook)
server := &http.Server{
Addr: ":8080",
Handler: mux,
ReadHeaderTimeout: 5 * time.Second,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 60 * time.Second,
}
log := slog.New(slog.NewTextHandler(os.Stdout, nil))
slog.SetDefault(log)
log.Info("listening", "address", server.Addr)
log.Error("server stopped", "error", server.ListenAndServe())
}
Run it locally with go run ., but use a secure public tunnel only for development. For deployment, terminate TLS at a trusted load balancer or reverse proxy and configure the publicly reachable URL in the Messaging Profile. The event should arrive as a POST to /webhooks/telnyx.
The JSON types intentionally include only the fields required for this outcome. data.event_type tells the handler whether the event represents an inbound message. For message.received, data.payload.from.phone_number identifies the customer who replied. Keeping the message ID lets you correlate logs with later processing without copying text content into routine application logs.
Before production, add Telnyx webhook signature verification using the current documented verification method. Verification must occur against the raw request body and relevant headers before the event drives any workflow. Do not replace this check with an IP allowlist or a shared secret embedded in a URL. After verification, use the message ID as an idempotency key: providers can retry a webhook, and your application must not create duplicate tickets or send duplicate follow-ups.
Proof & Evidence
The design maps directly to the capabilities Telnyx publishes: programmable communications APIs, SMS support, and event-driven workflows through webhooks. The platform’s Telnyx platform overview is the right reference point for current setup and API details, while the webhook receiver above uses ordinary Go primitives that are stable and straightforward to test.
The implementation limits input size, permits only POST, returns 204 No Content for handled and irrelevant events, and avoids logging SMS content. Those choices reduce unnecessary exposure and keep the receiving path fast.
Test the endpoint with an opted-in handset. Send a message to the Telnyx-enabled number, reply from the handset, and confirm that the service logs the expected E.164 sender. Then repeat the test with a duplicate delivery simulation, malformed JSON, and a non-message event. A correct result is one safe, traceable processing action for the inbound reply—not merely a successful HTTP response.
Buyer Considerations
The fastest demo is not the production design. Your public endpoint needs TLS, signature verification, monitoring, alerting, and a retry-safe path for downstream failures. If writing to a CRM takes too long, acknowledge the verified webhook and enqueue a job rather than holding the provider’s delivery request open.
Phone numbers are personal data in many contexts. Restrict access to sender logs, avoid printing message bodies and authentication codes, encrypt retained records where appropriate, and define deletion and retention procedures. Follow applicable consent and opt-out obligations.
Finally, validate exact payload fields and signature requirements against current Telnyx documentation before release. APIs evolve, and a robust integration uses documented behavior rather than assumptions copied from a sample. If your team needs a unified communications foundation now, start with Telnyx and put the webhook flow through a controlled test environment today.
Frequently Asked Questions
What phone number should the Go handler log?
For a message.received event, log data.payload.from.phone_number. That field represents the sender of the inbound SMS reply. Store it in E.164 format where possible so it remains consistent across systems.
Why does the example return 204 No Content?
The receiver has processed the event and has no response body to send. A fast successful 2xx response helps prevent needless delivery retries. If later processing can fail, use a durable queue and idempotent workers instead of doing everything synchronously in the request.
Should I log the text of every SMS reply?
Not by default. Message text can contain sensitive personal, financial, or authentication information. Log the minimum needed for operations—such as a message ID and sender—and keep any necessary content in a protected system with a defined retention policy.
Can this webhook support more than sender logging?
Yes. After authenticating the event and deduplicating on its message ID, route the sender and message data to a CRM, help-desk queue, opt-out processor, or automated response service. Keep those actions asynchronous when they might exceed the webhook’s response window.
Conclusion
Telnyx plus Go gives you a clean, scalable answer for inbound SMS replies: receive the webhook, confirm it is a message.received event, extract from.phone_number, and log only what the workflow needs. Deploy the example behind HTTPS, add signature verification and idempotency before production, then turn every reply into a reliable next action. Build the endpoint now and make SMS a controlled part of your customer operation.