## Overview
The ZignSec Messaging API is designed to provide a robust, secure, and efficient solution for phone verification and two-factor authentication (2FA). It enables businesses to send one-time codes and other notification messages via SMS, ensuring that only the intended recipient can access secure services.
This API is built with flexibility in mind, offering different authentication methods to meet the varying needs and security policies of our partners.
## Usage
The practical application of the ZignSec Messaging API can be divided into several key use cases and important configuration areas.
### Pre-requisites
Before starting with the ZignSec Messaging API, there are several key configuration rules that must be observed to ensure proper operation:
#### Whitelist countries
- The API sends messages only to destination countries that have been explicitly whitelisted.
- You may need to confirm or modify this list to meet your target market requirements.
- For some countries (US/CA or UAE) there is a separate onboarding procedure for each merchant
#### Whitelist senders and configure defaults
- The sender (or “from” field) in your SMS messages must be whitelisted.
- Default sender configurations are managed on the merchant level via our support team.
- It is important to set the approved “from” fields to ensure that messages are delivered without interruption.
### Two-Factor authentication
For organizations that require an additional layer of security, the API supports two-factor authentication. In this use case, a time-sensitive verification code (generated code is valid for 5 minutes by default) is sent via SMS to confirm the identity of the user attempting to log in or perform a sensitive operation. Two-factor authentication helps prevent unauthorized access and ensures that only verified users can complete transactions.
### Sending SMS Message
The API streamlines the process of sending SMS messages by allowing businesses to easily dispatch communication to customers globally. Messages can be used not only for verification purposes but also for sending alerts, reminders, or transactional notifications.
### Choosing Authentication Mechanism
The API supports two authentication methods that allow our merchants to decide the best approach for securing their transactions:
- **Subscription Key:** A traditional method using an API key provided to subscribers. This key needs to be included in every API call to ensure that the request is authorized. For security reasons it shouldn’t be used from the frontend (public facing web site or mobile application), and only participates in the backend to backend communications.
- **OAuth2 (Recommended):** A more modern and secure approach to authentication, OAuth2 allows for better control over access scopes, token management, and enhanced security. It is recommended for most users as it aligns with current industry standards and best practices for API security.
## Core functionalities
### Environments
We maintain 2 environments:
- **PROD** <https://gateway.zignsec.com/api/v5/openapi/messaging/> – for production usage
- **TEST** <https://test-gateway.zignsec.com/api/v5/openapi/messaging/> – for tests (please contact our support if before running a batch or performing load test to avoid issues with rates and limits)
#### Examples
Postman collection: [Link to Collection](https://25357801.fs1.hubspotusercontent-eu1.net/hubfs/25357801/Support%20Files/Postman%20collections/ZignSec%20-%20Phone%20Messaging%20and%20Verification%20-%20examples.postman_collection.json)
### Two-factor authentication
For 2FA scenario we send a regular send message request, but use a verification code placeholder in the message text
#### Verification code placeholder
The following placeholder formats are supported:
- `{code}` – is replaced with a verification code generated using default rules (6-digits number unless specific configuration set for the current credentials)
- `{code:dd}` – where **dd** is a 2-digit number like **02** or **12** – will be replaced with the **dd** number of chars from the configured alphabet (by default it’s digits **0123456789**). For example `{code:05}` can be replaced with a code **01234**
- `{0}` is left for backward compatibility and will be replaced with a 4-digits code
Here is an example using subscription key (you can also find oauth2 examples in our samples collection)
#### Two-Factor Authentication Example
##### Create Session
**Request**
```http
POST https://test-gateway.zignsec.com/api/v5/sessions/messaging/sms
Content-Type: application/json
Zs-Product-Key: Your-Subscription-Key
Host: test-gateway.zignsec.com
```
```json
{
"country_code": "se",
"gdpr_user_id": "my-gdpr-user-id",
"relay_state": "my-customer-id",
"webhook": "https://my-webhook-url.com/",
"metadata": {
"to": "+467012345678",
"text": "Your code is: {code}"
}
}
```
**Response**
```json
{
"id": "842954fd-cf60-458a-a3e5-f9bcfd2032c5",
"status": "Pending",
"errors": [],
"result": {
"parts": 1
}
}
```
##### Get session status
In-progress example
``` http
GET https://test-gateway.zignsec.com/api/v5/sessions/messaging/sms/842954fd-cf60-458a-a3e5-f9bcfd2032c5
```
Returns session in **Pending** status
``` json
{
"id": "842954fd-cf60-458a-a3e5-f9bcfd2032c5",
"status": "Pending",
"errors": [],
"result": {
"smsDeliveryStatus": {
"dpCode": "DP16",
"code": 401,
"status": "Dispatched",
"description": "Dispatched - Message has been dispatched to SMSC.",
"updated": "2025-04-17T16:21:58.5812279Z"
},
"parts": 1
}
}
```
and when message is sent it might return session in terminal status:
``` json
{
"id": "842954fd-cf60-458a-a3e5-f9bcfd2032c5",
"status": "Finished",
"errors": [],
"result": {
"smsDeliveryStatus": {
"dpCode": "DP16",
"code": 0,
"status": "Delivered",
"description": "OK",
"updated": "2025-04-17T16:22:48.2103752Z"
},
"parts": 1
}
}
```
Also, when session changes its status to terminal, webhook is sent (NOTE: webhook is not sent if create session returned error immediately and changed the session to the terminal status from **Created** to **Failed** or **Rejected**, without an attempt to send the message)
``` json
{
"data": {
"errors": [],
"id": "842954fd-cf60-458a-a3e5-f9bcfd2032c5",
"result": {
"parts": 1,
"smsDeliveryStatus": {
"code": 0,
"description": "OK",
"dpCode": "DP16",
"status": "Delivered",
"updated": "2025-04-17T16:22:48.2103752Z"
}
},
"status": "Finished"
},
"event": "session_finished",
"event_time": "2025-04-17T16:22:48.2477468Z",
"gdpr_user_id": "my-gdpr-user-id",
"id": "11371337-01de-43b7-a5e3-63a85f426402",
"info": {
"sessionId": "842954fd-cf60-458a-a3e5-f9bcfd2032c5",
"sessionStatus": "Finished"
},
"integration_id": "Messaging",
"relay_state": "my-customer-id",
"session_created": "2025-04-17T16:22:37.8998829Z",
"session_id": "842954fd-cf60-458a-a3e5-f9bcfd2032c5",
"version": 1
}
```
Terminal session statuses are: **Finished**, **Failed** and **Rejected**.
##### Verify code
To verify the code, we send a get request to the proper endpoint:
``` http
GET https://test-gateway.zignsec.com/api/v5/sessions/messaging/sms/6d7941e2-3bf1-41e9-99f8-065efd5a2b77/234048
```
###### Valid code
And return status code **204 No content** (with no content) says the code is valid
###### Expired code
When the expiration timeout elapsed, it returns **410 Gone** with error
``` json
{
"errors": [
{
"code": "EXPIRED",
"description": "Verification code expired. ",
"statusCode": 410
}
]
}
```
###### Code mismatch
It returns **404 Not Found** with error
``` json
{
"errors": [
{
"code": "CODE_MISMATCH",
"description": "Verification code doesn't match the expected value",
"statusCode": 404
}
]
}
```
### Sending SMS message
It’s similar to the previous example, but text doesn’t contain any placeholders
``` json
{
"country_code": "se",
"gdpr_user_id": "my-gdpr-user-id",
"relay_state": "my-customer-id",
"webhook": "https://my-webhook-url.com",
"metadata": {
"from": "ZignSecTest",
"to": "+467012345678",
"text": "This is a sample text message - hello from ZignSec!"
}
}
```
And response is a session id with status **Pending**
``` json
{
"id": "90dfe237-1321-4db2-a7d0-0b692133cf45",
"status": "Pending",
"errors": [],
"result": { "parts": 1 }
}
```
### Error handling
The general approach is described in the Common integration guidelines, and response http status code indicates an error. Error details might be returned in the response errors array, here is the list of error codes:
| Error code | When | What | What to do |
|----|----|----|----|
| NO_AVAIABLE_SERVICE | On create session | No service available for the given destination | Make sure the phone number is correct and contact support |
| NO_COUNTRY_BY_PHONE | On create session | Country not detected from the given phone | Check the phone number is correct and raise a ticket with our support |
| COUNTRY_BLOCKED | On create session | Country is not a whitelisted message destination | Contact support to enable the destination country |
| SENDER_NOT_ALLOWED | On create session | From number is not a whitelisted sender for the given country | Contact support explicitly to configure the allowed senders |
| SENDER_NOT_SET | On create session | From number is not set neither in request nor in merchant settings | Specify one of the allowed senders in the request or contact support to setup defaults |
| NO_MARKET | On create session | The requested market is not configured | Contact support to find out if it’s possible to add the necessary market |
| SEND_FAILED | On create session | Failed sending message | Check the phone number is valid and find a potential reason in the provider’s delivery status. Contact support if it continues |
| DELIVERY_FAILED | On delivery status check | Failed delivering message | Same as above |
| TIMEOUT | On delivery status check | Timeout elapsed waiting for the delivery status | Check the phone number is valid. Contact support to increase timeout if it happens often |
| REJECTED | On delivery status check | Message rejected (not charged) | Contact support to find out if destination can be unblocked |
| SCHEDULE_UPDATE_FAILED | On create session | Internal error, retry may help | Retry. Contact support if issue persists |