___

Use these formatting rules, headers, and patterns when you send requests to the Infobip API and parse its responses.

___

## Conventions

The following formatting rules apply across the API:

- **Phone numbers:** Provide phone numbers in international [E.164](https://en.wikipedia.org/wiki/E.164) format: country code followed by the subscriber number, digits only, without a leading `+` or `00`. For example, `+41 79 302 67 27` is sent as `41793026727`.
- **Dates and times:** Date-time values in requests and responses use ISO 8601 format with a time-zone offset, for example `2017-07-20T06:47:45.777+0000`. The format pattern is `yyyy-MM-dd'T'HH:mm:ss.SSSZ`. The offset has no colon (`+0000`, not `+00:00`), so some parsers need this pattern set explicitly.

    Different offsets can represent the same instant. For example, `2017-07-20T06:47:45.777+0000` and `2017-07-20T07:47:45.777+0100` are equal. The offset reflects the time zone configured for your account, user, or API key, so treat it as variable.

    Parse values into the native date-time type of your language and let it handle the offset. For code samples, see [Date formats](https://www.infobip.com/docs/developer-resources/api-lifecycle/backward-compatibility#date-formats-what-your-integration-must-handle) in Backward compatibility.
- **Prices and currency:** Prices in responses use the charging currency of your account. To change the charging currency, contact your account manager or [Support](https://www.infobip.com/contact).
- **URL encoding:** Query parameters in the API reference examples are not URL encoded, so they stay readable. If your HTTP library does not encode query parameters automatically, encode them yourself. For example, the `+` in `sentSince=2026-01-01T00:00:00.000+0100` is read as a space unless you send it as `%2B`. With curl, use `-G` with `--data-urlencode`, as in the [Pagination](#pagination) example.

___

## Content types

The `Content-Type` header tells the API the format of the request body, and the `Accept` header sets the format of the response. Most endpoints use JSON.

### Request content type [#request-content-type-content-types]

Most endpoints accept `application/json`. Some use `multipart/form-data` for file uploads, and some support `application/xml`. Check the documentation for your target endpoint to confirm which content types it supports. Request and response bodies are UTF-8.

NOTE
For SMS, the character encoding of the message (GSM-7 or Unicode) also sets the message length and cost. See [Send messages in multiple languages](https://www.infobip.com/docs/sms/sms-multilingual).

Any request with a body, typically `POST` and `PUT` requests, must include a `Content-Type` header that matches the format of the data you are sending. For example, you can format an SMS message in either JSON or XML, but you must set the `Content-Type` header accordingly.

The following example sends JSON. Replace `{baseUrl}` and `{apiKey}` with your own values. See [API authentication](https://www.infobip.com/docs/developer-resources/authentication-and-access/api-authentication).

```bash
curl -X POST 'https://{baseUrl}/sms/3/messages' \
-H 'Authorization: App {apiKey}' \
-H 'Content-Type: application/json' \
-d '{
  "messages": [
    {
      "sender": "InfoSMS",
      "destinations": [ { "to": "41793026727" } ],
      "content": { "text": "This is a sample message" }
    }
  ]
}'
```

```json
{
  "bulkId": "178213036575107951052629",
  "messages": [
    {
      "messageId": "178213036575107951052630",
      "status": {
        "groupId": 1,
        "groupName": "PENDING",
        "id": 26,
        "name": "PENDING_ACCEPTED",
        "description": "Message sent to next instance"
      },
      "destination": "41793026727"
    }
  ]
}
```

The following example sends an email as `multipart/form-data`. With `-F`, curl sets the `Content-Type` header automatically. The response is JSON:

```bash
curl -X POST 'https://{baseUrl}/email/3/send' \
-H 'Authorization: App {apiKey}' \
-F 'from=Jane Doe <jane.doe@example.com>' \
-F 'to=john.smith@example.com' \
-F 'subject=Mail subject text' \
-F 'text=Mail body text'
```

```json
{
  "bulkId": "aibsmm6cb2hv56ie37uv",
  "messages": [
    {
      "to": "john.smith@example.com",
      "messageId": "8s5h44stvt3im3tdx6jd",
      "status": {
        "groupId": 1,
        "groupName": "PENDING",
        "id": 26,
        "name": "PENDING_ACCEPTED",
        "description": "Message accepted, pending for delivery."
      }
    }
  ]
}
```

### Response content type [#response-content-type-content-types]

By default, JSON and XML request bodies receive a response in the same format. Other requests, such as `multipart/form-data` requests and requests without a body, receive JSON. To receive the response in a different format, use the `Accept` header or a path extension.

Set the [Accept](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Accept) header to the format you want the response in. The following example requests delivery reports in XML:

```bash
curl 'https://{baseUrl}/sms/3/reports' \
-H 'Authorization: App {apiKey}' \
-H 'Accept: application/xml'
```

```xml
<?xml version='1.0' encoding='UTF-8'?>
<deliveryreports>
<results>
<result>
<bulkid>178213036575107951052629</bulkid>
<messageid>178213036575107951052630</messageid>
<to>41793026727</to>
<status>
<groupid>3</groupid>
<groupname>DELIVERED</groupname>
<id>5</id>
<name>DELIVERED_TO_HANDSET</name>
<description>Message delivered to handset</description>
</status>
      ...
    </result>
</results>
</deliveryreports>
```

If you cannot set the `Accept` header, append `.json` or `.xml` to the request path instead (legacy). The following request returns the same XML response as the Accept header example:

```bash
curl 'https://{baseUrl}/sms/3/reports.xml' \
-H 'Authorization: App {apiKey}'
```

___

## Response parsing

Parse responses according to the [JSON](https://www.json.org/) or [XML](https://www.w3.org/TR/REC-xml/) specification, using the native support in your language or an established library. When you parse a response:

- Ignore fields you do not recognize. Infobip can add response fields at any time.
- Read properties by name, never by position. JSON does not guarantee the order of properties in an object.

For code samples, see [Backward compatibility](https://www.infobip.com/docs/developer-resources/api-lifecycle/backward-compatibility).

___

## Pagination

List and log endpoints return a limited number of results per call. Set the page size with the `limit` query parameter, up to the maximum for the endpoint. If you omit `limit`, you get 50 results. For SMS logs and delivery reports, the maximum is 1000, and only the last 48 hours are available. Some endpoints also support cursor-based pagination. Check the endpoint documentation to see whether it supports cursors.

If an endpoint does not support cursors and a call returns as many results as `limit`, there may be more results. To retrieve them, narrow the time range and query again, for example with the `sentSince` and `sentUntil` query parameters.

For example, `GET /sms/3/logs` uses cursor-based pagination when you set `useCursor=true`. Omit `cursor` on the first call. The response includes a `cursor` object (results trimmed):

```bash
curl -G 'https://{baseUrl}/sms/3/logs' \
-H 'Authorization: App {apiKey}' \
--data-urlencode 'limit=50' \
--data-urlencode 'useCursor=true'
```

```json
{
  "results": [
    {
      "messageId": "178213036575107951052630"
    }
  ],
  "cursor": {
    "limit": 50,
    "nextCursor": "3E0BB71578C67F9D76D704BE8C60943E"
  }
}
```

To get the next page, send `useCursor=true` again and set `cursor` to the `nextCursor` value. `--data-urlencode` encodes the value, so you can pass it as returned:

```bash
curl -G 'https://{baseUrl}/sms/3/logs' \
-H 'Authorization: App {apiKey}' \
--data-urlencode 'limit=50' \
--data-urlencode 'useCursor=true' \
--data-urlencode 'cursor={nextCursor}'
```

```json
{
  "results": [
    {
      "messageId": "178213036575107951052631"
    }
  ],
  "cursor": {
    "limit": 50,
    "nextCursor": "8EC214C0B7FFFAD86A6ECC9B696C6DBE"
  }
}
```

NOTE
If you send `cursor` without `useCursor=true`, the API ignores the cursor, without an error. It returns the first page of non-cursor results, which can be in a different order, and the response has no `cursor` object.

Stop when a response has no `nextCursor`. A page with fewer results than `limit` is not proof of the last page.

___

## 400 Bad Request errors

If the request body cannot be processed, the API returns HTTP `400 Bad Request`. For the error response body and how to handle it, see [Handling errors](https://www.infobip.com/docs/developer-resources/api-fundamentals/handling-errors). The following are common causes:

- The `Content-Type` header is missing.
- `Content-Type` does not match the submitted body.
- The body is not valid JSON or XML.
- The body does not match the request model of the endpoint.

NOTE
Endpoints generally ignore unrecognized parameters instead of rejecting the request, so a misspelled optional parameter has no effect and returns no error. Check parameter names against the request model of the endpoint. For Messages API requests, the [Validate Messages API message](https://www.infobip.com/docs/api/platform/messages-api/sending-message/validate-messages-api-message) endpoint reports unrecognized parameters as `skippableViolations`, so you can catch typos before you send.

___

Related pages

[API authentication](https://www.infobip.com/docs/developer-resources/authentication-and-access/api-authentication)
Authenticate requests using API keys, OAuth 2.0, IBSSO tokens, or HTTP Basic authentication.

[Handling errors](https://www.infobip.com/docs/developer-resources/api-fundamentals/handling-errors)
How Infobip APIs report request errors and delivery error codes, and how to retry failed requests.

[Backward compatibility](https://www.infobip.com/docs/developer-resources/api-lifecycle/backward-compatibility)
What the backward-compatibility guarantee covers and how to write integrations resilient to routine updates.