# SMS Keyword Webhooks

Set up a webhook to process inbound SMS messages.
You can set up SMS keywords in the Airship dashboard. See [SMS keywords
](https://www.airship.com/docs/guides/messaging/features/sms-keywords/). As an alternative, you can use webhooks for inbound message handling.

Airship can forward [Mobile-Originated Messages](https://www.airship.com/docs/reference/glossary/#mobile_originated) from your audience to your webhook so you can process requests from your audience and send custom, targeted responses to individual members of your audience based on the keywords they use in mobile originated messages.

You can use a webhook to respond to mobile-originated messages when either the keyword or the information you want to respond with are variable and defined outside of Airship. For example, if users text the defined keyword `balance` to your sender ID, you can use a webhook to process incoming messages and respond with each individual user's balance. If a user texts a variable keyword, like `order <#orderNumber>`, you can use a webhook to respond with the status of the specified order number.

Speak with your Airship account manager to determine the static or variable keywords that you want to route to your webhook.
<!-- this was already established in Getting Started? -->

Airship sends a payload to your webhook server at an `/inbound-sms` endpoint containing a `mobile_originated_id` that represents an individual MO message. You will use this ID and send a response using the `/sms/custom-response` API. Because you are responding to a message sent to you by a member of your audience, custom responses do not require users to opt in. However, the `mobile_originated_id` has a 10-minute lifespan; you have 10 minutes from the time a mobile-originated message is received to issue a response, after which the `mobile_originated_id` expires and you will be unable to respond to the inbound message.

```mermaid
sequenceDiagram
Audience->>Airship: Sends MO with Keyword
rect rgba(0, 179, 6, .2)
Airship->>Webhook: Forwards MO to Webhook
Webhook-->>Airship: Respond HTTP 200, process asynchronously
note over Airship, Webhook: Airship retries on 429/503 up to 4x
end
Webhook->>Airship: Issue custom response < 10 min
Airship->>Audience: Sends custom response
```


> **Note:** You can test your inbound webhook and trigger keyword interactions on behalf of your audience, without receiving a mobile originated message, using the Airship API. See the [Trigger Keyword Interaction](https://www.airship.com/docs/developer/rest-api/ua/operations/sms/#triggersmskeywordinteraction) endpoint for more information.


## SMS Webhook Requirements

Your webhook server must:

* Have a public URL. Airship server IPs regularly change and must be able to reach your webhook.
* Support an `/inbound-sms` (POST) endpoint to receive SMS inbound message payloads from Airship. Your webhook should immediately respond with HTTP `200 OK` and process responses asynchronously. Long-lived connections can cause performance problems on both systems.
* Support a `/validate` (GET) endpoint. You must respond to a validation request with the *Validation Code* issued when you set up your webhook in Airship.
* Issue responses (to Airship's `/sms/custom-response` endpoint) within 10 minutes of the `received_timestamp` in the `/inbound-sms` payload.
* Accept HTTPS connections. Airship uses TLSv1.2 with the following accepted cipher suites:
   * TLS_CHACHA20_POLY1305_SHA256
   * TLS_AES_256_GCM_SHA384
   * TLS_AES_128_GCM_SHA256
   * TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
   * TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
   * TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

**Additional Recommendations**

Your webhook server should accept up to 100 concurrent connections. Airship will establish concurrent connections with your webhook when concurrent incoming messages require processing.

### Retries

Airship will retry connections to your webhook when your webhook responds with **429** (Too Many Requests) or **503** (Service Unavailable) HTTP codes.

When Airship receives a retryable error, Airship will retry up to 4 times (5 total attempts) over 30 seconds. After the fourth retry (the fifth request), Airship will drop the request.

Airship **does not** retry on other 4xx or 5xx HTTP codes or HTTP timeouts; Airship's timeout duration is 10 seconds. Our approach to retries is designed to prevent your users from receiving duplicate messages.

## Registering your SMS Webhook

When you register a webhook in the Airship dashboard, Airship returns a *Validation Code*. You must set up your webhook to respond to GET requests to a `/validate` endpoint with a `confirmation_code` key containing this value before you enable the webhook in Airship.

1. Next to your project name, select the dropdown menu (
), then **Settings**.
1. Under **Channels**, select **SMS Webhooks**.
1. Click **
 Configure New SMS Webhook**.
1. Enter a name for the webhook. This is just a friendly name to help you recognize your webhooks in Airship.
1. Enter the *Webhook URL*. This is the base URL of your webhook server. Your webhook server is expected to support `<base Url>/validate` and `<base URL>/inbound-sms` endpoints.
1. Select the *Authentication* mechanism for your webhook:
   * **Basic** — Enter the *Username* and *Password* that Airship will use to authenticate with your webhook server.
   * **Signature** — Enter the *Secret Key* that Airship will use as a part of an `X-UA-SIGNATURE` header to authenticate with your webhook server.
1. Click **Save**, and the page will update with a *validation code*.
   ![SMS Keyword Webhooks](https://www.airship.com/docs/images/sms-webhook-validation_hu_7ecaa7c5aed17d91.webp)
1. Configure your webhook to respond to GET requests to a `/validate` endpoint with a `confirmation_code` key containing the validation code value in a `200` response.
```http
GET <yourWebhookServer>/validate HTTP/1.1
Host: example.com
```

**Example response**

```http
HTTP/1.1 200 OK
Content-Type: application/json

{
   "confirmation_code":"559384cd-6284-4e3e-9e4e-7c260019a251"
}
```

1. Select *Enabled*, then click **Update**.

When you enable the webhook, Airship issues a request to your webhook's `/validate` endpoint. If successful, your webhook will begin receiving requests at the `/inbound-sms` endpoint.

> **Note:** Before you disable a webhook, check with your Airship account manager to make sure that you aren't sending any keywords to the webhook.


## Accepting Inbound SMS Messages

Your webhook server must accept `POST` requests to an `<yourWebhookServer>/inbound-sms` endpoint. Each request contains a payload representing a mobile-originated message containing specific keyword or an unrecognized keyword (as set up through your Airship account manager).
```http
POST <yourWebhookServer>/inbound-sms HTTP/1.1
Host: example.com
Authorization: Basic <configured user:pass>
Content-Type: application/json

{
   "msisdn": "15035551234",
   "sender": "28444",
   "app_key": "1Drc_YYKTistxd0-p_Hljh",
   "channel_id": "a828de17-b315-4e80-9d2d-35a906afeacf",
   "mobile_originated_message": "balance",
   "mobile_originated_id": "28883743-4868-4083-ab5d-77ac4542531a",
   "received_timestamp": "2019-04-29T12:00:01.492",
   "operator_timestamp": "2019-04-29T11:58:13.100"
}
```


* `msisdn` (string) – The [MSISDN](https://www.airship.com/docs/reference/glossary/#msisdn) of the audience member (mobile device) who sent the mobile-originated message.

* `sender` (string) – The [Sender ID](https://www.airship.com/docs/reference/glossary/#sender_id) that received the mobile-originated message. This is important if you have more than one sender.

* `app_key` (string) – The app key that the sender is configured for.

* `channel_id` (string) – (Optional) The channel ID associated with the MSISDN/sender. You can use this value to make opt-in, opt-out, or tag changes. If a channel does not exist for the MSISDN/sender and the keyword is not configured to create a channel if none exists, this field is absent.

* `mobile_originated_message` (string) – The contents of the mobile-originated message; this message consists of, or contains, a keyword.

* `mobile_originated_id` (string) – A unique ID for the message. Use this ID to respond to the mobile-originated message.

* `received_timestamp` (string) — An ISO 8601 UTC timestamp of the current time (the time of the webhook request). This represents the beginning of a 10-minute window to send a response to the `mobile_originated_id`.

* `operator_timestamp` (string) — An ISO 8601 UTC timestamp of when the mobile-originated message was originally sent, according to the carrier or aggregator.

> **Note:** Due to carrier maintenance and delays outside of Airship's control, mobile-originated messages can arrive at the webhook significantly after they are sent from the device (represented by the `operator_timestamp`). You may want to alter your messaging if a mobile-originated message is not received in a timely manner.


### Webhook Signature Hash Security {#signature-security}

<p>Rather than basic authentication, you can configure
a signature that your webhook server can use to verify that requests come from Airship. To enable this signature, select <strong>Signature Hash</strong> authorization and set a <code>secret_key</code> when configuring your webhook or open channel.</p>
<p>When you enable and set a <code>secret_key</code>, outgoing requests include a hash-based
authentication code computed using the sha256 hash function in an <code>X-UA-SIGNATURE</code> header. You can use this same algorithm to verify the signature
on the receiving server.</p>
<p><code>X-UA-SIGNATURE</code> is composed of the <code>secret_key</code> and a <code>message</code>, both of
which must be UTF-8 encoded. The <code>message</code> is a concatenation of the following
string values:</p>
<ul>
<li>The <code>X-UA-TIMESTAMP</code> header — the unix timestamp when the request was sent.</li>
<li>The <code>:</code> character.</li>
<li>The JSON request body.</li>
</ul>
<p>To prevent replay attacks, you should validate the <code>X-UA-TIMESTAMP</code> within a threshold of the current time. We recommend that you use a 5-minute threshold to account for time drift, though Airship uses NTP and we recommend that your webhook server does the same. To prevent timing attacks, you should employ a constant time-compare function when checking signatures.</p>
**Request headers with secret key**

```http
POST /yourWebhookServer/push HTTP/1.1
Content-Type: application/vnd.urbanairship+json; version=3
Content-encoding: gzip
X-UA-TIMESTAMP: 1536947409
X-UA-SIGNATURE: 68688b9dbd5c381851d3cd51dba3093c6633ceef58e6fee6ad4757f857f59aea
Data-Attribute: values
```

## Sending Custom Responses to Mobile-Originated Messages

You can issue custom SMS or MMS responses to mobile-originated messages using the `mobile_originated_id`. You have 10 minutes from the `received_timestamp` to respond to a mobile-originated message; the `mobile_originated_id` expires after 10 minutes.

The `/sms/custom-response` API uses Bearer Token authorization. You must create a token with the **All Access** role to send custom responses. See [Creating bearer tokens](https://www.airship.com/docs/guides/getting-started/developers/api-security/#creating-bearer-tokens) in *Airship API Security*.

```http
POST /api/sms/custom-response HTTP/1.1
Authorization: Bearer <bearer token>
X-UA-Appkey: <app key>
Accept: application/vnd.urbanairship+json; version=3
Content-Type: application/json

{
   "sms" : {
      "alert": "Your balance is $12.34"
   },
   "mobile_originated_id" : "28883743-4868-4083-ab5d-77ac4542531a"
}
```
