SimRelay API (1.0)

Download OpenAPI specification:

API documentation for SimRelay.

Authentication

SimRelay supports multiple authentication methods:

1. OAuth2 (SimRelay Chrome Extension)

The SimRelay Chrome Extension uses OAuth2 Authorization Code flow with PKCE for secure authentication. Simply install the extension and sign in with your SimRelay account.

Token Expiration:

  • Access tokens: 15 days
  • Refresh tokens: 30 days

2. API Keys

For server-to-server integrations, use API keys. Create them at Settings > API Keys.

Authorization: Bearer sk_live_xxxxxxxxxxxxx

3. Personal Access Tokens

For mobile apps or simple integrations, use the /api/auth/login endpoint to obtain a token.

Messaging

Send an SMS

Queues an SMS for delivery and returns immediately with a message id.

The from number must be one you control: either a BYOS number (a SIM in your own Android device) or a customer-owned SIM we host for you at our SMS provider. Sending must also be switched on for that number under Numbers in the dashboard. Numbers from the shared pool can never send.

Delivery is attempted at most once. If the message cannot be sent before timeout_seconds elapses it is marked expired and any credits reserved for it are returned. Credits are only ever consumed by a message the network accepted.

Supply Idempotency-Key to make retries safe: repeating a request with the same key and the same body returns the original message instead of sending a second one.

Authorizations:
bearerAuthapiKeyAuth
header Parameters
Idempotency-Key
string <= 255 characters

Client-generated key making this request safe to retry. Unique per organization.

Request Body schema: application/json
required
from
required
string

One of your sending-enabled numbers, in E.164 format.

to
required
string

Destination number in E.164 format.

text
required
string <= 1530 characters

Message body. Billing is per segment: 160 characters per segment for GSM-7 text (153 when the message spans several segments), or 70/67 when the body contains characters outside the GSM-7 alphabet and has to be sent as UCS-2.

timeout_seconds
integer [ 10 .. 3600 ]
Default: 120

How long to keep trying before the message fails. Messages from a BYOS number need at least 60 seconds, because the device has to pick the message up first.

webhook_url
string <uri>

HTTPS URL to receive status callbacks for this message. Omit it and no callbacks are sent. Must resolve to a public address.

webhook_secret
string >= 8 characters

Signs this message's callbacks. The X-Webhook-Signature-256 header carries sha256= followed by an HMAC-SHA256 of <X-Webhook-Timestamp>.<raw body>.

client_reference
string <= 255 characters

Your own identifier, echoed back on the message and its callbacks.

Responses

Request samples

Content type
application/json
{
  • "from": "+4915112345678",
  • "to": "+4915198765432",
  • "text": "Your code is 123456",
  • "timeout_seconds": 120,
  • "webhook_secret": "stringst",
  • "client_reference": "string"
}

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "status": "queued",
  • "from": "string",
  • "to": "string",
  • "text": "string",
  • "encoding": "gsm7",
  • "segments": 0,
  • "credits_charged": 0,
  • "client_reference": "string",
  • "error_code": "string",
  • "error_message": "string",
  • "expires_at": "2019-08-24T14:15:22Z",
  • "sent_at": "2019-08-24T14:15:22Z",
  • "failed_at": "2019-08-24T14:15:22Z",
  • "created_at": "2019-08-24T14:15:22Z"
}

Get the status of a sent message

Authorizations:
bearerAuthapiKeyAuth
path Parameters
uuid
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "status": "queued",
  • "from": "string",
  • "to": "string",
  • "text": "string",
  • "encoding": "gsm7",
  • "segments": 0,
  • "credits_charged": 0,
  • "client_reference": "string",
  • "error_code": "string",
  • "error_message": "string",
  • "expires_at": "2019-08-24T14:15:22Z",
  • "sent_at": "2019-08-24T14:15:22Z",
  • "failed_at": "2019-08-24T14:15:22Z",
  • "created_at": "2019-08-24T14:15:22Z"
}

Health

Basic health check

Returns 200 OK if the application and database are accessible. Lightweight check for load balancers and monitoring.

Responses

Response samples

Content type
application/json
{
  • "status": "ok",
  • "timestamp": "2019-08-24T14:15:22Z"
}

Detailed health check

Checks database, cache, and queue system. Returns detailed status for each service.

Responses

Response samples

Content type
application/json
{
  • "status": "ok",
  • "timestamp": "2019-08-24T14:15:22Z",
  • "checks": {
    }
}

SIM Lock

Acquire a lock on a SIM

Authorizations:
bearerAuthapiKeyAuth
path Parameters
hosted_sim
required
integer

Responses

Get lock status for a SIM

Authorizations:
bearerAuthapiKeyAuth
path Parameters
hosted_sim
required
integer

Responses

Release a lock on a SIM

Authorizations:
bearerAuthapiKeyAuth
path Parameters
hosted_sim
required
integer

Responses

Messages

Get messages for a SIM

Authorizations:
bearerAuthapiKeyAuth
path Parameters
hosted_sim
required
integer
query Parameters
per_page
integer [ 1 .. 100 ]

Number of messages per page (default 50)

limit
integer [ 1 .. 100 ]

Alternative to per_page for compatibility (default 50)

page
integer >= 1

Page number for pagination (default 1)

Responses

Agents

Register a new AI agent

Public endpoint. Returns an inactive API key that must be claimed by a human via the claim_url before it can be used. Rate-limited per IP (configurable via site_settings.agent_registration_rate_limit_per_hour, default 5/hour). Unclaimed registrations expire after 72 hours.

If a callback_url is provided, a one-shot webhook_secret is also returned — store it immediately. All future callbacks to that URL are signed with HMAC-SHA256: X-Webhook-Signature, X-Webhook-Signature-256 and X-Webhook-Timestamp headers (5-minute replay window).

Request Body schema: application/json
required
name
required
string <= 255 characters
description
string <= 2000 characters
callback_url
string <uri>

HTTPS URL that receives signed event callbacks.

object

Responses

Request samples

Content type
application/json
{}

Response samples

Content type
application/json
{
  • "api_key": "sk_aBcDeFgH...",
  • "claim_url": "http://example.com",
  • "verification_code": "A7K3M9X2",
  • "expires_at": "2019-08-24T14:15:22Z",
  • "webhook_secret": "string",
  • "message": "string"
}

Check the claim status of an agent registration

Authenticated via the agent's API key (Bearer sk_…).

Authorizations:
apiKeyAuth

Responses

Response samples

Content type
application/json
{
  • "status": "unclaimed",
  • "name": "string",
  • "claim_url": "string",
  • "expires_at": "2019-08-24T14:15:22Z",
  • "organization_id": 0,
  • "claimed_at": "2019-08-24T14:15:22Z"
}

Numbers

Browse available number pool by country

Authorizations:
bearerAuthapiKeyAuth
query Parameters
country
string = 2 characters

ISO 3166-1 alpha-2 country filter (e.g. DE).

Responses

Request a new number (requires human approval)

Creates a pending NumberRequest the human owner must approve. Deduped per (organization, type, country_code) — a second pending request with the same triple returns 409.

Authorizations:
bearerAuthapiKeyAuth
Request Body schema: application/json
required
type
required
string
Enum: "shared" "exclusive"
country_code
string = 2 characters

Optional. ISO 3166-1 alpha-2.

hosted_sim_id
integer

Optional. Specific SIM to request rather than picking from pool.

metadata
object

Responses

Request samples

Content type
application/json
{
  • "type": "shared",
  • "country_code": "st",
  • "hosted_sim_id": 0,
  • "metadata": { }
}

List number requests scoped to the authenticated agent/organization

Authorizations:
bearerAuthapiKeyAuth

Responses

Get a specific number request

Authorizations:
bearerAuthapiKeyAuth
path Parameters
uuid
required
string <uuid>

Responses

Cancel a pending number request

Authorizations:
bearerAuthapiKeyAuth
path Parameters
uuid
required
string <uuid>

Responses

Join the waitlist for an unavailable country

When numbers become available, the agent's registered callback_url receives a signed waitlist.number_available event. Idempotent — re-posting for the same country returns the existing entry.

Authorizations:
bearerAuthapiKeyAuth
Request Body schema: application/json
required
country_code
required
string = 2 characters

Responses

Request samples

Content type
application/json
{
  • "country_code": "US"
}

Current waitlist status for the authenticated organization

Authorizations:
bearerAuthapiKeyAuth

Responses

User

Get current authenticated user

Returns user information and authentication context (Sanctum token or API key)

Authorizations:
bearerAuthapiKeyAuth

Responses

Response samples

Content type
application/json
{
  • "user": {
    },
  • "auth_type": "api_key",
  • "organization": {
    },
  • "api_key": {
    }
}

Auth

Login with email and password (mobile)

Request Body schema: application/json
required
email
required
string <email>
password
required
string <password>

Responses

Request samples

Content type
application/json
{
  • "email": "user@example.com",
  • "password": "pa$$word"
}

Response samples

Content type
application/json
{
  • "2fa_required": true,
  • "tmp_token": "string"
}

Complete 2FA login with TOTP code

Request Body schema: application/json
required
tmp_token
required
string
code
required
string

TOTP code from authenticator app

Responses

Request samples

Content type
application/json
{
  • "tmp_token": "string",
  • "code": "string"
}

Response samples

Content type
application/json
{
  • "token": "string",
  • "user": {
    }
}

SIMs

Get all accessible SIMs for the user

Retrieve all SIMs that the authenticated user has access to through their team and organization memberships, or for API keys, all SIMs in the organization.

Authorizations:
bearerAuthapiKeyAuth

Responses

Response samples

Content type
application/json
{
  • "data": [
    ]
}

API Keys

List all API keys for the authenticated user

Returns all API keys belonging to the authenticated user's organization. Only accessible via Sanctum authentication, not API keys.

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "data": [
    ]
}

Create a new API key

Creates a new API key for the authenticated user's organization. Only accessible via Sanctum authentication.

Authorizations:
bearerAuth
Request Body schema: application/json
required
name
required
string

Display name for the API key

permissions
required
Array of strings
Items Enum: "numbers.read" "numbers.lock" "messages.read" "webhooks.receive"

Array of permission strings

Responses

Request samples

Content type
application/json
{
  • "name": "Production API Key",
  • "permissions": [
    ]
}

Response samples

Content type
application/json
{
  • "api_key": {
    },
  • "plain_text_key": "sk_live_1234567890abcdef"
}

Get a specific API key

Returns details of a specific API key. Only accessible via Sanctum authentication.

Authorizations:
bearerAuth
path Parameters
api_key
required
integer

API key ID

Responses

Response samples

Content type
application/json
{
  • "id": 1,
  • "name": "Production API Key",
  • "key_prefix": "sk_live_1234",
  • "permissions": [
    ],
  • "last_used_at": "2024-01-15T10:30:00Z",
  • "created_at": "2024-01-01T00:00:00Z",
  • "updated_at": "2024-01-01T00:00:00Z"
}

Update an API key

Updates an existing API key's name or permissions. Only accessible via Sanctum authentication.

Authorizations:
bearerAuth
path Parameters
api_key
required
integer

API key ID

Request Body schema: application/json
required
name
string

Display name for the API key

permissions
Array of strings
Items Enum: "numbers.read" "numbers.lock" "messages.read" "webhooks.receive"

Array of permission strings

Responses

Request samples

Content type
application/json
{
  • "name": "string",
  • "permissions": [
    ]
}

Response samples

Content type
application/json
{
  • "id": 1,
  • "name": "Production API Key",
  • "key_prefix": "sk_live_1234",
  • "permissions": [
    ],
  • "last_used_at": "2024-01-15T10:30:00Z",
  • "created_at": "2024-01-01T00:00:00Z",
  • "updated_at": "2024-01-01T00:00:00Z"
}

Delete an API key

Deletes an API key. This action cannot be undone. Only accessible via Sanctum authentication.

Authorizations:
bearerAuth
path Parameters
api_key
required
integer

API key ID

Responses

Regenerate an API key

Regenerates the secret key for an existing API key. The old key will immediately stop working. Only accessible via Sanctum authentication.

Authorizations:
bearerAuth
path Parameters
api_key
required
integer

API key ID

Responses

Response samples

Content type
application/json
{
  • "api_key": {
    },
  • "plain_text_key": "sk_live_9876543210fedcba"
}

Webhook Integrations

List all webhook integrations

Returns all webhook integrations for the authenticated user's organization.

Authorizations:
bearerAuthapiKeyAuth

Responses

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "organization": {
    }
}

Create a new webhook integration

Creates a new webhook integration. A secure secret is auto-generated and returned (only shown once).

Authorizations:
bearerAuthapiKeyAuth
Request Body schema: application/json
required
name
required
string <= 255 characters

Display name for the webhook

url
required
string <uri> <= 2048 characters

URL to send webhook payloads to

object

Custom headers to include in webhook requests

timeout_seconds
integer [ 1 .. 120 ]

Request timeout in seconds (default 30)

retry_count
integer [ 0 .. 10 ]

Number of retry attempts on failure (default 3)

Responses

Request samples

Content type
application/json
{
  • "name": "My Webhook",
  • "headers": {
    },
  • "timeout_seconds": 30,
  • "retry_count": 3
}

Response samples

Content type
application/json
{
  • "message": "Webhook integration created successfully.",
  • "data": {
    }
}

Get a specific webhook integration

Returns details of a specific webhook integration including its mappings.

Authorizations:
bearerAuthapiKeyAuth
path Parameters
webhook_integration
required
integer

Webhook integration ID

Responses

Response samples

Content type
application/json
{
  • "data": {
    }
}

Update a webhook integration

Updates an existing webhook integration.

Authorizations:
bearerAuthapiKeyAuth
path Parameters
webhook_integration
required
integer

Webhook integration ID

Request Body schema: application/json
required
name
required
string <= 255 characters
url
required
string <uri> <= 2048 characters
object
timeout_seconds
integer [ 1 .. 120 ]
retry_count
integer [ 0 .. 10 ]
is_active
boolean

Enable or disable the webhook

Responses

Request samples

Content type
application/json
{
  • "name": "string",
  • "headers": {
    },
  • "timeout_seconds": 1,
  • "retry_count": 10,
  • "is_active": true
}

Response samples

Content type
application/json
{
  • "message": "Webhook integration updated successfully.",
  • "data": {
    }
}

Delete a webhook integration

Deletes a webhook integration and all its mappings.

Authorizations:
bearerAuthapiKeyAuth
path Parameters
webhook_integration
required
integer

Webhook integration ID

Responses

Response samples

Content type
application/json
{
  • "message": "Webhook integration deleted successfully."
}

Regenerate webhook secret

Regenerates the webhook secret. The old secret will immediately stop working.

Authorizations:
bearerAuthapiKeyAuth
path Parameters
webhook_integration
required
integer

Webhook integration ID

Responses

Response samples

Content type
application/json
{
  • "message": "Webhook secret regenerated successfully.",
  • "data": {
    }
}

Test a webhook integration

Sends a test payload to the webhook URL to verify connectivity.

Authorizations:
bearerAuthapiKeyAuth
path Parameters
webhook_integration
required
integer

Webhook integration ID

Responses

Response samples

Content type
application/json
{
  • "success": true,
  • "http_status": 200,
  • "response_body": "string",
  • "response_time_ms": 150
}

Webhook Mappings

List webhook mappings

Returns all mappings for a specific webhook integration.

Authorizations:
bearerAuthapiKeyAuth
path Parameters
webhook_integration
required
integer

Webhook integration ID

Responses

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "webhook_integration": {
    }
}

Create a webhook mapping

Creates a new mapping to associate a team with a webhook integration.

Authorizations:
bearerAuthapiKeyAuth
path Parameters
webhook_integration
required
integer

Webhook integration ID

Request Body schema: application/json
required
team_id
required
integer

Team ID to associate with this webhook

forwarding_mode
required
string
Enum: "always" "lock_required"

When to forward messages:

  • always: Forward all messages for this team
  • lock_required: Only forward messages when team has an active lock

Responses

Request samples

Content type
application/json
{
  • "team_id": 1,
  • "forwarding_mode": "always"
}

Response samples

Content type
application/json
{
  • "message": "Webhook mapping created successfully.",
  • "data": {
    }
}

Get a specific webhook mapping

Returns details of a specific webhook mapping.

Authorizations:
bearerAuthapiKeyAuth
path Parameters
webhook_integration
required
integer

Webhook integration ID

webhook_mapping
required
integer

Webhook mapping ID

Responses

Response samples

Content type
application/json
{
  • "data": {
    }
}

Update a webhook mapping

Updates an existing webhook mapping.

Authorizations:
bearerAuthapiKeyAuth
path Parameters
webhook_integration
required
integer

Webhook integration ID

webhook_mapping
required
integer

Webhook mapping ID

Request Body schema: application/json
required
forwarding_mode
required
string
Enum: "always" "lock_required"
is_active
boolean

Enable or disable the mapping

Responses

Request samples

Content type
application/json
{
  • "forwarding_mode": "always",
  • "is_active": true
}

Response samples

Content type
application/json
{
  • "message": "Webhook mapping updated successfully.",
  • "data": {
    }
}

Delete a webhook mapping

Deletes a webhook mapping.

Authorizations:
bearerAuthapiKeyAuth
path Parameters
webhook_integration
required
integer

Webhook integration ID

webhook_mapping
required
integer

Webhook mapping ID

Responses

Response samples

Content type
application/json
{
  • "message": "Webhook mapping deleted successfully."
}

WebSocket

Get WebSocket configuration for clients

Returns the WebSocket server URL, port, authentication method, and other necessary details for clients to connect to the configured broadcaster (e.g., Reverb).

Authorizations:
bearerAuthapiKeyAuth

Responses

Response samples

Content type
application/json
{
  • "broadcaster": "reverb",
  • "key": "your_reverb_app_key",
  • "ws_url": "ws://localhost:8080",
  • "ws_host": "localhost",
  • "ws_port": 8080,
  • "ws_scheme": "http",
  • "force_tls": false,
  • "auth_method": "bearer_token",
  • "auth_header": "Authorization: Bearer <token>",
}

BYOS Devices

List BYOS devices

Returns a paginated list of BYOS devices for the authenticated user's organizations. Supports filtering by device status.

Authorizations:
oauth2_byos
query Parameters
status
string
Enum: "active" "disabled" "revoked" "pending_verification"

Filter devices by status

per_page
integer [ 1 .. 100 ]
Default: 15

Number of devices per page

Responses

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "meta": {
    },
  • "links": {
    }
}

Register a new BYOS device

Registers a new device with SIM slot declarations. Each SIM slot receives a verification code that must be sent via SMS to the Twilio verification number to prove SIM ownership.

Flow:

  1. App sends sim_slots array (e.g. [1] or [1, 2] for dual-SIM)
  2. Server creates device in pending_verification status with pending SIM cards
  3. Response includes a verification_code per SIM and the twilio_number to SMS it to
  4. App sends SMS containing the code to twilio_number
  5. Twilio webhook receives SMS, extracts code, activates SIM with the sender's real phone number
  6. Device transitions to active on first SIM verification
Authorizations:
oauth2_byos
Request Body schema: application/json
required
install_id
required
string <uuid>

App-generated UUID, persisted in app local storage on first launch. Not a hardware identifier.

sim_slots
required
Array of integers [ 1 .. 2 ] items [ items [ 1 .. 10 ] ]

SIM slot numbers to register. Each slot will receive a verification code.

device_model
required
string <= 100 characters

Android device model

app_version
required
string <= 50 characters

SimRelay app version

device_name
string <= 255 characters

User-friendly device name (optional)

Responses

Request samples

Content type
application/json
{
  • "install_id": "550e8400-e29b-41d4-a716-446655440000",
  • "sim_slots": [
    ],
  • "device_model": "SM-S921B",
  • "app_version": "1.2.3",
  • "device_name": "Work Phone"
}

Response samples

Content type
application/json
{
  • "id": 1,
  • "install_id": "550e8400-e29b-41d4-a716-446655440000",
  • "device_name": "Work Phone",
  • "device_model": "SM-S921B",
  • "app_version": "1.2.3",
  • "status": "pending_verification",
  • "twilio_number": "+12025551234",
  • "sim_cards": [
    ],
  • "created_at": "2019-08-24T14:15:22Z"
}

Get device details

Returns full details for a specific BYOS device including organization info and message count.

Authorizations:
oauth2_byos
path Parameters
device
required
integer

BYOS device ID

Responses

Response samples

Content type
application/json
{
  • "id": 1,
  • "install_id": "550e8400-e29b-41d4-a716-446655440000",
  • "phone_number": "+14155551234",
  • "device_name": "Samsung Galaxy S24",
  • "status": "active",
  • "is_online": true,
  • "created_at": "2019-08-24T14:15:22Z",
  • "twilio_number": "+12025551234",
  • "sim_cards": [
    ],
  • "device_model": "SM-S921B",
  • "app_version": "1.2.3",
  • "config_version": 1,
  • "battery_level": 85,
  • "last_seen_at": "2019-08-24T14:15:22Z",
  • "messages_received_count": 42,
  • "organization": {
    },
  • "updated_at": "2019-08-24T14:15:22Z"
}

Update device metadata

Updates device name, phone number, or app version. Phone number changes are synced to the HostedSim record.

Authorizations:
oauth2_byos
path Parameters
device
required
integer

BYOS device ID

Request Body schema: application/json
required
device_name
string <= 255 characters
app_version
string <= 50 characters
fcm_token
string or null <= 255 characters

Firebase Cloud Messaging registration token for this device. Use this endpoint when the token rotates between heartbeats; otherwise send it on the heartbeat.

Responses

Request samples

Content type
application/json
{
  • "device_name": "Updated Device Name",
  • "app_version": "1.3.0",
  • "fcm_token": "string"
}

Response samples

Content type
application/json
{
  • "id": 1,
  • "install_id": "550e8400-e29b-41d4-a716-446655440000",
  • "phone_number": "+14155551234",
  • "device_name": "Samsung Galaxy S24",
  • "status": "active",
  • "is_online": true,
  • "created_at": "2019-08-24T14:15:22Z",
  • "twilio_number": "+12025551234",
  • "sim_cards": [
    ],
  • "device_model": "SM-S921B",
  • "app_version": "1.2.3",
  • "config_version": 1,
  • "battery_level": 85,
  • "last_seen_at": "2019-08-24T14:15:22Z",
  • "messages_received_count": 42,
  • "organization": {
    },
  • "updated_at": "2019-08-24T14:15:22Z"
}

Delete device

Permanently deletes a device and all associated records including SIM cards and hosted SIMs. Message logs are preserved (hosted_sim_id set to null). This action cannot be undone.

Authorizations:
oauth2_byos
path Parameters
device
required
integer

BYOS device ID

Responses

Disable device

Temporarily disables a device. Device status becomes 'disabled' and will not receive messages.

Authorizations:
oauth2_byos
path Parameters
device
required
integer

BYOS device ID

Responses

Response samples

Content type
application/json
{
  • "id": 1,
  • "install_id": "550e8400-e29b-41d4-a716-446655440000",
  • "phone_number": "+14155551234",
  • "device_name": "Samsung Galaxy S24",
  • "status": "active",
  • "is_online": true,
  • "created_at": "2019-08-24T14:15:22Z",
  • "twilio_number": "+12025551234",
  • "sim_cards": [
    ],
  • "device_model": "SM-S921B",
  • "app_version": "1.2.3",
  • "config_version": 1,
  • "battery_level": 85,
  • "last_seen_at": "2019-08-24T14:15:22Z",
  • "messages_received_count": 42,
  • "organization": {
    },
  • "updated_at": "2019-08-24T14:15:22Z"
}

Enable device

Re-enables a disabled device. Device status becomes 'active' and will resume receiving messages.

Authorizations:
oauth2_byos
path Parameters
device
required
integer

BYOS device ID

Responses

Response samples

Content type
application/json
{
  • "id": 1,
  • "install_id": "550e8400-e29b-41d4-a716-446655440000",
  • "phone_number": "+14155551234",
  • "device_name": "Samsung Galaxy S24",
  • "status": "active",
  • "is_online": true,
  • "created_at": "2019-08-24T14:15:22Z",
  • "twilio_number": "+12025551234",
  • "sim_cards": [
    ],
  • "device_model": "SM-S921B",
  • "app_version": "1.2.3",
  • "config_version": 1,
  • "battery_level": 85,
  • "last_seen_at": "2019-08-24T14:15:22Z",
  • "messages_received_count": 42,
  • "organization": {
    },
  • "updated_at": "2019-08-24T14:15:22Z"
}

Get device configuration

Returns server configuration for the device including intervals, limits, features, and current plan details.

Authorizations:
oauth2_byos
path Parameters
device
required
integer

BYOS device ID

Responses

Response samples

Content type
application/json
{
  • "device": {
    },
  • "intervals": {
    },
  • "limits": {
    },
  • "features": {
    },
  • "metadata": {
    }
}

Send device heartbeat

Updates device health metrics and last_seen timestamp. Marks device as online and broadcasts status change event if device was offline.

The server uses adaptive timeouts based on Doze Mode state:

  • Normal: device marked offline after 360 seconds (6 minutes)
  • Doze Mode: device marked offline after 960 seconds (16 minutes)

Email alerts are deferred until two consecutive intervals are missed.

This is also the preferred place to keep the device's FCM registration token current: send fcm_token on every heartbeat. Use PATCH /api/byos/devices/{device} when the token rotates between heartbeats.

Authorizations:
oauth2_byos
path Parameters
device
required
integer

BYOS device ID

Request Body schema: application/json
optional
battery_level
integer [ 0 .. 100 ]

Current battery percentage (optional)

signal_strength
integer [ 0 .. 100 ]

Current signal strength percentage (optional, backward compat - updates first SIM card)

is_in_doze_mode
boolean
Default: false

Whether the Android device is currently in Doze Mode. Server uses a longer timeout (960s vs 360s) for doze devices.

Array of objects

Per-SIM signal strength updates (optional)

fcm_token
string <= 255 characters

Firebase Cloud Messaging registration token for this device, used to wake it when a message is queued for sending. Safe to send on every heartbeat: the server compares it and only writes when it changed. Omitting it, or sending an empty value, never clears a stored token.

Responses

Request samples

Content type
application/json
{
  • "battery_level": 85,
  • "signal_strength": 75,
  • "is_in_doze_mode": false,
  • "sim_cards": [
    ],
  • "fcm_token": "string"
}

Response samples

Content type
application/json
{
  • "success": true,
  • "next_heartbeat_in": 300,
  • "server_time": "2019-08-24T14:15:22Z"
}

Submit received SMS message

Submits an SMS message received by the BYOS device. Message is validated and queued for async processing.

Authorizations:
oauth2_byos
path Parameters
device
required
integer

BYOS device ID

Request Body schema: application/json
required
from
required
string <= 20 characters

Sender phone number

body
required
string <= 1600 characters

SMS message content

message_id
required
string <uuid>

Unique message identifier from device

received_at
string <date-time>

Timestamp when device received message (optional)

sim_slot
integer [ 1 .. 2 ]

SIM slot number for dual-SIM devices (optional)

Responses

Request samples

Content type
application/json
{
  • "from": "+19876543210",
  • "body": "Your verification code is 123456",
  • "message_id": "550e8400-e29b-41d4-a716-446655440000",
  • "received_at": "2019-08-24T14:15:22Z",
  • "sim_slot": 1
}

Response samples

Content type
application/json
{
  • "message": "SMS received and queued for processing",
  • "message_id": "550e8400-e29b-41d4-a716-446655440000"
}

Lease SMS queued for this device to send

Claims the messages waiting to be sent from this device's SIMs and returns them.

This call mutates state. Returning a message is the lease — it is handed out exactly once and a later call will not return it again. It is therefore not a safe read to retry blindly: if the response is lost in transit, those messages stay leased and end up failing as device_no_ack when the lease expires. That is deliberate. Re-offering a message could put the same SMS on the recipient's handset twice, which is worse than dropping it and cannot be detected downstream.

The device is normally woken by a silent FCM data push ({"type": "outbox.pending", ...}), but the push is only a latency optimisation: it can be dropped or delayed by Doze. Poll this endpoint every next_poll_in seconds regardless.

Never transmit a message after its expires_at — the server has given up on it by then and has already refunded the customer. Compare against server_time rather than the device clock.

Authorizations:
oauth2_byos
path Parameters
device
required
integer

BYOS device ID

Responses

Response samples

Content type
application/json
{
  • "messages": [
    ],
  • "server_time": "2019-08-24T14:15:22Z",
  • "next_poll_in": 20
}

Report the result of a leased message

Reports what happened to a message this device leased.

Report on the sentIntent outcome — whether the carrier accepted the message — not the delivery report. Delivery reports are carrier-dependent, often never arrive, and must never gate this call. For a multipart message the result is sent only when every part returned RESULT_OK.

Authorizations:
oauth2_byos
path Parameters
device
required
integer

BYOS device ID

uuid
required
string <uuid>

The message id from the lease

Request Body schema: application/json
required
lease_token
required
string <uuid>

The token issued with this message's lease.

result
required
string
Enum: "sent" "failed"
error_code
string or null <= 100 characters

Android result code, passed through verbatim — e.g. RESULT_ERROR_NO_SERVICE, RESULT_ERROR_RADIO_OFF, RESULT_ERROR_LIMIT_EXCEEDED, or an API-30+ RESULT_RIL_* code.

error_message
string or null <= 500 characters
segments
integer or null [ 1 .. 255 ]

Parts actually sent. Used to reconcile against the estimate billed at accept time.

Responses

Request samples

Content type
application/json
{
  • "lease_token": "d990dcdf-9d21-4e38-9863-7b208f605067",
  • "result": "sent",
  • "error_code": "string",
  • "error_message": "string",
  • "segments": 1
}

Response samples

Content type
application/json
{
  • "status": "sent"
}

Add SIM card to device

Adds a new SIM card slot to an existing device, pending SMS verification. Returns a verification code that must be sent via SMS to the Twilio number.

Authorizations:
oauth2_byos
path Parameters
device
required
integer

BYOS device ID

Request Body schema: application/json
required
sim_slot
required
integer [ 1 .. 10 ]

Physical SIM slot number on the device

Responses

Request samples

Content type
application/json
{
  • "sim_slot": 2
}

Response samples

Content type
application/json
{
  • "id": 1,
  • "sim_slot": 1,
  • "phone_number": null,
  • "status": "pending",
  • "verification_code": "SR-A2B3",
  • "twilio_number": "+12025551234"
}

Update SIM card

Updates SIM card metadata like phone number or slot number. Phone number changes sync to the associated HostedSim.

Authorizations:
oauth2_byos
path Parameters
device
required
integer

BYOS device ID

simCard
required
integer

SIM card ID

Request Body schema: application/json
required
phone_number
string

Phone number in E.164 format

sim_slot
integer or null [ 1 .. 10 ]

Responses

Request samples

Content type
application/json
{
  • "phone_number": "+14155559999",
  • "sim_slot": 2
}

Response samples

Content type
application/json
{
  • "id": 1,
  • "phone_number": "+14155551234",
  • "sim_slot": 1,
  • "status": "active",
  • "signal_strength": 75,
  • "is_active": true,
  • "hosted_sim_id": 10,
  • "created_at": "2019-08-24T14:15:22Z",
  • "updated_at": "2019-08-24T14:15:22Z"
}

Remove SIM card

Deactivates a SIM card from the device. Sets status to inactive.

Authorizations:
oauth2_byos
path Parameters
device
required
integer

BYOS device ID

simCard
required
integer

SIM card ID

Responses

Re-trigger SIM verification

Generates a new verification code for a pending or inactive SIM card. Use this when the original code has expired (codes expire after 5 minutes). Cannot be used on already-active SIM cards.

Authorizations:
oauth2_byos
path Parameters
device
required
integer

BYOS device ID

simCard
required
integer

SIM card ID

Responses

Response samples

Content type
application/json
{
  • "id": 1,
  • "sim_slot": 1,
  • "phone_number": null,
  • "status": "pending",
  • "verification_code": "SR-A2B3",
  • "twilio_number": "+12025551234"
}