Documentation

Dry Run

Dry Run lets you build and test against the API without sending a single real message. Turn it on from the app and every POST /api/sms/send is validated, rate-limited, and logged exactly as a real send would be — but Hiras never hands the message to the SIM. No text goes out, no load is spent.

It’s the mode to develop against: wire up your integration, watch the responses, and only switch to real sending once everything looks right.

Turning it on

Dry Run is a host-wide switch in the app. While it’s on, every send is a dry run — there is no per-request override. It persists across restarts, so remember to switch it off before you expect real messages to go out. The mode field on GET /health and GET /api/diagnostics tells you which mode the gateway is currently in.

What a dry-run response looks like

A dry run returns HTTP 200 with a body that mirrors a real success, but with three clear tells — mode, smsSent, and status:

{
  "success": true,
  "mode": "dry-run",
  "smsSent": false,
  "messageId": "msg_...",
  "status": "dry-run",
  "segments": 1,
  "simSlot": 1
}

If the message would split into multiple SMS segments, the response adds a warning describing the split — the same warning a real send would give — so you can catch long-message costs before they happen.

What still runs

Dry Run is a realistic rehearsal, not a bypass:

  • Validation runs — a malformed request fails in dry run exactly as it would for real.
  • The rate limiter runs — you can genuinely hit a 429 while testing, which is useful for exercising your back-off code. See Security.
  • The live activity log records the attempt, tagged as a dry run.

What doesn’t

  • No SMS is sent and no load is spent — the SIM is never touched.
  • Dry runs are not written to your durable history or your today/month stats. Those numbers stay truthful, reflecting only real sends.

Next

  • Failure Simulation — test your error path, not just the happy path.
  • REST API — the fields these responses share with a real send.