Getting Started
This section takes you from nothing to a phone that sends a message on command from your own server. It is four steps, and the whole path is meant to take under an hour.
In a hurry? The Quickstart is the whole path compressed into one runnable file — install, pair, send, receive — with the reasoning stripped out. The pages below are the same ground, explained.
What you need
- An Android device, API 26 (Android 8.0) or newer, with an active SIM and a plan that permits person-to-person SMS. A spare or second-hand handset is the normal choice — this device will be plugged in and running permanently.
- The app, from Google
Play . To
build it yourself instead you need the Flutter SDK and
adb— note that sideloading has real consequences on Android 15+, see Play Protect. - A server that speaks the Luno protocol. The fastest route is the
@luno-oss/*SDK, which implements the server half for you and runs on Node, Bun, Deno or Cloudflare Workers. - HTTPS. The node refuses plaintext transport. For local development a
tunnel (
cloudflared,ngrok,tailscale funnel) is the usual answer;http://is permitted only by debug builds on a LAN.
Do not use your personal SIM for testing. Delivery-report and rate-limit behaviour is best explored on a SIM you are willing to have flagged.
The path
Install the app
Install from Google Play, or build a flavored APK and install it over adb.
→ Installation
Stand up a backend
Create a Luno engine, give it a store, and mount it on the framework you already use. → Backend SDK
Pair the device
Mint a pairing session on the server, then scan the QR code or type the code into the app. The device receives a Keystore-sealed credential and connects. → Pairing
Send your first message
Call luno.sms.send(...) and watch the message move through sms_accepted →
sms_sent → delivery_report. → First message
A note on the mental model
It helps to keep one sentence in mind while setting this up:
The node’s entire responsibility is: receive a command, act on the radio, report faithfully what happened.
Everything else — who may send, how many messages per minute, which recipients are permitted, how long a pairing code lives, what happens to a message after delivery — belongs to your backend. The node deliberately holds no policy of its own, so changing policy never requires shipping an app update.