> This page is for Developers.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.emnify.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.emnify.com/_mcp/server.

> Send SMS messages longer than 160 characters using concatenation with User Data Headers (UDH) via the API.

Single SMS messages have a limit of 160 characters so for longer SMS messages, a strategy of concatenation should be employed.
Concatenation allows sending multiple SMS messages which are then joined as a single long SMS on the destination device.

Specifying that SMS messages should be concatenated via the API is done using the `udh` parameter which stands for User Data Header.

## User Data Header (UDH)

[User Data Headers (UDH)](https://en.wikipedia.org/wiki/User_Data_Header) are a short strings of bytes at the start of an SMS used to indicate the handling of the content of an SMS.
Specifying that messages should be concatenated and in what order may be done in these headers.

The following **two API calls** would concatenate two SMS messages into one on the destination device:

### Request

POST [https://cdn.emnify.net/api/v1/endpoint/\{endpoint\_id}/sms](https://cdn.emnify.net/api/v1/endpoint/\{endpoint_id}/sms)

**`Standard SMS`**

```curl Standard SMS
curl -X POST https://cdn.emnify.net/api/v1/endpoint/12345/sms \
     -H "Authorization: Bearer <token>" \
     -H "Content-Type: application/json" \
     -d '{
  "payload": "This is the message text",
  "source_address": "12345689"
}'
```

**`Standard SMS`**

```python Standard SMS
import requests

url = "https://cdn.emnify.net/api/v1/endpoint/12345/sms"

payload = {
    "payload": "This is the message text",
    "source_address": "12345689"
}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

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

print(response.json())
```

**`Standard SMS`**

```javascript Standard SMS
const url = 'https://cdn.emnify.net/api/v1/endpoint/12345/sms';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"payload":"This is the message text","source_address":"12345689"}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

**`Standard SMS`**

```go Standard SMS
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://cdn.emnify.net/api/v1/endpoint/12345/sms"

	payload := strings.NewReader("{\n  \"payload\": \"This is the message text\",\n  \"source_address\": \"12345689\"\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

**`Standard SMS`**

```ruby Standard SMS
require 'uri'
require 'net/http'

url = URI("https://cdn.emnify.net/api/v1/endpoint/12345/sms")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"payload\": \"This is the message text\",\n  \"source_address\": \"12345689\"\n}"

response = http.request(request)
puts response.read_body
```

**`Standard SMS`**

```java Standard SMS
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://cdn.emnify.net/api/v1/endpoint/12345/sms")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"payload\": \"This is the message text\",\n  \"source_address\": \"12345689\"\n}")
  .asString();
```

**`Standard SMS`**

```php Standard SMS
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://cdn.emnify.net/api/v1/endpoint/12345/sms', [
  'body' => '{
  "payload": "This is the message text",
  "source_address": "12345689"
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

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

**`Standard SMS`**

```csharp Standard SMS
using RestSharp;

var client = new RestClient("https://cdn.emnify.net/api/v1/endpoint/12345/sms");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"payload\": \"This is the message text\",\n  \"source_address\": \"12345689\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

**`Standard SMS`**

```swift Standard SMS
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [
  "payload": "This is the message text",
  "source_address": "12345689"
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://cdn.emnify.net/api/v1/endpoint/12345/sms")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### Request

POST [https://cdn.emnify.net/api/v1/endpoint/\{endpoint\_id}/sms](https://cdn.emnify.net/api/v1/endpoint/\{endpoint_id}/sms)

**`Standard SMS`**

```curl Standard SMS
curl -X POST https://cdn.emnify.net/api/v1/endpoint/12345/sms \
     -H "Authorization: Bearer <token>" \
     -H "Content-Type: application/json" \
     -d '{
  "payload": "This is the message text",
  "source_address": "12345689"
}'
```

**`Standard SMS`**

```python Standard SMS
import requests

url = "https://cdn.emnify.net/api/v1/endpoint/12345/sms"

payload = {
    "payload": "This is the message text",
    "source_address": "12345689"
}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

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

print(response.json())
```

**`Standard SMS`**

```javascript Standard SMS
const url = 'https://cdn.emnify.net/api/v1/endpoint/12345/sms';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"payload":"This is the message text","source_address":"12345689"}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

**`Standard SMS`**

```go Standard SMS
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://cdn.emnify.net/api/v1/endpoint/12345/sms"

	payload := strings.NewReader("{\n  \"payload\": \"This is the message text\",\n  \"source_address\": \"12345689\"\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

**`Standard SMS`**

```ruby Standard SMS
require 'uri'
require 'net/http'

url = URI("https://cdn.emnify.net/api/v1/endpoint/12345/sms")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"payload\": \"This is the message text\",\n  \"source_address\": \"12345689\"\n}"

response = http.request(request)
puts response.read_body
```

**`Standard SMS`**

```java Standard SMS
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://cdn.emnify.net/api/v1/endpoint/12345/sms")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"payload\": \"This is the message text\",\n  \"source_address\": \"12345689\"\n}")
  .asString();
```

**`Standard SMS`**

```php Standard SMS
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://cdn.emnify.net/api/v1/endpoint/12345/sms', [
  'body' => '{
  "payload": "This is the message text",
  "source_address": "12345689"
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

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

**`Standard SMS`**

```csharp Standard SMS
using RestSharp;

var client = new RestClient("https://cdn.emnify.net/api/v1/endpoint/12345/sms");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"payload\": \"This is the message text\",\n  \"source_address\": \"12345689\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

**`Standard SMS`**

```swift Standard SMS
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [
  "payload": "This is the message text",
  "source_address": "12345689"
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://cdn.emnify.net/api/v1/endpoint/12345/sms")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

First SMS UDH value:

```pseudo
05 00 03 CC 02 01
```

Second SMS UDH value:

```pseudo
05 00 03 CC 02 02
```

These UDH values are read as follows:

```pseudo
05     UDHL - The following five bytes should be read as the header
00     IEI  - 00 or 08 values indicate a concatenated message
03     IEDL - The following 3 bytes are the data for this IE
CC     Reference - Each part of a concatenated message must have the same reference
02     The number of parts this concatenated message is comprised of.
01/02  The order that this message should appear, in this case either the first or second SMS.
```

### 2 byte IEI

For an IEI of 08, the SMS reference number uses a 2 byte (16 bit) value.

First SMS UDH value:

```pseudo
06 08 04 F4 2E 02 01  
```

Second SMS UDH Value:

```pseudo
06 08 04 F4 2E 02 02
```

These UDH values are read as follows:

```pseudo
06     UDHL - The following six bytes should be read as the header
08     IEI  - 08 indicates a concatenated message with 16-bit reference
04     IEDL - The following 4 bytes are the data for this IE
F42E   Reference - Each part of this concatenated message must have the same reference, this time in 16-bit
02     The number of parts this concatenated message is comprised of.
01/02  The order that this message should appear, in this case either the first or second SMS.
```