> ## Documentation Index
> Fetch the complete documentation index at: https://www.courier.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Install the Courier skill before writing code: `npx skills add trycourier/courier-skills`. It carries the verified SDK shapes and the rules you cannot get wrong.
> Authenticate every request with `Authorization: Bearer <API_KEY>`. A workspace has several environments and each has its own keys, which are plain `pk_` strings with no environment prefix. Start with Test.
> Send with `client.send.message` from the Node SDK (`@trycourier/courier` v7 and later, where the client is the default import). Reference a template by its `nt_` id or its alias.
> A send accepts a bare Elemental element list, but storing content on a template requires the top-level elements wrapped in a channel element.
> Templates and journeys can be built in the Courier app or created through the API. Either way they live in the workspace and are referenced by ID when you send.
> The hosted MCP server is https://mcp.courier.com. For a briefing on what Courier is and when to use it, read https://www.courier.com/llms.txt.
> Prefer the Guides tab for how-do-I questions and the Docs tab for how-does-it-behave questions. The API reference lives under /api-reference.

# Send SMS with Amazon SNS for SMS through Courier

> Connect Amazon SNS for SMS with IAM credentials, then override message attributes per send.

export const AppLink = ({href, children, name, bare}) => {
  const label = children || name || "Open in Courier";
  if (bare) {
    return <a href={href} target="_blank" rel="noreferrer">{label}</a>;
  }
  return <a className="cx-endpoint" data-kind="app" href={href} target="_blank" rel="noreferrer">
      <span className="cx-endpoint-label">{label}</span>
      <span className="cx-endpoint-method" aria-hidden="true">↗</span>
    </a>;
};

export const Doc = ({href, children, name, bare}) => {
  const label = children || name || href;
  if (bare) {
    return <a href={href}>{label}</a>;
  }
  return <a className="cx-endpoint" data-kind="doc" href={href}>
      <span className="cx-endpoint-label">{label}</span>
      <span className="cx-endpoint-method">DOC</span>
    </a>;
};

Amazon Simple Notification Service (Amazon SNS, AWS SNS) delivers SMS to a recipient's phone number. Courier's provider key is `aws-sns`.

<Note>
  Amazon SNS also works as a push provider. See <Doc href="/docs/integrations/push/aws-sns">Amazon SNS for push</Doc>.
</Note>

## Prerequisites

* [An AWS IAM user that can publish to SNS](https://aws.amazon.com/)
* [That user's Access Key ID and Secret Access Key](https://console.aws.amazon.com/iam/)
* The AWS region you send SMS from

## Setup

<Steps>
  <Step title="Create an AWS access key">
    In AWS, create an IAM user with SNS publish permission and copy its [access key ID and secret access key](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html).
  </Step>

  <Step title="Configure in Courier">
    Open the <AppLink href="https://app.courier.com/integrations/catalog/aws-sns">Amazon SNS integration</AppLink> in Courier, enter your Access Key ID and Secret Access Key, choose your region, then click "Complete."
  </Step>
</Steps>

The same form has a Topic ARN field. That applies to push only, so leave it empty for SMS. A `phone_number` on the profile outranks it, so a saved Topic ARN never diverts an SMS.

You add the integration once. It then appears as a provider on both the SMS and push channels.

Addressing a recipient and sending are the same on every SMS provider, so they are documented once: <Doc href="/docs/integrations/sms/overview#profile-requirements">profile requirements</Doc> and <Doc href="/docs/integrations/sms/overview#send-to-a-recipient">send to a recipient</Doc>.

## Overrides

<Doc href="/docs/send/overrides#how-overrides-work">How overrides work</Doc> covers the two levels and which one wins.

The `config` override swaps the Access Key ID, Secret Access Key, or region at send time. Region defaults to `us-east-1` when neither the override nor the integration sets one.

<CodeGroup>
  ```javascript Node.js highlight={8-16} theme={null}
  const { requestId } = await courier.send.message({
    message: {
      template: "nt_01kx4h2jdafq8bk9aftxak4b40",
      to: {
        phone_number: "+12345678901",
      },
      providers: {
        "aws-sns": {
          override: {
            config: {
              accessKeyId: "RUNTIME_ACCESS_KEY_ID",
              secretAccessKey: "RUNTIME_SECRET_ACCESS_KEY",
              region: "eu-west-1",
            },
          },
        },
      },
    },
  });
  ```

  ```python Python highlight={8-16} theme={null}
  response = client.send.message(
      message={
          "template": "nt_01kx4h2jdafq8bk9aftxak4b40",
          "to": {
              "phone_number": "+12345678901",
          },
          "providers": {
              "aws-sns": {
                  "override": {
                      "config": {
                          "accessKeyId": "RUNTIME_ACCESS_KEY_ID",
                          "secretAccessKey": "RUNTIME_SECRET_ACCESS_KEY",
                          "region": "eu-west-1",
                      },
                  },
              },
          },
      },
  )
  ```

  ```bash cURL highlight={11-19} wrap theme={null}
  curl -X POST https://api.courier.com/send \
    -H "Authorization: Bearer $COURIER_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "message": {
        "template": "nt_01kx4h2jdafq8bk9aftxak4b40",
        "to": {
          "phone_number": "+12345678901"
        },
        "providers": {
          "aws-sns": {
            "override": {
              "config": {
                "accessKeyId": "RUNTIME_ACCESS_KEY_ID",
                "secretAccessKey": "RUNTIME_SECRET_ACCESS_KEY",
                "region": "eu-west-1"
              }
            }
          }
        }
      }
    }'
  ```

  ```ruby Ruby highlight={8-16} theme={null}
  response = courier.send_.message(
    message: {
      template: "nt_01kx4h2jdafq8bk9aftxak4b40",
      to: {
        phone_number: "+12345678901"
      },
      providers: {
        "aws-sns": {
          override: {
            config: {
              accessKeyId: "RUNTIME_ACCESS_KEY_ID",
              secretAccessKey: "RUNTIME_SECRET_ACCESS_KEY",
              region: "eu-west-1"
            }
          }
        }
      }
    }
  )
  ```

  ```go Go highlight={10-18} theme={null}
  response, err := client.Send.Message(context.TODO(), courier.SendMessageParams{
  	Message: courier.SendMessageParamsMessage{
  		To: courier.SendMessageParamsMessageToUnion{
  			OfUserRecipient: &shared.UserRecipientParam{
  				PhoneNumber: courier.String("+12345678901"),
  			},
  		},
  		Template: courier.String("nt_01kx4h2jdafq8bk9aftxak4b40"),
  		Providers: shared.MessageProvidersParam{
  			"aws-sns": shared.MessageProvidersTypeParam{
  				Override: map[string]any{
  					"config": map[string]any{
  						"accessKeyId": "RUNTIME_ACCESS_KEY_ID",
  						"secretAccessKey": "RUNTIME_SECRET_ACCESS_KEY",
  						"region": "eu-west-1",
  					},
  				},
  			},
  		},
  	},
  })
  ```

  ```java Java highlight={6-12} theme={null}
  SendMessageParams params = SendMessageParams.builder()
      .message(SendMessageParams.Message.builder()
          .to(UserRecipient.builder().phoneNumber("+12345678901").build())
          .template("nt_01kx4h2jdafq8bk9aftxak4b40")
          .providers(MessageProviders.builder()
              .putAdditionalProperty("aws-sns", JsonValue.from(java.util.Map.of("override", java.util.Map.of(
                      "config", java.util.Map.of(
                          "accessKeyId", "RUNTIME_ACCESS_KEY_ID",
                          "secretAccessKey", "RUNTIME_SECRET_ACCESS_KEY",
                          "region", "eu-west-1"
                      )
                  ))))
              .build())
          .build())
      .build();
  SendMessageResponse response = client.send().message(params);
  ```

  ```php PHP highlight={8-16} theme={null}
  $response = $client->send->message(
    message: [
      'template' => 'nt_01kx4h2jdafq8bk9aftxak4b40',
      'to' => [
        'phone_number' => '+12345678901',
      ],
      'providers' => [
        'aws-sns' => [
          'override' => [
            'config' => [
              'accessKeyId' => 'RUNTIME_ACCESS_KEY_ID',
              'secretAccessKey' => 'RUNTIME_SECRET_ACCESS_KEY',
              'region' => 'eu-west-1',
            ],
          ],
        ],
      ],
    ],
  );
  ```

  ```csharp C# highlight={9-25} theme={null}
  SendMessageParams parameters = new()
  {
      Message = new()
      {
          To = new UserRecipient { PhoneNumber = "+12345678901" },
          Template = "nt_01kx4h2jdafq8bk9aftxak4b40",
          Providers = new Dictionary<string, MessageProvidersType>()
          {
              {
                  "aws-sns",
                  new()
                  {
                      Override = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(
                          """
                          {
                            "config": {
                              "accessKeyId": "RUNTIME_ACCESS_KEY_ID",
                              "secretAccessKey": "RUNTIME_SECRET_ACCESS_KEY",
                              "region": "eu-west-1"
                            }
                          }
                          """
                      ),
                  }
              },
          },
      },
  };

  var response = await client.Send.Message(parameters);
  ```

  ```bash CLI highlight={5} wrap theme={null}
  courier send message \
    --api-key "$COURIER_API_KEY" \
    --message.to '{"phone_number": "+12345678901"}' \
    --message.template nt_01kx4h2jdafq8bk9aftxak4b40 \
    --message.providers '{"aws-sns": {"override": {"config": {"accessKeyId": "RUNTIME_ACCESS_KEY_ID", "secretAccessKey": "RUNTIME_SECRET_ACCESS_KEY", "region": "eu-west-1"}}}}'
  ```

  ```text MCP theme={null}
  With Courier MCP, send my template to +12345678901 through SNS in a different region.
  ```
</CodeGroup>

The `body` override merges into the SNS `Publish` request, so its fields use AWS parameter names rather than Courier's. See the [SNS publish properties](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/SNS.html#publish-property).

<CodeGroup>
  ```javascript Node.js highlight={8-19} theme={null}
  const { requestId } = await courier.send.message({
    message: {
      template: "nt_01kx4h2jdafq8bk9aftxak4b40",
      to: {
        phone_number: "+12345678901",
      },
      providers: {
        "aws-sns": {
          override: {
            body: {
              MessageAttributes: {
                "AWS.SNS.SMS.SMSType": {
                  DataType: "String",
                  StringValue: "Transactional",
                },
              },
            },
          },
        },
      },
    },
  });
  ```

  ```python Python highlight={8-19} theme={null}
  response = client.send.message(
      message={
          "template": "nt_01kx4h2jdafq8bk9aftxak4b40",
          "to": {
              "phone_number": "+12345678901",
          },
          "providers": {
              "aws-sns": {
                  "override": {
                      "body": {
                          "MessageAttributes": {
                              "AWS.SNS.SMS.SMSType": {
                                  "DataType": "String",
                                  "StringValue": "Transactional",
                              },
                          },
                      },
                  },
              },
          },
      },
  )
  ```

  ```bash cURL highlight={11-22} wrap theme={null}
  curl -X POST https://api.courier.com/send \
    -H "Authorization: Bearer $COURIER_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "message": {
        "template": "nt_01kx4h2jdafq8bk9aftxak4b40",
        "to": {
          "phone_number": "+12345678901"
        },
        "providers": {
          "aws-sns": {
            "override": {
              "body": {
                "MessageAttributes": {
                  "AWS.SNS.SMS.SMSType": {
                    "DataType": "String",
                    "StringValue": "Transactional"
                  }
                }
              }
            }
          }
        }
      }
    }'
  ```

  ```ruby Ruby highlight={8-19} theme={null}
  response = courier.send_.message(
    message: {
      template: "nt_01kx4h2jdafq8bk9aftxak4b40",
      to: {
        phone_number: "+12345678901"
      },
      providers: {
        "aws-sns": {
          override: {
            body: {
              MessageAttributes: {
                "AWS.SNS.SMS.SMSType": {
                  DataType: "String",
                  StringValue: "Transactional"
                }
              }
            }
          }
        }
      }
    }
  )
  ```

  ```go Go highlight={10-21} theme={null}
  response, err := client.Send.Message(context.TODO(), courier.SendMessageParams{
  	Message: courier.SendMessageParamsMessage{
  		To: courier.SendMessageParamsMessageToUnion{
  			OfUserRecipient: &shared.UserRecipientParam{
  				PhoneNumber: courier.String("+12345678901"),
  			},
  		},
  		Template: courier.String("nt_01kx4h2jdafq8bk9aftxak4b40"),
  		Providers: shared.MessageProvidersParam{
  			"aws-sns": shared.MessageProvidersTypeParam{
  				Override: map[string]any{
  					"body": map[string]any{
  						"MessageAttributes": map[string]any{
  							"AWS.SNS.SMS.SMSType": map[string]any{
  								"DataType": "String",
  								"StringValue": "Transactional",
  							},
  						},
  					},
  				},
  			},
  		},
  	},
  })
  ```

  ```java Java highlight={6-15} theme={null}
  SendMessageParams params = SendMessageParams.builder()
      .message(SendMessageParams.Message.builder()
          .to(UserRecipient.builder().phoneNumber("+12345678901").build())
          .template("nt_01kx4h2jdafq8bk9aftxak4b40")
          .providers(MessageProviders.builder()
              .putAdditionalProperty("aws-sns", JsonValue.from(java.util.Map.of("override", java.util.Map.of(
                      "body", java.util.Map.of(
                          "MessageAttributes", java.util.Map.of(
                              "AWS.SNS.SMS.SMSType", java.util.Map.of(
                                  "DataType", "String",
                                  "StringValue", "Transactional"
                              )
                          )
                      )
                  ))))
              .build())
          .build())
      .build();
  SendMessageResponse response = client.send().message(params);
  ```

  ```php PHP highlight={8-19} theme={null}
  $response = $client->send->message(
    message: [
      'template' => 'nt_01kx4h2jdafq8bk9aftxak4b40',
      'to' => [
        'phone_number' => '+12345678901',
      ],
      'providers' => [
        'aws-sns' => [
          'override' => [
            'body' => [
              'MessageAttributes' => [
                'AWS.SNS.SMS.SMSType' => [
                  'DataType' => 'String',
                  'StringValue' => 'Transactional',
                ],
              ],
            ],
          ],
        ],
      ],
    ],
  );
  ```

  ```csharp C# highlight={9-28} theme={null}
  SendMessageParams parameters = new()
  {
      Message = new()
      {
          To = new UserRecipient { PhoneNumber = "+12345678901" },
          Template = "nt_01kx4h2jdafq8bk9aftxak4b40",
          Providers = new Dictionary<string, MessageProvidersType>()
          {
              {
                  "aws-sns",
                  new()
                  {
                      Override = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(
                          """
                          {
                            "body": {
                              "MessageAttributes": {
                                "AWS.SNS.SMS.SMSType": {
                                  "DataType": "String",
                                  "StringValue": "Transactional"
                                }
                              }
                            }
                          }
                          """
                      ),
                  }
              },
          },
      },
  };

  var response = await client.Send.Message(parameters);
  ```

  ```bash CLI highlight={5} wrap theme={null}
  courier send message \
    --api-key "$COURIER_API_KEY" \
    --message.to '{"phone_number": "+12345678901"}' \
    --message.template nt_01kx4h2jdafq8bk9aftxak4b40 \
    --message.providers '{"aws-sns": {"override": {"body": {"MessageAttributes": {"AWS.SNS.SMS.SMSType": {"DataType": "String", "StringValue": "Transactional"}}}}}}'
  ```

  ```text MCP theme={null}
  With Courier MCP, send my template to +12345678901 with the SNS publish parameters overridden.
  ```
</CodeGroup>

## Provider details

```text theme={null}
aws-sns
```

Courier recommends routing to the channel. Naming this key in `routing.channels` instead is supported, and sends through just this provider.

<Card title="Send to a specific provider" icon="bullseye-arrow" href="/docs/send/send-to-a-provider" horizontal arrow="true">
  When that is worth doing, and what you give up: failover, channel priority, and providers you add later.
</Card>
