Android SMS Gateway API — Link, Re-link & Manage Devices

XSender lets you turn an Android phone running the XSender Android Gateway app into an SMS-sending device. This page documents the HTTP API the Android app uses, so you can register, link, relink, or remotely manage devices from another application (your own mobile app, a Flutter wrapper, an MDM tool, a fleet-management dashboard, etc.).

Architecture

  1. Admin or user generates a device pairing token in Gateway → Android SMS → Devices → Add Device.
  2. The Android app — or your own integration — calls POST /api/gateway/sms/android/register-session with that token. XSender exchanges it for a long-lived session token and creates a Gateway + WhatsappDevice/AndroidSession row.
  3. Once registered, the device polls GET /api/logs/sms/pending for queued messages and POSTs delivery results to /api/logs/sms/update-statuses.
  4. SIM slots are managed through the /api/gateway/sms/android/sim/* CRUD endpoints.

Authentication

All endpoints (except register-session) require the long-lived session token in a Bearer header:

Authorization: Bearer eyJ0eXAiOiJKV1Qi...

The token is issued by register-session and bound to one device. Calling logout revokes it.

Register a session — POST /api/gateway/sms/android/register-session

This is the one and only un-authenticated endpoint. It takes a one-time pairing token (the QR-code value shown in the XSender panel) and returns a long-lived session token.

Request

{
  "pairing_token": "ATKN-9f2d6c1b-...",
  "device_name":   "Office Phone — Pixel 7",
  "device_uuid":   "a1b2c3d4-e5f6-...",
  "android_version": "14",
  "app_version":     "1.4.0"
}

Response — 200 OK

{
  "success": true,
  "data": {
    "session_token": "eyJ0eXAiOiJKV1Qi...",
    "gateway_uid":   "0f2c1b8d-9e6a-4f0b-bcde-1234567890ab",
    "user":          { "id": 17, "name": "Acme Marketing" },
    "sims":          [
      { "uid": "sim-1", "slot": 0, "label": "Main", "active": true },
      { "uid": "sim-2", "slot": 1, "label": "OTP",  "active": false }
    ]
  }
}

Re-linking: if the device's device_uuid matches a previously registered device, the existing session is reactivated and the same gateway_uid is returned. You do not get duplicate gateways — perfect for "factory reset → re-pair" flows.

Logout / Unlink — POST /api/gateway/sms/android/logout

Header: Authorization: Bearer {session_token}. Marks the gateway offline and revokes the token. The device row stays in the database — re-running register-session with the same device_uuid brings it back to life.

SIM management — /api/gateway/sms/android/sim

MethodPathPurpose
POST/simCreate a SIM row (slot, label, country code).
PUT/sim/{uid}Update a SIM (label, country code, active flag).
DELETE/sim/{uid}Remove a SIM. Active campaigns assigned to it stop.
POST/sim/update-statusReport a SIM's quota / signal / IMSI on a heartbeat.

Sample — update SIM status

{
  "sim_uid":           "sim-1",
  "active":            true,
  "signal_strength":   -78,
  "messages_sent_24h": 412,
  "imsi":              "310260000000001"
}

Polling for outgoing messages

Fetch pending — GET /api/logs/sms/pending

{
  "success": true,
  "data": [
    {
      "uid":        "msg-9c2e",
      "number":     "+15555550123",
      "body":       "Your OTP is 482915",
      "sim_uid":    "sim-2",
      "priority":   "high"
    }
  ]
}

Report results — POST /api/logs/sms/update-statuses

{
  "statuses": [
    { "uid": "msg-9c2e", "status": "sent",   "delivered_at": "2026-05-23 12:01:14" },
    { "uid": "msg-aa10", "status": "failed", "error":        "RADIO_NOT_AVAILABLE" }
  ]
}

Building your own client app

Because every endpoint is plain HTTP + JSON with token auth, you can ship your own native or cross-platform client — Flutter, React Native, Kotlin, iOS, even a desktop relay.

Minimum behaviour for a viable client:

  1. One-time: scan the pairing QR (or paste the token) and call register-session; persist the returned session_token in secure storage.
  2. Foreground service / WorkManager polls GET /api/logs/sms/pending every 5–15 s (configurable in the device profile).
  3. For each row, dispatch via the OS's SMS API on the selected SIM slot, then POST the result to /api/logs/sms/update-statuses.
  4. Every minute, POST a heartbeat to /sim/update-status with current signal, quota, and active flag — the panel uses this to show the device as online.

Security & operational notes