https://tools.tornevall.net/api/sms
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.
Queue an SMS for sending.
POST /api/sms/send
Content-Type: application/json
Authorization: Bearer YOUR_API_TOKEN
{
"destination": "+46701234567",
"message": "Hello from API",
"class": "-1",
"central": "",
"incident": false
}
| 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.
{
"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.
401 Unauthorized when the remote credential is missing or invalid422 Unprocessable Entity when request validation fails500 when the message cannot be queuedRead the current status of an outgoing SMS.
GET /api/sms/{pduid}/status
Authorization: Bearer YOUR_API_TOKEN
{
"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.
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.
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.
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.