# Get Started

TSG Global makes sending and receiving messages & calls easy. Find the documentation you need to build exactly what you need. We’ll handle the complexity of mobile carrier and global regulations.

## Document Formatting

We generally format our API documents in the following manner:

1. Overview: the purpose of the end-point
2. Authentication: how to authenticate to the end-point
3. Method: details regarding the API method and examples.

We have several API types. Most are REST-based, but we also have GraphQL APIs. We use common HTTP features such as HTTP verbs and HTTP status codes. Requests must be made via HTTPS (calls over plain HTTP will fail).

## Get your Credentials

Some of our APIs currently require an API key. For those services, an API key will be generated for you and be available to view via the Customer Portal here: <https://customer-portal.tsgglobal.com/>.&#x20;

For other services, you will be able to generate a Bearer token using your unique email address and password assigned to your Customer Portal user to access resources. When it doubt, simply check the Authentication section for the resource you are attempting to access.

## SMPP

We also provide a SMPP interface for high-volume users. SMPP is available on the canonical port 2775. An encrypted, secure connection is also provided over TLS (1.1 or 1.2) on port 2776. We highly recommend you connect via TLS in order to securely transport your messages to us.

Happy coding!


# ISO/IEC/SOC Certification

An overview of TSG Global, Inc. ISO/IEC/SOC certifications and frameworks. If you have any questions, or if you wish to report a potential security issue, please contact security\@tsgglobal.com

As part of our information security management system (ISMS), TSG Global, Inc. is certified under ISO/IEC 27001, a management system that provides specific requirements and practices intended to bring information security under management control. We also actively follow the SOC 2 Type II framework. Our compliance with these standards assures your protection in many ways:

<figure><img src="/files/kDBh6gr8vLBQ3PP9eojB" alt=""><figcaption><p>TSG Global, Inc. uses Consilium Lab's automation platform to continuously monitor 100+ internal security controls across the organization against the highest possible standards. Automated alerts and evidence collection allows TSG Global, Inc. to confidently prove its security and compliance posture any day of the year, while fostering a security-first mindset and culture of compliance across the organization.</p></figcaption></figure>

**TSG Global ISO 27001 Certification Employee Trainings**

Security is a company-wide endeavor. All employees complete an annual security training program and employ best practices when handling customer data.

**Penetration Tests**

TSG Global, Inc. works with industry-leading security firms to perform annual network and application layer penetration tests.

**Secure Software Development**

TSG Global, Inc. utilizes a variety of manual and automatic data security and vulnerability checks throughout the software development lifecycle.

**Data Encryption**

Data is encrypted both in-transit using TLS and at rest.

**Vulnerability Disclosure Program**

If you believe you’ve discovered a bug in TSG Global, Inc.’s security, please get in touch at <security@tsgglobal.com>. Our security team promptly investigates all reported issues.

## Organizational Security

Information Security Program&#x20;

We have an Information Security Program in place that is communicated throughout the organization. Our Information Security Program follows the criteria set forth by the SOC 2 Framework. SOC 2 is a widely known information security auditing procedure created by the American Institute of Certified Public Accountants.

**Third-Party Audits**&#x20;

Our organization undergoes independent third-party assessments to test our security and compliance controls.

**Third-Party Penetration Testing**&#x20;

We perform an independent third-party penetration at least annually to ensure that the security posture of our services is uncompromised.

**Roles and Responsibilities**

Roles and responsibilities related to our Information Security Program and the protection of our customer’s data are well defined and documented. Our team members are required to review and accept all of the security policies.

**Security Awareness Training**

Our team members are required to go through employee security awareness training covering industry standard practices and information security topics such as phishing and password management.

**Confidentiality**

All team members are required to sign and adhere to an industry standard confidentiality agreement prior to their first day of work.

**Background Checks**

We perform background checks on all new team members in accordance with local laws.

## Cloud Security

**Cloud Infrastructure Security**&#x20;

All of our services are hosted with Amazon Web Services (AWS). They employ a robust security program with multiple certifications. For more information on our provider’s security processes, please visit AWS Security.

**Data Hosting Security**&#x20;

All of our data is hosted on Amazon Web Services (AWS) databases. These databases are all located in the United States. Please reference the above vendor specific documentation linked above for more information.

**Encryption at Rest**

All databases are encrypted at rest.

**Encryption in Transit**&#x20;

Our applications encrypt in transit with TLS/SSL only.

**Vulnerability Scanning**&#x20;

We perform vulnerability scanning and actively monitor for threats.

**Logging and Monitoring**

We actively monitor and log various cloud services.

**Business Continuity and Disaster Recovery**

We use our data hosting provider’s backup services to reduce any risk of data loss in the event of a hardware failure. We utilize monitoring services to alert the team in the event of any failures affecting users.

**Incident Response**

We have a process for handling information security events which includes escalation procedures, rapid mitigation and communication.

## Access Security

**Permissions and Authentication**&#x20;

Access to cloud infrastructure and other sensitive tools are limited to authorized employees who require it for their role. Where available we have Single Sign-on (SSO), 2-factor authentication (2FA) and strong password policies to ensure access to cloud services are protected.

**Least Privilege Access Control**&#x20;

We follow the principle of least privilege with respect to identity and access management.

**Quarterly Access Reviews**

We perform quarterly access reviews of all team members with access to sensitive systems.

**Password Requirements**

All team members are required to adhere to a minimum set of password requirements and complexity for access.

**Password Managers**

All employees are required to utilize a business password manager to manage passwords and maintain password complexity.

**Vendor and Risk Management**

**Annual Risk Assessments**

We undergo at least annual risk assessments to identify any potential threats, including considerations for fraud.

**Vendor Risk Management**

Vendor risk is determined and the appropriate vendor reviews are performed prior to authorizing a new vendor.


# Staging Environment Access

Describes how to access our staging environment for testing.

## Introduction

This document outlines the steps customers should take to onboard onto our staging environment, focusing on connecting using SMPP/SMTP and HTTP API protocols for both SMS and MMS messaging.

{% hint style="warning" %}

## Disclaimers

Please be advised that you will be connecting to an active staging/testing environment hosted by TSG Global. There will be changes actively pushed to our staging environment that may occasionally break some features without warning. Additionally, to control costs, we do not scale our staging environment to the same degree as our production environment, so throughput may occasionally become an issue. We will work closely with your testing team in a dedicated Slack channel to ensure you have a robust testing experience that you are happy with prior to migrating to production.
{% endhint %}

## Prerequisites

Before connecting to our staging environment:

1. Ensure that you have valid credentials provided by our support team.
2. Ensure that you have joined the Slack channel setup with your team to assist you with any technical questions you may have during testing.
3. Set up a testing machine or environment on your end.
4. Familiarize yourself with the SMPP protocol and HTTP API concepts if you haven't already.
5. Review the TSG Global API documents located at: <https://docs.tsgglobal.com>

## SMS via SMPP

### Configuration Details

SMPP Host: smsc.staging.tsgglobal.com

SMPP Port: 2775 for TCP or 2776 for TLS connections

Bind type: Transceiver

System ID: Provided by our support team.

Password: Provided by our support team.

### Steps to Connect

1. Install an SMPP client or library compatible with your system.
2. Configure the SMPP client using the provided configuration details.
3. Connect to the staging SMPP server.
4. Test by sending and receiving SMS messages.
5. Review the sample delivery reports and error messages (if any) for troubleshooting.
6. For any additional information please refer to <https://docs.tsgglobal.com/api-reference/programmable-sms/smpp>

<br>

## Sending SMS via HTTP API

### Endpoint Information

Base URL: <https://sms-api.staging.tsgglobal.com>

Endpoint: See API documentation here: <https://docs.tsgglobal.com/api-reference/programmable-sms/send-an-sms-message>

Authentication Key: Provided by our support team.

### Steps to Connect

1. Configure the HTTP client or tool you will use for testing (e.g., Postman, CURL)
2. Set the request headers per the API documentation:

Authorization: Bearer: \[Your-Authentication-Key]

Content-Type: application/json

3. For sending, make the necessary POST requests.
4. Review the API response for any errors and to ensure successful delivery.

<br>

## Receiving SMS via HTTP webhook

To receive SMS message via webhook please provide your webhook URL according to the docs provided at: <https://docs.tsgglobal.com/api-reference/programmable-sms/receive-an-sms-message>

<br>

## MMS via SMTP

### Configuration Details

SMPP Host: smtp.staging.tsgglobal.com

SMPP Port: 2775 for TCP or 2776 for TLS connections

Bind type: Transceiver

System ID: Provided by our support team.

Password: Provided by our support team.

### Steps to Connect

7. Install an SMTP client or library compatible with your system.
8. Configure the SMTP client using the provided configuration details.
9. Connect to the staging SMTP server.
10. Test by sending and receiving MMS messages.
11. Review the sample delivery reports and error messages (if any) for troubleshooting.

<br>

For any additional information please refer to: <https://docs.tsgglobal.com/api-reference/programmable-mms/smtp>

\
Sending MMS via HTTP API
------------------------

### Endpoint Information

Base URL: <https://mms-api.staging.tsgglobal.com>

Endpoint: See API documentation here:&#x20;

<https://docs.tsgglobal.com/api-reference/programmable-mms/send-an-mms-message>

Authentication Key: Provided by our support team.

### Steps to Connect

5. Configure the HTTP client or tool you will use for testing (e.g., Postman, CURL)
6. Set the request headers per the API documentation:

Authorization: Bearer: \[Your-Authentication-Key]

Content-Type: application/json

7. For sending, make the necessary POST requests.
8. Review the API response for any errors and to ensure successful delivery.

<br>

## Receiving MMS via HTTP webhook

To receive SMS message via webhook please provide your webhook URL according to the docs provided at: <https://docs.tsgglobal.com/api-reference/programmable-mms/receive-an-mms-message>

## Troubleshooting

Below are some frequently encountered issues that may assist:

1. Ensure you're using the correct credentials.
2. Check your network/firewall settings to ensure communication isn't being blocked.
3. Review error logs and messages for clues.
4. Reach out to our support team with detailed error messages for assistance.

## Conclusion

After successful testing on the staging environment, inform our support team so that they can assist you with transitioning to the production environment.&#x20;

<br>


# Programmable SMS

TSG Global makes sending and receiving SMS easy. Find the documentation and tools you need to build exactly what you want, fast. We’ll handle the complexity of mobile carrier and global regulations.


# Send an SMS Message

## Overview

This method allows you to send an SMS message. Using TSG Global APIs, you can send outgoing SMS messages from your enabled phone numbers to mobile phones around the globe.

## Authentication

{% hint style="info" %}
Authentication is done by passing your TSG Global API key via the Authorization header in the format "Authorization: Bearer \<api\_key>" (using the messaging API key specifically). API credentials can be found here: <https://customer-portal.tsgglobal.com/account>
{% endhint %}

## Method

## Send an SMS message.

<mark style="color:green;">`POST`</mark> `https://sms.tsgglobal.world/messages`

Sends a new SMS message.

#### Request Body

| Name                                   | Type          | Description                                                                                                                                    |
| -------------------------------------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| from<mark style="color:red;">\*</mark> | string        | Alphanumeric string representing the sender. Either an E.164 format number or Sender ID.                                                       |
| to<mark style="color:red;">\*</mark>   | array(string) | One or more recipient numbers in E.164 format. Recipients will be de-duplicated (the same number will only be sent once).                      |
| body<mark style="color:red;">\*</mark> | string        | Message contents. UTF8-encoded. If a custom encoding is specified, this should be a base64 encoded representation of the raw data.             |
| encoding                               | int           | Specifies message encoding.                                                                                                                    |
| force\_encoding                        | int           | Normally the system will try to infer what encoding type is best suited for your message, however you can override it using this field instead |
| registered\_delivery                   | int           | Defaults to off. Set to request a delivery receipt from the carrier. `1-3` (always, on success, on error)                                      |
| deliver\_at                            | datetime      | Specifies a future datetime at which to schedule message delivery. Has to be UTC, e.g. "2017-08-04T08:00:00"                                   |
| expires\_at                            | datetime      | Specifies a future datetime when the message should be expired                                                                                 |

{% tabs %}
{% tab title="200 Message successfully received." %}

```javascript
### A single message was sent to 9999999 and 12342341234. ###

{
  "9999999": {
    "updated_at": "2017-09-28T08:28:39.132046",
    "type": "outbound",
    "to": "9999999",
    "status": "new",
    "scheduled_at": null,
    "expires_at": null,
    "processed_at": null,
    "object": "sms",
    "location": null,
    "inserted_at": "2017-09-28T08:28:39.132037",
    "id": "1e7bd5e9-d9ba-41de-814e-3fe755e60e83",
    "from": "15550555055",
    "encoding": 3,
    "delivery_receipt": 0,
    "delivered_at": null,
    "body": "hello world"
  },
  "12342341234": {
    "updated_at": "2017-09-28T08:28:39.132046",
    "type": "outbound",
    "to": "12342341234",
    "status": "new",
    "scheduled_at": null,
    "expires_at": null,
    "processed_at": null,
    "object": "sms",
    "location": null,
    "inserted_at": "2017-09-28T08:28:39.132038",
    "id": "2e6ed7eb-a16f-4e56-b9f2-f66000921da3",
    "from": "15550555055",
    "encoding": 3,
    "delivery_receipt": 0,
    "delivered_at": null,
    "body": "hello world"
  }
}

### A 3-part multipart message was sent to 9999999 and 12342341234. ###

{
  "9999999": {
    "updated_at": "2017-09-28T08:28:39.132046",
    "udh": {
      "ref_num": 234,
      "count": 3
    },
    "parts": [
      {"id": "3203283d-7a98-49ad-a8d4-17b45a8373b8"},
      {"id": "2a87beb4-791c-480d-9b77-1780d785847c"},
      {"id": "98c8ec04-54e3-40bb-b256-35ebb5c15280"}
    ],
    "type": "outbound",
    "to": "9999999",
    "status": "new",
    "scheduled_at": null,
    "expires_at": null,
    "processed_at": null,
    "object": "sms",
    "location": null,
    "inserted_at": "2017-09-28T08:28:39.132037",
    "id":"3203283d-7a98-49ad-a8d4-17b45a8373b8",
    "from": "15550555055",
    "encoding": 3,
    "delivery_receipt": 0,
    "delivered_at": null,
    "body": "hello world [..]"
  },
  "12342341234": {
    "updated_at": "2017-09-28T08:28:39.132046",
    "udh": {
      "ref_num": 541,
      "count": 3
    },
    "parts": [
      {"id": "3322dcb5-d668-4148-b94c-3f4b3faf670e"},
      {"id": "b5fe304f-374e-4558-95f7-4a3ffdfb7784"},
      {"id": "fbfb2ddc-f7e4-42b5-9bb8-6778f6d45987"}
    ],
    "type": "outbound",
    "to": "12342341234",
    "status": "new",
    "scheduled_at": null,
    "expires_at": null,
    "processed_at": null,
    "object": "sms",
    "location": null,
    "inserted_at": "2017-09-28T08:28:39.132038",
    "id": "3322dcb5-d668-4148-b94c-3f4b3faf670e",
    "from": "15550555055",
    "encoding": 3,
    "delivery_receipt": 0,
    "delivered_at": null,
    "body": "hello world [..]"
  }
}  
```

{% endtab %}
{% endtabs %}

The entire multipart message id (top level) and first part id (under parts) will always match.

## Encoding

In most cases, we handle the encoding for you — we’ll efficiently transcode it to either fit ASCII, Latin-1 or UTF-16.&#x20;

The API supports UTF-8. Characters outside of the Latin-1 set will set the encoding to UCS2 (i.e. UTF-16) You can override the encoding by using the `force_encoding` field instead.

Below is a table of all the encodings, however only a few are supported for the API.

<table><thead><tr><th>int</th><th>Description</th><th>Supported By API</th><th data-hidden data-type="number"></th><th data-hidden>Segment size</th></tr></thead><tbody><tr><td>0</td><td>SMSC Default (GSM 7 bit / GSM 3.38)</td><td>Yes</td><td>0</td><td>160 (153)</td></tr><tr><td>1</td><td>IA5 (CCITT T.50)/ASCII (ANSI X3.4)</td><td>No</td><td>null</td><td></td></tr><tr><td>2</td><td>Octet unspecified (8-bit binary)</td><td>No</td><td>null</td><td></td></tr><tr><td>3</td><td>Latin 1 (ISO-8859-1)</td><td>Yes</td><td>0</td><td>140 (134)</td></tr><tr><td>4</td><td>Octet unspecified (8-bit binary)</td><td>No</td><td>null</td><td></td></tr><tr><td>5</td><td>JIS (X 0208-1990)</td><td>No</td><td>null</td><td></td></tr><tr><td>6</td><td>Cyrllic (ISO-8859-5)</td><td>No</td><td>null</td><td></td></tr><tr><td>7</td><td>Latin/Hebrew (ISO-8859-8)</td><td>No</td><td>null</td><td></td></tr><tr><td>8</td><td>UCS2/UTF-16 (ISO/IEC-10646)</td><td>Yes</td><td>0</td><td>70 (67)</td></tr><tr><td>9</td><td>Pictogram Encoding</td><td>No</td><td>null</td><td></td></tr><tr><td>10</td><td>Music Codes (ISO-2022-JP)</td><td>No</td><td>null</td><td></td></tr><tr><td>13</td><td>Extended Kanji JIS (X 0212-1990)</td><td>No</td><td>null</td><td></td></tr><tr><td>14</td><td>Korean Graphic Character Set (KS C 5601/KS X 1001)</td><td>No</td><td>null</td><td></td></tr></tbody></table>

{% hint style="info" %}
**Good to know:** message scheduling can be specified for up to 2 years in advance. We guarantee up to the minute accuracy.
{% endhint %}

### SMS message length

Messages have limited length and exceeding that length will cause message to split into multiple messages that need to be concatenated at the destination (as per GSM messaging standard).

| Encoding | 1 segment max length | Multi segment max length | Max segments |
| -------- | -------------------- | ------------------------ | ------------ |
| 0        | 160                  | 153                      | 6            |
| 3        | 140                  | 134                      | 5            |
| 8        | 70                   | 68                       | 6            |

Since multipart messages need to contain additional information on segment ordering and concatenation rules those segments can carry little less information than single-segment messages.&#x20;

Each segment is technically another SMS message.

## Example request

Simple message sent from one number to another using only the required parameters.&#x20;

```
{
    "from": "12003004000",
    "to": ["120030040001"],
    "body": "This is a sample test SMS message"
}
```

## Example Responses

A single message was sent to 9999999 and 12342341234.

```json
{
  "9999999": {
    "updated_at": "2017-09-28T08:28:39.132046",
    "type": "outbound",
    "to": "9999999",
    "status": "new",
    "scheduled_at": null,
    "expires_at": null,
    "processed_at": null,
    "object": "sms",
    "location": null,
    "inserted_at": "2017-09-28T08:28:39.132037",
    "id": "1e7bd5e9-d9ba-41de-814e-3fe755e60e83",
    "from": "15550555055",
    "encoding": 3,
    "delivery_receipt": 0,
    "delivered_at": null,
    "body": "hello world"
  },
  "12342341234": {
    "updated_at": "2017-09-28T08:28:39.132046",
    "type": "outbound",
    "to": "12342341234",
    "status": "new",
    "scheduled_at": null,
    "expires_at": null,
    "processed_at": null,
    "object": "sms",
    "location": null,
    "inserted_at": "2017-09-28T08:28:39.132038",
    "id": "2e6ed7eb-a16f-4e56-b9f2-f66000921da3",
    "from": "15550555055",
    "encoding": 3,
    "delivery_receipt": 0,
    "delivered_at": null,
    "body": "hello world"
  }
}
```

A 3-part multipart message was sent to 9999999 and 12342341234.

```json
{
  "9999999": {
    "updated_at": "2017-09-28T08:28:39.132046",
    "udh": {
      "ref_num": 234,
      "count": 3
    },
    "parts": [
      {"id": "3203283d-7a98-49ad-a8d4-17b45a8373b8"},
      {"id": "2a87beb4-791c-480d-9b77-1780d785847c"},
      {"id": "98c8ec04-54e3-40bb-b256-35ebb5c15280"}
    ],
    "type": "outbound",
    "to": "9999999",
    "status": "new",
    "scheduled_at": null,
    "expires_at": null,
    "processed_at": null,
    "object": "sms",
    "location": null,
    "inserted_at": "2017-09-28T08:28:39.132037",
    "id":"2285c9b4-8b3e-4c72-a30d-a3481a68b6a5",
    "from": "15550555055",
    "encoding": 3,
    "delivery_receipt": 0,
    "delivered_at": null,
    "body": "hello world [..]"
  },
  "12342341234": {
    "updated_at": "2017-09-28T08:28:39.132046",
    "udh": {
      "ref_num": 541,
      "count": 3
    },
    "parts": [
      {"id": "3322dcb5-d668-4148-b94c-3f4b3faf670e"},
      {"id": "b5fe304f-374e-4558-95f7-4a3ffdfb7784"},
      {"id": "fbfb2ddc-f7e4-42b5-9bb8-6778f6d45987"}
    ],
    "type": "outbound",
    "to": "12342341234",
    "status": "new",
    "scheduled_at": null,
    "expires_at": null,
    "processed_at": null,
    "object": "sms",
    "location": null,
    "inserted_at": "2017-09-28T08:28:39.132038",
    "id": "2e6ed7eb-a16f-4e56-b9f2-f66000921da3",
    "from": "15550555055",
    "encoding": 3,
    "delivery_receipt": 0,
    "delivered_at": null,
    "body": "hello world [..]"
  }
}
```


# Receive an SMS Message

## Overview

Receive inbound SMS messages to your numbers. Get your message returned via SMPP or via a webhook URL that you provide. For production traffic, we don’t recommend using this endpoint, but instead registering a webhook.

## Authentication

{% hint style="info" %}
Authentication is done by passing your TSG Global API key via the Authorization header in the format "Authorization: Bearer \<api\_key>" (using the messaging API key specifically). API credentials can be found here: <https://customer-portal.tsgglobal.com/account>
{% endhint %}

## Method

## Returns a single message. Useful for manually checking message status.

<mark style="color:blue;">`GET`</mark> `https://sms.tsgglobal.world/messages/<uuid>`

You can either use a message id, or one of the part ids. In the case of the latter, you will see detailed information about the part (the raw SMS).

We don’t recommend using this endpoint - perhaps only for testing. For production traffic, we recommend registering a webhook (see below).

#### Path Parameters

| Name                                   | Type   | Description                                           |
| -------------------------------------- | ------ | ----------------------------------------------------- |
| uuid<mark style="color:red;">\*</mark> | String | The UUID for the message ID you are wanting to query. |

## Example Responses

Single message

```json
{
  "id": "03b4641f-17a6-4565-bdba-1ce905be3312",
  "type": "outbound",
  "from": "12341234",
  "to": "12342341234",
  "object": "sms",
  "body": "hello"
  "encoding": 3,
  "delivery_receipt": "no",
  "status": "new",
  "location": null,
  "inserted_at": "2017-09-17T19:12:32.792699",
  "updated_at": "2017-09-17T19:12:32.792704",
  "scheduled_at": null,
  "processed_at": null,
  "delivered_at": null,
  "expires_at": null
}
```

Longer message consisting of multiple UDH parts

```json
{
  "id": "0ab46aaa-17a6-a5a5-7dba-1ce905be3312",
  "udh": {
    "ref_num": 541,
    "count": 3
  },
  "parts": [
    {"id": "3322dcb5-d668-4148-b94c-3f4b3faf670e"},
    {"id": "b5fe304f-374e-4558-95f7-4a3ffdfb7784"},
    {"id": "fbfb2ddc-f7e4-42b5-9bb8-6778f6d45987"}
  ],
  "type": "outbound",
  "from": "12341234",
  "to": "12342341234",
  "object": "sms",
  "body": "hello this is an extremely long message that spans 3 actual SMS messages sent from the carrier to the user. The phone will reassemble all of these messages into one longer, single message. We're currently at 2 parts, but let's keep going until we hit 3 parts. At a simple text message (no emoji), that will probably be around 3*140 characters, encoded as latin-1",
  "encoding": 3,
  "delivery_receipt": "no",
  "status": "new",
  "location": null,
  "inserted_at": "2017-09-17T19:12:32.792699",
  "updated_at": "2017-09-17T19:12:32.792704",
  "scheduled_at": null,
  "processed_at": null,
  "delivered_at": null,
  "expires_at": null
}
```

## Set your webhook URL for your Number

The new webhook will deliver both new messages as well as delivery receipts. You can distinguish the event type based on the `object` parameter (`sms` for messages, `sms_dlr` for delivery receipts).

**Note: Webhook objects will also return Message objects, and include a `parts` section in the case of a UDH multi-part message.**&#x20;

Your webhook **must** return 200 OK HTTP status code to acknowledge the event, otherwise we’ll attempt to redeliver up to 17 times over 2-3 days (with exponential backoff).

```json
{ "body": "Thank you for texting my webhook number!" }
```

You can optionally send back a JSON response with the `body` key, containing a message response (which will be encoded with the same encoding rules mentioned under the Message Send API) to be sent back to the originator. *We currently only support the `body` key, but are evaluating adding `encoding` and other functionality supported by Message Send.*&#x52;eceive your Content.

## Message Object

Represents a single message. This can be either one actual SMS, or more if the message was longer and split into multiple UDH parts.

This is done because of convenience for our users, generally it’s more important to track the status of a whole message, instead of individual parts. Note that you can still retrieve the number of parts sent (for billing purposes) etc., as well as view part information as needed.

If the low level SMS details are important (down to the PDU), then our SMPP API might be more suitable for you.

In the case of a single message, id, represents the actual sms id.

In the case of a multipart message, the id is representing all the parts. The object will also contain a parts section which will contain information about each of the individual sms parts that were sent. (currently just the part ids, you can use those to retrieve more information via the above Message Get API). To get the number of actual sms sent (in v1, that was the X-Message-Count header), you can either check the length of parts array, or check udh.count.

Below is an example of the package that will be sent to your webhook.

```
{
  "body": "Test 4",
  "delivered_at": null,
  "delivery_receipt": "no",
  "encoding": 3,
  "expires_at": null,
  "from": "14252437709",
  "id": "0658b5fd-d36d-49ae-9e58-d0a7f053f1bb",
  "inserted_at": "2022-04-06T21:49:29.926166",
  "location": null,
  "object": "sms",
  "processed_at": null,
  "scheduled_at": null,
  "status": "new",
  "to": "13462239287",
  "type": "inbound",
  "udh": {
    "count": null,
    "ref_num": null,
    "seq_num": null
  },
  "updated_at": "2022-04-06T21:49:29.926166"
}
```

## Delivery Receipts

### Delivery Receipt Object

| Name                  | Description                                                                                                                    |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| id                    | <p><strong>string</strong><br>Unique identifier for the object</p>                                                             |
| type                  | <p><strong>string</strong><br>Message type, either <code>inbound</code> or <code>outbound</code>.</p>                          |
| from                  | <p><strong>string</strong><br>Number (or sender ID) of the original sender</p>                                                 |
| to                    | <p><strong>string</strong><br>Number of the message recipient</p>                                                              |
| object                | <p><strong>string</strong><br>Always set to <code>sms\_dlr</code>.</p>                                                         |
| delivery\_status      | <p><strong>string</strong><br>Delivery status.</p>                                                                             |
| submitted\_at         | <p><strong>timestamp</strong><br>Time at which the message was submitted</p>                                                   |
| done\_at              | <p><strong>timestamp</strong><br>Time at which the message has reached it’s final state (minute accuracy, seconds ignored)</p> |
| delivery\_error\_code | <p><strong>string</strong><br>If unsuccessful, will contain upstream error code.</p>                                           |
| inserted\_at          | <p><strong>timestamp</strong><br>Denotes when the message was initially received.</p>                                          |
| updated\_at           | <p><strong>timestamp</strong><br>Denotes when the data last changed.</p>                                                       |
| sms.id                | <p><strong>uuid</strong><br>ID of the matching SMS.</p>                                                                        |

### Delivery Status

| Id          | Description                                                                   |
| ----------- | ----------------------------------------------------------------------------- |
| delivered   | Message was successfully delivered.                                           |
| expired     | Message validity period has expired (for instance, the phone was turned off). |
| deleted     | Message has been deleted.                                                     |
| undelivered | Message is undeliverable (for instance the number doesn’t exist)              |
| accepted    | Message was accepted and will be sent.                                        |
| unknown     | Delivery status is unknown.                                                   |
| rejected    | Message was rejected by the carrier                                           |
| failed      | Delivery was unsuccessful.                                                    |
| enroute     | Message is enroute.                                                           |
| skipped     | Message was skipped.                                                          |

### Example DLR

```json
{
  "id": "500fe938-fd2d-4dc1-a186-592e71112388",
  "type": "inbound",
  "from": "15678234",
  "to": "12342341234",
  "object": "sms_dlr",
  "delivery_status": "delivered",
  "delivery_error_code": "000",
  "inserted_at": "2017-09-17T19:12:32.792699",
  "updated_at": "2017-09-17T19:12:32.792704",
  "submitted_at": "2017-06-01T18:00:00",
  "done_at": "2017-06-01T18:00:05",
  "sms": {
    "id": "03b4641f-17a6-4565-bdba-1ce905be3312"
  }
}
```


# Delivery Receipts (DLRs)

## Overview

{% hint style="danger" %}
DLRs are requested on a per-message basis. If you do not request a DLR, you will not have a record of the result of the transaction.
{% endhint %}

A Delivery Receipt (DLR) is **an acknowledgement from a destination carrier network that a message was successfully accepted or rejected** (and the reason the message was rejected). TSG Global supports DLRs on SMS and MMS if a customer has their requested delivery status flag set appropriately. The DLRs will be delivered to your inbound webhook/URI if requested.

## DLR Example

Below is an example DLR:

```
{
  "delivery_error_code": "000",
  "delivery_status": "delivered",
  "done_at": "2022-04-13T21:35:00",
  "from": "14252437709",
  "id": "a2692312-2050-4a50-9123-ca7b4cde0db7",
  "inserted_at": "2022-04-13T21:35:22.401373",
  "object": "sms_dlr",
  "sms": {
    "id": "a4c56a01-4daf-4ae1-9732-025b427add13"
  },
  "submitted_at": "2022-04-13T21:35:00",
  "to": "18574914340",
  "type": "inbound",
  "updated_at": "2022-04-13T21:35:22.401373"
}
```

## DLR Error Codes

A list of current DLR error codes can be found here:\
<https://support.tsgglobal.com/hc/en-us/articles/4643124175131-Common-DLR-Error-Codes>


# SMPP

## SMPP

We also provide an SMPP interface for high-volume users. SMPP is available on the canonical port 2775. An encrypted, secure connection is also provided over TLS (1.1 or 1.2) on port 2776.

We highly recommend you connect via TLS in order to securely transport your messages to us. The normal, non-TLS connection is provided mainly for legacy backwards compatibility reasons.

## Authentication <a href="#authentication" id="authentication"></a>

{% hint style="info" %}
Authentication is done by SMPP credentials you received from TSG team or can be found in the customer portal.&#x20;
{% endhint %}


# Headers

## Authentication

{% hint style="info" %}
Authentication is done by passing your TSG Global API key via the Authorization header in the format "Authorization: Bearer \<api\_key>"
{% endhint %}

## Parameters & Content-Type

Parameters should be JSON encoded and passed in the request body (with the Content-Type header set to `application/json`). IDs are always UUIDv4. Timestamps are in the ISO8601 format and in UTC.

## <br>


# Errors

We use HTTP response codes to indicate specific error classes (2xx range is success, 4xx failed based on the provided parameters, 5xx are server errors). Each error has a machine readable id, and a human readable explanation. Authentication is done by passing the API key via the Authorization header.

### Status Codes <a href="#status-codes" id="status-codes"></a>

| Code | Description                                                                                         |
| ---- | --------------------------------------------------------------------------------------------------- |
| 200  | The request was a success.                                                                          |
| 401  | Request failed because user is not authenticated.                                                   |
| 403  | Request failed because user does not have authorization to access a specific resource.              |
| 404  | Resource doesn’t exist.                                                                             |
| 409  | The request conflicts with another request.                                                         |
| 422  | Your request was understood, but contained invalid parameters.                                      |
| 500  | Something went wrong on the server, check status site and/or report the issue.                      |
| 503  | Service is temporarily unavailable. Generally this is temporary and the requests should be retried. |

### &#x20;Error Types <a href="#error-types" id="error-types"></a>

| Type            | Description                                          |
| --------------- | ---------------------------------------------------- |
| unauthenticated | Request failed because the user is authenticated.    |
| unauthorized    | User does not have access to the specified resource. |
| not\_found      | Resource was not found.                              |
| server\_error   | Internal server error.                               |
| invalid\_params | Parameters were not valid.                           |


# Programmable MMS


# Send an MMS Message

## Overview

Easily send an MMS message with some media content.

## Authentication

{% hint style="info" %}
Authentication is done by passing your TSG Global API key via the Authorization header in the format "Authorization: Bearer \<api\_key>" (using the messaging API key specifically). API credentials can be found here: <https://customer-portal.tsgglobal.com/account>
{% endhint %}

## Method

## Send an MMS message.

<mark style="color:green;">`POST`</mark> `https://mmsc.tsgglobal.world/mms`

The MMS API attempts to mirror an MM4 request, as such it shares some structural similarities and naming. Particularly the use of the ‘type’ field to denote the type of request. Currently only Forward Requests are available.

#### Request Body

| Name                                    | Type                 | Description                                                                                                                                                                  |
| --------------------------------------- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| id                                      | string               | An id, this id may be used to track the message. Note: this can be considered a reference\_id.                                                                               |
| type<mark style="color:red;">\*</mark>  | string               | What type of data should we expect with this message. Should always be `"mms-forward-req"`Note: failure to provide this value will cause the request to fail immediately.    |
| expires\_at                             | datetime             | An ISO8601 formatted timestamp, this designates when the message should expire within the system, expired messages will be dropped if they expire before leaving the queues. |
| expires\_in                             | integer              | A duration in seconds after the message has been received to expire, this will be added to the time of receiving the message to create an `expires_at` value.                |
| transaction\_id                         | string               | This field will be used as the transaction-id of the message, if none is provided, one will be generated.                                                                    |
| from<mark style="color:red;">\*</mark>  | string               | The originator number, should be formatted as E164.                                                                                                                          |
| to<mark style="color:red;">\*</mark>    | list\<string>        | A list of recipients, each number should be formatted as E164.                                                                                                               |
| subject                                 | string               | An optional subject header to apply to the message.                                                                                                                          |
| headers                                 | map                  | An optional map of additional headers to include in the message.                                                                                                             |
| metadata                                | map                  | Any additional data to include in the payload, will be returned on response.                                                                                                 |
| parts<mark style="color:red;">\*</mark> | list                 | A list of parts that make up the body of the message.                                                                                                                        |
| kind                                    | string               | What kind of content does the part contain?, default “plain”.                                                                                                                |
| headers                                 | map\<string, string> | Any additional headers to include in the part.                                                                                                                               |
| content\_type                           | string               | What is the media type of the part?, if none is given this will default to text/plain, unless the kind is a uri or data-uri.                                                 |
| content\_location                       | string               | The name of the attachment, in case a custom SMIL is provided, this will allow referencing the part.                                                                         |
| content\_encoding                       | string               | Any special encodings applied to the body of the part, usually a compression method.                                                                                         |
| transfer\_encoding                      | string               | Any special encodings applied to the body of the part, normally for transport over HTTP/S.                                                                                   |
| body<mark style="color:red;">\*</mark>  | string               | The body or content of the part, may or not be encoded as required.                                                                                                          |
| uri                                     | string               | A URI that is publically accessible that can be downloaded to get the content of the MMS. Content exceeding 3mb will be rejected.                                            |
| request\_delivery\_reports              | boolean              | Requesting DLR for the message to be sent to you. Defaults to false                                                                                                          |

{% tabs %}
{% tab title="200: OK Upon successfully sending an MMS request you will receive a response. This does not mean that the MMS has been sent or delivered, only that it has been accepted by the system for further processing." %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}

## Example POST

```
{
  "data": {
    "type": "mms-forward-req",
    "attributes": {
      "from": "+12223334444",
      "to": [
        "+14252437709"
      ],
      "headers": {},
      "metadata": {},
      "parts": [
        {
          "headers": {},
          "metadata": {},
          "content_location": "body.txt",
          "kind": "plain",
          "content_type": "text/plain",
          "body": "This is a test MMS for the body"
        },
        {
          "headers": {},
          "metadata": {},
          "content_location": "aurora.jpg",
          "kind": "uri",
          "uri": "https://s3.amazonaws.com/content.mms.smshub.world/sample/sample-768x1024.jpg"
        }
      ]
    }
  }
}
```

```json
{
  "data": {
    "id": "1354f59f-7cfc-46de-981a-f750d443f9ec",
    "type": "mms-forward-req",
    "attributes": {
      "from": "+12342341234",
      "to": ["+12003004000"],
      "subject": "This is a test",
      "transaction_id": "c52e6196-4ef6-4ce4-8c89-a0a12791c298",
      "request_delivery_reports": true,
      "headers": {
        "cc": ["+12003005000@example.com"],
        "to": ["+12003004000@example.com", "+12003004001@example.com"]
      },
      "parts": [
        {
          "kind": "plain",
          "headers": {},
          "content_type": "text/plain",
          "content_location": "my_text.txt",
          "content_encoding": "identity",
          "transfer_encoding": "identity",
          "body": "Hello, World",
          "uri": null,
          "metadata": {}
        },
        {
          "body": null,
          "content_encoding": "identity",
          "content_location": null,
          "content_type": "image/png",
          "decoded": false,
          "headers": {},
          "kind": "uri",
          "metadata": {},
          "transfer_encoding": "identity",
          "uri": "http://example.com/image.png"
        }
      ]
    }
  }
}
```

**Delivery Receipts (DLRs)**

DLRs for MMS messages are customer-enabled by optionally flagging a request for a DLR when POSTing to the API. Please include “request\_delivery\_reports”: true as in the above example, requesting that a DLR be sent to you. Omitting or setting it to false will result in no DLRs being forwarded to you.

**Part Kinds**

* `plain`

```json
{
  "kind": "plain",
  "body": "Hello, World"
}
```

Plain parts are used for text attachments, these include `text/*` media types that do not include any binary or restricted characters (i.e. nulls).

* `data-uri`

```json
{
  "kind": "data-uri",
  "content_location": "MyText.txt",
  "uri": "data:text/plain;name=<MyText.txt>,Hello%20World"
}
```

RFC2397 data URIs may be used to specify content\_encoding, content\_type and body in a single string. These strings however have a 65535 character limit.

* `uri`

```json
{
  "kind": "uri",
  "content_type": "item.png",
  "uri": "http://example.org/item.png"
}
```

Parts can also be provided as URIs, the content\_type will be taken from the request or determined based on the extension of the link.

Content downloaded from a URI must be 3 MB or less, otherwise it will be rejected and the message will have a nulled attachment.

{% hint style="warning" %}
The requested resource MUST return a valid `Content-Length`, failure to do so will result in the attachment being nullified. **NOTE:** The server MUST respond to HEAD and GET requests for the attachment to be retrieved.
{% endhint %}

* `embedded`

```json
{
  "kind": "embedded",
  "content_type": "image/png",
  "transfer_encoding": "base64",
  "body": "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4QwLFhYQGrly9gAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAApUlEQVQ4y2P8//8/Q1N6wH8GMkDdzA2MjI1p/v+l5MQYRMQESNL85tUHhmePXjEwMTAwkKwZWQ8TqRovnbmFwmeiRDNJBsA065mokW4ATLOUnBiGHAu5NmO44NKZWxh+xGczhgEwGy6ducXw5tUHFMPwRTNKGMBsevboFYYYUQaIiAlgaCCUyJiwpTCYIbgCjmAsiIgJEJ28mWAZg1QA08NIaXYGABYVP8mp45LoAAAAAElFTkSuQmCC"
}
```

Parts MAY be embedded, in which all the data is included but MAY be compressed or encoded in a different format for transfer. Data in an embedded body must NOT exceed 1Mb (when compressed)

The body of the part will be decoded by applying:

* `transfer_encoding`
* `content_encoding`

To encode the part, apply the encodings in the reverse.

**Note:** All headers are subject to filter and may be excluded.

Any headers that start with following will not be added to the message:

* `x-mms-`
* `content-`
* `checksum-`
* `x-checksum-`
* `message-id`

## Example 200 OK Response

```
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Server: Cowboy
Date: Wed, 23 Oct 2019 18:50:03 GMT
X-Request-ID: FdBbQM5NGxGrvxkAAAUG

{
  "data": {
    "id": "4e36a1f7-fd9c-4851-8087-918902fc204e",
    "type": "mms-forward-res",
    "attributes": {
      "inserted_at": "2019-10-24T00:48:53.312285Z",
      "transaction_id": "e7184cf1-1837-4318-a2cd-82c847830541",
      "from": "12003004005",
      "to": ["13746648333"],
      "subject": "Hello",
      "headers": {},
      "messages": [{
        "message_id": "9f3a72e9-7dc2-4741-96c7-ff2049b49b11",
        "to": "13746648333"
      }],
      "parts": [
        {
          "id": "text-part@localhost",
          "content_type": "text/plain",
          "content_length": "11",
          "content_encoding": "identity",
          "transfer_encoding": "identity",
          "kind": "plain"
        }
      ]
    }
  }
}
```

`data.attributes.messages` will contain a message for each recipient. The provided `message_id` will be used to reference the message in DLRs.

## Additional Examples

### Example - Escape Special Characters

```
# Single character
\n - Line-feed / New-line
\r - Carriage-return
\s - Whitespace (spaces are printable however)
\t - Horizontal-tab
# Unicode
\uXXXX - Unicode character, here X is a hexadecimal value
```

### Example - New Lines in Body

```javascript
// Incorrect
{
  "body": "These
    are
    new
    lines
    that
    aren't
    escaped
    "
}

// Correct
{
  "body": "These\nare\nnew\nlines\nthat\nare\nescaped"
}
```

### Example - the UTF-8 character - for more information please refer to RFC8259

```javascript
{
  "body": "Have a smile 😁"
}
```

### Example - JSON Unicode escape

```javascript
{
  "body": "Have a smile \uD83D\uDE00",
}
```

## Frequently Asked Questions

Q - What is the maximum plain body text limit for an MMS message \
A - We recommend using 1000 characters or less.&#x20;

Q - How many participants can I have in an MMS conversation\
A - We recommend having 10 or fewer participants in an MMS conversation.

Q - My request failed with a 400 Bad Request and a message saying unexpected character at X \
A - The JSON payload was malformed, did you include any new lines inside strings?&#x20;

Q - How can I send a Line-feed/Carriage-return/other-non-printable-characters?\
A - JSON supports several escape sequences for handling non-printable-characters (see above).&#x20;

Q - Can I send UTF-8 characters? \
A - Yes you can, the API supports UTF-8 encoding.

Q - Can I send an emoji?\
A - Yes you can, either using the unicode escape sequence or the UTF-8 character.


# Send an MMS Message Using Templates

## Overview

This functionality enables users to create MMS templates (both content and attachments) which they can use to send MMS messages in a simpler and more performant (less resource intensive) way.&#x20;

Why Templates?

### Why Use MMS Templates?

MMS templates let you define your message content and media attachments once, then send personalized messages at scale — without re-uploading media or rebuilding payloads for every request.

* **Faster sends** — Pre-staged media means smaller payloads and lower latency per message. Skip the base64 encoding and inline attachment overhead.
* **Personalization at scale** — Use `{placeholder}` syntax to inject per-recipient details (names, appointment times, order numbers) into both subject lines and message bodies.
* **Brand consistency** — Lock down approved copy and creative assets in a template so every message stays on-brand, regardless of who triggers the send.
* **Preview before you send** — Render a fully-resolved preview with real placeholder values to catch issues before they hit your customers' phones.
* **Simpler integration** — Your send call is just a template ID, a recipient list, and a params object. No need to reconstruct the full message every time.

***

### Common Use Cases

#### Appointment Reminders with Rich Media

A healthcare provider creates a template with their clinic's logo and a message: *"Hi {patient\_name}, your appointment with {doctor\_name} is on {date} at {time}. Reply CONFIRM or call us to reschedule."* One template, thousands of personalized reminders — each with consistent branding and a professional look that SMS can't match.

#### Marketing Campaigns with Branded Creative

A retail brand launches a flash sale. Their marketing team uploads a promotional image once, locks the copy — *"{first\_name}, our Summer Sale starts now! Show this MMS in-store for an extra 10% off."* — and triggers sends to segmented customer lists via API. No re-uploading the image per batch. No copy drift between segments.

#### Transactional Notifications

An e-commerce platform sends order confirmations with a product thumbnail: *"Thanks {customer\_name}! Your order #{order\_id} has shipped. Track it here: {tracking\_url}"* The product image and layout stay consistent across millions of orders, while every detail is unique per customer.

***

### Quickstart: Send Your First Template MMS

Go from zero to a delivered MMS in three API calls. This guide walks through the full lifecycle: Create a template, Preview it, and Send it.

Prerequisites

* A TSG Global account with MMS enabled
* Your messaging API key (found in Customer Portal → Account)
* A provisioned phone number capable of sending MMS

Authentication

All requests require your TSG Global messaging API key passed via the Authorization header:

Authorization: Bearer \<api\_key>

You can find your messaging API key in the TSG Global Customer Portal under your account settings.

***

Step 1: Create a Template

Define your message copy with placeholders and attach media. Placeholders use {variable\_name} syntax and will be replaced with real values when you preview or send.

{% tabs %}
{% tab title="cURL" %}
curl -X POST <https://mmsc.tsgglobal.world/mms/templates\\>
-H "Content-Type: application/json"\
-H "Authorization: Bearer \<api\_key>"\
-d '{ "data": { "type": "mms-template", "attributes": { "name": "order-confirmation", "subject\_template": "Order #{order\_id} Confirmed", "body\_template": "Hi {customer\_name}, your order #{order\_id} has shipped! Track it here: {tracking\_url}", "parts": \[ { "kind": "uri", "uri": "<https://cdn.example.com/brand-logo.png>", "content\_type": "image/png", "content\_location": "brand-logo.png" } ] } } }'
{% endtab %}

{% tab title="Python" %}
import requests

resp = requests.post( "<https://mmsc.tsgglobal.world/mms/templates>", headers={ "Content-Type": "application/json", "Authorization": "Bearer \<api\_key>", }, json={ "data": { "type": "mms-template", "attributes": { "name": "order-confirmation", "subject\_template": "Order #{order\_id} Confirmed", "body\_template": "Hi {customer\_name}, your order #{order\_id} has shipped! Track it here: {tracking\_url}", "parts": \[ { "kind": "uri", "uri": "<https://cdn.example.com/brand-logo.png>", "content\_type": "image/png", "content\_location": "brand-logo.png", } ], }, } }, )

template = resp.json() template\_id = template\["data"]\["id"] print(f"Created template: {template\_id}")
{% endtab %}
{% endtabs %}

Save the returned template\_id — you'll need it for the next two steps.

***

Step 2: Preview (Optional but Recommended)

Render the template with real values to verify everything looks right — without actually sending anything.

{% tabs %}
{% tab title="cURL" %}
curl -X POST <https://mmsc.tsgglobal.world/mms/templates/TEMPLATE\\_ID/preview\\>
-H "Content-Type: application/json"\
-H "Authorization: Bearer \<api\_key>"\
-d '{ "data": { "type": "mms-template-preview-req", "attributes": { "from": "18005551234", "to": \["19175559876"], "params": { "customer\_name": "Jane", "order\_id": "78432", "tracking\_url": "<https://track.example.com/78432>" } } } }'
{% endtab %}

{% tab title="Python" %}
preview = requests.post( f"<https://mmsc.tsgglobal.world/mms/templates/{template\\_id}/preview>", headers={ "Content-Type": "application/json", "Authorization": "Bearer \<api\_key>", }, json={ "data": { "type": "mms-template-preview-req", "attributes": { "from": "18005551234", "to": \["19175559876"], "params": { "customer\_name": "Jane", "order\_id": "78432", "tracking\_url": "<https://track.example.com/78432>", }, }, } }, )

print(preview\.json())
{% endtab %}
{% endtabs %}

Check the response. The subject should read "Order #78432 Confirmed" and the body should start with "Hi Jane, your order #78432 has shipped!"

***

Step 3: Send It

Same shape as the preview call — just swap the endpoint from /preview to /send.

{% tabs %}
{% tab title="cURL" %}
curl -X POST <https://mmsc.tsgglobal.world/mms/templates/TEMPLATE\\_ID/send\\>
-H "Content-Type: application/json"\
-H "Authorization: Bearer \<api\_key>"\
-d '{ "data": { "type": "mms-template-send-req", "attributes": { "from": "18005551234", "to": \["19175559876"], "params": { "customer\_name": "Jane", "order\_id": "78432", "tracking\_url": "<https://track.example.com/78432>" }, "request\_delivery\_reports": true } } }'
{% endtab %}

{% tab title="Python" %}
send = requests.post( f"<https://mmsc.tsgglobal.world/mms/templates/{template\\_id}/send>", headers={ "Content-Type": "application/json", "Authorization": "Bearer \<api\_key>", }, json={ "data": { "type": "mms-template-send-req", "attributes": { "from": "18005551234", "to": \["19175559876"], "params": { "customer\_name": "Jane", "order\_id": "78432", "tracking\_url": "<https://track.example.com/78432>", }, "request\_delivery\_reports": True, }, } }, )

result = send.json() print(f"Message sent! ID: {result\['data']\['id']}")
{% endtab %}
{% endtabs %}

That's it — three calls from template creation to a delivered MMS.

***

What's Next?

* List your templates — GET /mms/templates to see all saved templates
* Clean up — DELETE /mms/templates/:id to remove templates you no longer need
* Send at scale — Pass multiple numbers in the to array to reach a list in one call
* Track delivery — Set request\_delivery\_reports: true and configure a webhook to receive DLRs

### Relevant pages:

{% content-ref url="/pages/VH6BURy3AyAZj6IM64Qp" %}
[Create MMS Template](/api-reference/programmable-mms/send-an-mms-message-using-templates/create-mms-template)
{% endcontent-ref %}

{% content-ref url="/pages/yFXmV06rXNKCjfOtshvl" %}
[Preview MMS Template](/api-reference/programmable-mms/send-an-mms-message-using-templates/preview-mms-template)
{% endcontent-ref %}

{% content-ref url="/pages/woVqRCJV1Q4ev2vh3Y8t" %}
[Send MMS Using Template](/api-reference/programmable-mms/send-an-mms-message-using-templates/send-mms-using-template)
{% endcontent-ref %}

{% content-ref url="/pages/zmHfsMtBolMZDDxC3ptI" %}
[List MMS templates](/api-reference/programmable-mms/send-an-mms-message-using-templates/list-mms-templates)
{% endcontent-ref %}

{% content-ref url="/pages/kJzj1j6Rtv8oSxXoxSyg" %}
[Get Single MMS template](/api-reference/programmable-mms/send-an-mms-message-using-templates/get-single-mms-template)
{% endcontent-ref %}

{% content-ref url="/pages/ER4MwX31FbSEVDbQ8aI2" %}
[Delete MMS Template](/api-reference/programmable-mms/send-an-mms-message-using-templates/delete-mms-template)
{% endcontent-ref %}


# Create MMS Template

### Authentication

{% hint style="info" %}
Authentication is done by passing your TSG Global API key via the Authorization header in the format "Authorization: Bearer \<api\_key>" (using the messaging API key specifically). API credentials can be found here: <https://customer-portal.tsgglobal.com/account>
{% endhint %}

<mark style="color:green;">`POST`</mark> `https://mmsc.tsgglobal.world/mms/templates`

Creates a new MMS template, the template has placeholders so you can use it to fill per-customer information as needed.

### **Request body**

| Name                                       | Type   | Description                                                                        |
| ------------------------------------------ | ------ | ---------------------------------------------------------------------------------- |
| `data.type`                                | string | Must be `"mms-template"`                                                           |
| `data.attributes.name`                     | string | **Required.** Template name                                                        |
| `data.attributes.body_template`            | string | **Required.** Body text with `{placeholder}` syntax                                |
| `data.attributes.subject_template`         | string | Optional. Subject line with `{placeholder}` syntax                                 |
| `data.attributes.parts`                    | array  | Optional. List of attachment parts (see below)                                     |
| `data.attributes.parts[].kind`             | string | **Required.** One of `"data-uri"`, `"uri"`, `"plain"`, `"embedded"`                |
| `data.attributes.parts[].content_location` | string | Optional. Filename for the attachment                                              |
| `data.attributes.parts[].uri`              | string | Required for `"uri"` and `"data-uri"` kinds. The resource URI or RFC 2397 data URI |
| `data.attributes.parts[].body`             | string | Required for `"plain"` kind                                                        |
| `data.attributes.parts[].content_type`     | string | Optional. MIME type (default: `"text/plain"`)                                      |

Placeholders use the pattern `{key}` where key matches `[a-zA-Z_][a-zA-Z0-9_]*`. Extracted placeholders are returned in the response.

### &#x20;Example with placeholders

#### Example of a request

Besides the text in `body_template` there's 2 parts: a Base64 encoded attachment (`kind: "data-uri"`) and a image that's referenced by a URL (`"kind": "uri"`).

```json
{
  "data": {
    "type": "mms-template",
    "attributes": {
      "name": "visit-thank-you",
      "subject_template": "Hello {name}",
      "body_template": "Dear {name}, welcome to {company}.",
      "parts": [
        {
          "kind": "data-uri",
          "content_location": "brochure.txt",
          "uri": "data:text/plain,Hello%20Brochure"
        },
        {
          "kind": "uri",
          "content_location": "unnamed-1.png",
          "uri": "https://www.tsgglobal.com/wp-content/uploads/2025/01/unnamed-1.png"
        }
      ]
    }
  }
}
```

#### Example response

```json
{
  "data": {
    "attributes": {
      "name": "visit-thank-you",
      "parts": [
        {
          "uri": "https://content-mms.staging.smshub.world/templates/491aa990-1fbb-4058-8af0-c78049010d2f/attachments/1-brochure.txt",
          "content_type": "text/plain",
          "content_location": "brochure.txt"
        },
        {
          "uri": "https://content-mms.staging.smshub.world/templates/491aa990-1fbb-4058-8af0-c78049010d2f/attachments/2-unnamed-1.png",
          "content_type": "image/png",
          "content_location": "unnamed-1.png"
        }
      ],
      "inserted_at": "2026-03-20T19:53:02.165449",
      "updated_at": "2026-03-20T19:53:02.165449",
      "placeholders": [
        "name",
        "company"
      ],
      "body_template": "Dear {name}, welcome to {company}.",
      "subject_template": "Hello {name}"
    },
    "id": "491aa990-1fbb-4058-8af0-c78049010d2f",
    "type": "mms-template"
  }
}

```

### Example without placeholders

This is an example with no placeholders (notice the lack of `{placeholder}` syntax.

#### Example of a request

This is an example without placeholders and a single image attachment provided via  (`"kind": "uri"`). **Note:** the attachment has to be publicly accessible.&#x20;

```json
{
  "data": {
    "type": "mms-template",
    "attributes": {
      "name": "no-placeholder-example",
      "subject_template": "New deals!",
      "body_template": "Check our new deals!",
      "parts": [
        {
          "kind": "uri",
          "content_location": "unnamed-1.png",
          "uri": "https://www.tsgglobal.com/wp-content/uploads/2025/01/unnamed-1.png"
        }
      ]
    }
  }
}
```

#### Example response

```json
{
  "data": {
    "attributes": {
      "name": "no-placeholder-example",
      "parts": [
        {
          "uri": "https://content-mms.staging.smshub.world/templates/491aa990-1fbb-4058-8af0-c78049010d2f/attachments/2-unnamed-1.png",
          "content_type": "image/png",
          "content_location": "unnamed-1.png"
        }
      ],
      "inserted_at": "2026-03-20T19:53:02.165449",
      "updated_at": "2026-03-20T19:53:02.165449",
      "placeholders": [
        "name",
        "company"
      ],
      "body_template": "Check out our new deals!",
      "subject_template": "New deals!"
    },
    "id": "491aa990-1fbb-4058-8af0-c78049010d2f",
    "type": "mms-template"
  }
}
```


# Preview MMS Template

For testing and debugging purposes, you can preview how the resulting MMS will look like without actually sending.

<mark style="color:green;">`POST`</mark> `https://mmsc.tsgglobal.world/mms/templates/:id/preview`

Renders a preview of the template with the given parameters without sending, where `:id`  is the ID of the created template.

### **Request body**

| Name                     | Type             | Description                                                                                            |
| ------------------------ | ---------------- | ------------------------------------------------------------------------------------------------------ |
| `data.type`              | string           | Must be `"mms-template-preview-req"`                                                                   |
| `data.attributes.from`   | string           | **Required.** Sender number (E.164)                                                                    |
| `data.attributes.to`     | array of strings | **Required.** Recipient numbers (E.164)                                                                |
| `data.attributes.params` | object           | **Required.** Key-value map of placeholder values. Must match all placeholders defined in the template |

### Example

#### Example request

```json
{
  "data": {
    "type": "mms-template-preview-req",
    "attributes": {
      "from": "18003004001",
      "to": ["17818434375"],
      "params": {
        "name": "Jane",
        "company": "TSG"
      }
    }
  }
}
```

#### Example response

<pre class="language-json"><code class="lang-json"><strong>{
</strong>  "data": {
    "attributes": {
      "metadata": {},
      "from": "18003004001",
      "parts": [
        {
          "metadata": {},
          "uri": null,
          "body": "Dear Jane, welcome to TSG.",
          "kind": "plain",
          "headers": {},
          "content_type": "text/plain",
          "content_location": null
        },
        {
          "metadata": {},
          "uri": "https://content-mms.staging.smshub.world/templates/491aa990-1fbb-4058-8af0-c78049010d2f/attachments/1-brochure.txt",
          "body": null,
          "kind": "uri",
          "headers": {},
          "content_type": null,
          "content_location": "brochure.txt"
        },
        {
          "metadata": {},
          "uri": "https://content-mms.staging.smshub.world/templates/491aa990-1fbb-4058-8af0-c78049010d2f/attachments/2-unnamed-1.png",
          "body": null,
          "kind": "uri",
          "headers": {},
          "content_type": null,
          "content_location": "unnamed-1.png"
        }
      ],
      "to": [
        "17818434375"
      ],
      "subject": "Hello Jane",
      "request_delivery_reports": false
    },
    "id": "f67481a0-a532-4dda-b931-6973ce292558",
    "type": "mms-forward-req"
  }
}
</code></pre>

### Example without placeholders

#### Example request

```json
{
  "data": {
    "type": "mms-template-preview-req",
    "attributes": {
      "from": "18003004001",
      "to": ["17818434375"],
      "params": {}
    }
  }
}
```

#### Example response

<pre class="language-json"><code class="lang-json"><strong>{
</strong>  "data": {
    "attributes": {
      "metadata": {},
      "from": "18003004001",
      "parts": [
        {
          "metadata": {},
          "uri": null,
          "body": "New deals available!",
          "kind": "plain",
          "headers": {},
          "content_type": "text/plain",
          "content_location": null
        },
        {
          "metadata": {},
          "uri": "https://content-mms.staging.smshub.world/templates/491aa990-1fbb-4058-8af0-c78049010d2f/attachments/2-unnamed-1.png",
          "body": null,
          "kind": "uri",
          "headers": {},
          "content_type": null,
          "content_location": "unnamed-1.png"
        }
      ],
      "to": [
        "17818434375"
      ],
      "subject": "New deals!",
      "request_delivery_reports": false
    },
    "id": "f67481a0-a532-4dda-b931-6973ce292558",
    "type": "mms-forward-req"
  }
}
</code></pre>


# Send MMS Using Template

<mark style="color:green;">`POST`</mark> `https://mmsc.tsgglobal.world/mms/templates/:id/send`

Uses an existing template and sends the MMS.

### **Request body**

| Name                                       | Type             | Description                                                                                            |
| ------------------------------------------ | ---------------- | ------------------------------------------------------------------------------------------------------ |
| `data.type`                                | string           | Must be `"mms-template-send-req"`                                                                      |
| `data.attributes.from`                     | string           | **Required.** Sender number (E.164)                                                                    |
| `data.attributes.to`                       | array of strings | **Required.** Recipient numbers (E.164)                                                                |
| `data.attributes.params`                   | object           | **Required.** Key-value map of placeholder values. Must match all placeholders defined in the template |
| `data.attributes.transaction_id`           | string           | Optional. Client-provided transaction identifier                                                       |
| `data.attributes.request_delivery_reports` | boolean          | Optional. Requesting DLR for the message to be sent to you. Defaults to false. Default: `false`        |
| `data.attributes.metadata`                 | object           | Optional. Additional metadata (default: `{}`)                                                          |

### Example

#### Example request

```json
{
  "data": {
    "type": "mms-template-send-req",
    "attributes": {
      "from": "18003004001",
      "to": ["17818434375"],
      "params": {
        "name": "Jane",
        "company": "TSG"
      }
    }
  }
}
```

#### Example response

```json
{
  "data": {
    "attributes": {
      "messages": [
        {
          "to": "17818434375",
          "message_id": "035273d3-c20d-47ee-9d4c-7b732d36fbe0"
        }
      ],
      "from": "18003004001",
      "parts": [
        {
          "kind": "plain",
          "content_type": "text/plain",
          "transfer_encoding": "identity",
          "content_encoding": "identity"
        },
        {
          "kind": "uri",
          "transfer_encoding": "identity",
          "content_encoding": "identity",
          "content_location": "brochure.txt"
        },
        {
          "kind": "uri",
          "transfer_encoding": "identity",
          "content_encoding": "identity",
          "content_location": "unnamed-1.png"
        }
      ],
      "to": [
        "17818434375"
      ],
      "inserted_at": "2026-03-20T19:53:33.795259",
      "subject": "Hello Jane",
      "headers": {},
      "expires_at": null,
      "transaction_id": "e261793b-da9a-400f-9231-22e736af4d1c"
    },
    "id": "e13b4f90-5a39-405d-a729-0f2b9bca9d60",
    "type": "mms-forward-res"
  }
}
```

### Example without placeholders

### Example request

```json
{
  "data": {
    "type": "mms-template-send-req",
    "attributes": {
      "from": "18003004001",
      "to": ["17818434375"],
      "params": {}
    }
  }
}
```

### Example response

```json
{
  "data": {
    "attributes": {
      "messages": [
        {
          "to": "17818434375",
          "message_id": "035273d3-c20d-47ee-9d4c-7b732d36fbe0"
        }
      ],
      "from": "18003004001",
      "parts": [
        {
          "kind": "plain",
          "content_type": "text/plain",
          "transfer_encoding": "identity",
          "content_encoding": "identity"
        },
        {
          "kind": "uri",
          "transfer_encoding": "identity",
          "content_encoding": "identity",
          "content_location": "unnamed-1.png"
        }
      ],
      "to": [
        "17818434375"
      ],
      "inserted_at": "2026-03-20T19:53:33.795259",
      "subject": "New deals!",
      "headers": {},
      "expires_at": null,
      "transaction_id": "e261793b-da9a-400f-9231-22e736af4d1c"
    },
    "id": "e13b4f90-5a39-405d-a729-0f2b9bca9d60",
    "type": "mms-forward-res"
  }
}
```


# List MMS templates

<mark style="color:$success;">`GET`</mark> `https://mmsc.tsgglobal.world/mms/templates`

Returns all the templates for the account.

### Example response

```json
{
  "data": [
    {
      "attributes": {
        "name": "visit-thank-you",
        "parts": [
          {
            "metadata": {},
            "uri": "https://content-mms.staging.smshub.world/templates/491aa990-1fbb-4058-8af0-c78049010d2f/attachments/1-brochure.txt",
            "headers": {},
            "content_type": "text/plain",
            "content_location": "brochure.txt"
          },
          {
            "metadata": {},
            "uri": "https://content-mms.staging.smshub.world/templates/491aa990-1fbb-4058-8af0-c78049010d2f/attachments/2-unnamed-1.png",
            "headers": {},
            "content_type": "image/png",
            "content_location": "unnamed-1.png"
          }
        ],
        "inserted_at": "2026-03-20T19:53:02.165449",
        "updated_at": "2026-03-20T19:53:02.165449",
        "placeholders": [
          "name",
          "company"
        ],
        "body_template": "Dear {name}, welcome to {company}.",
        "subject_template": "Hello {name}"
      },
      "id": "491aa990-1fbb-4058-8af0-c78049010d2f",
      "type": "mms-template"
    },
    {
      "attributes": {
        "name": "visit-thank-you",
        "parts": [
          {
            "metadata": {},
            "uri": "https://content-mms.staging.smshub.world/185f821e-aac8-4296-88f4-035f155087f5/templates/1-brochure.txt",
            "headers": {},
            "content_type": "text/plain",
            "content_location": "brochure.txt"
          },
          {
            "metadata": {},
            "uri": "https://content-mms.staging.smshub.world/185f821e-aac8-4296-88f4-035f155087f5/templates/2-unnamed-1.png",
            "headers": {},
            "content_type": "image/png",
            "content_location": "unnamed-1.png"
          }
        ],
        "inserted_at": "2026-03-20T17:08:33.315490",
        "updated_at": "2026-03-20T17:08:33.315490",
        "placeholders": [
          "name",
          "company"
        ],
        "body_template": "Dear {name}, welcome to {company}.",
        "subject_template": "Hello {name}"
      },
      "id": "185f821e-aac8-4296-88f4-035f155087f5",
      "type": "mms-template"
    },
    {
      "attributes": {
        "name": "visit-thank-you",
        "parts": [
          {
            "metadata": {},
            "uri": "https://content-mms.staging.smshub.world/0a4cfbcc-533f-4a87-aed7-e49bdfc20025/templates/1-brochure.txt",
            "headers": {},
            "content_type": "text/plain",
            "content_location": "brochure.txt"
          }
        ],
        "inserted_at": "2026-03-20T16:53:12.572326",
        "updated_at": "2026-03-20T16:53:12.572326",
        "placeholders": [
          "name",
          "company"
        ],
        "body_template": "Dear {name}, welcome to {company}.",
        "subject_template": "Hello {name}"
      },
      "id": "0a4cfbcc-533f-4a87-aed7-e49bdfc20025",
      "type": "mms-template"
    }
  ]
}
```


# Get Single MMS template

<mark style="color:$success;">`GET`</mark> `https://mmsc.tsgglobal.world/mms/templates/:id`

Returns a single template by ID.

### Example response

```json
{
  "data": {
    "attributes": {
      "name": "visit-thank-you",
      "parts": [
        {
          "metadata": {},
          "uri": "https://content-mms.staging.smshub.world/templates/491aa990-1fbb-4058-8af0-c78049010d2f/attachments/1-brochure.txt",
          "headers": {},
          "content_type": "text/plain",
          "content_location": "brochure.txt"
        },
        {
          "metadata": {},
          "uri": "https://content-mms.staging.smshub.world/templates/491aa990-1fbb-4058-8af0-c78049010d2f/attachments/2-unnamed-1.png",
          "headers": {},
          "content_type": "image/png",
          "content_location": "unnamed-1.png"
        }
      ],
      "inserted_at": "2026-03-20T19:53:02.165449",
      "updated_at": "2026-03-20T19:53:02.165449",
      "placeholders": [
        "name",
        "company"
      ],
      "body_template": "Dear {name}, welcome to {company}.",
      "subject_template": "Hello {name}"
    },
    "id": "491aa990-1fbb-4058-8af0-c78049010d2f",
    "type": "mms-template"
  }
}
```


# Delete MMS Template

<mark style="color:$danger;">`DELETE`</mark> `https://mmsc.tsgglobal.world/mms/templates/:id`

Deletes a MMS template. Returns `204 No Content` on success.


# Receive an MMS Message

## Overview

Get your message returned via SMTP or via a webhook URL that you provide.

## Routing Address

When requesting routing for your MMS messages, you may either specify an MM4 (SMTP) or HTTP endpoint.

It’s possible to provide Basic authentication details with the routing address:

HTTP Routing Address

`(http|https)://[<username>:<password>@]<hostname>[:<port>][/*<path>]`&#x20;

**Examples**

* `http://example.com/inbound_messages`
* `http://username:password@example.com:8080/inbound_messages`
* `https://johndoe:secret@example.com:8080/messages/mms/tsg_inbound`

MM4 Routing Address

`mm4://[<username>:<password>@]<hostname>[:<port>]`

**Examples**

* `mm4://example.com:2526`
* `mm4://johndoe:secret@example.com:2526`

## Webhook Format

All requests are made using the POST HTTP Verb to the specified endpoint.

Similar to the HTTP API, the webhook uses the very same format for delivering messages.

The request will include the following headers:

```http
Accept: application/json
Content-Type: application/json
User-Agent: Marshmallow/prod-x.y.z
X-Session-ID: aaaaaaaa-aaaa-4aaa-aaaa-aaaaaaaaaaaa
```

**NOTE:** additional headers may be included that are not listed here.

## Webhook Response

When responding to the webhook request, respond with a 2xx status, more specifically:

* 200 OK
* 202 Accepted
* 204 No Content

Any of these statuses will be accepted as an acknowledgement of receive.

Otherwise the MMS system will assume delivery failed and will retry an additional 2 times within it’s current timeframe. If this fails once more, the message will be placed unto the retry and tried at a later time. The message will be retried a total of 20 times with an exponential backoff.

Once a message is received by the system and it’s routing is determined, it cannot be re-routed.

**Note:** All messages will keep their routing, changing a did’s routing will NOT affect messages already in-flight, this ensures that a message meant for an old endpoint will be delivered to that endpoint and nowhere else.

## Example Response

```
{
  "data": [
    {
      "attributes": {
        "expires_at": null,
        "from": "14252437709",
        "headers": {
          "to": [
            "+13462239287/TYPE=PLMN@mmsc.tsgglobal.world"
          ]
        },
        "inserted_at": "2022-04-06T21:50:06.316116",
        "metadata": {},
        "parts": [
          {
            "body": null,
            "content_encoding": "identity",
            "content_length": null,
            "content_location": "476CC8E7CD30DBE0..unk",
            "content_type": "application/smil",
            "decoded": false,
            "headers": {},
            "id": "7a1ebff0-a8b7-4a24-b951-85b04ac6855a",
            "kind": "uri",
            "metadata": {},
            "transfer_encoding": "identity",
            "uri": "https://content.mms.smshub.world/prod/7160ce4c-0205-4e47-9eb7-3954991911c2/parts/476CC8E7CD30DBE0..unk"
          },
          {
            "body": null,
            "content_encoding": "identity",
            "content_length": null,
            "content_location": "image0000.JPG",
            "content_type": "image/jpeg",
            "decoded": false,
            "headers": {},
            "id": "7c2459ec-95b9-454d-8d9a-0293442b6459",
            "kind": "uri",
            "metadata": {},
            "transfer_encoding": "identity",
            "uri": "https://content.mms.smshub.world/prod/7160ce4c-0205-4e47-9eb7-3954991911c2/parts/photo.JPG"
          }
        ],
        "pool_name": null,
        "request_delivery_reports": false,
        "subject": "",
        "to": [
          "13462239287"
        ],
        "transaction_id": "74def178-695b-4f04-9acd-efb3b0e7dab9",
        "version": "2020-01-14"
      },
      "id": "61d55de8-8ccd-4bf3-8b51-848a8c21919b",
      "type": "mms-forward-req"
    }
  ]
}
```


# Receive DLRs

## Overview

You can receive DLR messages via SMTP or HTTP webhook on the same URL as regular messages. The original message is referenced in the `message_id` attribute.

## DLR status codes

| status code   | Description                                                                                                                                                            |
| ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Deferred      | The handset has retrieved the MMS header, but has not downloaded the full message from the mobile network. The handset may still download the message at a later time. |
| Expired       | The handset did not retrieve the message before the message expiration time.                                                                                           |
| Forwarded     | The message has been sent successfully to the mobile network.                                                                                                          |
| Indeterminate | The mobile network could not determine if the message was delivered correctly.                                                                                         |
| Rejected      | The message has been rejected by the MMS gateway or mobile network.                                                                                                    |
| Retrieved     | The message was successfully delivered to the handset and the handset was configured to acknowledge the message with a delivery receipt.                               |
| Unrecognised  | The handset of the mobile subscriber does not recognize the message content.                                                                                           |

## Webhook Format

All requests are made using the POST HTTP Verb to the specified endpoint.

The request will include the following headers:

```http
Accept: application/json
Content-Type: application/json
User-Agent: Marshmallow/prod-x.y.z
X-Session-ID: aaaaaaaa-aaaa-4aaa-aaaa-aaaaaaaaaaaa
```

**NOTE:** additional headers may be included that are not listed here.

Example payload:

````json
```json
{
    "data": [
        {
            "id": "465542bf-6cf0-4023-8c72-cc9eede0ce01",
            "type": "mms-delivery-report-res",
            "attributes": {
                "id": "465542bf-6cf0-4023-8c72-cc9eede0ce01",
                "message_id": "9f3a72e9-7dc2-4741-96c7-ff2049b49b11",
                "mm_status_code": "Retrieved",
                "from": "12345678912",
                "to": [
                    "+92345678912/TYPE=PLMN"
                ],
                "transaction_id": "baf01b87-b987-4625-ae56-2ed506c41f7a"
            }
        }
    ]
}
```
````

## Webhook Response

You must respond with a 2xx status code to acknowledge the DLR message.

If you respond with a 5xx status code the MMS system will retry delivery later with an exponential backoff, similar to MMS delivery.

3xx and 4xx status codes will be considered as a permanent failure and we won't attempt re-delivery


# SMTP

## Overview

It is possible to send MMS messages via SMTP using the MM4 services instead of the HTTP API.

## Authentication

MM4 servers support PLAIN and LOGIN AUTH mechanism.

Use the provided SMPP system\_id as the username, and the API Key as the password.

System IDs are normally 15 characters in length

## Available MM4 Endpoints

**TCP**

* `mmsc.tsgglobal.world:2525`

**TLS/SSL**

* `mmsc.tsgglobal.world:2465`

It is recommended to utilize the TLS port when capable. TLS supports versions 1.1 and 1.2.

## MM4 Commands

* `AUTH` - Mandatory
* `DATA` - Mandatory
* `EHLO` - Mandatory
* `HELO` - Available
* `MAIL` - Mandatory
* `NOOP` - Available, use to test if the connection is working
* `QUIT` - Available, optional, closing the connection also works
* `RCPT` - Mandatory
* `RSET` - Available
* `STARTTLS` - Disabled, use the TLS port instead
* `VRFY` - Unimplemented, and would be disabled

## MM4 Exchange Example

All lines must end with a `CRLF`. Some data has been omitted for brevity.

Note, arrows `> <` have been included in the example to denote origin of message.

* `>` Is a response from the server
* `<` Is input from the client

```
#
< NOOP
> 250 OK
< EHLO your_hostname
> MM4 server babble
< AUTH LOGIN
> 334 VXNlcm5hbWU6
< base64-encoded-system-id
> 334 UGFzc3dvcmQ6
< base64-encoded-api-key
> 235 Authentication successful
< MAIL FROM:<E164-number@hostname>
> 250 Sender OK
< RCPT TO:<E164-number@hostname>
> 250 Recipient OK
< DATA
> 354 enter mail, end with line containing only '.'
< your-mms-content-here
< .
> 250 queued as <message-id>
< QUIT
> 221 BYE
```

Note the order of the commands:

* AUTH must be used before MAIL and RCPT.
* RCPT can only be used after a MAIL command.
* DATA can only be used after a MAIL and RCPT commands.
* QUIT, NOOP can be used at anytime (except while entering mail.)

Failure to do so will result in various errors

```
#
# AUTH before HELO
503 ERROR: send EHLO first

# RCPT or MAIL before EHLO
503 ERROR: send EHLO or HELO first

# RCPT before MAIL
503 ERROR: send MAIL first

# DATA before MAIL
503 ERROR: need MAIL command

# DATA before RCPT
503 ERROR: need RCPT command
```

<br>


# Phone Numbers

Get new numbers and manage existing numbers on your account.


# Search For New Available Numbers

## Overview

Use this API to find a new local numbers that you can instantly use for messaging and voice. We allow users to search for numbers based on a contains field (NPANXX), or based on state + ratecenter. We allow you to search for consecutive numbers, and let you specify a quantity of numbers (up to 100 at a time).

These local numbers are instantly available for voice and SMS, or MMS (if you manually enable MMS on these numbers).

{% hint style="info" %}
**Note:** this is for long-code numbers only, for toll-free numbers check this section:

[Toll-free phone numbers - search & ordering](/api-reference/phone-numbers/toll-free-phone-numbers-search-and-ordering).
{% endhint %}

## Authentication

{% hint style="info" %}
This function is available via our new GraphQL API. You can read more about how to authenticate to this API [here](/graphql-api-and-authentication).
{% endhint %}

## Example Query Using State and Rate Center

```
query {
  numbers(state: "MA", rateCenter:"BOSTON", quantity: 5, consecutive:false) {
    numbers {
      city
      telephoneNumber
      province
      e911Allowed
      mmsAllowed
    }
  }
}
```

## Example Response

```
{
  "data": {
    "numbers": {
      "numbers": [
        {
          "city": "Chelsea",
          "e911Allowed": "Y",
          "mmsAllowed": "Y",
          "province": "MA",
          "telephoneNumber": "8572391650"
        },
        {
          "city": "Chelsea",
          "e911Allowed": "Y",
          "mmsAllowed": "Y",
          "province": "MA",
          "telephoneNumber": "8572391651"
        },
        {
          "city": "Chelsea",
          "e911Allowed": "Y",
          "mmsAllowed": "Y",
          "province": "MA",
          "telephoneNumber": "8572391653"
        },
        {
          "city": "Chelsea",
          "e911Allowed": "Y",
          "mmsAllowed": "Y",
          "province": "MA",
          "telephoneNumber": "8572391654"
        },
        {
          "city": "Chelsea",
          "e911Allowed": "Y",
          "mmsAllowed": "Y",
          "province": "MA",
          "telephoneNumber": "8572391655"
        }
      ]
    }
  }
}
```

## Example Query Using Contains

```
query {
  numbers(contains: "425", quantity: 5, consecutive:false) {
		numbers {
      city
      telephoneNumber
      province
      e911Allowed
      mmsAllowed
    }
  }
}
```

## Example Response

```
{
  "data": {
    "numbers": {
      "numbers": [
        {
          "city": "Everett",
          "e911Allowed": "Y",
          "mmsAllowed": "Y",
          "province": "WA",
          "telephoneNumber": "4253864153"
        },
        {
          "city": "Everett",
          "e911Allowed": "Y",
          "mmsAllowed": "Y",
          "province": "WA",
          "telephoneNumber": "4253864154"
        },
        {
          "city": "Everett",
          "e911Allowed": "Y",
          "mmsAllowed": "Y",
          "province": "WA",
          "telephoneNumber": "4253864157"
        },
        {
          "city": "Everett",
          "e911Allowed": "Y",
          "mmsAllowed": "Y",
          "province": "WA",
          "telephoneNumber": "4253864159"
        },
        {
          "city": "Everett",
          "e911Allowed": "Y",
          "mmsAllowed": "Y",
          "province": "WA",
          "telephoneNumber": "4253864163"
        }
      ]
    }
  }
}
```


# Add Number to Cart

## Overview

Reserve up to 100 numbers at any time in your cart.

## Authentication

{% hint style="info" %}
This function is available via our new GraphQL API. You can read more about how to authenticate to this API [here](/graphql-api-and-authentication).
{% endhint %}

## Example Mutation

```
mutation ReserveNumbers($numbers: [String]) {
  numbersReserve(numbers: $numbers) {
    reserved
    reservedTotal
    excluded
    excludedTotal
    requested
    requestedTotal
  }
}
```

### Query Variables

```
{
  "numbers": ["8572144932", "8572144940"]
}
```

## Example Response

```
{
  "data": {
    "numbersReserve": {
      "excluded": [],
      "excludedTotal": 0,
      "requested": [
        "8572391650",
        "8572391651"
      ],
      "requestedTotal": 2,
      "reserved": [
        "8572391651",
        "8572391650"
      ],
      "reservedTotal": 2
    }
  }
}
```


# Get Reserved Numbers In Cart

## Overview

View all the numbers currently reserved in your cart.

## Authentication

{% hint style="info" %}
This function is available via our new GraphQL API. You can read more about how to authenticate to this API [here](/graphql-api-and-authentication).
{% endhint %}

## Example Query

```
query {
  reservedList {
      numbers {
      telephoneNumber
      city
      lata
    }
  }
}
```

## Example Response

```
{
  "data": {
    "reservedList": {
      "numbers": [
        {
          "city": "BOSTON",
          "lata": "128",
          "telephoneNumber": "8572391650"
        },
        {
          "city": "BOSTON",
          "lata": "128",
          "telephoneNumber": "8572391651"
        }
      ]
    }
  }
}
```


# Remove Reserved Number From Cart

## Overview

Remove reserved numbers you no longer want from your cart.

## Authentication

{% hint style="info" %}
This function is available via our new GraphQL API. You can read more about how to authenticate to this API [here](/graphql-api-and-authentication).
{% endhint %}

## Example Mutation

```
mutation CartRemove($numbers:[String]) {
  releaseReserved(numbers:$numbers) {
    excluded
    excludedCount
    releasedCount
    totalCount
  }
}
```

### Query Variables

```
{
  "numbers": ["8572391651"]
}
```

## Example Response

```
{
  "data": {
    "releaseReserved": {
      "excluded": [],
      "excludedCount": 0,
      "releasedCount": 1,
      "totalCount": 1
    }
  }
}
```


# Checkout Numbers in Cart

## Overview

Checkout and purchase all of the currently reserved numbers in your cart.

## Authentication

{% hint style="info" %}
This function is available via our new GraphQL API. You can read more about how to authenticate to this API [here](/graphql-api-and-authentication).
{% endhint %}

## Example Mutation

This function will add all the numbers currently reserved in your cart to your TSG Global account.

```
mutation OrderNumbers {
  numbersOrder {
    orderId
    items {
      tn
      trunkGroup
      tnNote
    }
  }
}
```

### Example Response

```
{
  "data": {
    "numbersOrder": {
      "items": [
        {
          "tn": "8572391650",
          "tnNote": null,
          "trunkGroup": null
        }
      ],
      "orderId": 0
    }
  }
}
```


# Disconnect Number

## Overview

Disconnect a number currently assigned to your account.

## Authentication

{% hint style="info" %}
This function is available via our new GraphQL API. You can read more about how to authenticate to this API [here](/graphql-api-and-authentication).
{% endhint %}

Per your MSA, there is a 90 day number holding requirement. You can not specify a disconnect date, and the number will be disconnected at the earliest possible time (immediately if outside of the 90 day window).

## Example Mutation

```
# if a number is 12345600000
mutation {
  disconnectNumbers(numbers: ["12345600000"]) {
    internalId
    orderId
    orderName
    requests {
      disconnectAt
      numbers
      requestId
      requestName
      requestNotes
    }
  }
}
```

### Example Response

This is an example of a response - this one will disconnect right away (a disconnectAt timestamp is provided to provide some info for the user):

```
{
  "data": {
    "disconnectNumbers": {
      "internalId": "999000053-ORD",
      "orderId": "a0d0512f-7b61-4517-9e23-fd708344d52e",
      "orderName": "Disconnect order",
      "requests": [
        {
          "disconnectAt": "2021-09-21T13:52:36.664129Z",
          "numbers": [
            "15013929384"
          ],
          "requestId": "2551e1c6-b99b-469a-b4b0-10439685f536",
          "requestName": "Disconnect request",
          "requestNotes": "Disconnect request will be executed right away"
        }
      ]
    }
  }
}
```

Another response example - this one has a delayed disconnect request:

```
{
  "data": {
    "disconnectNumbers": {
      "internalId": "999000030-ORD",
      "orderId": "bf8a1a4d-9d4c-48e6-9feb-720bb3fc529e",
      "orderName": "Disconnect order",
      "requests": [
        {
          "disconnectAt": "2021-09-15T23:49:59.000000Z",
          "numbers": [
            "15013929405"
          ],
          "requestId": "f9cd9320-a32f-43d6-bcf3-90652446e3a5",
          "requestName": "Delayed disconnect request",
          "requestNotes": "Disconnect request delayed due to too recent activation date (90 day disconnect rule)"
        }
      ]
    }
  }
}
```

<br>


# Get Number Information

## Overview

Get basic information relating to a number, including rate center, state, sms enablement, and other data.

## Authentication

{% hint style="info" %}
Authentication is done by passing your TSG Global API key via the Authorization header in the format "Authorization: Bearer \<api\_key>"
{% endhint %}

## SMS and MMS Configuration Method

## Returns information about the did (currently SMS and MMS configuration only).

<mark style="color:blue;">`GET`</mark> `https://api-service.tsgglobal.world/v5/dids/<number>`

Please ensure that your client processes only recognized properties from the response, as new properties may be added without prior notice. All added props will be documented here.&#x20;

#### Path Parameters

| Name                                     | Type   | Description                    |
| ---------------------------------------- | ------ | ------------------------------ |
| number<mark style="color:red;">\*</mark> | string | The number that was looked up. |

{% tabs %}
{% tab title="200: OK " %}

````javascript
```json
{
    "number": "13603556404",
    "number_type": "long-code" | "short-code" | "toll-free",
    "mms_enabled": true | false,
    "mms_uri": "mm4://hooks.staging.tsgglobal.com",
    "sms_enabled": true | false,
    "campaign_id": null | "C12345",
    "compliance_status": "non_compliant" | "pending" | "compliant",
    "sms_status": "NONE" | "PENDING" | "ACTIVE" | "ERROR" | "DSBL-PND",
    "use_case_type": "" | "p2p" | "a2p",
    "nnid": "" | "12345" | null,
    "sms_post_ver": "smpp" | "postv1" | "postv2" | "post3jam",
    "sms_uri": null | "https://hooks.staging.tsgglobal.com",
    "x_api_key_header": null | "" | "abcd1234",
    "ten_dlc_registered": true | false,
    "tmobile_ten_dlc_registered": true | false
}
```
````

Possible sms\_status values:\
\
"N/A" or "NONE" - number not sms enabled\
"PENDING" - number pending to be enabled\
"DSBL-PND" - number pending to be disabled\
"ACTIVE" - number sms enabled\
"ERROR" - unable to sms enable number - contact support
{% endtab %}
{% endtabs %}

## Additional Data Method

## Lookup additional phone number information.

<mark style="color:blue;">`GET`</mark> `https://api-service.tsgglobal.world/v1/did/lookup?did=<1NPANXXXXXX>`

If did param is omitted all numbers on the matching account will be listed one per line.&#x20;

#### Path Parameters

| Name | Type   | Description                                                 |
| ---- | ------ | ----------------------------------------------------------- |
| did  | string | `1NPANXXXXXX`, `+NPANXXXXXX`, `12022011234`, `+12022011234` |

{% tabs %}
{% tab title="200: OK " %}

```javascript
DID, ROUTING INFO, ACTIVATION DATE, LAST USED DATE, SEC USED, DID RATE, ORDER ID, RATE CENTER, STATE, TIER, PORTED, SMS ENABLED, SMS STATUS, SMS POST VERSION, SMS POST URL, PROVISIONING DATA, MAX CHANNELS
"17867469428","SIP/XXXX","2022-01-11 00:00:00","2022-05-01 00:00:01","0","0.0030000000","CUS9079-SMS","MIAMI","FL","0","N","t","ACTIVE","postv1","","ppm-did-billing-RFC2833-no+","2000"
```

{% endtab %}
{% endtabs %}


# Manage Number for SMS & 10DLC


# Enable SMS/10DLC on a Number

## Overview

This method allows you to enable SMS on (almost) any number with TSG Global.

{% hint style="success" %}
Numbers that are searched and ordered in your cart are already SMS enabled, and you do not need to perform this function to make them SMS enabled.
{% endhint %}

## Authentication

{% hint style="info" %}
Authentication is done by passing your TSG Global API key via the Authorization header in the format "Authorization: Bearer \<api\_key>"
{% endhint %}

## Method

## Enable SMS on a phone number.

<mark style="color:green;">`POST`</mark> `https://api-service.tsgglobal.world/v2/sms-enablement`

#### Request Body

| Name                                     | Type   | Description                                                                                                                                                                                                                                           |
| ---------------------------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| did<mark style="color:red;">\*</mark>    | String | The DID you would like to modify"                                                                                                                                                                                                                     |
| action<mark style="color:red;">\*</mark> | String | \[add \| update] (use update if you need to ammend information for already SMS-enabled number - eg. change webhook url or add campaign id)                                                                                                            |
| use\_case\_type                          | String | \[a2p \| p2p \| account\_default] - p2p can be used only if you have p2p use-case approved                                                                                                                                                            |
| p2p\_nnid                                | String | to be used with use\_case\_type p2p and approved nnid for p2p traffic                                                                                                                                                                                 |
| mms\_enable                              | String | \[true \| false] - if not set, account default value will be used                                                                                                                                                                                     |
| mms\_routing                             | String | http, https, mm4, mm4s url to deliver inbound mms to - if not set, account default value will be used                                                                                                                                                 |
| webhook\_url                             | String | http or https SMS webhook url if you want inbound SMS delivered via webhook (leave blank for SMPP or account default value)                                                                                                                           |
| webhook\_type                            | String | \[smpp, postv1, postv2, post3jam] - leave blank for account default settings. It determines inbound message format. postv2 recommended for http(s) deliveries (if webhook url set)                                                                    |
| x\_api\_key\_header                      | String | This value will be passed as x-api-key header in the webhook http call. Can be used to secure your webhook API. (should not be provided if webhook\_type is smpp)                                                                                     |
| campaign\_id                             | String | If the number is needs to be 10DLC registered and assigned to an active campaign, the campaign id should be provided here to complete 10DLC provisioning. Note: sole proprietor campaigns only allow 1 number at a time.                              |
| campaign\_sub\_id                        | String | In case your campaign is associated with the sub id please provide one. Otherwise, do not provide this parameter.                                                                                                                                     |
| skip\_number\_validation                 | String | Setting this optional prop to "true" allows you to provision number that you provided LOA for and you got confirmation from TSG team that it was accepted. Using this prop without TSG confirmation will have no effect - your request will be stale. |

{% hint style="info" %}
Please be aware that this API endpoint has strict parameter parsing. In case an unknown or invalid parameter is provided in the request body, the request will be rejected with an error.
{% endhint %}

{% tabs %}
{% tab title="200: OK Success" %}

```javascript
Success
```

{% endtab %}
{% endtabs %}


# Disable SMS on a Number

## Overview

This method allows you to remove SMS functionality from a number.

## Authentication

{% hint style="info" %}
Authentication is done by passing your TSG Global API key via the Authorization header in the format "Authorization: Bearer \<api\_key>"
{% endhint %}

## Method

## Disable SMS on a DID.

<mark style="color:green;">`POST`</mark> `https://api-service.tsgglobal.world/v2/sms-enablement`

#### Request Body

| Name                                  | Type   | Description                     |
| ------------------------------------- | ------ | ------------------------------- |
| did<mark style="color:red;">\*</mark> | String | The DID you want to sms disable |
| action                                | String | delete                          |

{% hint style="info" %}
Please be aware that this API endpoint has strict parameter parsing. In case an unknown or invalid parameter is provided in the request body, the request will be rejected with an error.
{% endhint %}

{% tabs %}
{% tab title="200: OK Success" %}

```javascript
Succ
```

{% endtab %}
{% endtabs %}


# Update inbound SMS webhook/URI

## Overview

This method allows you to update your inbound messaging webhook/URI for a phone number.

{% hint style="danger" %}
If you are an HTTP API Customer and do not utilize SMPP the `posturl` must be a fully qualified URL i.e. <http://someapi.somedomain.com/somescript.php>\
\
Leaving the `posturl` blank or not including it in your API call will convert the number from HTTP POST to SMPP\
\
Please be sure to have SMPP credentials setup and tested before converting numbers to SMPP or message loss could occur (which is bad).
{% endhint %}

## Authentication

{% hint style="info" %}
Authentication is done by passing your TSG Global API key via the Authorization header in the format "Authorization: Bearer \<api\_key>"
{% endhint %}

## Method

## Update per-did configuration. Currently only sms webhook URL is available using this enpodint.

<mark style="color:green;">`POST`</mark> `https://api-service.tsgglobal.world/v1/sms/webhook`

#### Request Body

| Name                                  | Type   | Description                                                                                                                                                       |
| ------------------------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| webhook\_url                          | String | e.g. <https://example.com/webhook>                                                                                                                                |
| did<mark style="color:red;">\*</mark> | String | DID you want to set/update SMS webhook endpoint for                                                                                                               |
| webhook\_type                         | String | postv2 (default) \| postv1 \| post3jam \| smpp                                                                                                                    |
| x\_api\_key\_header                   | String | This value will be passed as x-api-key header in the webhook http call. Can be used to secure your webhook API. (should not be provided if webhook\_type is smpp) |

{% tabs %}
{% tab title="200: OK " %}

```javascript
Success
```

{% endtab %}
{% endtabs %}

## Example CURL

```
curl -n https://api-service.tsgglobal.world/v1/sms/webhook -XPOST -H "Authorization: Bearer <api_key>" \
-H "Content-Type: application/json" -d '{
  "webhook_url": "https://example.com/webhook",
  "did": "12003004000"
}'
```


# Manage Number for MMS


# Enable MMS on a Number

## Overview

This method allows you to enable MMS on a phone number.

{% hint style="danger" %}
As a prerequisite to use MMS, the number you are enabling must already be SMS enabled, and your account must have MMS enabled. Contact <support@tsgglobal.com> if you have any concerns.
{% endhint %}

## Authentication

{% hint style="info" %}
Authentication is done by passing your TSG Global API key via the Authorization header in the format "Authorization: Bearer \<api\_key>"
{% endhint %}

## Method

<mark style="color:green;">`POST`</mark> `https://api-service.tsgglobal.world/v2/dids/<number>/mms/enable`

#### Path Parameters

| Name                                     | Type   | Description                             |
| ---------------------------------------- | ------ | --------------------------------------- |
| number<mark style="color:red;">\*</mark> | String | The phone number you want to MMS enable |

#### Request Body

| Name                                  | Type   | Description                                                                                                          |
| ------------------------------------- | ------ | -------------------------------------------------------------------------------------------------------------------- |
| uri<mark style="color:red;">\*</mark> | String | A URI pointing to the destination at which you want to receive the messages. Can either be HTTP(S) or an MMS server. |

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
  "mms_enabled": true,
  "mms_uri": "http://mms.example.com",
  "number": "12342341234",
  "sms_enabled": true,
  "sms_uri": null # null means SMPP
}
```

{% endtab %}
{% endtabs %}


# Disable MMS on a Number

## Overview

This method allows you to disable MMS on a phone number.

## Authentication

{% hint style="info" %}
Authentication is done by passing your TSG Global API key via the Authorization header in the format "Authorization: Bearer \<api\_key>"
{% endhint %}

## Method

## Disable MMS on a phone number.

<mark style="color:green;">`POST`</mark> `https://api-service.tsgglobal.world/v2/dids/<number>/mms/disable`

#### Path Parameters

| Name                                     | Type   | Description                           |
| ---------------------------------------- | ------ | ------------------------------------- |
| number<mark style="color:red;">\*</mark> | string | The phone number you want to disable. |

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
    // Response
}
```

{% endtab %}
{% endtabs %}


# Update inbound MMS webhook/URI

## Overview

Update the webhook/URI for inbound MMS messages.

{% hint style="danger" %}
As a prerequisite to use MMS, the number you are enabling must already be SMS enabled, and your account must have MMS enabled. Contact <support@tsgglobal.com> if you have any concerns.
{% endhint %}

## Authentication

{% hint style="info" %}
Authentication is done by passing your TSG Global API key via the Authorization header in the format "Authorization: Bearer \<api\_key>"
{% endhint %}

## Method

To enable MMS, call the below end-point and set the PostURL for inbound MMS.

<mark style="color:green;">`POST`</mark> `https://api-service.tsgglobal.world/v2/dids/<number>/mms/enable`

#### Path Parameters

| Name                                     | Type   | Description                                           |
| ---------------------------------------- | ------ | ----------------------------------------------------- |
| number<mark style="color:red;">\*</mark> | String | The phone number you would like to update sms uri for |

#### Request Body

| Name                                  | Type   | Description                                                                                                          |
| ------------------------------------- | ------ | -------------------------------------------------------------------------------------------------------------------- |
| uri<mark style="color:red;">\*</mark> | String | A URI pointing to the destination at which you want to receive the messages. Can either be HTTP(S) or an MMS server. |

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
  "mms_enabled": true,
  "mms_uri": "http://mms.example.com",
  "number": "12342341234",
  "sms_enabled": true,
  "sms_uri": null # null means SMPP
}
```

{% endtab %}
{% endtabs %}


# Manage Number for Voice


# List Destination Priority

## Overview

This method lets you list the voice destination priority for phone numbers.

## Authentication

{% hint style="info" %}
Authentication is done by passing your TSG Global API key via the Authorization header in the format "Authorization: Bearer \<api\_key>"
{% endhint %}

## Method

## List destination priority associated with a phone numbers.

<mark style="color:blue;">`GET`</mark> `https://api-service.tsgglobal.world/v1/did/priority/lookup`

{% tabs %}
{% tab title="200: OK " %}

````javascript
```
DID,ROUTING INFO,PRIORITY,CALL TYPE
13603556939,SIP/+13603556939@SIP/13603556939@209.119.133.123,1,1
13603556939,SIP/13603556939@SIP/13603556939@209.119.133.123,2,1
13603556404,SIP/13603556404@8.30.173.27,1,1
13603556404,SIP/13603556404@8.36.70.27,2,1
```
````

{% endtab %}
{% endtabs %}


# Add Destination Priority

## Overview

This method lets you update the voice destination priority for phone numbers.

## Authentication

{% hint style="info" %}
Authentication is done by passing your TSG Global API key via the Authorization header in the format "Authorization: Bearer \<api\_key>"
{% endhint %}

## Method

## Add a destination priority associated with a phone number.

<mark style="color:green;">`POST`</mark> `https://api-service.tsgglobal.world/v1/did/priority`

#### Request Body

| Name                                          | Type   | Description                                        |
| --------------------------------------------- | ------ | -------------------------------------------------- |
| did<mark style="color:red;">\*</mark>         | String | The phone number (e.g. 12022011234)                |
| priority<mark style="color:red;">\*</mark>    | String | 1-3 in order of preferred priority.                |
| destination<mark style="color:red;">\*</mark> | String | `192.168.1.1` (for VOIP), `16352321233` (for PSTN) |
| call\_type<mark style="color:red;">\*</mark>  | String | `VOIP`, `PSTN`                                     |
| call\_option                                  | String | `WP`, `NP`                                         |

For VOIP Call Type you need to enter just the IP Address of the Gateway and we will format the rest of the destination. For PSTN Call Type you need to just enter the PSTN Destination in e.164 format or e.164 (-) the Plus.

Type must only contain one of the following `VOIP` = VOIP Destination | `PSTN` = PSTN Destination (This is case sensitive.)

`NP` = VOIP DID Sent to Gateway with out plus | `WP` = VOIP DID Sent to Gateway with plus. (This is case sensitive.)

### Example POST (PSTN)

```
curl -n https://api-service.tsgglobal.world/v1/did/priority -XPOST -H "Authorization: Bearer <api_key>" \
-H "Content-Type: application/json" -d '{
  "did": "12003004000",
  "destination": "16352321233",
  "priority": 2,
  "call_type": "PTSN",
  "call_option": "NP"
}'
```

### Example POST (VOIP)

```
curl -n https://api-service.tsgglobal.world/v1/did/priority -XPOST -H "Authorization: Bearer <api_key>" \
-H "Content-Type: application/json" -d '{
  "did": "12003004000",
  "destination": "192.168.1.1",
  "priority": 3,
  "call_type": "VOIP",
  "call_option": "NP"
}'
```

## **Error Codes**

* `-1000` Invalid or Blank API Key
* `-1001` Invalid or Blank Call Option
* `-1003` Invalid or No DID Provided
* `-1004` Invalid or No Priority Provided
* `-1005` Invalid or No Destination Provided
* `-1006` Invalid or No Call Type Provided
* `-1007` Priority Already Exists Use Another Priority
* `-1008-V` Priority Added to Database as VoIP Destination
* `-1008-P` Priority Added to Database as PSTN Destination
* `-1010` Unknown Error Please Contact TSG Support with URL String for Review


# Update Destination Priority

## Overview

This method allows you to update existing destination priorities for phone numbers.

## Authentication

{% hint style="info" %}
Authentication is done by passing your TSG Global API key via the Authorization header in the format "Authorization: Bearer \<api\_key>"
{% endhint %}

## Method

## Add a destination priority associated with a phone number.

<mark style="color:purple;">`PATCH`</mark> `https://api-service.tsgglobal.world/v1/did/priority`

#### Request Body

| Name                                           | Type   | Description                                                                                                                                                               |
| ---------------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| did<mark style="color:red;">\*</mark>          | String | The phone number (e.g. 12022011234)                                                                                                                                       |
| priority<mark style="color:red;">\*</mark>     | String | 1-3 in order of preferred priority.                                                                                                                                       |
| destination<mark style="color:red;">\*</mark>  | String | `192.168.1.1` (for VOIP), `16352321233` (for PSTN)                                                                                                                        |
| call\_type<mark style="color:red;">\*</mark>   | String | `VOIP`, `PSTN`                                                                                                                                                            |
| call\_option<mark style="color:red;">\*</mark> | String | `WP`, `NP`                                                                                                                                                                |
| dnis                                           | String | Number for TSG to send to your switch as a Diled Number ID e.g. `DID == 13605551212` but you want TSG to send you `3605551212` or `14085551212` instead of the DID number |

For VOIP Call Type you need to enter just the IP Address of the Gateway and we will format the rest of the destination. For PSTN Call Type you need to just enter the PSTN Destination in e.164 format or e.164 (-) the Plus.

Type must only contain one of the following `VOIP` = VOIP Destination | `PSTN` = PSTN Destination (This is case sensitive.)

`NP` = VOIP DID Sent to Gateway with out plus | `WP` = VOIP DID Sent to Gateway with plus. (This is case sensitive.)

### Example PATCH

```
curl -n https://api-service.tsgglobal.world/v1/did/priority -XPATCH -H "Authorization: Bearer <api_key>" \
-H "Content-Type: application/json" -d '{
  "did": "12003004000",
  "destination": "16352321233",
  "priority": 2,
  "call_type": "PTSN",
  "call_option": "NP"
}'
```

## **Error Codes**

* `-1000` Invalid or Blank API Key
* `-1001` Invalid or Blank Call Option
* `-1003` Invalid or No DID Provided
* `-1004` Invalid or No Priority Provided
* `-1005` Invalid or No Destination Provided
* `-1006` Invalid or No Call Type Provided
* `-1007` Priority Already Exists Use Another Priority
* `-1008-V` Priority Added to Database as VoIP Destination
* `-1008-P` Priority Added to Database as PSTN Destination
* `-1010` Unknown Error Please Contact TSG Support with URL String for Review


# Delete Destination Priority

## Overview

This method allows you to remove destination priorities for phone numbers.

## Authentication

{% hint style="info" %}
Authentication is done by passing your TSG Global API key via the Authorization header in the format "Authorization: Bearer \<api\_key>"
{% endhint %}

## Method

## Delete a destination priority associated with a phone number.

<mark style="color:red;">`DELETE`</mark> `https://api-service.tsgglobal.world/v1/did/priority`

#### Path Parameters

| Name                                       | Type   | Description                         |
| ------------------------------------------ | ------ | ----------------------------------- |
| did<mark style="color:red;">\*</mark>      | String | The phone number (e.g. 12022011234) |
| priority<mark style="color:red;">\*</mark> | String | 1-3 in order of preferred priority. |

## Example POST

```
curl -n https://api-service.tsgglobal.world/v1/did/priority -XDELETE -H "Authorization: Bearer <api_key>" \
-H "Content-Type: application/json" -d '{
  "did": "12003004000",
  "priority": 2
}'
```

## **Error Codes**

* `-1000` Invalid or Blank API Key
* `-1003` Invalid or No DID Provided
* `-1004` Invalid or No Priority Provided
* `-1007` Priority Does NOT Exists, Delete an already created priority.
* `-1008` Deleted Priority from Routing.
* `-1010` Can not Delete Priority 1, Please Submit a DID cancel request.

{% hint style="info" %}
**Good to know:** message scheduling can be specified for up to 2 years in advance. We guarantee up to the minute accuracy.
{% endhint %}


# Protect your phone number

Have you ever experienced the discomfort and frustration of your phone number is changed to a different SMS carrier without your consent?

We offer a solution for that. With TSG you can protect messaging portion of your number from being SMS enabled with another SMS vendor in just a few clicks and get notified every time an attempt is made.\
If you would like to Text Protect your numbers, change the webhook notifications URL or remove protection for some of the numbers please reach out to <support@tsgglobal.com> and we will be happy to assist.\
\
For webhook API specification please check the [next page](/api-reference/phone-numbers/protect-your-phone-number/textprotect-webhook).


# TextProtect Webhook

To receive notification on every unauthorized attempt for changing your number messaging provider please provide an URL that exposes HTTP POST endpoint and accepts the body model like in the example below.

```json
{
 "number": "1200300400",
 "sms_account": "TSG100000",
 "requester_nnid": "123456",
 "requester": "carrier",
 "timestamp": "2023-03-30T08:14:19.688501",
 "description": "Request rejected by TextProtect"
}
```

Please respond with 200 OK on success, otherwise, our webhook will retry for the next 72 hours with exponential backoff. If we are unable to deliver the webhook after 72 hours the retry will stop.&#x20;


# Toll-free phone numbers - search & ordering

Shows how to search and order toll-free numbers.

Use this API to find new toll-free numbers. We allow users to search for numbers based on a contains field. We allow you to search for consecutive numbers, and let you specify a quantity of numbers (up to 10 at a time).

To use Toll-free numbers there's only 2 steps - search and order, no reservation or checkout necessary.

## Authentication

{% hint style="info" %}
This function is available via our new GraphQL API. You can read more about how to authenticate to this API [here](/graphql-api-and-authentication).
{% endhint %}

## Search for toll-free numbers

To search for numbers use the `searchPhoneNumbersQuery` GraphQL query, it'll return a list of numbers you can order. The numbers aren't reserved, so maybe they won't be available until you decide to order, in that case, just search for new numbers.

```graphql
query searchPhoneNumbersQuery(
  $contains: String
  $quantity: Int
  $consecutive: Boolean
) {
  tollfreeNumbers(
    contains: $contains
    quantity: $quantity
    consecutive: $consecutive
  ) {
    numbers
  }
}
```

### Example variables

```json
{
  "contains":"888xxxxxxx",
  "quantity":2,
  "consecutive":false
}
```

### Example response

```json
{
  "data": {
    "tollfreeNumbers": {
      "numbers": [
        "18886834580",
        "18886834690"
      ]
    }
  }
}
```

## Order toll-free numbers

To order toll-free numbers, pass the numbers from the previous call and set smsEnable to true or false, depending if you want to enable the numbers for SMS.

It usually takes about 10 minutes for voice service activation. For SMS you need to submit a Verified Sender form for ordered numbers.

```graphql
mutation orderTollfreeNumbersMutation(
  $numbers: [String]
  $smsEnable: Boolean
) {
  orderTollfreeNumbers(numbers: $numbers, smsEnable: $smsEnable) {
    numbers
    orderId
  }
}
```

### Example variables

```json
{
  "numbers": ["18886830411"],
  "smsEnable":true
}
```

### Example response

```json
{
  "data": {
    "orderTollfreeNumbers": {
      "numbers": ["18886830411"],
      "orderId":"999000261-ORD"
    }
  }
}
```

{% hint style="info" %}
**Remember:** After ordering toll-free numbers, you should register a campaign for them using the Toll-Free Verified Sender Form, you can find the [form here](https://customer-portal.tsgglobal.com/tf-verification-form).

More info on campaign registration can be [here](https://support.tsgglobal.com/hc/en-us/articles/5872363711387-New-Toll-Free-SMS-MMS-Verified-Sender-Requirements).
{% endhint %}

## Disconnecting toll-free numbers

To disconnect a toll-free number, check the following section.

{% content-ref url="/pages/V4CG3FJf8ZuPBSmAK8gZ" %}
[Disconnect Number](/api-reference/phone-numbers/disconnect-number)
{% endcontent-ref %}


# Reports


# CDR Records


# Get Count of CDR Records

## Overview

Get the total number of CDR records between a start and end datetime.

## Authentication

{% hint style="info" %}
This function is available via our new GraphQL API. You can read more about how to authenticate to this API [here](/graphql-api-and-authentication).
{% endhint %}

## Method

See documentation [here](/graphql-api-and-authentication).


# Get CDR Records

## Overview

Get call (and messaging) delivery records from your account.

## Authentication

{% hint style="info" %}
This function is available via our new GraphQL API. You can read more about how to authenticate to this API [here](/graphql-api-and-authentication).
{% endhint %}

##

## Endpoint

<mark style="color:green;">`POST`</mark> <https://api.portal.tsgglobal.world/graphql>

## Method

After sending messages or creating calls, you can check those by using the `cdrRecords` query which returns a `paginatedCdrResult` object type. This query is a bit more complex due to the usage of advanced GraphQL features like fragments and cursor based pagination.

Arguments which can be sent are listed below. The exclamation mark (`!`)means a parameter is mandatory, otherwise it's optional:

```
companyId: ID
For which company to list CDRs (only for admin users)

type: CdrType!
The type of the CDR records to list

startDatetime: DateTime!
Will return all records with datetime >= startDatetime

endDatetime: DateTime!
Will return all records with datetime < endDatetime (UTC based), max value is now

cursor: String
Used to paginate, returns results for the passed cursor (if any)

limit: Int
Limit the number of results per page, default is 100, max is 1000
```

### Sample Query

```
query cdrRecordsQuery(
      $type: CdrType!
      $startDatetime: DateTime!
      $endDatetime: DateTime!
      $limit: Int
      $cursor: String
    ) {
      cdrRecords(
        type: $type
        startDatetime: $startDatetime
        endDatetime: $endDatetime
        limit: $limit
        cursor: $cursor
      ) {
        exportLink
        paginationInfo {
          nextCursor
          limit
        }
        cdrs {
          ... on ApiCdr {
            datetime
            from
            destination
            status
            charge
            type
          }
          ... on MessageCdr {
            datetime
            fromNumber
            toNumber
            direction
            status
            charge
            type
          }
          ... on VoiceCdr {
            datetime
            callId
            sourceAni
            destinationNumber
            didUsed
            sessionTime
            status
            calledRate
            charge
            callType
            aniIi
          }
        }
      }
    }
```

In this query GraphQL fragments are used (e.g. `... on MessageCdr { ... }`, they are needed because what we return is a union of types for `cdrs`, and the fields are depending on the passed `type`. In our example below we're using `SMS`, but the fragments can be specified for each field in a general query, only change the type.

In our case the type is `SMS`, you send it as an uppercase string, example of variables sent:

### Sample Variables

```
{
  "type": "SMS",
  "startDatetime": "2022-04-26T07:00:00.000Z",
  "endDatetime": "2022-04-26T17:13:05.377Z",
  "limit": 20
}
```

### Sample Response

```
{
  "data": {
    "cdrRecords": {
      "cdrs": [
        {
          "__typename": "MessageCdr",
          "account": "ACMEANCHO",
          "charge": "0.0095000000",
          "cost": "0.0051500000",
          "datetime": "2022-01-02T00:00:00Z",
          "direction": "SMS / MO Surcharge: T-Mobile - TF",
          "fromNumber": "12247512345",
          "status": "SENT",
          "surcharge": "0.0025000000",
          "toNumber": "18447312345",
          "uniqueId": "45e868c1-96b2-474c-a60f-98b76d812343"
        },
        {
          "__typename": "MessageCdr",
          "account": "ACMEANCHO",
          "charge": "0.0010000000",
          "cost": "0.0000000000",
          "datetime": "2022-01-02T00:00:00Z",
          "direction": "SMS / MO: AT&T - LO-ZERO",
          "fromNumber": "18134512345",
          "status": "SENT",
          "surcharge": "0.0000000000",
          "toNumber": "19725212345",
          "uniqueId": "22854899-1bc9-47b2-9a90-98b76d812344"
        },
        {
          "__typename": "MessageCdr",
          "account": "ACMEANCHO",
          "charge": "0.0095000000",
          "cost": "0.0051500000",
          "datetime": "2022-01-02T00:00:01Z",
          "direction": "SMS / MT Surcharge: T-Mobile - TF",
          "fromNumber": "18777312345",
          "status": "SENT",
          "surcharge": "0.0025000000",
          "toNumber": "16502912345",
          "uniqueId": "ce8590ac-0674-4ef8-8a7f-98b76d812345"
        },
      ],
      "exportLink": "https://api.portal.tsgglobal.world/export/call_records?sig=abe5dfefb701b284db7b8d18e4673654e788ab42a1ef51bcbc4f153ga218f2fa&end_datetime=2022-01-10T23%3A59%3A59.999Z&fields=account%2Cunique_id%2Ccharge%2Cfrom_number%2Cto_number%2Cstatus%2Cdatetime%2Ccost%2Csurcharge%2Cdirection&start_datetime=2022-01-01T00%3A00%3A00.000Z&type=sms&company_internal_id=ACMEANCHO&new_export=true&user_id=e17bbdf0-e72a-4998-bcfb-8f3e92123456",
      "paginationInfo": {
        "limit": 100,
        "nextCursor": null
      }
    }
  }
}
```

### Pagination

We're using pagination for this endpoint because there can be milions of records for short time frames. To paginate through the results tweak the previous query so it looks like this (notice the new `$limit` and `$cursor` arguments):

query($type: CdrType!, $startDatetime: DateTime!, $endDatetime: DateTime!, $companyId: ID, $limit: Int, $cursor: String) { cdrRecords(type: $type, startDatetime: $startDatetime, endDatetime: $endDatetime, companyId: $companyId, limit: $limit, cursor: $cursor) {

```
query($type: CdrType!, $startDatetime: DateTime!, $endDatetime: DateTime!, $companyId: ID, $limit: Int, $cursor: String) {
  cdrRecords(type: $type, startDatetime: $startDatetime, endDatetime: $endDatetime, companyId: $companyId, limit: $limit, cursor: $cursor) {    
		
		cdrs {
			__typename
			... on MessageCdr {
				account
				uniqueId
				charge
				fromNumber
				toNumber
				status
				datetime
				cost
				surcharge
				direction
			}
			
			... on ApiCdr {
				account
				charge
				destination
				datetime
				status
				from
				uniqueId
				type
			}
			
			... on VoiceCdr {
				account
				charge
				destination
				datetime
				status				
				uniqueId
				aniIi
				callId
				callType
				destinationNumber
				sourceAni
				calledRate
				didUsed
				sessionTime
			}
		}
		
		paginationInfo {
			limit
			nextCursor
		}
    exportLink
  }
}
```

and variables (`limit=2` and `cursor=null`):

```json
{
	"type": "SMS",
	"startDatetime": "2022-01-01T00:00:00.000Z",
	"endDatetime": "2022-01-10T23:59:59.999Z",
	"companyId": "65deb62c-bb16-4a9d-927a-ec1abb37a832",
	"limit": 2,
	"cursor": null
}
```

The results we get have `paginationInfo` filled differently, notice the `limit` and `nextCursor` properties below:

```
{
  "data": {
    "cdrRecords": {
      "cdrs": ["...edited for readability..."],
      "exportLink": "...edited for readability...",
      "paginationInfo": {
        "limit": 2,
		"nextCursor": "123456"
      }
    }
  }
}
```

We need to use the `nextCursor` value to get the next page, the variables now look like the following:

```
{
	"type": "SMS",
	"startDatetime": "2022-01-01T00:00:00.000Z",
	"endDatetime": "2022-01-10T23:59:59.999Z",
	"companyId": "65deb62c-bb16-4a9d-927a-ec1abb37a832",
	"limit": 2,
	"cursor": "123456"
}
```

This will get us the next round of results with another `nextCursor` value:

```
{
  "data": {
    "cdrRecords": {
      "cdrs": ["...edited for readability..."],
      "exportLink": "...edited for readability...",
      "paginationInfo": {
        "limit": 2,
		"nextCursor": "554433"
      }
    }
  }
}
```

We can paginate until the result we get has `nextCursor: null`, when it's `null` it means we reached the end.

### Exporting CDRs

You can export CDRs by using the `exportLink` which the `cdrRecords` query provides. The easiest way is to click on the link, but you can also do a server-side or client-side download if you want to save the results.

The links in the above example won't work since they're fake but you can generate one with your queries. The export will trigger a CSV file download (via HTTP streams) and include the fields you specified in the query, but the pagination options will be ignored.

Example of an export Link:

```
https://api.portal.tsgglobal.world/export/call_records? \
sig=abe5dfefb701b284db7b8d18e4673654e788ab42a1ef51bcbc4f153ga218f2fa& \
fields=account,unique_id,charge,from_number,to_number,status,datetime,cost,surcharge,direction& \
start_datetime=2022-01-01T00:00:00.000Z& \
end_datetime=2022-01-10T23:59:59.999Z& \
type=sms& \
company_internal_id=ACMEANCHO& \
new_export=true& \
user_id=e17bbdf0-e72a-4998-bcfb-8f3e92123456
```

#### Notes

* The export link is protected by a signature and cannot be tampered with, once generated it's public.
* The export process has a timeout of 20 minutes, so if you notice the export timing out reduce the startDatetime and endDatetime period to something manageable and try again


# Compliance & Identity


# Toll-Free Verified Sender (Order)

## Overview

Use this API to create and query the status of current Verified Sender Forms (VSFs). Failure to provide VSFs results in blocking to Canada and lower throughputs to US destinations for toll-free numbers. Submitting a VSF removes the block temporarily until the VSF is either approved, or rejected.

## Authentication

{% hint style="info" %}
This function is available via our new GraphQL API. You can read more about how to authenticate to this API [here](/graphql-api-and-authentication).
{% endhint %}

## Mutation - to Create a new VSF

```graphql
mutation (
  $businessName: String!,
  $businessRegisteredAddress: String!,
  $businessRegisteredCity: String!,
  $businessRegisteredState: String!,
  $businessRegisteredZip: String!,
  $businessContactFirstName: String!,
  $businessContactLastName: String!,
  $businessContactEmail: String!,
  $businessContactPhone: String!,
  $fortune500Or1000Company: String!,
  $numbers: [VerifiedSenderFormNumberInput!]!,
  $numbersExplanation: String!,
  $useCase: String!,
  $howDoConsumersOptIn: String!,
  $commercialMessages: String!,
  $numberPublishedLocation: String!,
  $messageSenderWebsite: String!,
  $termsAndPrivacy: String!,
  $callToAction: String!,
  $sampleMessages: [String!]!,
  $helpMessageContainsOptOutInstructions: String!,
  $stopKeywordIsSupportedAsAnOptOutMethod: String!,
  $estimatedMonthlyMessageVolume: String!,
  $previouslyAnotherMessagingServiceTraffic: String!,
  $previouslyAnotherMessagingServiceContent: String,
  $previouslyAnotherMessagingServiceNumbers: [String],
  $canadianTrafficMostly: String!,
  $covid19Related: String!,
  $attachments: [String!]!
) {
  submitVerifiedSenderForm(
    businessName: $businessName,
    businessRegisteredAddress: $businessRegisteredAddress,
    businessRegisteredCity: $businessRegisteredCity,
    businessRegisteredState: $businessRegisteredState,
    businessRegisteredZip: $businessRegisteredZip,
    businessContactFirstName: $businessContactFirstName,
    businessContactLastName: $businessContactLastName,
    businessContactEmail: $businessContactEmail,
    businessContactPhone: $businessContactPhone,
    fortune500Or1000Company: $fortune500Or1000Company,
    numbers: $numbers,
    numbersExplanation: $numbersExplanation,
    useCase: $useCase,
    howDoConsumersOptIn: $howDoConsumersOptIn,
    commercialMessages: $commercialMessages,
    numberPublishedLocation: $numberPublishedLocation,
    messageSenderWebsite: $messageSenderWebsite,
    termsAndPrivacy: $termsAndPrivacy,
    callToAction: $callToAction,
    sampleMessages: $sampleMessages,
    helpMessageContainsOptOutInstructions: $helpMessageContainsOptOutInstructions,
    stopKeywordIsSupportedAsAnOptOutMethod: $stopKeywordIsSupportedAsAnOptOutMethod,
    estimatedMonthlyMessageVolume: $estimatedMonthlyMessageVolume,
    previouslyAnotherMessagingServiceTraffic: $previouslyAnotherMessagingServiceTraffic,
    previouslyAnotherMessagingServiceContent: $previouslyAnotherMessagingServiceContent,
    previouslyAnotherMessagingServiceNumbers: $previouslyAnotherMessagingServiceNumbers,
    canadianTrafficMostly: $canadianTrafficMostly,
    covid19Related: $covid19Related,
    attachments: $attachments
  ) {
    id
    finishedAt
    insertedAt
    name
    status
    data {
      ...VerifiedSenderFormFields
    }
    
    #
  }
}

fragment VerifiedSenderFormFields on VerifiedSenderFormOrderData {
  type
  businessName
  businessRegisteredAddress
  businessRegisteredCity
  businessRegisteredState
  businessRegisteredZip
  businessContactFirstName
  businessContactLastName
  businessContactEmail
  businessContactPhone
  fortune500Or1000Company
  numbers {
    number
  }
  numbersExplanation
  useCase
  howDoConsumersOptIn
  commercialMessages
  numberPublishedLocation
  messageSenderWebsite
  termsAndPrivacy
  callToAction
  sampleMessages
  helpMessageContainsOptOutInstructions
  stopKeywordIsSupportedAsAnOptOutMethod
  estimatedMonthlyMessageVolume
  previouslyAnotherMessagingServiceTraffic
  previouslyAnotherMessagingServiceContent
  previouslyAnotherMessagingServiceNumbers
  canadianTrafficMostly
  covid19Related
}
```

### Sample Arugments

```graphql
### Arguments
{
  "businessName": "[TESTTEST] ACME Inc.",
  "businessRegisteredAddress": "[TESTTEST] Street 1B",
  "businessRegisteredCity": "[TESTTEST] Denver",
  "businessRegisteredState": "Colorado",
  "businessRegisteredZip": "123467",
  "businessContactFirstName": "John",
  "businessContactLastName": "Doe",
  "businessContactEmail": "email@acme.org",
  "businessContactPhone": "12345678910",
  "fortune500Or1000Company": "no",
  "numbers": [
    {
      "number": "12345678910"
    },
    {
      "number": "12345678911"
    }
  ],
  "numbersExplanation": "",
  "useCase": "[TESTTEST] actions, discounts, etc.",
  "howDoConsumersOptIn": "via website",
  "commercialMessages": "yes",
  "numberPublishedLocation": "https://acme.org/numbers",
  "messageSenderWebsite": "https://acme.org",
  "termsAndPrivacy": "https://acme.org/terms",
  "callToAction": "whoa",
  "sampleMessages": [
    "this is a sample message"
  ],
  "helpMessageContainsOptOutInstructions": "yes",
  "stopKeywordIsSupportedAsAnOptOutMethod": "yes",
  "estimatedMonthlyMessageVolume": "10000",
  "previouslyAnotherMessagingServiceTraffic": "yes, on Bandwidth",
  "previouslyAnotherMessagingServiceContent": "hello customer",
  "previouslyAnotherMessagingServiceNumbers": [
    "123456789"
  ],
  "canadianTrafficMostly": "unsure",
  "covid19Related": "unsure",
  "attachments": ["data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg=="]
}
```

## Query - to List VSF Orders

Use the below query to list your Verified Sender Form Orders and retrieve the status of the request.

```graphql
query($page: Int, $publicId: String, $type: String, $addedStartDate: DateTime, $addedEndDate: DateTime) {
  orders(page: $page, publicId: $publicId, type: $type, addedStartDate: $addedStartDate, addedEndDate: $addedEndDate) {
    page
    pageSize
    totalPages
    orders {
      id
      publicId
      name
      insertedAt
      data {
        ...VerifiedSenderFormFields
      }
    }
  }
}

fragment VerifiedSenderFormFields on VerifiedSenderFormOrderData {
  type
  businessName
  businessRegisteredAddress
  businessRegisteredCity
  businessRegisteredState
  businessRegisteredZip
  businessContactFirstName
  businessContactLastName
  businessContactEmail
  businessContactPhone
  fortune500Or1000Company
  numbers {
    number
  }
  numbersExplanation
  useCase
  howDoConsumersOptIn
  commercialMessages
  numberPublishedLocation
  messageSenderWebsite
  termsAndPrivacy
  callToAction
  sampleMessages
  helpMessageContainsOptOutInstructions
  stopKeywordIsSupportedAsAnOptOutMethod
  estimatedMonthlyMessageVolume
  previouslyAnotherMessagingServiceTraffic
  previouslyAnotherMessagingServiceContent
  previouslyAnotherMessagingServiceNumbers
  canadianTrafficMostly
  covid19Related
}
```

### Sample Arugments

```graphql
### Arguments (all are optional)
{
  "page": 1,
  "publicId": "VSF",
  "type": "verified_sender_form",
  "addedStartDate": "2022-01-01T12:00:00Z",
  "addedEndDate": "2022-12-01T12:00:00Z"
}
```


# Short Code Submission (Order)

## Overview

This form allows you to order short code numbers for your messaging campaigns.

## Authentication

{% hint style="info" %}
This function is available via our new GraphQL API. You can read more about how to authenticate to this API [here](/graphql-api-and-authentication).
{% endhint %}

## Mutation - Submit a short code form (order)

Using a GraphQL mutation you can submit the form, the example command is below. This creates an order which will be verified and the short code numbers will be ordered based on the submitted data.&#x20;

```graphql
mutation (
    $businessName: String!
    $businessRegisteredAddress: String!
    $businessRegisteredCity: String!
    $businessRegisteredState: String!
    $businessRegisteredZip: String!
    $businessContactFirstName: String!
    $businessContactLastName: String!
    $businessContactEmail: String!
    $businessContactPhone: String!
    $useCase: String!
    $termsAndConditionsWebsite: String!
    $privacyPolicyWebsite: String!
    $callToActionLocations: String!
    $callToActionLanguage: String!
    $optInKeywords: String!
    $optInConfirmation: String!
    $welcomeMessage: String!
    $exampleAlerts: String!
    $helpResponseText: String!
    $stopResponseText: String!
    $customerSupportContactEmail: String!
    $customerSupportContactPhone: String!
    $customerSupportUrl: String!
    $attachments: [String!]!
  ) {
    submitShortcodeForm(
      businessName: $businessName,
      businessRegisteredAddress: $businessRegisteredAddress,
      businessRegisteredCity: $businessRegisteredCity,
      businessRegisteredState: $businessRegisteredState,
      businessRegisteredZip: $businessRegisteredZip,
      businessContactFirstName: $businessContactFirstName,
      businessContactLastName: $businessContactLastName,
      businessContactEmail: $businessContactEmail,
      businessContactPhone: $businessContactPhone,
      useCase: $useCase,
      termsAndConditionsWebsite: $termsAndConditionsWebsite,
      privacyPolicyWebsite: $privacyPolicyWebsite,
      callToActionLocations: $callToActionLocations,
      callToActionLanguage: $callToActionLanguage,
      optInKeywords: $optInKeywords,
      optInConfirmation: $optInConfirmation,
      welcomeMessage: $welcomeMessage,
      exampleAlerts: $exampleAlerts,
      helpResponseText: $helpResponseText,
      stopResponseText: $stopResponseText,
      customerSupportContactEmail: $customerSupportContactEmail,
      customerSupportContactPhone: $customerSupportContactPhone,
      customerSupportUrl: $customerSupportUrl,
      attachments: $attachments,
    ) {
      id
      publicId
      insertedAt
      name
      status
      statusNote
      finishedAt
      data {
        ...ShortcodeFormFields
      }
    }
  }

fragment ShortcodeFormFields on ShortcodeFormOrderData {
  type
  businessName
  businessRegisteredAddress
  businessRegisteredCity
  businessRegisteredState
  businessRegisteredZip
  businessContactFirstName
  businessContactLastName
  businessContactEmail
  businessContactPhone
  useCase
  termsAndConditionsWebsite
  privacyPolicyWebsite
  callToActionLocations
  callToActionLanguage
  optInKeywords
  optInConfirmation
  welcomeMessage
  exampleAlerts
  helpResponseText
  stopResponseText
  customerSupportContactEmail
  customerSupportContactPhone
  customerSupportUrl
  attachments
}
```

## Sample arguments

The payload should be formatted like this, do note that the attachments is an array of base64 encoded images and/or docs.

```json
{
  "businessName": "ACME Inc.",
  "businessRegisteredAddress": "Street 1B",
  "businessRegisteredCity": "Denver",
  "businessRegisteredState": "Colorado",
  "businessRegisteredZip": "123467",
  "businessContactFirstName": "John",
  "businessContactLastName": "Doe",
  "businessContactEmail": "john.doe@acme.org",
  "businessContactPhone": "12345678910",
  "useCase": "We'll be sending promo messages using short code numbers",
  "termsAndConditionsWebsite": "terms_and_conditions.acme.com",
  "privacyPolicyWebsite": "privacy_policy.acme.com",
  "callToActionLocations": "top and bottom of the page at acme.com",
  "callToActionLanguage": "JOIN NOW, SAVE MONEY, etc.",
  "optInKeywords": "JOIN",
  "optInConfirmation": "YES",
  "welcomeMessage": "Welcome to our shortcode campaign!",
  "exampleAlerts": "New offers available! Join now to save 20%.",
  "helpResponseText": "This is the HELP menu:\n\nSend STOP to stop all messages.",
  "stopResponseText":
    "You used STOP to stop all messages, you'll no longer recieve any promo messages from us.",
  "customerSupportContactEmail": "our_support@company.com",
  "customerSupportContactPhone": "18881231234",
  "customerSupportUrl": "www.our_support.com",
  "attachments": [
    "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg=="
  ]
}
```

## Query - list short code form orders

To retrieve the status of the request, and to list your short code orders you can use the query bellow.

```graphql
query($page: Int, $publicId: String, $type: String, $addedStartDate: DateTime, $addedEndDate: DateTime) {
  orders(page: $page, publicId: $publicId, type: $type, addedStartDate: $addedStartDate, addedEndDate: $addedEndDate) {
    page
    pageSize
    totalPages
    orders {
      id
      publicId
      name
      insertedAt
      data {
        ...ShortcodeFormFields
      }
    }
  }
}


fragment ShortcodeFormFields on ShortcodeFormOrderData {
  type
  businessName
  businessRegisteredAddress
  businessRegisteredCity
  businessRegisteredState
  businessRegisteredZip
  businessContactFirstName
  businessContactLastName
  businessContactEmail
  businessContactPhone
  useCase
  termsAndConditionsWebsite
  privacyPolicyWebsite
  callToActionLocations
  callToActionLanguage
  optInKeywords
  optInConfirmation
  welcomeMessage
  exampleAlerts
  helpResponseText
  stopResponseText
  customerSupportContactEmail
  customerSupportContactPhone
  customerSupportUrl
  attachments
}
```

And the variables look like this.

```json
{
  "page": 1,
  "publicId": "SCF",
  "type": "shortcode_form"
}
```

You can do a more detailed search, e.g. by using the full `publicId.`

```json
{
  "page": 1,
  "publicId": "SCF-5XXY1YJHLK",
  "type": "shortcode_form"
}
```

You can also specify a date range

```json
{
  "page": 1,
  "publicId": "SCF",
  "type": "shortcode_form",
  "addedStartDate": "2022-01-01T12:00:00Z",
  "addedEndDate": "2022-12-01T12:00:00Z"
}
```


# GraphQL API & Authentication

Describes how to authenticate to our GraphQL API.

## What is GraphQL?

GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.

You can learn more about the GraphQL framework here: <https://graphql.org/>

For testing it would be good to use [Postman](https://www.postman.com/) or [Insomnia](https://insomnia.rest/) or some other similar API client.

## How do I access the TSG Global GraphQL API?

{% hint style="danger" %}
This authentication method is different than the API key authentication method used for other TSG Global services, and the TNID service.
{% endhint %}

You can generate a Bearer token to access our GraphQL API using the username and password you use to access our [Customer Portal](https://customer-portal.tsgglobal.com). This token lasts for 7 days.

## Generate Bearer Token

<mark style="color:green;">`POST`</mark> `https://api.portal.tsgglobal.world/account/login`

#### Request Body

| Name                                       | Type   | Description              |
| ------------------------------------------ | ------ | ------------------------ |
| email<mark style="color:red;">\*</mark>    | string | Your user email address. |
| password<mark style="color:red;">\*</mark> | string | Your password.           |

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
    "token": "POAPK_*********",
    "user": {
        "email": "test.user@tsgglobal.com",
        "first_name": "Test",
        "id": "*****",
        "last_name": "User",
        "level": "basic_user"
    }
}
```

{% endtab %}

{% tab title="401: Unauthorized Invalid email or password." %}

```javascript
{
    "errors": [
        {
            "id": "unauthorized",
            "message": "Invalid email or password."
        }
    ]
}
```

{% endtab %}
{% endtabs %}

When you query the API, you will want to pass your credentials in the header, with the header name "Authorization" and the value as "Bearer \<token>".

If you are missing these credentials, please email us at: <support@tsgglobal.com>

## Where can I test the GraphQL API and view more documentation?

You can test various features and view additional documentation in the GraphiQL interface we provide here: <https://api.portal.tsgglobal.world/graphiql>

## What URL should I use to perform my queries and mutations?

Please use: <https://api.portal.tsgglobal.world/graphql> (note this is different than the GraphiQL UI).


