← Back to docs

SMS API Reference

SMS API Reference

Base URL

https://tools.tornevall.net/api/sms

Authentication

Remote SMS integrations use the dedicated SMS core API credential. Ordinary Tools API-key scopes do not authorize SMS send/status or inbound gateway requests.

Send the dedicated credential in one of these headers:

Authorization: Bearer YOUR_API_TOKEN

or:

X-Api-Key: YOUR_API_TOKEN

The legacy apikey request parameter remains accepted where the endpoint contract already supported it, but header-based authentication is recommended for new integrations.

Authenticated Tools web sessions and explicitly trusted internal access paths are separate from the remote API credential contract.


POST /send

Queue an SMS for sending.

Request

POST /api/sms/send
Content-Type: application/json
Authorization: Bearer YOUR_API_TOKEN
{
  "destination": "+46701234567",
  "message": "Hello from API",
  "class": "-1",
  "central": "",
  "incident": false
}

Fields

Field Required Type Notes
destination Yes string Recipient phone number
message Yes string Message text, maximum 512 characters
class No string SMS message class
central No string Optional SMS central name
incident No boolean Mark the message as an incident. Incident messages are intended for urgent operational alerts and bypass application-level incident cooldowns where supported.

Before the text is written to the SMSTools queue, Tools normalizes characters that the current modem path does not handle reliably. Swedish letters are preserved. Unicode quotes, dash variants, and selected GSM extension-table characters are converted to readable basic characters instead of risking ? substitutions on the receiving handset.

Response

{
  "success": true,
  "pduid": 4106,
  "incident": false,
  "message": "SMS queued for sending"
}

A queued incident message is persisted with incident=1. This flag identifies urgent messages in the outgoing queue; it is not a carrier delivery receipt.

Errors

  • 401 Unauthorized when the remote credential is missing or invalid
  • 422 Unprocessable Entity when request validation fails
  • 500 when the message cannot be queued

GET /{pduid}/status

Read the current status of an outgoing SMS.

Request

GET /api/sms/{pduid}/status
Authorization: Bearer YOUR_API_TOKEN

Response

{
  "pduid": 4106,
  "recipient": "+46701234567",
  "message": "Hello from API",
  "status": "queued",
  "incident": false,
  "tries": 0,
  "created_at": 0,
  "updated_at": 1709035200
}

Typical status values include queued, spooled, and unknown.

Tools also observes the SMSTools queue periodically and can record when an outbound row receives new attempts/timestamps or leaves pduout. This is queue/modem-side evidence and must not be treated as a carrier delivery receipt.


POST /inbound

The inbound gateway endpoint uses the same dedicated SMS core API credential. The request body is the SMS gateway webhook payload expected by Tools.

A normal Tools API token does not gain inbound gateway access by carrying an SMS-related scope value.


Admin: unknown-prefix AI fallback

Administrators can configure the optional unknown-prefix AI fallback from the SMS admin interface. This does not change the public inbound request authentication or payload contract.

The Incoming SMS detail page also exposes Handle now for stored messages that have not reached a terminal processing result. It runs that existing row through the current prefix/AI logic without creating another inbox row. A completed AI decision that intentionally stays silent is shown as handled rather than pending, while failures remain retryable. The message detail view labels SMS_CENTRAL as the SMS center (SMSC); it is not a callback URL.

Fresh pending messages received through the direct modem/database path are picked up automatically and run through that same handling. HTTP-created rows are marked independently of an optional caller webhook ID and use the same per-message serialization, so they are not raced by the direct-DB poller. When a stored inbound row contains SMS_DEVICE_ID, serialized processing preserves that original device identifier for configured prefix callbacks. Unknown-prefix AI replies use bounded recent history for the same sender; earlier linked replies are read from the live outbox when present and from durable SMS audit excerpts after the modem has consumed the outbox row. Handle now remains a recovery action for rows that failed or otherwise need manual reprocessing.


SMSTools inbound file handling

When the local SMSTools receive hook hands an incoming message to Tools, Tools stores the valid message in the shared gsm.pduin inbox before it evaluates the first word as a possible prefix.

This means ordinary personal SMS without a configured prefix are still visible under SMS Admin -> Incoming SMS. After storage, an active prefix can run its configured callback. If no active prefix matches, the optional administrator-configured AI personal-reply fallback may evaluate the full message and either queue a reply or stay silent.

The local SMSTools bridge is an internal process path and does not require the external SMS core API credential. Repeated processing of the same received message is deduplicated before another row or automatic reply is created.

The included bridge accepts both a direct file argument and the native SMSTools-style event arguments, for example php bin/smstools-incoming.php RECEIVED /var/spool/sms/incoming/<file>. The production SMSTools event handler must point to this bridge (or invoke the equivalent Artisan command) for local modem receives to enter this pipeline.