# Getting Started

httpSMS is an open-source service that converts your Android phone into an SMS Gateway so you can send and receive SMS messages using an intuitive HTTP API with support for end-to-end encryption.

## Authentication

API requests to [httpSMS](https://httpsms.com/) are authenticated using API keys in the `x-api-key`  header. Any request that doesn't include an API key will return a  `401 (Unauthorized)` response.

You can get your API key from the dashboard at [https://httpsms.com/settings](https://httpsms.com/settings/)

## Install the Android App

To send and receive SMS messages using your android phone, you will need to [download and install our android app](https://github.com/NdoleStudio/httpsms/releases/latest/download/HttpSms.apk) on your phone so it can be triggered to send an SMS message when you make a request to the HTTP SMS API.&#x20;

Android App 👉 <https://github.com/NdoleStudio/httpsms/releases/latest/download/HttpSms.apk>

## Send an SMS

To send an SMS message using an android phone, send an authenticated `POST` request to the [`https://api.httpsms.com/v1/messages/send`](https://api.httpsms.com/v1/messages/send) endpoint.

## Send an SMS message

> Add a new SMS message to be sent by your Android phone

```json
{"openapi":"3.1.1","info":{"title":"httpSMS API Reference","version":"b45115e"},"servers":[{"url":"https://api.httpsms.com/v1"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","name":"x-api-Key","in":"header"}},"schemas":{"responses.MessageResponse":{"type":"object","required":["data","message","status"],"properties":{"data":{"$ref":"#/components/schemas/entities.Message"},"message":{"type":"string"},"status":{"type":"string"}}},"entities.Message":{"type":"object","required":["attachments","contact","content","created_at","encrypted","id","max_send_attempts","order_timestamp","owner","request_received_at","send_attempt_count","sim","status","type","updated_at","user_id"],"properties":{"attachments":{"type":"array","items":{"type":"string"}},"contact":{"type":"string"},"content":{"type":"string"},"created_at":{"type":"string"},"delivered_at":{"type":"string"},"encrypted":{"type":"boolean"},"expired_at":{"type":"string"},"failed_at":{"type":"string"},"failure_reason":{"type":"string"},"id":{"type":"string"},"last_attempted_at":{"type":"string"},"max_send_attempts":{"type":"integer"},"order_timestamp":{"type":"string"},"owner":{"type":"string"},"received_at":{"type":"string"},"request_id":{"type":"string"},"request_received_at":{"type":"string"},"scheduled_at":{"type":"string"},"scheduled_send_time":{"type":"string"},"send_attempt_count":{"type":"integer"},"send_time":{"description":"SendDuration is the number of nanoseconds from when the request was received until when the mobile phone send the message","type":"integer"},"sent_at":{"type":"string"},"sim":{"description":"SIM is the SIM card to use to send the message\n* SMS1: use the SIM card in slot 1\n* SMS2: use the SIM card in slot 2\n* DEFAULT: used the default communication SIM card","allOf":[{"$ref":"#/components/schemas/entities.SIM"}]},"status":{"type":"string"},"type":{"type":"string"},"updated_at":{"type":"string"},"user_id":{"type":"string"}}},"entities.SIM":{"type":"string","enum":["SIM1","SIM2"]},"responses.BadRequest":{"type":"object","required":["data","message","status"],"properties":{"data":{"type":"string"},"message":{"type":"string"},"status":{"type":"string"}}},"responses.Unauthorized":{"type":"object","required":["data","message","status"],"properties":{"data":{"type":"string"},"message":{"type":"string"},"status":{"type":"string"}}},"responses.UnprocessableEntity":{"type":"object","required":["data","message","status"],"properties":{"data":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}},"message":{"type":"string"},"status":{"type":"string"}}},"responses.InternalServerError":{"type":"object","required":["message","status"],"properties":{"message":{"type":"string"},"status":{"type":"string"}}},"requests.MessageSend":{"type":"object","required":["content","from","to"],"properties":{"attachments":{"description":"Attachments are optional. When you provide a list of attachments, the message will be sent out as an MMS","type":"array","items":{"type":"string"}},"content":{"type":"string"},"encrypted":{"description":"Encrypted is an optional parameter used to determine if the content is end-to-end encrypted. Make sure to set the encryption key on the httpSMS mobile app","type":"boolean"},"from":{"type":"string"},"request_id":{"description":"RequestID is an optional parameter used to track a request from the client's perspective","type":"string"},"send_at":{"description":"SendAt is an optional parameter used to schedule a message to be sent in the future. The time is considered to be in your profile's local timezone and you can queue messages for up to 20 days (480 hours) in the future.","type":"string"},"to":{"type":"string"}}}}},"paths":{"/messages/send":{"post":{"description":"Add a new SMS message to be sent by your Android phone","tags":["Messages"],"summary":"Send an SMS message","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/responses.MessageResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/responses.BadRequest"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/responses.Unauthorized"}}}},"422":{"description":"Unprocessable Entity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/responses.UnprocessableEntity"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/responses.InternalServerError"}}}}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/requests.MessageSend"}}},"description":"Send message request payload","required":true}}}}}
```

You can also use the code samples below to send an SMS message using our API on your favorite programing language.

{% tabs %}
{% tab title="PHP" %}

```php
// initialize guzzle client https://github.com/guzzle/guzzle
$client = new GuzzleHttp\Client();

$apiKey = "Get API Key from https://httpsms.com/settings";

$res = $client->request('POST', 'https://api.httpsms.com/v1/messages/send', [
  'headers' => [
    'x-api-key' => $apiKey,
  ],
  'json'    => [
    'content' => 'This is a sample text message',
    'from'    => "+18005550199",
    'to'      => '+18005550100'
  ]
]);

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

{% endtab %}

{% tab title="Javascript" %}

```javascript
let apiKey = "Get API Key from https://httpsms.com/settings";

fetch('https://api.httpsms.com/v1/messages/send', {
    method: 'POST',
    headers: {
        'x-api-key': apiKey,
        'Accept': 'application/json',
        'Content-Type': 'application/json'
    },
    body: JSON.stringify({
        "content": "This is a sample text message",
        "from": "+18005550199",
        "to": "+18005550100"
    })
})
.then(res => res.json())
.then((data) => console.log(data));
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
import json

api_key = "Get API Key from https://httpsms.com/settings"

url = 'https://api.httpsms.com/v1/messages/send'

headers = {
    'x-api-key': api_key,
    'Accept': 'application/json',
    'Content-Type': 'application/json'
}

payload = {
    "content": "This is a sample text message",
    "from": "+18005550199",
    "to": "+18005550100"
}

response = requests.post(url, headers=headers, data=json.dumps(payload))

print(response.json())
```

{% endtab %}

{% tab title="curl" %}

```bash
curl --location --request POST 'https://api.httpsms.com/v1/messages/send' \
--header 'x-api-key: Get API Key from https://httpsms.com/settings' \
--header 'Content-Type: application/json' \
--data-raw '{
    "from": "+18005550199",
    "to": "+18005550100",
    "content": "This is a sample text message"
}'
```

{% endtab %}

{% tab title="Go" %}

```go
import "github.com/NdoleStudio/httpsms-go"

client := htpsms.New(htpsms.WithAPIKey(/* API Key from https://httpsms.com/settings */))

client.Messages.Send(context.Background(), &httpsms.MessageSendParams{
    Content: "This is a sample text message",
    From:    "+18005550199",
    To:      "+18005550100",
})
```

{% endtab %}

{% tab title="c-sharp" %}

```csharp
var client = new HttpClient();
client.DefaultRequestHeaders.Add("x-api-key", ""/* Get API Key from https://httpsms.com/settings */);

var response = await client.PostAsync(
    "https://api.httpsms.com/v1/messages/send",
    new StringContent(
        JsonSerializer.Serialize(new {
            from = "+18005550199",
            To = "+18005550100",
            Content = "This is a sample text message",
        }),
        Encoding.UTF8,
        "application/json"
    )
);

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

{% endtab %}

{% tab title="Java" %}

```java
var client = HttpClient.newHttpClient();

var apiKey = "Get API Key from https://httpsms.com/settings";

JSONObject request = new JSONObject();
request.put("content", "This is a sample text message");
request.put("from", "+18005550199")
request.put("to", "+18005550100")

// create a request
var request = HttpRequest.newBuilder()
  .uri(URI.create("https://api.httpsms.com/v1/messages/send"))
  .header("accept", "application/json")
  .header("x-api-key", apiKey)
  .setEntity(new StringEntity(request.toString()))
  .POST()
  .build();

// use the client to send the request
var response = client.send(request, new JsonBodyHandler<>(APOD.class));

// the response:
System.out.println(response.body().get());
```

{% endtab %}
{% endtabs %}

## Install

The best way to interact with the httpSMS API is by using one of our official SDK client libraries:

{% tabs %}
{% tab title="JavaScript" %}

```bash
npm install httpsms
# or
yarn install httpsms
```

{% endtab %}

{% tab title="Go" %}

```bash
# install the go package using the "go get" command
go get github.com/NdoleStudio/httpsms-go
```

{% endtab %}
{% endtabs %}


# Introduction

httpSMS uses webhooks to push real-time notifications to your application about SMS events for example when an SMS is received by your Android you will get a notification about this event.

## Creating Webhooks

You will need the following to receive webhooks with httpSMS.

1. **Callback URL** - httpSMS will send a `POST` to this URL every time an event is triggered. This&#x20;
2. **Signing Key** - When httpSMS sends a `POST` request to your endpoint, you can use the signing key to verify that the request is actually coming from the httpSMS server. The signing key is a random string that will be used to create a [JWT auth token](https://jwt.io/introduction).
3. **Events** - This is the list of httpSMS events that will be forwarded to your callback URL. We support only the following events at the moment
   * `message.phone.received` - This event is emitted when your Android phone receives a new SMS
   * `message.phone.sent` - This event is emitted when the httpSMS app on your phone sends out an SMS.
   * `message.phone.delivered` - This event is emitted when an SMS is delivered to the recipient's phone.
   * `message.send.failed` - This event is emitted when an SMS fails to be sent out by your Android phone
   * `message.send.expired` - This event is emitted when an SMS expires before being sent out by your Android phone.
   * `message.send.expired` - This event is emitted when an SMS expires before being sent out by your Android phone.
   * `message.call.missed` - This event is emitted when your Android phone receives a missed phone call.
   * `phone.heartbeat.offline` - This event is emitted when the httpSMS server did not get a heartbeat (ping) from your Android phone in the last 1 hour.
   * `phone.heartbeat.online` - This event is emitted when the httpSMS server receives a heartbeat (ping) from your Android phone after it was previously offline.
4. **Phone Numbers**  - This is the list of phone numbers whose events you want to listen to. You can have multiple phone numbers on your account but you can also configure the webhook to listen to events only for a subset of your phone numbers.

{% hint style="info" %}
Webhooks can be set up and managed from [Settings > Webhooks](https://httpsms.com/settings#webhooks)[ ](https://httpsms.com/settings)in your httpSMS dashboard or programmatically [using the httpSMS API](https://api.httpsms.com/index.html#/Webhooks/post_webhooks).
{% endhint %}

<figure><img src="/files/ZuThtEGxPWmJlWVUDSIk" alt="Add an httpSMS webhook"><figcaption></figcaption></figure>

## Webhook Request

When a webhook event occurs in httpSMS, a `POST` request will be sent to your configured `callbackURL`.

Each webhook request from httpSMS has a timeout of `5` seconds so ensure that you can process webhook requests as fast as possible. Return a `200` response code to show that the webhook event was processed successfully.&#x20;

If your server responds with a `5XX` status code, the webhook request will be retried a maximum of 4 times with at least a 1 second delay between each retry.

### Webhook Request Headers

Each webhook request from httpSMS will contain the following headers

* `X-Event-Type` - This is the name of the event. e.g in the case of a message received on the Android phone, the X-Event-Type will be \``message.phone.received`
* `Authorization` - Every webhook request made by httpSMS will contain a JWT Bearer token signed with the `HS256` algorithm and the signing key which you set when you created the webhook. We recommend you use a popular [JWT  library](https://jwt.io/libraries) to validate this token.
* `Content-Type` - This will always be `application/json`

### Webhook Request Body

httpSMS uses [CloudEvents ](https://cloudevents.io/)internally so every webhook request payload will be a valid cloud event serialized as JSON. You can use a popular [cloudevent SDK](https://github.com/cloudevents/spec#sdks) to validate and process the webhook request payload. You can see the list of [webhook events with their payload on the Events page](/webhooks/events).

### Recipes

We have written sample code to receive webhook events on your server on popular programing languages and frameworks, you can copy and inspect the code for your inspiration from GitHub.

<table><thead><tr><th width="156">Framework</th><th>Code</th></tr></thead><tbody><tr><td>Laravel - PHP</td><td><a href="https://github.com/NdoleStudio/httpsms-recipes/tree/main/laravel">https://github.com/NdoleStudio/httpsms-recipes/tree/main/laravel</a></td></tr><tr><td>Express - JS</td><td><a href="https://github.com/NdoleStudio/httpsms-recipes/tree/main/express">https://github.com/NdoleStudio/httpsms-recipes/tree/main/express</a></td></tr></tbody></table>


# Events

List of supported httpSMS webhook events with the request payload.

## `message.phone.received`&#x20;

This event is emitted when your Android phone receives a new SMS. It contains the SMS sender and recipient address together with the content of the SMS.

```json
{
    "data": {
        "contact": "+18005550100",
        "content": "This is a test incoming message",
        "message_id": "0b0123bb-ef2e-468f-908a-c026d51636aa",
        "owner": "+18005550199",
        "sim": "SIM1",
        "timestamp": "2023-06-29T03:21:19.814Z",
        "user_id": "XtABz6zdeFMoBLoltz6SREDvRSh2"
    },
    "datacontenttype": "application/json",
    "id": "f4aed1d3-ab4f-42b9-b9dd-9fc7182f7197",
    "source": "/v1/messages/receive",
    "specversion": "1.0",
    "time": "2023-06-29T03:21:19.524331882Z",
    "type": "message.phone.received"
}
```

***

## `message.phone.sent`

&#x20;This event is emitted when the httpSMS app on your Android phone sends out an SMS.

```json
{
    "data": {
        "contact": "+18005550100",
        "content": "This is a test outgoing message",
        "id": "ff313c14-17a3-4f74-bcb2-ca77213a64af",
        "owner": "+18005550100",
        "request_id": "optional request id",
        "sim": "SIM1",
        "timestamp": "2023-07-17T19:05:45.166Z",
        "user_id": "TcZ3PaOieTexxXJKAQJWO8rr1Mv1"
    },
    "datacontenttype": "application/json",
    "id": "cf241cb9-0762-43d0-8b74-4f763f788c93",
    "source": "/v1/messages/ff313c14-17a3-4f74-bcb2-ca77213a64af/events",
    "specversion": "1.0",
    "time": "2023-07-17T19:05:45.877240866Z",
    "type": "message.phone.sent"
}
```

***

## `message.phone.delivered`

This event is emitted when an SMS is delivered to the recipient's phone.

```json
{
    "data": {
        "contact": "+18005550100",
        "content": "This is a sample outgoing message",
        "id": "5be8f09e-7007-4fe9-86b6-591d63fd38ad",
        "owner": "+18005550100",
        "request_id": null,
        "sim": "SIM2",
        "timestamp": "2023-07-17T18:54:22.262Z",
        "user_id": "XtABz6zdeFMoBLoltz6SREDvRSh2"
    },
    "datacontenttype": "application/json",
    "id": "f4b86c6d-8c90-4ba7-a599-516a27f1a1e9",
    "source": "/v1/messages/5be8f09e-7007-4fe9-86b6-591d63fd38ad/events",
    "specversion": "1.0",
    "time": "2023-07-17T18:54:20.012355134Z",
    "type": "message.phone.delivered"
}
```

***

## `message.send.failed`

This event is emitted when an SMS fails to be sent out by the httpSMS app on your Android phone

```json
{
    "data": {
        "contact": "+18005550100",
        "content": "This is a sample outgoing message",
        "error_message": "MOBILE_APP_INACTIVE",
        "id": "508d783f-df33-4eaf-85e8-0fcab9958654",
        "owner": "+18005550100",
        "request_id": null,
        "sim": "SIM2",
        "timestamp": "2023-07-17T18:56:01.218Z",
        "user_id": "XtABz6zdeFMoBLoltz6SREDvRSh2"
    },
    "datacontenttype": "application/json",
    "id": "d69c96fb-9f46-498b-811d-3adfb785e439",
    "source": "/v1/messages/508d783f-df33-4eaf-85e8-0fcab9958654/events",
    "specversion": "1.0",
    "time": "2023-07-17T18:55:58.979647773Z",
    "type": "message.send.failed"
}
```

***

## `message.send.expired`

This event is emitted when an SMS expires before being sent out by your Android phone. It can happen in cases where your Android phone is powered off.

```json
{
    "data": {
        "contact": "+18005550100",
        "content": "This is a sample outgoing message",
        "is_final": true,
        "message_id": "ff313c14-17a3-4f74-bcb2-ca77213a64af",
        "owner": "+18005550100",
        "send_attempt_count": 2,
        "request_id": null,
        "sim": "SIM1",
        "timestamp": "2023-07-17T19:10:43.461254738Z",
        "user_id": "XtABz6zdeFMoBLoltz6SREDvRSh2"
    },
    "datacontenttype": "application/json",
    "id": "8f5a9eaf-c495-4487-b11c-1824b8df6da2",
    "source": "/v1/messages/send",
    "specversion": "1.0",
    "time": "2023-07-17T19:10:43.461263458Z",
    "type": "message.send.expired"
}
```

***

## `phone.heartbeat.offline`

This event is emitted when the httpSMS server didn't get a ping (heartbeat) from the phone in the past 1 hour. The httpSMS app on your android phone sends a ping to the server ever 15 minutes. If the server doesn't receive a heartbeat event in a 1 hour interval, then your phone is considered to be offline.

```json
{
    "data": {
        "phone_id": "ff313c14-17a3-4f74-bcb2-ca77213a64af",
        "monitor_id": "ff313c14-17a3-4f74-bcb2-ca77213a64af",
        "owner": "+18005550100",
        "last_heartbeat_timestamp": "2023-07-17T19:10:43.461254738Z",
        "timestamp": "2023-07-17T20:20:23.461254738Z",
        "user_id": "XtABz6zdeFMoBLoltz6SREDvRSh2"
    },
    "datacontenttype": "application/json",
    "id": "8f5a9eaf-c495-4487-b11c-1824b8df6da2",
    "source": "/v1/messages/send",
    "specversion": "1.0",
    "time": "2023-07-17T19:10:43.461263458Z",
    "type": "phone.heartbeat.offline"
}
```

***

## `phone.heartbeat.online`

This event is emitted when the httpSMS server receives a heartbeat (ping) from your Android phone after it was previously offline.

```json
{
    "data": {
        "phone_id": "ff313c14-17a3-4f74-bcb2-ca77213a64af",
        "monitor_id": "ff313c14-17a3-4f74-bcb2-ca77213a64af",
        "owner": "+18005550100",
        "last_heartbeat_timestamp": "2023-07-17T19:10:43.461254738Z",
        "timestamp": "2023-07-17T20:20:23.461254738Z",
        "user_id": "XtABz6zdeFMoBLoltz6SREDvRSh2"
    },
    "datacontenttype": "application/json",
    "id": "8f5a9eaf-c495-4487-b11c-1824b8df6da2",
    "source": "/v1/messages/send",
    "specversion": "1.0",
    "time": "2023-07-17T19:10:43.461263458Z",
    "type": "phone.heartbeat.online"
}
```

***

## `message.call.missed`

This event is emitted when your Android phone receives a missed phone call. You can use this event to trigger some automation e.g You may want to reply that the phone number is used sending SMS messages and they shouldn't call the phone number.

```json
{
    "data": {
        "contact": "+18005550199",
        "message_id": "682a47cd-adfd-4b5c-b4f2-65302746ac52",
        "owner": "+18005550100",
        "sim": "SIM1",
        "timestamp": "2022-06-05T14:26:09.527976+03:00",
        "user_id": "XtABz6zdeFMoBLoltz6SREDvRSh2"
    },
    "datacontenttype": "application/json",
    "id": "f39d4b09-e2b7-42e2-b08f-d45820a18b05",
    "source": "/v1/messages/calls/missed",
    "specversion": "1.0",
    "time": "2024-04-14T17:48:35.3664741Z",
    "type": "message.call.missed"
}
```


# Phone API Keys

Manage multiple Android phones under one httpSMS account by creating unique API keys per phone.

If you have multiple phones, you can create a unique phone API key for your Android phones. These API keys can only be used on the httpSMS app on your Android phone so it can send heartbeats, register received messages and register sent, failed and SMS delivered events.

{% hint style="info" %}
These phone API keys should only be used on the httpSMS Android app. If you want to interact with the full [httpSMS API](https://api.httpsms.com/index.html)  use the API key under your account settings page instead <https://httpsms.com/settings>
{% endhint %}

## Create a phone API key

You can create a unique API key for your phone using this link <https://httpsms.com/phone-api-keys> and click on the blue `CREATE API KEY` button.

<figure><img src="/files/hDQcSRZtR14KChxnRxi3" alt=""><figcaption><p>Phone API Keys</p></figcaption></figure>

After creating the phone API key you can click on the blue `VIEW` button to see the API key and you will also get a QR code which you can scan using the httpSMS android app to login.

{% hint style="info" %}
[Download and install ](https://apk.httpsms.com/HttpSms.apk)the latest version of the httpSMS Android app before using the phone API key to login.
{% endhint %}

### Remove phone from phone API key

A phone number on your account can only be associated to 1 api key at a time. When you login to the Android app using an API key, the httpSMS system will automatically remove the association between the phone number and previous phone API keys.

You can also manually remove the association between a phone number and an API key by clicking the `REMOVE` button beside the phone number. Note that when you remove a phone number from a phone API key you will need to logout of the httpSMS android app and login again.

### Delete phone API key

You can also delete a phone API key bu clicking the `DELETE` button as shown in the screenshot above.&#x20;

{% hint style="info" %}
After deleting a phone API key, you will need to logout of the httpSMS Android app and login again with a new API key for the app to function properly
{% endhint %}


# Control SMS Send Rate

Whether you're sending hundreds or thousands of messages, our intelligent queue system ensures reliable delivery at your chosen pace.

The httpSMS application allows you to apply backpressure and send out SMS messages at a predictable rate which is configurable under the application settings. This means for example if you set the rate at 10 SMS per minute it means the httpSMS application will send out 1 SMS every 10 seconds since there are 60 seconds in 1 minute.

### Modify SMS per minute send rate

To modify the rate of sending SMS messages per phone number under the settings page [https://httpsms.com/settings](https://httpsms.com/settings#phones) and tap on the "**EDIT**" button on the phone number and you will be able to update the **"Messages Per Minute".** By default, when you register a new Android Phone on the httpSMS app, the SMS send rate is 10 SMS per minute but you can increase this up to 29 SMS per minute which is the [maximum permitted by an unrooted android phone](https://android.googlesource.com/platform/frameworks/opt/telephony/+/master/src/java/com/android/internal/telephony/SmsUsageMonitor.java#84).

<figure><img src="/files/fYGVfgTmxaQlOkZCbfgh" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
The **Messages Per Minute** setting affects single SMS messages sent via the API and [bulk SMS messages](https://httpsms.com/blog/how-to-send-sms-messages-from-excel) sent by uploading an excel file.
{% endhint %}


# Scheduling SMS Messages

Complete guide on scheduling SMS messages to be sent in the future on the httpSMS platform

With scheduled text messages, you can gain greater control over when your messages will reach your recipients, allowing you to perfectly time promotions, critical alerts, or follow-ups to hit your recipients' phones at the ideal moment.

{% hint style="info" %}
You can schedule messages to be sent up to 20 days (480 hours) in the future.&#x20;
{% endhint %}

## Scheduling Messages with the httpSMS API&#x20;

When sending messages with the httpSMS API you can use the optional `send_at` parameter to schedule the SMS to be sent at a future time and date. Send the time in the [RFC 3389 format](https://datatracker.ietf.org/doc/html/rfc3339) which also includes the time zone e.g.  `1996-12-19T16:39:57-08:00`

```bash
curl -L \
  --request POST \
  --url 'https://api.httpsms.com/v1/messages/send' \
  --header 'Content-Type: application/json' \
  --header 'x-api-Key: YOUR_API_KEY' \
  --data '{
    "from": "+18005550199",
    "to": "+18005550100",
    "content": "Scheduling a text message in the future",
    "send_at": "2025-12-19T16:39:57-08:00"
  }'
```

## Scheduling bulk messages with Excel

When ending [bulk messages on httpSMS](https://httpsms.com/bulk-messages), you can use the optional `SendTime(optional)` column in the [excel template](https://httpsms.com/templates/httpsms-bulk.xlsx) to set the time when the SMS message will be sent out. \
\
When using excel, set the time in your local time zone in the following format `YYYY-MM-DDTHH:MM:SS` e.g. you can set the time like this `2023-11-13T02:10:01`&#x20;

<figure><img src="/files/w7PGiIuwxXMZ5DBcdGct" alt=""><figcaption></figcaption></figure>


# Outgoing Message Queue

Complete guide on how httpSMS queues outgoing SMS messages for reliable delivery, including rate-based dispatch, scheduled sending, and send schedule windows.

### How the Message Queue Works

When you send an SMS through **httpSMS** (via the API, bulk send, or Excel upload), messages don't go directly to your Android phone. Instead, they enter an **outgoing message queue** that intelligently schedules delivery to ensure reliability and prevent carrier throttling.

The queue determines **when** each message is dispatched to your phone based on three factors:

1. **Explicit send time:** If you specify a `send_at` time, the message is sent at exactly that time
2. **Rate-based dispatch delay:** Messages without a send time are spaced out based on your configured send rate
3. **Send schedule window:** Messages can be held until your configured active hours (if enabled)

### 1. Explicit Send Time (Bypass Queue Logic)

When you specify a `send_at` time in your API request or a `SendTime` column in your Excel upload, the message **bypasses** both rate-limiting and schedule window logic entirely. The message will be dispatched to your phone at exactly the time you specified.

This is ideal for:

* Time-sensitive alerts that must go out at a precise moment
* Promotional messages timed for a specific campaign window
* Appointment reminders scheduled for a specific time before the appointment

#### Sending a single message at a specific time

```bash
curl -L \
  --request POST \
  --url 'https://api.httpsms.com/v1/messages/send' \
  --header 'Content-Type: application/json' \
  --header 'x-api-Key: YOUR_API_KEY' \
  --data '{
    "from": "+18005550199",
    "to": "+18005550100",
    "content": "Your appointment is in 1 hour",
    "send_at": "2025-12-19T16:39:57-08:00"
  }'
```

The `send_at` field accepts time in [RFC 3339 format](https://datatracker.ietf.org/doc/html/rfc3339) which includes the time zone (e.g., `1996-12-19T16:39:57-08:00`). You can schedule messages up to 20 days (480 hours) in the future.

{% hint style="info" %}
&#x20;If you specify a `send_at` time that is in the past, the message will be sent immediately.
{% endhint %}

#### Setting send time in bulk Excel uploads

When using the [bulk messages Excel template](https://httpsms.com/templates/httpsms-bulk.xlsx), you can set the optional `SendTime(optional)` column to specify when each message should be sent. Use the format `YYYY-MM-DDTHH:MM:SS` in your local time zone (e.g., `2023-11-13T02:10:01`).

Each row with a `SendTime` value will be dispatched at exactly that time, independent of other messages in the batch.

### 2. Rate-Based Dispatch Delay

When you send messages **without** a `send_at` time (especially in bulk), httpSMS automatically spaces out delivery based on your phone's configured **Messages Per Minute** rate. This prevents carrier throttling and ensures reliable delivery.

#### How rate-based dispatch works

The system calculates a dispatch delay for each message based on its position in the batch:

```
interval = 60 seconds ÷ messages_per_minute
delay    = message_index × interval
```

**Example:** If your phone is configured for 10 messages per minute:

| Message | Index | Delay | Dispatched At |
| ------- | ----- | ----- | ------------- |
| 1st     | 0     | 0s    | Immediately   |
| 2nd     | 1     | 6s    | +6 seconds    |
| 3rd     | 2     | 12s   | +12 seconds   |
| 4th     | 3     | 18s   | +18 seconds   |
| 10th    | 9     | 54s   | +54 seconds   |

This ensures your phone sends at most 10 SMS per minute, matching the configured rate.

#### Per-phone indexing for bulk sends

When sending bulk messages to multiple recipients from the same phone number, the index is calculated per phone. This means messages to different recipient numbers are all spaced according to the sending phone's rate, ensuring the sending phone isn't overwhelmed.

When using Excel/CSV uploads with multiple sender phones (different `From` numbers), each phone gets its own independent index counter. Messages from Phone A don't affect the timing of messages from Phone B.

#### Configuring Messages Per Minute

To modify the send rate for your phone number:

1. Go to [https://httpsms.com/settings](https://httpsms.com/settings#phones)
2. Tap the **"EDIT"** button on the phone number
3. Update the **"Messages Per Minute"** value

**Default:** 10 messages per minute for newly registered phones.

**Maximum:** 29 messages per minute (the [maximum permitted by an unrooted Android phone](https://android.googlesource.com/platform/frameworks/opt/telephony/+/master/src/java/com/android/internal/telephony/SmsUsageMonitor.java#84)).

{% hint style="info" %}
If you're sending large batches, a lower rate (5-10/min) is more reliable. Higher rates (20+/min) may trigger carrier spam filters depending on your region.
{% endhint %}

### 3. Send Schedule Window

The send schedule window allows you to restrict message delivery to specific hours of the day. When enabled, messages sent outside the configured window are held in the queue and dispatched when the next window opens.

This is useful for:

* Respecting recipient quiet hours (no messages at 3 AM)
* Complying with regional messaging regulations
* Concentrating delivery during business hours

{% hint style="info" %}
Messages with an explicit `send_at` time bypass the send schedule window entirely. Only messages without a specified send time are subject to window restrictions.
{% endhint %}

#### Configuring the Send Schedule

You can configure the send schedule window for each phone number in your account settings at [https://httpsms.com/settings](https://httpsms.com/settings#phones). Click **"EDIT"** on the phone number and set:

* **Schedule Active** — Enable or disable the schedule window
* **Start Time** — The time of day when sending begins (e.g., `08:00`)
* **End Time** — The time of day when sending stops (e.g., `21:00`)
* **Timezone** — The timezone for the schedule (e.g., `America/New_York`)

#### How the schedule window works

| Current Time vs Window | Behavior                                               |
| ---------------------- | ------------------------------------------------------ |
| Within window          | Message dispatched immediately (subject to rate delay) |
| Before window opens    | Message held until window start time                   |
| After window closes    | Message held until next day's window start time        |

### Bulk Send via API

When sending to multiple recipients using the bulk API endpoint, all messages are automatically queued with rate-based dispatch delays:

```bash
curl -L \
  --request POST \
  --url 'https://api.httpsms.com/v1/messages/bulk-send' \
  --header 'Content-Type: application/json' \
  --header 'x-api-Key: YOUR_API_KEY' \
  --data '{
    "from": "+18005550199",
    "to": ["+18005550100", "+18005550101", "+18005550102"],
    "content": "Hello from httpSMS!"
  }'
```

In this example, with a default rate of 10 messages/minute:

* Message to `+18005550100` → sent immediately
* Message to `+18005550101` → sent after 6 seconds
* Message to `+18005550102` → sent after 12 seconds

### Summary: Queue Decision Flow

```mermaid
flowchart TD
     A[Message received by httpSMS API] --> B{Has explicit send_at time?}
     B -->|YES| C[Dispatch at exactly that time]
     C --> D[Bypasses rate-limit AND schedule window]
     B -->|NO| E[Calculate rate-based delay]
     E --> F["delay = index × (60s ÷ messages_per_minute)"]
     F --> G{Send schedule window enabled?}
     G -->|YES| H{Within active window?}
     G -->|NO| I[Dispatch with rate delay only]
     H -->|YES| I
     H -->|NO| J[Hold until window opens]
     J --> I
 
     classDef terminal fill:#22c55e,stroke:#16a34a,color:#fff
     class D,I terminal
```

### Key Points

* **Explicit send time always wins** — Setting `send_at` bypasses all queue logic
* **Rate limiting prevents throttling** — Messages are spaced based on your configured rate
* **Schedule windows respect quiet hours** — Messages without a send time are held until the window opens
* **Per-phone independence** — Each sending phone has its own rate counter and schedule
* **Past send times are handled gracefully** — If `send_at` is in the past, the message sends immediately


