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

# Send an SMS

> Send transactional SMS messages to Mozambican numbers with Torpedo

## Requirements

* An active paid plan and SMS credits
* SMS credits in your workspace (purchase from the billing page)
* SMPP must be enabled on your Torpedo instance

***

## Basic send

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.torpedo.co.mz/api/v1/sms \
    -H "X-API-Key: YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "to": "+258841234567",
      "body": "Your verification code is 482910. Expires in 10 minutes."
    }'
  ```

  ```js Node.js theme={null}
  const res = await fetch('https://api.torpedo.co.mz/api/v1/sms', {
    method: 'POST',
    headers: {
      'X-API-Key': process.env.TORPEDO_API_KEY,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      to: '+258841234567',
      body: 'Your verification code is 482910. Expires in 10 minutes.',
    }),
  })
  const { data } = await res.json()
  console.log(data.id) // message ID
  console.log(data.status) // 'queued'
  ```

  ```python Python theme={null}
  import httpx

  res = httpx.post(
      'https://api.torpedo.co.mz/api/v1/sms',
      headers={'X-API-Key': TORPEDO_API_KEY},
      json={
          'to': '+258841234567',
          'body': 'Your verification code is 482910. Expires in 10 minutes.',
      },
  )
  data = res.json()['data']
  print(data['id'], data['status'])  # queued
  ```

  ```go Go theme={null}
  package main

  import (
  	"bytes"
  	"encoding/json"
  	"fmt"
  	"net/http"
  	"os"
  )

  func main() {
  	payload, _ := json.Marshal(map[string]string{
  		"to":   "+258841234567",
  		"body": "Your verification code is 482910. Expires in 10 minutes.",
  	})

  	req, _ := http.NewRequest("POST", "https://api.torpedo.co.mz/api/v1/sms", bytes.NewBuffer(payload))
  	req.Header.Set("X-API-Key", os.Getenv("TORPEDO_API_KEY"))
  	req.Header.Set("Content-Type", "application/json")

  	resp, _ := http.DefaultClient.Do(req)
  	defer resp.Body.Close()
  	fmt.Println(resp.Status)
  }
  ```

  ```java Java theme={null}
  import java.net.http.*;
  import java.net.URI;

  var body = """
      {"to":"+258841234567","body":"Your verification code is 482910. Expires in 10 minutes."}""";

  var request = HttpRequest.newBuilder()
      .uri(URI.create("https://api.torpedo.co.mz/api/v1/sms"))
      .header("X-API-Key", System.getenv("TORPEDO_API_KEY"))
      .header("Content-Type", "application/json")
      .POST(HttpRequest.BodyPublishers.ofString(body))
      .build();

  var response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
  System.out.println(response.body());
  ```

  ```csharp C# theme={null}
  using var client = new HttpClient();
  client.DefaultRequestHeaders.Add("X-API-Key", Environment.GetEnvironmentVariable("TORPEDO_API_KEY"));

  var payload = new { to = "+258841234567", body = "Your verification code is 482910. Expires in 10 minutes." };
  var response = await client.PostAsJsonAsync("https://api.torpedo.co.mz/api/v1/sms", payload);
  Console.WriteLine(await response.Content.ReadAsStringAsync());
  ```
</CodeGroup>

The response is `202 Accepted` — delivery is asynchronous.

***

## Phone number format

The `to` field must be a valid Mozambican mobile number in E.164 format:

```
+258 8X XXXXXXX
```

Accepted prefixes: `84`, `82`, `83`, `85`, `86`, `87` (Vodacom, Movitel, tmcel).

```json theme={null}
{ "to": "+258841234567" }  ✓
{ "to": "841234567" }      ✗  missing country code
{ "to": "+1234567890" }    ✗  not a Mozambican number
```

## SMS status lifecycle

```
queued → sent → delivered
              ↘ failed
```

Poll `GET /api/v1/sms/{id}` to check the current status.

***

## Idempotency

Pass an `Idempotency-Key` header to prevent duplicate sends on retries:

```bash theme={null}
curl -X POST https://api.torpedo.co.mz/api/v1/sms \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Idempotency-Key: order-789-sms-confirmation" \
  -H "Content-Type: application/json" \
  -d '{ "to": "+258841234567", "body": "Your order has shipped." }'
```

If a request with the same key was already accepted, Torpedo returns the original `202` without sending again. Keys are scoped to your workspace.

***

## Credits and quota

Each SMS deducts one credit from your workspace balance. If your balance reaches zero, sends return `402`:

```json theme={null}
{
  "errors": [{ "message": "No SMS credits remaining. Contact support to top up." }]
}
```

Purchase additional credits from the billing page in your dashboard.

***

## Suppression

Addresses that permanently fail delivery (`UNDELIV`, `REJECTD` SMPP error codes) are automatically added to the suppression list. Sending to a suppressed number returns `422`:

```json theme={null}
{
  "errors": [{ "message": "Recipient '+258841234567' is suppressed (reason: hard_bounce)" }]
}
```

Remove an address from the suppression list via `DELETE /api/v1/suppressions/{address}?channel=sms`.
