# Send to Many People
URL: /docs/sending/send-many
LLM index: /llms.txt
Description: Blasts vs Audiences: when to use each, how to create and send to both, and campaign volume caps.

# Send to Many People

Surge has two mechanisms for sending to multiple recipients: **Blasts** for one-time sends and **Audiences** for reusable contact lists. The choice between them depends on whether the same group of people will receive messages more than once.

## Blasts vs Audiences

**Use a Blast** when you have a list of recipients you're assembling specifically for this send. You pass the recipient list at send time and don't need to maintain it afterward — weekly flash sales, event announcements, one-time notifications.

**Use an Audience** when the same group of people receives messages regularly. You maintain the audience over time (adding and removing contacts), then blast the whole audience — weekly newsletters, customer cohorts, or geographic segments.

Both send the same underlying message; the difference is how you manage the recipient list.

---

## Blasts

### Send to a list of phone numbers

The simplest case: pass <Tooltip tip="International phone number format: starts with +, country code, then subscriber number, no spaces or punctuation. Example: +18015551234.">E.164</Tooltip> phone numbers directly in the `to` array.

<CodeGroup items={["Python","TypeScript","Ruby","Elixir","cURL"]}>

```python Python
from surge import Surge

surge = Surge()

blast = surge.blasts.create(
    account_id="{account_id}",
    from_="pn_01jrzhe8d9enptypyx360pcmxm",
    body="Flash sale: 30% off everything this weekend. Shop at acme.com/sale",
    to=["+18015551234", "+18025551234", "+18035551234"],
)
```

```typescript TypeScript
import Surge from "@surgeapi/node";

const surge = new Surge();

const blast = await surge.blasts.create("{account_id}", {
  from: "pn_01jrzhe8d9enptypyx360pcmxm",
  body: "Flash sale: 30% off everything this weekend. Shop at acme.com/sale",
  to: ["+18015551234", "+18025551234", "+18035551234"],
});
```

```ruby Ruby
require "surge_api"

surge = SurgeAPI::Client.new

blast = surge.blasts.create(
  "{account_id}",
  from_: "pn_01jrzhe8d9enptypyx360pcmxm",
  body: "Flash sale: 30% off everything this weekend. Shop at acme.com/sale",
  to: ["+18015551234", "+18025551234", "+18035551234"]
)
```

```elixir Elixir
client = Surge.Client.new(System.get_env("SURGE_API_KEY"))

{:ok, blast} =
  Surge.Blasts.create(client, "{account_id}", %{
    from: "pn_01jrzhe8d9enptypyx360pcmxm",
    body: "Flash sale: 30% off everything this weekend. Shop at acme.com/sale",
    to: ["+18015551234", "+18025551234", "+18035551234"]
  })
```

```bash cURL
curl -X POST https://api.surge.app/accounts/{account_id}/blasts \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "pn_01jrzhe8d9enptypyx360pcmxm",
    "body": "Flash sale: 30% off everything this weekend. Shop at acme.com/sale",
    "to": ["+18015551234", "+18025551234", "+18035551234"]
  }'
```

</CodeGroup>

### Send to contacts

Pass contact IDs (with `ctc_` prefix) instead of phone numbers. This links the blast to your contact records for tracking and opt-out management.

<CodeGroup items={["Python","TypeScript","Ruby","Elixir","cURL"]}>

```python Python
blast = surge.blasts.create(
    account_id="{account_id}",
    from_="pn_01jrzhe8d9enptypyx360pcmxm",
    body="Your subscription renews tomorrow. Manage it at acme.com/account",
    to=[
        "ctc_01jrzhe8d9enptypyx360pcmxa",
        "ctc_01jrzhe8d9enptypyx360pcmxb",
        "ctc_01jrzhe8d9enptypyx360pcmxc",
    ],
)
```

```typescript TypeScript
const blast = await surge.blasts.create("{account_id}", {
  from: "pn_01jrzhe8d9enptypyx360pcmxm",
  body: "Your subscription renews tomorrow. Manage it at acme.com/account",
  to: [
    "ctc_01jrzhe8d9enptypyx360pcmxa",
    "ctc_01jrzhe8d9enptypyx360pcmxb",
    "ctc_01jrzhe8d9enptypyx360pcmxc",
  ],
});
```

```ruby Ruby
blast = surge.blasts.create(
  "{account_id}",
  from_: "pn_01jrzhe8d9enptypyx360pcmxm",
  body: "Your subscription renews tomorrow. Manage it at acme.com/account",
  to: [
    "ctc_01jrzhe8d9enptypyx360pcmxa",
    "ctc_01jrzhe8d9enptypyx360pcmxb",
    "ctc_01jrzhe8d9enptypyx360pcmxc"
  ]
)
```

```elixir Elixir
{:ok, blast} =
  Surge.Blasts.create(client, "{account_id}", %{
    from: "pn_01jrzhe8d9enptypyx360pcmxm",
    body: "Your subscription renews tomorrow. Manage it at acme.com/account",
    to: [
      "ctc_01jrzhe8d9enptypyx360pcmxa",
      "ctc_01jrzhe8d9enptypyx360pcmxb",
      "ctc_01jrzhe8d9enptypyx360pcmxc"
    ]
  })
```

```bash cURL
curl -X POST https://api.surge.app/accounts/{account_id}/blasts \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "pn_01jrzhe8d9enptypyx360pcmxm",
    "body": "Your subscription renews tomorrow. Manage it at acme.com/account",
    "to": [
      "ctc_01jrzhe8d9enptypyx360pcmxa",
      "ctc_01jrzhe8d9enptypyx360pcmxb",
      "ctc_01jrzhe8d9enptypyx360pcmxc"
    ]
  }'
```

</CodeGroup>

### Schedule a blast

Add `send_at` to queue the blast for a future time:

<CodeGroup items={["Python","TypeScript","Ruby","Elixir","cURL"]}>

```python Python
blast = surge.blasts.create(
    account_id="{account_id}",
    name="April sale launch",
    from_="pn_01jrzhe8d9enptypyx360pcmxm",
    body="Acme Corp: Our biggest sale of the year starts now. Shop: acme.com/spring",
    to=["+18015551234", "+18025551234", "+18035551234"],
    send_at="2026-06-01T09:00:00Z",
)
```

```typescript TypeScript
const blast = await surge.blasts.create("{account_id}", {
  name: "April sale launch",
  from: "pn_01jrzhe8d9enptypyx360pcmxm",
  body: "Acme Corp: Our biggest sale of the year starts now. Shop: acme.com/spring",
  to: ["+18015551234", "+18025551234", "+18035551234"],
  send_at: "2026-06-01T09:00:00Z",
});
```

```ruby Ruby
blast = surge.blasts.create(
  "{account_id}",
  name: "April sale launch",
  from_: "pn_01jrzhe8d9enptypyx360pcmxm",
  body: "Acme Corp: Our biggest sale of the year starts now. Shop: acme.com/spring",
  to: ["+18015551234", "+18025551234", "+18035551234"],
  send_at: "2026-06-01T09:00:00Z"
)
```

```elixir Elixir
{:ok, blast} =
  Surge.Blasts.create(client, "{account_id}", %{
    name: "April sale launch",
    from: "pn_01jrzhe8d9enptypyx360pcmxm",
    body: "Acme Corp: Our biggest sale of the year starts now. Shop: acme.com/spring",
    to: ["+18015551234", "+18025551234", "+18035551234"],
    send_at: "2026-06-01T09:00:00Z"
  })
```

```bash cURL
curl -X POST https://api.surge.app/accounts/{account_id}/blasts \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "April sale launch",
    "from": "pn_01jrzhe8d9enptypyx360pcmxm",
    "body": "Acme Corp: Our biggest sale of the year starts now. Shop: acme.com/spring",
    "to": ["+18015551234", "+18025551234", "+18035551234"],
    "send_at": "2026-06-01T09:00:00Z"
  }'
```

</CodeGroup>

---

## Audiences

### Create an audience

An audience is a named contact list. Create it first, then populate it.

<CodeGroup items={["Python","TypeScript","Ruby","Elixir","cURL"]}>

```python Python
audience = surge.audiences.create(
    account_id="{account_id}",
    name="Premium subscribers",
)
```

```typescript TypeScript
const audience = await surge.audiences.create("{account_id}", {
  name: "Premium subscribers",
});
```

```ruby Ruby
audience = surge.audiences.create(
  "{account_id}",
  name: "Premium subscribers"
)
```

```elixir Elixir
# Surge.Audiences isn't typed in the Elixir SDK yet — use the raw client.
{:ok, audience} =
  Surge.Client.request(client, :post, "/accounts/{account_id}/audiences",
    json: %{name: "Premium subscribers"}
  )
```

```bash cURL
curl -X POST https://api.surge.app/accounts/{account_id}/audiences \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Premium subscribers"
  }'
```

</CodeGroup>

```json
{
  "id": "aud_01jrzhe8d9enptypyx360pcmxz",
  "name": "Premium subscribers"
}
```

### Add contacts to the audience

<CodeGroup items={["Python","TypeScript","Ruby","Elixir","cURL"]}>

```python Python
surge.audiences.add_contact(
    audience_id="aud_01jrzhe8d9enptypyx360pcmxz",
    id="ctc_01jrzhe8d9enptypyx360pcmxa",
)
```

```typescript TypeScript
await surge.audiences.addContact("aud_01jrzhe8d9enptypyx360pcmxz", {
  id: "ctc_01jrzhe8d9enptypyx360pcmxa",
});
```

```ruby Ruby
surge.audiences.add_contact(
  "aud_01jrzhe8d9enptypyx360pcmxz",
  id: "ctc_01jrzhe8d9enptypyx360pcmxa"
)
```

```elixir Elixir
{:ok, _} =
  Surge.Client.request(client, :post,
    "/audiences/aud_01jrzhe8d9enptypyx360pcmxz/contacts",
    json: %{id: "ctc_01jrzhe8d9enptypyx360pcmxa"}
  )
```

```bash cURL
curl -X POST https://api.surge.app/audiences/aud_01jrzhe8d9enptypyx360pcmxz/contacts \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "ctc_01jrzhe8d9enptypyx360pcmxa"
  }'
```

</CodeGroup>

Repeat for each contact, or build this into the workflow that creates or updates contacts.

### Blast the audience

Pass the audience ID in the `to` array.

<Note>
Surge expands the audience at send time and applies opt-out status automatically — opted-out contacts are skipped, so you never need to filter the list yourself.
</Note>

<CodeGroup items={["Python","TypeScript","Ruby","Elixir","cURL"]}>

```python Python
blast = surge.blasts.create(
    account_id="{account_id}",
    from_="pn_01jrzhe8d9enptypyx360pcmxm",
    body="Your monthly update from Acme Corp: acme.com/newsletter/april",
    to=["aud_01jrzhe8d9enptypyx360pcmxz"],
)
```

```typescript TypeScript
const blast = await surge.blasts.create("{account_id}", {
  from: "pn_01jrzhe8d9enptypyx360pcmxm",
  body: "Your monthly update from Acme Corp: acme.com/newsletter/april",
  to: ["aud_01jrzhe8d9enptypyx360pcmxz"],
});
```

```ruby Ruby
blast = surge.blasts.create(
  "{account_id}",
  from_: "pn_01jrzhe8d9enptypyx360pcmxm",
  body: "Your monthly update from Acme Corp: acme.com/newsletter/april",
  to: ["aud_01jrzhe8d9enptypyx360pcmxz"]
)
```

```elixir Elixir
{:ok, blast} =
  Surge.Blasts.create(client, "{account_id}", %{
    from: "pn_01jrzhe8d9enptypyx360pcmxm",
    body: "Your monthly update from Acme Corp: acme.com/newsletter/april",
    to: ["aud_01jrzhe8d9enptypyx360pcmxz"]
  })
```

```bash cURL
curl -X POST https://api.surge.app/accounts/{account_id}/blasts \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "pn_01jrzhe8d9enptypyx360pcmxm",
    "body": "Your monthly update from Acme Corp: acme.com/newsletter/april",
    "to": ["aud_01jrzhe8d9enptypyx360pcmxz"]
  }'
```

</CodeGroup>

You can mix audience IDs, contact IDs, and raw phone numbers in the same `to` array.

---

## Volume caps

Campaign volume limits apply to all sends, including blasts:

| Campaign volume | T-Mobile limit |
|---|---|
| `low` | 2,000 SMS segments per day |
| `high` | Up to 200,000 segments per day (subject to TCR trust score) |

Surge queues messages within your daily cap and delivers them in order. If you regularly approach the `low` cap, request a volume increase through support after your campaign is approved.

---

## Tracking a blast

Blast-level delivery metrics (deliverability rate, opt-out rate) are available in the dashboard under the Blasts section. Per-message delivery status comes through the `message.sent`, `message.delivered`, and `message.failed` webhook events — see [Track Message Delivery](./track-delivery) for the full mechanism.
