# HTTP Specification

The SMS HTTP specification defines how to exchange SMS messages with DIDWW over HTTP. It includes information about
inbound SMS delivery to your systems and outbound SMS submission to the DIDWW network, covering request formats,
authentication, failover handling, and callback mechanisms.

**Inbound SMS Specification**

Technical details for receiving inbound SMS from DIDWW via HTTP.

[Inbound SMS Specification](#sms-in-specification)

**Outbound SMS Specification**

API reference for sending outbound SMS to the DIDWW network.

[Outbound SMS Specification](#sms-out-specification)

---



## Inbound SMS Specification

The Inbound SMS service lets you receive text messages by having DIDWW forward them to your HTTP endpoint.
Find out how requests are sent, which variables you can use, the formats supported for the request body, and key
technical details such as retries and failover.



### HTTP Request Details from DIDWW

When a message is received on one of your DIDs, DIDWW will send an HTTP request to the **Request URL** configured in
your [SMS to HTTP IN Trunk](../create-sms-http-trunk-in.html#sms-in-http).

| Property | Description |
| --- | --- |
| **HTTP Methods** | Supported methods are `GET`, `POST`, and `PUT`. |
| **Source IPs** | Requests may originate from `46.19.209.214` or `185.238.173.74`. |
| **Connection Type** | HTTPS (recommended) and HTTP are supported. |

Note

Allow requests from **46.19.209.214** and **185.238.173.74** in your firewall.

### Available Variables

| Variable | Description |
| --- | --- |
| `{SMS_UUID}` | The unique ID of the received message. |
| `{SMS_SRC_ADDR}` | The sender's phone number (source address), for more information see [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986.html). |
| `{SMS_DST_ADDR}` | The DID number that received the SMS (destination address), for more information see [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986.html). |
| `{SMS_TEXT}` | The raw text of the SMS message body. |
| `{SMS_TEXT_BASE64_ENCODED}` | The SMS message body, encoded using [Base64](https://en.wikipedia.org/wiki/Base64). |
| `{SMS_TIME}` | The date and time the message was received, for more information see [RFC 1123](https://www.rfc-editor.org/rfc/rfc1123.html#page-55). |

Note

You can use these variables to construct the **Request URL**, **Query Parameters**, **Headers**, and **Body** of the
request in your trunk configuration.

### Request Body Formats

When DIDWW forwards an inbound SMS to your HTTP endpoint, the SMS data is placed in the **body** of the HTTP request.
The format is selected in your trunk settings and determines how your server should parse the data.

Available formats:
:   - **RAW**
    - **JSON** (`application/json`)
    - **URL encoded** (`application/x-www-form-urlencoded`)
    - **Multipart** (`multipart/form-data`)

Note

Choose the format that matches how your endpoint is designed.
For example, if your system expects JSON but receives URL encoded data, it will not parse correctly.

### Technical Details

*Failover*

If your endpoint does not respond with a `2xx` status code, DIDWW will re-attempt to deliver the message until its Time
To Live (TTL) of **3600 seconds (1 hour)** expires.


*Concatenated Messages*

The maximum size of an inbound SMS message is **64 KB**.
 Concatenated messages will be reassembled using **User Data Header (UDH)** before being delivered to your endpoint.
Information about fragmentation will not be transmitted.

---

## Outbound SMS Specification

DIDWW supports both Person-to-Person (P2P) and Application-to-Person (A2P) messaging.
Outbound SMS can be sent using the DIDWW REST API, which follows the [JSON:API
specification](https://jsonapi.org/format/), or via SMPP, which follows the standard SMPP specifications.





### Authentication

API requests are secured with two layers: IP whitelisting and HTTP Basic Authentication. Both must be valid for a
request to succeed.



#### 1. IP Whitelisting (Network Layer)

In your [HTTP OUT trunk configuration](../create-sms-http-trunk-out.html#user-panel-sms-http-out-trunk-create), specify
the Allowed IP addresses. The API rejects requests from any other source.

#### 2. Basic Authentication (Application Layer)

After IP validation, the system checks your credentials with **HTTP Basic Authentication**.
The following tabs show two ways to provide credentials in a cURL command: a convenient shortcut and a manual method.

*Simple Example (cURL shortcut)*

The easiest way to send credentials with cURL is the `-u` flag. It automatically combines your username and password,
Base64-encodes them, and adds the required `Authorization` header.

```
curl -u username:password \
  -X POST \
  -H "Content-Type: application/vnd.api+json" \
  https://sms-out.didww.com/outbound_messages \
  -d '{
    "data": {
      "type": "outbound_messages",
      "attributes": {
        "destination": "15551234567",
        "source": "12125551234",
        "content": "Hello World!"
      }
    }
  }'
```


*Manual Header Construction*

This method shows what the -u flag does behind the scenes.

> 1. Combine credentials: `username:password`
> 2. Base64 encode the string: `dXNlcm5hbWU6cGFzc3dvcmQ=`
> 3. Add the result as an `Authorization` header: `Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=`

```
curl -X POST \
  -H "Content-Type: application/vnd.api+json" \
  -H "Authorization: Basic am9objpkb2U=" \
  https://sms-out.didww.com/outbound_messages \
  -d '{
    "data": {
      "type": "outbound_messages",
      "attributes": {
        "destination": "15551234567",
        "source": "12125551234",
        "content": "Hello World!"
      }
    }
  }'
```

### Rate Limit

Outbound SMS requests sent via HTTP OUT trunks are subject to a rate limit.

The maximum request rate for HTTP OUT trunks is **10 requests per second (RPS)**.

If this limit is exceeded, the API returns an [429 Too Many Requests response error](#sms-out-spec-errors).

### Endpoints & Headers

All API requests use the `POST` method and must be sent to a valid API endpoint with the required headers.

HTTP OUT trunks have no location setting. The trunk's
[credentials](../create-sms-http-trunk-out.html#user-panel-sms-http-out-trunk-credentials) list the endpoints for each
DIDWW location: `https://us.sms-out.didww.com/outbound_messages` for **US, NY** and
`https://eu.sms-out.didww.com/outbound_messages` for **NL, AMS**. To use a location, send your requests to its endpoint.

| Component | Value |
| --- | --- |
| **Global Endpoint** | `https://sms-out.didww.com`   (Use this for general-purpose requests.) |
| **Regional Endpoints** | Use a regional endpoint for potentially lower latency:   - `https://us.sms-out.didww.com` (US, NY) - `https://eu.sms-out.didww.com` (NL, AMS) - `https://nyc.us.sms-out.didww.com` (US, NY) - `https://mia.us.sms-out.didww.com` (US, MIA) - `https://lac.us.sms-out.didww.com` (US, LA) - `https://sg.sms-out.didww.com` (SG) |
| **Request Paths** | Append to your chosen endpoint:   - **Single SMS:** `/outbound_messages` - **Bulk SMS:** `/bulk_outbound_messages` |
| **Content-Type Header** | `Content-Type: application/vnd.api+json` |
| **Authorization Header** | `Authorization: Basic <b64_value>`. See [Authentication](#sms-out-spec-authentication). |

### Outbound SMS Examples

*Single SMS without source*

Note

When `campaign_id` is provided and `source` is omitted, DIDWW randomly selects one of the Sender IDs registered under
that Sender ID Verification. In the DIDWW User Panel, the value used for `campaign_id` is displayed as **Campaign ID**
on the verification details page. See [Sender ID Verification
fields](../../sender-id-verifications/sender-id-verification-reference.html#sender-id-verification-fields).

http

```
POST /outbound_messages HTTP/1.1
Host: sms-out.didww.com
Content-Type: application/vnd.api+json
Authorization: Basic

{
  "data": {
    "type": "outbound_messages",
    "attributes": {
      "destination": "37041654321",
      "content": "Hello World!",
      "campaign_id": "1111aaa-1a1a-a1a1-aaaa-11aaaaa1111"
    }
  }
}
```

curl

```
curl -i -X POST https://sms-out.didww.com/outbound_messages -H "Content-Type: application/vnd.api+json" -H "Authorization: Basic" --data-raw '{"data": {"attributes": {"campaign_id": "1111aaa-1a1a-a1a1-aaaa-11aaaaa1111", "content": "Hello World!", "destination": "37041654321"}, "type": "outbound_messages"}}'
```

response

```
HTTP/1.1 201 Created
Content-Type: application/vnd.api+json

{
  "data": {
    "type": "outbound_messages",
    "id": "550e8400-e29b-41d4-a716-446655440000"
  }
}
```


*Single SMS*

Note

When `source` is present with a sender ID from the registered campaign, `campaign_id` is not required.

http

```
POST /outbound_messages HTTP/1.1
Host: sms-out.didww.com
Content-Type: application/vnd.api+json
Authorization: Basic

{
  "data": {
    "type": "outbound_messages",
    "attributes": {
      "destination": "37041654321",
      "source": "37041123456",
      "content": "Hello World!"
    }
  }
}
```

curl

```
curl -i -X POST https://sms-out.didww.com/outbound_messages -H "Content-Type: application/vnd.api+json" -H "Authorization: Basic" --data-raw '{"data": {"attributes": {"content": "Hello World!", "destination": "37041654321", "source": "37041123456"}, "type": "outbound_messages"}}'
```

response

```
HTTP/1.1 201 Created
Content-Type: application/vnd.api+json

{
  "data": {
    "type": "outbound_messages",
    "id": "550e8400-e29b-41d4-a716-446655440000"
  }
}
```


*Bulk SMS*

http

```
POST /bulk_outbound_messages HTTP/1.1
Host: sms-out.didww.com
Content-Type: application/vnd.api+json
Authorization: Basic

{
  "data": {
    "type": "bulk_outbound_messages",
    "attributes": {
      "destination": ["37041654321", "37041654322"],
      "source": "37041123456",
      "content": "Hello World!"
    }
  }
}
```

curl

```
curl -i -X POST https://sms-out.didww.com/bulk_outbound_messages -H "Content-Type: application/vnd.api+json" -H "Authorization: Basic" --data-raw '{"data": {"attributes": {"content": "Hello World!", "destination": ["37041654321", "37041654322"], "source": "37041123456"}, "type": "bulk_outbound_messages"}}'
```

response

```
HTTP/1.1 201 Created
Content-Type: application/vnd.api+json

{
  "data": {
    "type": "bulk_outbound_messages",
    "id": "2C4807D1-74E4-4639-BBC4-057402F052FF",
    "relationships": {
      "outbound_messages": {
        "data": [
          {"type": "outbound_messages", "id": "E34C1810-434B-4E64-AFD9-EC0568F324A9"},
          {"type": "outbound_messages", "id": "B6A48E34-3219-407D-99E6-770CF524F611"}
        ]
      }
    }
  }
}
```



#### Outbound SMS Attributes

| Attribute | Required? | Description |
| --- | --- | --- |
| `destination` | Required | Recipient's number in **E.164 format**. For bulk requests, use an array of numbers.   (maximum **1000 numbers** per request)  Note  If the destination region is not in your price list, you'll receive a callback with [code\_id: 2](#callback-error-codes-http). |
| `source` | Optional | DID number to use as the sender ID (E.164 format).  Note  The source DID must be authorized in your trunk's **Source Address Settings**.   Otherwise, you'll receive a callback with [code\_id: 8](#callback-error-codes-http). |
| `content` | Required | Message text (UTF-8). A single SMS supports up to **160 characters**. |
| `campaign_id` | Optional | Campaign ID of a registered [Sender ID Verification](../../sender-id-verifications/index.html#user-panel-sms-campaign). |

### Status Callbacks

You can receive events related to your message processing status using the **Callback** mechanism.
See the Callback URL configuration in [Outbound SMS trunk
settings](../create-sms-http-trunk-out.html#user-panel-sms-http-out-general-settings).

Note

Configure your firewall to allow requests from the DIDWW callback IP ranges:

> - **IPv4:** `46.19.208.0/21`, `185.238.173.74/32`
> - **IPv6:** `2a01:ad00::/32`

*Message Status Callback*

Sent after processing an outbound SMS.

**Payload Example:**

```
{
  "data": {
    "type": "outbound_message_callbacks",
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "attributes": {
      "time_start": "2025-08-12T12:24:30.45Z",
      "time_end": "2025-08-12T12:24:31.15Z",
      "destination": "15551234567",
      "source": "12125551234",
      "status": "Success",
      "code_id": null,
      "fragments_sent": 1,
      "price": 0.0075
    }
  }
}
```

**Attributes:**

| Attribute | Description |
| --- | --- |
| `time_start` | Time message routing started ([ISO 8601](https://tools.ietf.org/html/rfc3339#section-5.6)). |
| `time_end` | Time message processing finished ([ISO 8601](https://tools.ietf.org/html/rfc3339#section-5.6)). |
| `source` | Sender ID of the message. |
| `destination` | Recipient's number. |
| `status` | Processing status: `Success`, `Routing Error`, or `Failed`. |
| `fragments_sent` | Number of fragments used. |
| `price` | Cost per message fragment. |
| `code_id` | Error code if status is not `Success`. See [Callback Error Codes](#sms-out-spec-errors). |


*DLR Event Callback*

Sent from the carrier with the final delivery status (for example, `DELIVERED`, `FAILED`, or `EXPIRED`).

Note

To enable DLR event notifications, contact [support@didww.com](mailto:support%40didww.com).

**Payload Example:**

```
{
  "data": {
    "type": "dlr_event",
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "attributes": {
      "status": "DELIVERED",
      "time_start": "2025-08-12T12:24:32.00Z"
    }
  }
}
```

**Attributes:**

| Attribute | Description |
| --- | --- |
| `id` | ID of the related outbound message   (matches the `id` from the corresponding `outbound_message_callbacks`). |
| `status` | Final carrier status (e.g., `DELIVERED`, `FAILED`, `EXPIRED`). |
| `time_start` | Time the DLR event was generated ([ISO 8601](https://tools.ietf.org/html/rfc3339#section-5.6)). |



#### Callback Examples

*Single SMS Callback*

If you configure callbacks for your endpoint, the following attributes are returned for each outbound SMS.
In some cases, a [DLR event callback](#callback-dlr-event) may also be sent with additional status information.

| Unique ID | Time Start | Time End | Source | Destination | Status | Fragments Sent | Price |
| --- | --- | --- | --- | --- | --- | --- | --- |
| 83950010-3954-43a6-8419-c1417807672f | 2023-04-11 09:07:35 | 2023-04-11 09:07:35 | 447418350728 | 447418356937 | Success | 5 | 0.0375 |


*Bulk SMS Callback*

When sending bulk SMS, you receive callbacks for every destination number with a unique ID.
A [DLR event callback](#callback-dlr-event) may also be sent with final delivery details.

| Unique ID | Time Start | Time End | Source | Destination | Status | Fragments Sent | Price |
| --- | --- | --- | --- | --- | --- | --- | --- |
| dc38aa6b-c454-438f-9761-e3bdea13bee0 | 2023-04-11 09:14:30 | 2023-04-11 09:14:31 | 447418350728 | 37067738955 | Success | 1 | 0.0075 |
| 8075ceco-9fb9-41b6-8580-dabbbb41f0e9 | 2023-04-11 09:14:30 | 2023-04-11 09:14:31 | 447418350728 | 447418356937 | Success | 1 | 0.0075 |

### Handling Errors

#### API Error Responses

If your API request is malformed or unauthorized, the service returns an immediate error response.

*400 Bad Request*

Returned when the request payload does not follow [JSON:API](https://jsonapi.org/format/).

```
{
  "errors": [
    {
      "title": "Bad Request",
      "detail": "Invalid request",
      "code": "400",
      "status": "400"
    }
  ]
}
```


*401 Unauthorized*

Returned when the `Authorization` header is missing/invalid **or** the request comes from a non-allowed IP. See
[Authentication](#sms-out-spec-authentication).

```
{
  "errors": [
    {
      "title": "Unauthorized",
      "detail": "Authorization failed",
      "code": "401",
      "status": "401"
    }
  ]
}
```


*429 Too Many Requests*

Returned when the request rate exceeds the allowed [rate limit](#sms-out-spec-rate-limit).

```
{
  "errors": [
    {
      "title": "Too many requests",
      "detail": "too many requests in a given amount of time",
      "code": "429",
      "status": "429"
    }
  ]
}
```

#### Callback Error Codes and Retry Logic

*Callback Error Codes*

The `code_id` in a status callback provides specific details about a message failure.

| Code | Description |
| --- | --- |
| null | Message was sent successfully |
| 1, 3 | No routes found |
| 2 | No rate found |
| 4, 6 | Internal error |
| 5 | SMS trunk is blocked |
| 7 | Origination account is blocked |
| 8 | SMS source address is not allowed |
| 9 | SMS destination address is not allowed |
| 10, 11 | SMS Campaign not found or blocked |
| 100 | Insufficient balance |
| 101 | All delivery attempts failed within the TTL |
| 102 | No encoding available |
| 103 | Max balance attempts reached |
| 104 | Message defragmentation failed |
| 105 | Routing failed |


*Callback Retry Logic*

If your callback endpoint returns a **non-2xx** HTTP response or times out (**60 seconds**), the system will retry
delivery up to **9** more times.

| Callback Attempt | Wait Interval |
| --- | --- |
| 2 | 1 minute |
| 3 | 10 minutes |
| 4 | 30 minutes |
| 5 | 1 hour |
| 6 | 3 hours |
| 7 | 6 hours |
| 8 | 12 hours |
| 9 | 1 day |
| 10 | 2 days |

On this page
