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

# Sending SMS

> Send SMS campaigns to one or more recipients using the Phonovation SMS API.

## Send a campaign

Use `POST /api/v2/Campaign` to send a message to one or more recipients.

```mermaid title="Campaign processing flow" theme={"dark"}
flowchart LR
  Request["Campaign request"] --> Validate["Validate sender and recipients"]
  Validate --> Queue["Queue valid recipients"]
  Validate --> Errors["Return invalid recipients in errors"]
  Queue --> Webhook["Webhook: processing result"]
  Queue --> DLR["DLR: network delivery result"]
```

<CodeGroup>
  ```bash title="cURL" icon="terminal" highlight={2,6-8} wrap theme={"dark"}
  curl -X POST https://api.interactsms.com/api/v2/Campaign \
    -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "text": "Hello from Phonovation!",
      "from": "Phonovation",
      "recipientInfo": [
        { "msisdn": "353861234567" }
      ]
    }'
  ```

  ```python title="Python" icon="python" lines focus={4-15} theme={"dark"}
  import requests

  res = requests.post(
      "https://api.interactsms.com/api/v2/Campaign",
      headers={"Authorization": "Bearer YOUR_ACCESS_TOKEN"},
      json={
          "text": "Hello from Phonovation!",
          "from": "Phonovation",
          "recipientInfo": [
              {"msisdn": "353861234567"}
          ]
      }
  )

  print(res.json())
  ```

  ```csharp title="C#" icon="code" lines focus={8-19} theme={"dark"}
  using System.Net.Http.Headers;
  using System.Text;
  using System.Text.Json;

  using var client = new HttpClient();
  client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "YOUR_ACCESS_TOKEN");

  var campaign = new
  {
      text = "Hello from Phonovation!",
      from = "Phonovation",
      recipientInfo = new[] { new { msisdn = "353861234567" } }
  };

  var res = await client.PostAsync(
      "https://api.interactsms.com/api/v2/Campaign",
      new StringContent(JsonSerializer.Serialize(campaign), Encoding.UTF8, "application/json")
  );

  Console.WriteLine(await res.Content.ReadAsStringAsync());
  ```

  ```java title="Java" icon="java" lines focus={8-24} theme={"dark"}
  import java.net.URI;
  import java.net.http.HttpClient;
  import java.net.http.HttpRequest;
  import java.net.http.HttpResponse;

  String payload = """
  {
    "text": "Hello from Phonovation!",
    "from": "Phonovation",
    "recipientInfo": [
      { "msisdn": "353861234567" }
    ]
  }
  """;

  HttpRequest request = HttpRequest.newBuilder()
      .uri(URI.create("https://api.interactsms.com/api/v2/Campaign"))
      .header("Authorization", "Bearer YOUR_ACCESS_TOKEN")
      .header("Content-Type", "application/json")
      .POST(HttpRequest.BodyPublishers.ofString(payload))
      .build();

  HttpResponse<String> res = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
  System.out.println(res.body());
  ```

  ```php title="PHP" icon="php" lines focus={3-14} theme={"dark"}
  $client = new GuzzleHttp\Client();

  $res = $client->post('https://api.interactsms.com/api/v2/Campaign', [
      'headers' => ['Authorization' => 'Bearer YOUR_ACCESS_TOKEN'],
      'json' => [
          'text' => 'Hello from Phonovation!',
          'from' => 'Phonovation',
          'recipientInfo' => [
              ['msisdn' => '353861234567'],
          ],
      ],
  ]);

  echo $res->getBody();
  ```

  ```js title="JavaScript" icon="js" lines focus={1-14} theme={"dark"}
  const res = await fetch('https://api.interactsms.com/api/v2/Campaign', {
    method: 'POST',
    headers: {
      Authorization: 'Bearer YOUR_ACCESS_TOKEN',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      text: 'Hello from Phonovation!',
      from: 'Phonovation',
      recipientInfo: [{ msisdn: '353861234567' }]
    })
  });

  console.log(await res.json());
  ```
</CodeGroup>

**Response:**

```json title="Campaign response" icon="code" highlight={2,4} wrap theme={"dark"}
{
  "success": true,
  "message": "Campaign scheduled",
  "errors": []
}
```

## Multiple recipients

```json title="Multiple recipients payload" icon="code" highlight={5-6} wrap theme={"dark"}
{
  "text": "Your order is on the way!",
  "from": "Phonovation",
  "campaignName": "Order Notifications",
  "recipientInfo": [
    { "msisdn": "353861234567", "notifyId": "order-001" },
    { "msisdn": "353871234567", "notifyId": "order-002" }
  ]
}
```

The `notifyId` field is echoed back in webhooks and DLRs, letting you match every callback to the right record in your system. See [notifyId](/guides/notify-id) for use cases and full flow examples.

## Partial delivery

If a campaign contains a mix of valid and invalid numbers, **the valid numbers will still be sent to** — the request is not rejected as a whole. Invalid numbers are skipped and reported in the `errors` array of the response. Always check the response payload to identify any numbers that failed validation.

## Recipient limit

A single campaign request supports up to approximately **400,000 recipients**. For very large sends, split your audience into batches below this limit.

## Schedule for later

Add a `sendAt` timestamp (UTC) to schedule the campaign:

```json title="Scheduled campaign payload" icon="calendar" highlight={7} wrap theme={"dark"}
{
  "text": "Don't miss our sale tomorrow!",
  "from": "Phonovation",
  "recipientInfo": [
    { "msisdn": "353861234567" }
  ],
  "sendAt": "2030-06-01T09:00Z"
}
```

## Phone number format

| Format                  | Accepted                    |
| ----------------------- | --------------------------- |
| Irish with prefix       | `353871234567` ✓            |
| Irish with leading zero | `0871234567` ✓              |
| UK                      | `447911123456` ✓            |
| Other international     | Must include country code ✓ |

## Message length & credits

SMS messages are billed per **message part**. Understanding how parts work helps avoid unexpected credit usage.

### Standard GSM characters (recommended)

| Length        | Parts   |
| ------------- | ------- |
| 1–160 chars   | 1 part  |
| 161–306 chars | 2 parts |
| 307–459 chars | 3 parts |
| 460–612 chars | 4 parts |

Messages longer than 4 parts are not supported.

<Info>
  Long messages are delivered as a single seamless message on the recipient's device — they will not see separate parts.
</Info>

### Unicode characters

The API supports Unicode, which includes characters outside the standard GSM alphabet — accented characters (é, ü, ñ), non-Latin scripts, and emojis.

<Warning>
  **Unicode reduces the characters per part.** A standard SMS holds 160 GSM characters, but only **70 Unicode characters** per part. A short message with a single emoji can consume 2–4 credits.

  Additionally, some Unicode characters — particularly emojis — **may not display correctly** on all handsets. For reliable delivery, stick to standard GSM characters where possible.
</Warning>

## Sending hours

There are no system-enforced sending hour restrictions. However, you are responsible for adhering to Irish marketing regulations — see [Compliance](/guides/compliance) for details.

## Limits & billing

There are no rate limits on API calls themselves. Throughput is governed by:

* **Payload size** — very large batches may take longer to process
* **Account credits** — messages will not be sent if your account has insufficient credit
* **Billing tier** — contact [support@phonovation.com](mailto:support@phonovation.com) for details on your account limits
