Set Twilio Incoming SMS Hook
Tags: twilio, go
Published: 2021-12-29 19:20:43

## Set webhook URL

1, Go to "Develop > Phone numbers > Manage > Active Numbers", click the phone number you want to set the hook.

2, Scroll to the bottom to the page, in the "Messaging" section, click "Modify the Messaging Service configuration"

![twilio messaging configuration](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ppiqmrwo21r08tptqiak.png)

3, In this page, you will see several options under the "Incoming messages" section:

![incoming messages](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iiq3h0gzdkite6crzgi6.png)
 
For example you can disable the incoming message which will disallow message sending to your number such that twilio won't charge your account.

Since this article is for setting the incoming hooks, so let's choose the "Send to a webhook" option, then in the input box, write our hook URL (see below) and set the method to be POST.

## Code our webhook server

Now let's code our webhook server. Say our webhook URL in the above step is set to "https://example.org/twilio-hook", here we need to add an HTTP Post Endpoint to get the incoming message (here I am using the [Golang's Fiber Web Framework](https://gofiber.io)):

```go
package main

import (
	"encoding/xml"
	"fmt"
	"log"

	"github.com/gofiber/fiber/v2"
)

type TMLResp struct {
	XMLName xml.Name `xml:"Response"`
	Message string   `xml:"Message,omitempty"`
}

func buildTMLResp(msg string) string {
	b, _ := xml.Marshal(TMLResp{
		Message: msg,
	})
	return fmt.Sprintf("%s\n%s", xml.Header, b)
}

type SMSRequest struct {
	From string `form:"From"`
	Body string `form:"Body"`
}

func main() {
	app := fiber.New()

	app.Post("/twilio-hook", func(c *fiber.Ctx) error {
		log.Println("Body:")
		log.Println(string(c.Body()))
		reqParams := SMSRequest{}
		if err := c.BodyParser(&reqParams); err != nil {
			return c.SendStatus(fiber.StatusBadRequest)
		}
		// add our other logics here
		log.Printf("From: %s Message: %s\n", reqParams.From, reqParams.Body)
		c.Set(fiber.HeaderContentType, "application/xml")
		resp := fmt.Sprintf(
			"City: %s\nMessage: %s",
			reqParams.City,
			reqParams.Body,
		)
		return c.SendString(buildTMLResp(resp))
		// if we don't want to reply the message, just return an empty response
		// c.SendString(buildTMLResp(""))
	})

	app.Listen(":6767")
}
```

The above code will print the incoming message body, do some further logic then return a Twilio XML that twilio can further auto reply that message to the user who sent SMS to your number.

The incoming message body are parameters with form-url-encoded format, it contains several fields like below (in the code aove we use the `.BodyParser` method to parse the message to a struct which only contains the fields we are interested):

Please notice some GEO fields (FromZip, ToCity, etc.) might be missing if Twilio can't detect them.

```
ToCountry=US
ToState=NY
SmsMessageSid=SMc17347ab5ba2aab4e87fa7c0c1ff5d73
NumMedia=0
ToCity=WATER+MILL
FromZip=11901
SmsSid=SMc17347ab5ba2bab4e77fa6c0c1ef5d63
FromState=NY
SmsStatus=received
FromCity=RIVERHEAD
Body=Test+msg
FromCountry=US
To=%2B19171234567
MessagingServiceSid=MG3aae3946423ce3ebd25e4c37a84a385c
ToZip=11968
NumSegments=1
MessageSid=SMc17347ab5ba2aab4e87fa7c0c1ff5d73
AccountSid=AC7a6bfbacbc909235584ecef67565643b
From=%2B19171234568
ApiVersion=2010-04-01
```

The XML Message we sent back to Twilio is like this:
```xml
<Response>
    <Message>We got your message, thank you!</Message>
</Response>
```

Once Twilio got this XML response, it will reply a SMS with the content inside the `<Message></Message>` tag to the user.

If we don't want to reply that user, we can simply return an empty response, like an empty string:

```go
c.Set(fiber.HeaderContentType, "application/xml")
return c.SendString("<Response></Response>")
// or in the above code, use
// return c.SendString(buildTMLResp(""))
```

## Auto forward message

You can use the TwiML to further forward a message, like:
```html
<Response>
    <Message to='+13105555555'>{{From}}: {{Body}}</Message>
</Response>
```

Or you can use Twilio's GUI tool to do it and you can use this tool to forward to multiple numbers:
[Twilio GUI Tool: Forward to multiple numbers](https://www.twilio.com/code-exchange/sms-forwarding-multiple-numbers)

This will create a Twilio Cloud Function. Once you saved and published it, twilio will config that function as your incoming message's hook.

## Reference
* [Forward to multiple numbers](https://www.twilio.com/code-exchange/sms-forwarding-multiple-numbers)
* [Receive inbound SMS](https://www.twilio.com/docs/runtime/quickstart/serverless-functions-receive-inbound-sms#)
* [TwiML for SMS](https://www.twilio.com/docs/messaging/twiml)
* [Receive SMS and MMS Messages without Responding](https://support.twilio.com/hc/en-us/articles/223134127-Receive-SMS-and-MMS-Messages-without-Responding)
* [Set up twilio studio to forward message](https://support.twilio.com/hc/en-us/articles/115015962887-Forward-Incoming-SMS-Messages-with-Twilio-Studio)