Troubleshooting
Most problems fall into a handful of buckets. Work top to bottom; each section starts with the fastest thing to check.
Start with diagnostics
Before anything else, get a picture of the gateway’s health. Two ways:
- In the app — the Diagnostics screen checks the gateway is online, SMS permission is granted, battery optimisation is exempt, the Wi-Fi lock is held, the endpoint URL, your SIM(s), whether the last request was reachable, and how many messages went out today.
- Over the API — an authenticated
GET /api/diagnosticsreturns the same picture as JSON: uptime, active SIMs, today/month totals, webhook delivery health, and the current send mode.
A client can’t reach the gateway
- Confirm both devices are on the same network. Guest networks and AP isolation (client isolation) silently block device-to-device traffic — turn it off or use a different network.
- Confirm the address and port. It’s
http://<phone-ip>:8080, exactly as the app shows after you tap Start. A firewall on the calling device can block port 8080. - Hit
GET /health— no key needed. A healthy gateway returns{"status":"running", ...}. If that works but your authenticated calls don’t, it’s a key problem (below), not a network one.
401 Unauthorized
The API key is missing, malformed, or wrong. Copy the current key from the app (or re-scan the QR)
and send it as Authorization: Bearer sk_local_.... If you recently regenerated the key, every
client still using the old one gets 401 until you update it.
403 Forbidden: local network access only
The request arrived from an address outside the allowed private ranges, so the local-network guard rejected it before the key was even checked. You’re calling from outside the LAN — get on the same network, or reach the gateway over a VPN.
429 Too many requests
You’ve hit a rate limit. Honour the retryAfterSeconds value (and the Retry-After header) and
back off — don’t hammer. The limits are fixed; see Security for
the exact numbers.
A send returns success but no text arrives
status: "queued" means Android accepted the message — it is not a delivery receipt. Hiras
cannot see carrier-side delivery, and cannot detect “insufficient balance”; a carrier rejection
shows up as a failed send, not a specific reason. Check:
- A SIM is inserted and active, and SMS permission is granted.
- There’s signal and load on that SIM.
- Check the message’s outcome with
GET /api/messages/:id—sentvsfailed. - Reproduce with Dry Run on to confirm your request itself is valid, separately from the SIM.
Webhooks aren’t arriving
- Confirm the gateway is running and the webhook is enabled with a reachable
http/httpsURL. - Use the app’s Send test event to fire a delivery on demand.
- Verify your endpoint returns a 2xx quickly — a
4xxtells Hiras to stop and is never retried. - If deliveries arrive but you’re rejecting them, re-check your signature verification: compute the HMAC over the timestamp plus the raw body, keyed by your API key. The key is never sent, so don’t expect it in a header. See Webhooks.
The gateway keeps stopping
Android may suspend or kill background apps. Allow Hiras to ignore battery optimisation, and, if you want it back after a restart, enable start after reboot. Some OEMs are aggressive about killing background apps regardless; a full process kill stops the gateway. See Configuration.
Still stuck?
Email arcwhin@gmail.com with what you’re seeing — the diagnostics output helps.