NAV
shell ruby

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:

  1. clientRequestId. This should be the clientRequestId that you specified when you sent the request.
  2. smsServerRequestId. This should be the smsServerRequestId 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:

  1. Take the signature key that you have set up in the Application Settings.
  2. If the callback request is a POST request, take the Content-Type header value from the request. Otherwise, consider the content type equal to a blank string "", even if it might have a value.
  3. Take the request path.
  4. Take the payload. For POST requests it is the body of the request. For GET requests it is the query string.
  5. Take the value of the request header Date.
  6. Create a comma-separated list of the values for
    • request method lower cased, i.e. get or post
    • content type
    • request path
    • payload
    • date header value
  7. 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.
  8. 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

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.