Introduction
Welcome to the Rayo SMS API documentation.
You need to study this guide if you want to integrate your application with Web-to-SMS Functionality via Rayo SMS.
Base Endpoint
The endpoint that you should be sending your API requests to is:
Authentication
The endpoint, although public, it requires that you send your own, private, API Key as part of the HTTP Authorization
header.
You can get and manage your API keys from the Actions -> Settings
page inside the Rayo SMS Web application.
Note that you can have many API keys active at the same time. This will be useful when you decide to decommission an old API key and replace it with a new one. You might want to keep both active at the same time for a short period of time until all of your systems that integrate with Rayo SMS finally use the new API key. Or you can use two different API keys for different purposes. It's up to you.
In the following paragraphs, where we describe the different API features, we will give examples on how you would pass the Authorization as part of the HTTP Request Headers, but until then, here is an example of a valid header:
Authorization: Bearer 1212845e-3517-436f-8f31-86cfb51f6251
Where 1212845e-3517-436f-8f31-86cfb51f6251
, is valid API key. Replace this, with your own API key.
Important: Treat the API keys as confidential as you keep your passwords. Do not store them in version control systems and do not reveal to
public. Always use end-to-end encryption (HTTPS
) between the client application and the Rayo SMS endpoints when using the API.
API Reference
Sending an SMS
$ curl -v -X POST 'https://sms-api.rayo.gr/v1/send_sms' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer 5a2a5816-5f32-4234-a9a1-7d59986c06a5' \
-d '{
"toMobileNumber":"6972669766",
"fromLabel":"306972669766",
"smsBody":"test message"
}'
# This Ruby example uses [Rest Client library](https://github.com/rest-client/rest-client).
# You can use any other Ruby library that can construct standard HTTPS requests.
#
require 'rest-client'
api_key = '5a2a5816-5f32-4234-a9a1-7d59986c06a5'
sms_body = 'test message'
url = 'https://sms-api.rayo.gr/v1/send_sms'
payload = {
toMobileNumber: '6972669766',
fromLabel: '306972669766',
smsBody: sms_body
}.to_json
headers = {
'Content-Type' => 'application/json',
'Accept' => 'application/json',
'Authorization' => "Bearer #{api_key}"
}
response = RestClient.post url, payload, headers
Example Success Response JSON object:
{
"result": {
"username": "user1",
"resultCode": "1",
"resultDescription": "SUCCESS",
"clientRequestId": "932831",
"smsServerRequestId": "cc479845-0f15-4ae7-b645-6ef6489868c1",
"smsRequestScheduleId": "e0b107da-669a-40f5-b4d0-24fc70409307"
}
}
Sending an SMS requires you to send a POST
request to the path /send_sms
The HTTP Request should have the following headers, as a minimum requirement:
Request Headers
Name | Value |
---|---|
Content-Type | application/json |
Accept | application/json |
Authorization | Bearer [your API key here] |
For the Authorization
header above, replace the [your API key here]
with your
own API key. You can find instructions on how to get one here.
The payload of the request should be sent in the body of the request as a string. The string should be a string encoding of a JSON object. The JSON object should have the following properties:
JSON Object Properties
Name | Type | Description | Example |
---|---|---|---|
toMobileNumber |
string | The mobile number this sms will be sent to. It can be a comma-separated or semi-colon separated list of mobile numbers. | 306972669766 or 306972669766;306972669764 |
toGroup |
string | The name of the Group this sms will be sent to. Group is one of your groups registered in the application. You can specify multiple groups separated using ; |
High Valued Customers;Promotion Customers |
fromLabel |
string | The sender identifier. One of the sender ids that you have registered in the application. | BOXNOW |
smsBody |
string | The SMS content. | Hello! You have just won 5 Euro Gift Card! |
clientRequestId |
string | The client request id that will be attached to the sms request. This is optional. It can be used for searching/reporting. It's a business-level value that makes sense to your own business. The application does not process it at all, other than for indexing the message. | 9543212 |
callbackWhenProcessedFlag |
boolean | Default false . When true , SMS server will call the callback api endpoint to report back the status of delivery. You must have set up a callback api in the application settings. |
true |
simulateSendFlag |
boolean | Default false . When true , the SMS will not actually be delivered. This can be used to test the integration without consuming credits. |
false |
scheduledAt |
string | You can schedule a delivery to take place in the future. Important: It should not be earlier than 5 minutes in the future. It needs to be ISO8601 with Time Zone representation of a date and time | "2024-12-13T11:34:29+02:00" |
HTTP Response
Success
On successful sending of the HTTP request, you will get back a standard HTTP response code with value 200
. It will have
a body that will be a JSON object encoded as string. The JSON object will have the following structure:
Name | Type | Description |
---|---|---|
result |
object | JSON root level object. All the other properties, below, they are properties of this object. |
result.username |
string | The username identified by the API key used in the incoming SMS request. |
result.resultCode |
string | It will have the value "1" on success. Different from "1" on failure. |
result.resultDescription |
string | It will have the value "SUCCESS" on success. Different from "SUCCESS" on failure. |
result.clientRequestId |
string | It will be either null or it will have the value of the clientRequestId sent in the incoming SMS request. |
result.smsServerRequestId |
string | A unique identifier from the SMS server side. This uniquely identifies your SMS request. It will value null if you schedule the SMS in the future. |
result.smsRequestScheduleId |
string | A unique identifier of the schedule created when you schedule an SMS to be delivered in the future. It will have value null if you don't schedule. |
Take a look at the Example Response JSON object
.
Error
With regards to error handling, you can read the corresponding section bellow.
Get Balance in Credits
$ curl -v -X POST 'https://sms-api.rayo.gr/v1/balance_in_credits' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer 5a2a5816-5f32-4234-a9a1-7d59986c06a5'
# This Ruby example uses [Rest Client library](https://github.com/rest-client/rest-client).
# You can use any other Ruby library that can construct standard HTTPS requests.
#
require 'rest-client'
api_key = '5a2a5816-5f32-4234-a9a1-7d59986c06a5'
url = 'https://sms-api.rayo.gr/v1/balance_in_credits'
headers = {
'Accept' => 'application/json',
'Authorization' => "Bearer #{api_key}"
}
response = RestClient.get url, headers
Example Success Response JSON object:
{
"request_id": "7d6939ec-7213-4bf9-9b41-2902b54cfa71",
"balance": {
"credits": 4240.0
}
}
This is the API that will return your current balance in credits. It is a GET
request to the path
/balance_in_credits
The HTTP Request should have the following headers, as a minimum requirement:
Request Headers
Name | Value |
---|---|
Accept | application/json |
Authorization | Bearer [your API key here] |
For the Authorization
header above, replace the [your API key here]
with your
own API key. You can find instructions on how to get one here.
HTTP Response
Success
On successful return of the HTTP request, you will get back a standard HTTP response code with value 200
. It will have
a body that will be a JSON object encoded as string. The JSON object will have the following structure:
Name | Type | Description |
---|---|---|
`request_id | string | Unique identifier of your request. |
balance |
object | Object with details about your balance. |
balance.credits |
number | The credits remaining in your balance. |
Take a look at the Example Response JSON object
.
Error
With regards to error handling, you can read the corresponding section bellow.
Check Status of Sms Request
# Get the status of an SMS request by Client Request Id (clientRequestId).
#
$ curl -v -X GET 'https://sms-api.rayo.gr/v1/check_status?clientRequestId=<a-client-request-id>'' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer 5a2a5816-5f32-4234-a9a1-7d59986c06a5'
# Get the status of an SMS request by SMS Server Request Id (smsServerRequestId).
#
$ curl -v -X GET 'https://sms-api.rayo.gr/v1/check_status?smsServerRequestId=<an-sms-serveer-request-id>'' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer 5a2a5816-5f32-4234-a9a1-7d59986c06a5'
# This Ruby example uses [Rest Client library](https://github.com/rest-client/rest-client).
# You can use any other Ruby library that can construct standard HTTPS requests.
#
require 'rest-client'
api_key = '5a2a5816-5f32-4234-a9a1-7d59986c06a5'
# Get the status of an SMS request by Client Request Id (clientRequestId).
#
url = 'https://sms-api.rayo.gr/v1/check_status?clientRequestId=<a-client-request-id>'
headers = {
'Accept' => 'application/json',
'Authorization' => "Bearer #{api_key}"
}
response = RestClient.get url, headers
# Get the status of an SMS request by SMS Server Request Id (smsServerRequestId).
#
url = 'https://sms-api.rayo.gr/v1/check_status?smsServerRequestId=<an-sms-server-request-id>'
headers = {
'Accept' => 'application/json',
'Authorization' => "Bearer #{api_key}"
}
response = RestClient.get url, headers
Example Success Response JSON object:
[
{
"smsServerRequestId": "1396522",
"clientRequestId": "20240316203045",
"internalSmsOutDeliveryId": "1065597",
"mobileNumber": "306972669766",
"status": "delivered"
}
]
This is the API that will return back the status of an SMS Request. Note that an SMS Request might correspond to multiple outgoing SMS messages. This API request will return the status of each one of the outgoing message that belongs to the specified SMS request.
The SMS Request can be located by one, but not both, of the following:
clientRequestId
. This should be theclientRequestId
that you specified when you sent the request.smsServerRequestId
. This should be thesmsServerRequestId
that you got back in the response of the send request.
The HTTP Request should have the following headers, as a minimum requirement:
Request Headers
Name | Value |
---|---|
Accept | application/json |
Authorization | Bearer [your API key here] |
For the Authorization
header above, replace the [your API key here]
with your
own API key. You can find instructions on how to get one here.
Success
On successful return of the HTTP request, you will get back a standard HTTP response code with value 200
. It will have
a body that will be a JSON object encoded as string. The JSON object will have the following structure:
It will be an Array
of objects of the following structure.
Name | Type | Description |
---|---|---|
smsServerRequestId |
string | The SMS Server Request Id of the original SMS Request |
clientRequestId |
string | The Client Request Id that you have assigned to the SMS Request |
internalSmsOutDeliveryId |
string | Unique identifier of the outgoing SMS |
mobileNumber |
string | The destination mobile number for the specific outgoing SMS |
status |
string | The delivery status of the outgoing SMS. See below the table with possible values |
SMS Delivery Status
The possible delivery status values are:
Status | Explanation |
---|---|
new | Initial Status. |
temp_locked | Internal Status. |
processing_error | Failed to Process the Request. Message was not sent out. We will not retry to send it out. |
failure | We tried to send the message out multiple times, but we failed all of them. |
sent | The message was sent out. |
error | There is a temporary error. We will try to send the message again. |
delivered | Message was delivered to the handset. |
not_delivered | Message was sent out, but it was not delivered to the handset. |
unknown_delivery | Message was sent out, but we don't know whether it was delivered or not. |
An outgoing message that leaves our network is on status sent
.
If it is delivered to the handset, it will be on status delivered
.
If it cannot be delivered by the mobile network, it will be on
status not_delivered
. If we don't get a feedback from the
device whether the message has been delivered or not after a day,
it will be turned to unknown_delivery
.
Error
With regards to error handling, you can read the corresponding section bellow.
Note, that if you specify a clientRequestId
and/or an smsServerRequestId
that does not match
any SMS Request in your account, the API request will return HTTP Response Status code 404
and
the response body will be:
Delivery Updates via a Callback Webhook
You can set up your own endpoint which Rayo SMS API will call every time there is an update
on the status of an outgoing SMS. However, in order for this to take place, you need to have set the value
of parameter callbackWhenProcessedFlag
to true
when sending an SMS.
Go to Actions -> Settings
and locate the section Callbacks API
. The Callback URL is a service offered by
Rayo SMS. It gives you the ability to receive delivery reports via a specific URL.
You specify the URL, as well as whether you want the HTTP request to be a GET
or a POST
request.
Moreover, each call the Rayo SMS API does to your service as a callback, it will have
a signature that you can check to make sure that the request is legitimate and it is coming from our
servers. This signature is delivered in the HTTP Request Header Rayo-SMS-Signature
Whenever we need to update the status of a message, we will be calling your callback endpoint.
Parameters/Attributes of payload
The status of the message will be sent back to your endpoint alongside the following parameters:
Parameter Name | Type | Description |
---|---|---|
smsServerRequestId |
string | This is the unique identifier that matches the initial request to send an SMS. Note that each one request, may be corresponding to more than one SMS sent out. For example, if your request refers to a group with more than one member |
clientRequestId |
string | This is the identifier that you have provided when you sent your initial request. Since this parameter is optional on requests, then it may not be present on the delivery reports. |
internalSmsOutDeliveryId |
string | This is unique identifier for each SMS sent out. It is internally generated. |
senderId |
string | This is the Sender Identifier that has been used to send the SMS out. |
mobileNumber |
string | This is the mobile number that the SMS has been sent out to. |
status |
string | This is the delivery status of the outgoing SMS. Read about the possible values above. |
errorDescription |
string | Usually it contains no error but it may contain an error description if the status implies an error. |
requestTimestamp |
string | The timestamp, in iso8601 standard, the SMS request was received by our systems. |
lastStatusUpdatedTimestamp |
string | The timestamp of the last status update. |
Note that if you specify the HTTP Verb to be POST
then the parameters will be delivered to you
in the body of the request encoded as a JSON object. If you, instead, prefer the HTTP Verb to be
GET
then the parameters alongside their values are being URL-encoded.
Signature of the Callback Request
As we said above, for each callback request to your callback endpoint, the request will have an HTTP Header
with name Rayo-SMS-Signature
and value that signs the request.
The signature can be double-checked with the following algorithm:
- Take the signature key that you have set up in the Application Settings.
- If the callback request is a
POST
request, take theContent-Type
header value from the request. Otherwise, consider the content type equal to a blank string""
, even if it might have a value. - Take the request path.
- Take the payload. For
POST
requests it is the body of the request. ForGET
requests it is the query string. - Take the value of the request header
Date
. - Create a comma-separated list of the values for
- request method lower cased, i.e.
get
orpost
- content type
- request path
- payload
- date header value
- request method lower cased, i.e.
- Using the string you created in the previous step and the signing secret create a SHA256 hex digest, where the signing secret is used as a key and the string as the data.
- Compare the resulting SHA256 hex digest to the incoming signature. They should match.
Here is an example of checking the signature in a Ruby on Rails project:
require 'openssl'
class CallbacksController < ApplicationController
skip_before_action :verify_authenticity_token
def callback
# Retrieve the incoming signature from the request headers
incoming_signature = request.headers['Rayo-SMS-Signature']
# Retrieve the secret key from your application settings
signing_secret = ENV['SIGNATURE_KEY'] # here we assume that you pass it as an environment variable
# Perform the signature validation
if valid_signature?(incoming_signature, signing_secret)
render json: { message: "Signature valid" }, status: :ok
else
render json: { message: "Invalid signature" }, status: :unauthorized
end
end
private
def valid_signature?(incoming_signature, signing_secret)
# Step 1: Get the request method (lowercased)
request_method = request.method.downcase
# Step 2: Get the Content-Type header or use a blank string if method `get`
content_type = request.post? ? request.headers['Content-Type'].to_s : ""
# Step 3: Get the request path
request_path = request.path
# Step 4: Get the payload (body for POST, query string for GET)
payload = if request.post?
request.body.read # Body of the POST request
else
request.query_string # Query string for GET requests
end
# Step 5: Get the Date header value
date_header = request.headers['Date']
# Step 6: Create the string to sign
string_to_sign = [
request_method,
content_type,
request_path,
payload,
date_header
].join(',')
# Step 7: Create the SHA256 hex digest using the signing secret as the key
digest = OpenSSL::HMAC.hexdigest('SHA256', signing_secret, string_to_sign)
# Compare the resulting digest with the incoming signature
ActiveSupport::SecurityUtils.secure_compare(digest, incoming_signature)
end
end
Scheduling a Delivery in the Future
Read about it in the Sending an SMS section.
Deleting a schedule
# Delete a schedule using the schedule identifier
#
curl -v -X DELETE 'https://sms-api.rayo.gr/v1/sms_request_schedules/e0b107da-669a-40f5-b4d0-24fc70409307' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer 5a2a5816-5f32-4234-a9a1-7d59986c06a5
# This Ruby example uses [Rest Client library](https://github.com/rest-client/rest-client).
# You can use any other Ruby library that can construct standard HTTPS requests.
#
require 'rest-client'
api_key = '5a2a5816-5f32-4234-a9a1-7d59986c06a5'
# Delete a schedule using the schedule identifier
#
url = 'https://sms-api.rayo.gr/v1/sms_request_schedules/<schedule-identifier>'
headers = {
'Accept' => 'application/json',
'Authorization' => "Bearer #{api_key}"
}
response = RestClient.delete url, headers
You can delete a schedule that you have created. This is only possible as long as the schedule has not fired.
You have to pass the correct authorization headers as described here
More API Endpoints on the Way
We are in the process of developing more API endpoints that will allow you to
- Manage Contacts, and
- Manage groups
Errors
A lot of things might go wrong with your HTTP Requests. Rayo SMS API returns Standard HTTP Response Status Codes to indicate the success or failure of the request.
When the HTTP Response code is in the range 400-599
, this means that something has gone wrong.
The following are common error cases. You can see the HTTP Response Status Code and possible causes of error:
Status Code | Explanation |
---|---|
401 |
You have provided a non-existing or inactive API key |
422 |
When the data in the request are invalid. For example, for an SMS request, the fromLabel does not belong to you. |
500-599 |
Indicates an error that took place on the server side. Rayo SMS developers are automatically notified for such errors and will immediately try to remedy this situation. If your problem persists, use the contact form on Rayo SMS Web site to report the problem. |
In case you get an error in the range 500-599
, we are suggesting that you retry your
request. Maybe with an increasing wait time in-between the retries. You can retry up to a certain
amount of times before you give up.
Structure of JSON Object in Response Body when Error:
{
"result": {
"username": "...",
"resultCode": "0",
"resultDescription": "ERROR: ...",
"clientRequestId": "...",
"smsServerRequestId": null
},
"error": "..."
}
The body of the HTTP Response body, might give you more information about what was the problem. If it is
not empty, it will contain a JSON object. Take a look at the Structure of JSON Object in Response Body when Error
.