Relayion
How it worksUse casesPricingDocsAbout
Sign inGet started →

API Reference

The Relayion API lets you send and receive SMS through Android devices registered to your account. All requests go to:

https://api.relayion.com

All endpoints are versioned under /api/v1/. All responses use the JSON envelope:

// Success
{ "success": true, "data": { ... } }

// Error
{ "success": false, "error": { "message": "...", "code": "MACHINE_CODE" } }

Authentication

All API endpoints authenticate with an API key. Pass it as a Bearer token in the Authorization header on every request:

Authorization: Bearer rlyn_your_api_key

Getting an API key

Log in to app.relayion.com, go to Settings → API Keys, and click Create key. The full key is shown exactly once. Copy it immediately and store it securely (e.g. in an environment variable). Only the prefix rlyn_xxxxxxxx is retained in the Relayion Console for identification.

Key scopes

Each API key can be authorized to send from one or more devices and SIM slots via scopes configured in the Relayion Console. Routing defaults to the key's default scope. The optional deviceId and simSlotIndex fields on the outbound endpoint let you override routing per request to any scope the key is authorized for.

For inbound message access, the key automatically scopes queries to the phone numbers in its authorized scopes. If a SIM moves to a different device or slot, inbound history remains accessible without creating a new key.


Device discovery

Retrieve the devices registered to your account with their active SIM slots embedded. Use this to confirm device status, inspect SIM slot details, and select the right device when configuring API key scopes in the Relayion Console.

GET /api/v1/devices

Returns all active devices for the account. Soft-deleted devices are excluded. Read-only.

EXAMPLES

curl "https://api.relayion.com/api/v1/devices" \
  -H "Authorization: Bearer rlyn_your_api_key"
{
  "success": true,
  "data": [
    {
      "id": "b1c2d3e4-...",
      "name": "Office Phone 1",
      "status": "ONLINE",
      "isPaired": true,
      "pendingSetup": false,
      "lastSeenAt": "2026-04-25T08:00:00.000Z",
      "sims": [
        {
          "id": "c1d2e3f4-...",
          "slotIndex": 0,
          "phoneNumber": "+639171234567",
          "label": "Globe",
          "isDefault": true
        }
      ]
    }
  ]
}

Only devices where isPaired is true can receive outbound dispatch. Manage devices and label SIM slots from the Relayion Console at app.relayion.com.


Sending SMS

Submit outbound SMS requests via API key auth. The message is pushed to the device over WebSocket. If the device is offline, it is stored as queued and dispatched on reconnect.

POST /api/v1/outbound

FieldTypeRequiredNotes
recipientNumberstringYesE.164 format, e.g. +639171234567
bodystringYesMessage text
deviceIdstringNoRoute to a specific authorized device. Must be in the key's scopes.
simSlotIndexintegerNoPin to a specific SIM slot on the specified device. Requires deviceId.

Routing

Routing defaults to the key's default scope. Pass deviceId to route to a specific authorized device. Pass both deviceId and simSlotIndex to pin to a specific SIM slot on that device. If the target device is offline, the message is stored as QUEUED and dispatched automatically on reconnect.

EXAMPLES

curl -X POST https://api.relayion.com/api/v1/outbound \
  -H "Authorization: Bearer rlyn_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "recipientNumber": "+639171234567",
    "body": "Your appointment is confirmed."
  }'

Response (202)

{
  "success": true,
  "data": {
    "id": "g1h2i3j4-5b6c-7d8e-9f0a-1b2c3d4e5f6a",
    "accountId": "a1b2c3d4-...",
    "deviceId": "b1c2d3e4-...",
    "apiKeyId": "e1f2a3b4-...",
    "simSlotIndex": 0,
    "recipientNumber": "+639171234567",
    "body": "Your appointment is confirmed.",
    "status": "DISPATCHED",
    "createdAt": "2026-04-25T08:00:00.000Z",
    "dispatchedAt": "2026-04-25T08:00:00.001Z",
    "sentAt": null,
    "deliveredAt": null,
    "failedAt": null,
    "failureReason": null
  }
}

status is DISPATCHED if the device was online, QUEUED if offline. Status flow: QUEUED DISPATCHED SENT DELIVERED (or FAILED at any stage after dispatch).

Routing errors

CodeHTTPWhen
UNAUTHORIZED_DEVICE403deviceId specified is not in the key's authorized scopes
NO_ELIGIBLE_DEVICE422All devices in the key's scopes are offline or disabled

GET /api/v1/outbound

List outbound messages. Optional filters: deviceId, recipientNumber, simSlotIndex, status, from (ISO date), to (ISO date). Sorting: sortBy (createdAt | status | recipientNumber, default createdAt), sortOrder (desc | asc, default desc). Returns an array in the same shape as the POST response.

EXAMPLES

curl "https://api.relayion.com/api/v1/outbound?status=DELIVERED&from=2026-04-01T00%3A00%3A00Z" \
  -H "Authorization: Bearer rlyn_your_api_key"

GET /api/v1/outbound/:id

Get a single message by ID with its current delivery status. Returns 404 NOT_FOUND if the message does not exist or belongs to a different account.

EXAMPLES

curl "https://api.relayion.com/api/v1/outbound/g1h2i3j4-5b6c-7d8e-9f0a-1b2c3d4e5f6a" \
  -H "Authorization: Bearer rlyn_your_api_key"

Receiving SMS

Inbound SMS received by a paired device are stored in real time and available for retrieval via the API. For real-time push delivery to your server, see the Webhooks section.

GET /api/v1/inbound

List inbound messages for the bound phone number. Results are automatically pre-scoped to the bound phone number. Only messages received on that number are returned, regardless of which device or SIM slot received them. Optional filters: deviceId, senderNumber, simSlotIndex, from (ISO date), to (ISO date). Sorting: sortBy (createdAt | receivedAt | senderNumber, default createdAt), sortOrder (desc | asc, default desc).

EXAMPLES

curl "https://api.relayion.com/api/v1/inbound?senderNumber=%2B639181234567" \
  -H "Authorization: Bearer rlyn_your_api_key"
{
  "success": true,
  "data": [
    {
      "id": "h1i2j3k4-...",
      "accountId": "a1b2c3d4-...",
      "deviceId": "b1c2d3e4-...",
      "simSlotIndex": 0,
      "senderNumber": "+639181234567",
      "body": "Yes, please confirm my 3pm appointment.",
      "status": "RECEIVED",
      "receivedAt": "2026-04-25T08:05:00.000Z",
      "createdAt": "2026-04-25T08:05:00.000Z"
    }
  ]
}

GET /api/v1/inbound/:id

Get a single inbound message by ID. Returns the same shape as a single item above. Returns 404 NOT_FOUND if not found.

EXAMPLES

curl "https://api.relayion.com/api/v1/inbound/h1i2j3k4-9a8b-7c6d-5e4f-3a2b1c0d9e8f" \
  -H "Authorization: Bearer rlyn_your_api_key"

Conversations

A unified view of all messages (inbound and outbound) exchanged with a specific phone number, sorted oldest first. Use this for conversation threading.

GET /api/v1/conversations/:phoneNumber

The phone number must be URL-encoded (e.g. +63 %2B63). When called with an API key, results are automatically pre-scoped to the bound phone number. Only inbound messages received on that number and outbound messages sent from that number are returned. All filters are optional and combine as AND. Additional optional filters include deviceId, simSlotIndex, from (ISO date), to (ISO date), and direction (inbound | outbound). Sorting: sortOrder (asc | desc, default asc). Pagination uses page and limit (default 20, max 100). Returns { total: 0, messages: [] } if the phone number has no messages.

EXAMPLES

# Fetch only inbound messages from April 1 onwards
curl "https://api.relayion.com/api/v1/conversations/%2B639171234567?direction=inbound&from=2026-04-01T00%3A00%3A00Z" \
  -H "Authorization: Bearer rlyn_your_api_key"
{
  "success": true,
  "data": {
    "phoneNumber": "+639171234567",
    "total": 2,
    "messages": [
      {
        "id": "g1h2i3j4-...",
        "direction": "outbound",
        "deviceId": "b1c2d3e4-...",
        "simSlotIndex": 0,
        "simPhoneNumber": "+639171234567",
        "body": "Your appointment is confirmed.",
        "status": "DELIVERED",
        "sentAt": "2026-04-25T08:00:00.000Z",
        "deliveredAt": "2026-04-25T08:00:03.000Z",
        "createdAt": "2026-04-25T08:00:00.000Z",
        "timestamp": "2026-04-25T08:00:00.000Z"
      },
      {
        "id": "h1i2j3k4-...",
        "direction": "inbound",
        "deviceId": "b1c2d3e4-...",
        "simSlotIndex": 0,
        "simPhoneNumber": "+639171234567",
        "body": "Yes, please confirm my 3pm appointment.",
        "status": "RECEIVED",
        "receivedAt": "2026-04-25T08:05:00.000Z",
        "createdAt": "2026-04-25T08:05:00.000Z",
        "timestamp": "2026-04-25T08:05:00.000Z"
      }
    ]
  }
}

Webhooks

Relayion posts to your registered endpoint in real time when subscribed events occur. Create and manage webhooks from the Relayion Console at app.relayion.com. This section covers what your receiver needs to handle.

Event types

EventWhen it fires
inbound.receivedAn inbound SMS was received by the device and stored
outbound.queuedAn outbound request was accepted while the device was offline
outbound.dispatchedThe send instruction was delivered to the device via WebSocket
outbound.sentThe device confirmed the SMS was submitted to the carrier
outbound.deliveredThe device received a delivery receipt from the carrier
outbound.failedThe device reported the SMS failed to send
Same-category constraint: All events on a single webhook must be either all inbound.* or all outbound.*. Mixing categories is rejected with 422 MIXED_EVENT_CATEGORIES.

Signature verification

Every webhook request includes an X-Relayion-Signature header: the HMAC-SHA256 of the raw request body using your webhook secret, encoded as a hex string. Always verify this before processing.

const crypto = require('crypto');

function verifyWebhook(rawBody, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signature)
  );
}

// Express receiver
app.post('/webhooks/sms', express.raw({ type: 'application/json' }), (req, res) => {
  const sig = req.headers['x-relayion-signature'];
  if (!verifyWebhook(req.body, sig, process.env.WEBHOOK_SECRET)) {
    return res.status(400).send('Invalid signature');
  }
  const event = JSON.parse(req.body);
  // process event.event, event.data
  res.status(200).send('OK');
});

Important: Always verify against the raw body bytes before JSON parsing. Re-serializing parsed JSON can change whitespace or key order and will produce a different hash.

Payload shapes

The inbound.received payload has two forms depending on the includeBody setting on your webhook (configured in the Relayion Console). When includeBody is disabled (the default), the message body is omitted from the event. Use GET /api/v1/inbound/:id with the id from the payload to retrieve the full message on demand. Enable includeBody only if your endpoint and log infrastructure are appropriate for storing message content. The body is transmitted on every delivery attempt and retry.

// inbound.received, includeBody off (default)
{
  "event": "inbound.received",
  "timestamp": "2026-04-07T10:00:00Z",
  "data": {
    "id": "<inboundMessageId>",
    "deviceId": "<deviceId>",
    "senderNumber": "+639171234567",
    "simSlotIndex": 0,
    "simPhoneNumber": "+639171234567",
    "receivedAt": "2026-04-07T10:00:00Z"
  }
}

// inbound.received, includeBody on
{
  "event": "inbound.received",
  "timestamp": "2026-04-07T10:00:00Z",
  "data": {
    "id": "<inboundMessageId>",
    "deviceId": "<deviceId>",
    "senderNumber": "+639171234567",
    "body": "Yes, confirmed.",
    "simSlotIndex": 0,
    "simPhoneNumber": "+639171234567",
    "receivedAt": "2026-04-07T10:00:00Z"
  }
}

// outbound.queued
{
  "event": "outbound.queued",
  "timestamp": "2026-04-07T10:00:00Z",
  "data": {
    "id": "<messageId>",
    "recipientNumber": "+639171234567",
    "status": "queued",
    "createdAt": "2026-04-07T10:00:00Z"
  }
}

// outbound.dispatched
{
  "event": "outbound.dispatched",
  "timestamp": "2026-04-07T10:00:01Z",
  "data": {
    "id": "<messageId>",
    "recipientNumber": "+639171234567",
    "status": "dispatched",
    "dispatchedAt": "2026-04-07T10:00:01Z"
  }
}

// outbound.sent
{
  "event": "outbound.sent",
  "timestamp": "2026-04-07T10:00:02Z",
  "data": {
    "id": "<messageId>",
    "recipientNumber": "+639171234567",
    "status": "sent",
    "sentAt": "2026-04-07T10:00:02Z"
  }
}

// outbound.delivered
{
  "event": "outbound.delivered",
  "timestamp": "2026-04-07T10:01:00Z",
  "data": {
    "id": "<messageId>",
    "recipientNumber": "+639171234567",
    "status": "delivered",
    "deliveredAt": "2026-04-07T10:01:00Z"
  }
}

// outbound.failed
{
  "event": "outbound.failed",
  "timestamp": "2026-04-07T10:00:05Z",
  "data": {
    "id": "<messageId>",
    "recipientNumber": "+639171234567",
    "status": "failed",
    "failedAt": "2026-04-07T10:00:05Z",
    "failureReason": "No signal"
  }
}

Rate limits

Outbound SMS delivery is controlled by a per-device message bucket. Each device has a burst capacity (messages it can dispatch in a short window) and a sustained rate (how many messages are added back per minute for steady delivery). When the bucket is depleted, requests queue automatically. No error is returned and no message is dropped. Messages are delivered as soon as the bucket refills.

PlanBurst capacitySustained rateMonthly cap
Free5 messages1 / min500 messages
Starter50 messages20 / minNone
Pro100 messages50 / minNone
EnterpriseCustomCustomNone

The Free plan enforces a hard monthly cap of 500 outbound messages per calendar month. When that cap is reached the API returns 429 Too Many Requests:

{
  "success": false,
  "error": {
    "message": "Monthly message limit reached.",
    "code": "MONTHLY_LIMIT_EXCEEDED"
  }
}

Paid plans have no monthly message cap. Enterprise plans have custom burst capacity and sustained rates. Contact sales@relayion.com to discuss your requirements.

Questions? Email hello@relayion.com.
https://api.relayion.com

n8n

The Relayion n8n community node lets you integrate Relayion SMS into any n8n workflow. Install it from n8n's community nodes panel, then send messages, query outbound and inbound history, browse conversation threads, list devices, and trigger workflows automatically on SMS events.

By default, the workflow routes through the key's default scope. Use the optional deviceId and simSlotIndexfields on the Send SMS operation to target a specific authorized device or SIM slot. The credential's Test button calls GET /api/v1/devices to verify the key is valid.

Installation

In your n8n instance, go to Settings > Community Nodes > Install, enter the package name below, and restart n8n when prompted.

n8n-nodes-relayion

Credentials

Create a Relayion API credential in n8n with these three fields:

FieldRequiredNotes
API KeyYesBearer token, format rlyn_.... Found in the console under API Keys.
Base URLYesDefault https://api.relayion.com. Change only for self-hosted installs.
Webhook SecretNoRequired only when using the Relayion Trigger node. See Trigger node setup below.

Operations

The node covers four resources:

Outbound Message

OperationDescriptionNotes
Send SMSSubmit an outbound SMS to a recipient number.
GetRetrieve a sent message and its delivery status.Searchable dropdown or direct ID entry.
ListList sent messages with optional filters.Filters: status, recipient, date range. Sorting: created date, recipient number, status.

Inbound Message

OperationDescriptionNotes
GetRetrieve a specific received message.Searchable dropdown or direct ID entry.
ListList received messages with optional filters.Filters: sender, date range, SIM slot. Sorting: created date, received date, sender number.

Conversation

OperationDescription
GetGet a unified thread of all messages (sent and received) with a phone number, sorted by date.

Device

OperationDescription
ListList devices registered to this API key's account, with SIM information.

Simplify toggle

Get and List operations for Outbound and Inbound messages include a Simplify toggle (on by default). When on, the response is trimmed to the most useful fields. When off, the full API response is returned.

Trigger node setup

The Relayion Trigger starts a workflow when Relayion fires a webhook event. Setup is a one-time manual step — the trigger does not auto-register with Relayion.

  1. Add a Relayion Trigger node to your workflow and activate it. n8n displays a webhook URL.
  2. In the Relayion console go to Settings > Webhooks > Create. Paste the URL, select the events you want to subscribe to, and save.
  3. Copy the secret shown after creation. It is shown only once.
  4. Paste the secret into the Webhook Secret field of your Relayion API credential in n8n.
Security: Always set the Webhook Secret in production. Without it, the trigger accepts any incoming POST request without verifying its origin.

Trigger events

EventDescription
inbound.receivedAn SMS was received on your device.
outbound.queuedAn outbound SMS was accepted and queued.
outbound.dispatchedThe send instruction was delivered to the device.
outbound.sentThe device confirmed the SMS was submitted to the carrier.
outbound.deliveredA delivery receipt was received from the carrier.
outbound.failedThe SMS failed to send.

We use analytics cookies to understand how people use this site. No advertising, no cross-site tracking. Privacy Policy