Reference

The FlipSend API

One endpoint sends email, SMS and fax. Authenticate with an API key, post a message, read the result. All processing and storage happens in Australia.

Base URL

https://api.flipsidedigital.com.au/v1

Every request goes over HTTPS. Requests and responses are JSON.

Build and test against your staging account first, then switch to production. Only the base URL and the key change, nothing else about the request.

Authentication

Every request needs an API key. Create one in the FlipSend dashboard under Settings, then API keys. The key is shown once when you create it, so store it somewhere safe. Anyone holding a key can send on your account's credits.

Send it as a bearer token, or in an X-API-Key header:

Authorization: Bearer fs_live_xxxxxxxx
X-API-Key: fs_live_xxxxxxxx

Keys carry scopes. Grant only what an integration needs.

ScopeAllows
messages:sendSending messages
messages:readReading message status
optouts:readReading the opt-out feed

Check a key works:

curl https://api.flipsidedigital.com.au/v1/ping \
  -H "Authorization: Bearer $FLIPSEND_API_KEY"

{"ok":true,"tenant_id":"...","scopes":["messages:send","messages:read"]}

Send a message

POST /v1/messages. One endpoint for all three channels, the channel field selects which. Returns 202 Accepted with a message id once the message is queued.

Set reference to your own identifier, an order number or booking id. It is stored against the message and returned in status reads, so you can reconcile against your own records.

SMS

curl -X POST https://api.flipsidedigital.com.au/v1/messages \
  -H "Authorization: Bearer $FLIPSEND_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: appt-8891" \
  -d '{
    "channel":   "sms",
    "to":        "+61400111222",
    "body":      "Your appointment is confirmed for Wed 2 July, 2:30 pm.",
    "from":      "NorthDental",
    "reference": "APPT-8891"
  }'
FieldRequiredNotes
toYesAustralian mobile in E.164 format, e.g. +61400111222
bodyYesMessage text
fromNoA registered sender ID. Defaults to your account sender
referenceNoYour own identifier, echoed back

Email

curl -X POST https://api.flipsidedigital.com.au/v1/messages \
  -H "Authorization: Bearer $FLIPSEND_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "channel":   "email",
    "to":        "patient@example.com.au",
    "subject":   "Your statement is ready",
    "html":      "<p>Your statement is ready to view.</p>",
    "reference": "INV-10482"
  }'

One of html or text is required. Email is sent on your verified sending domain.

Fax

curl -X POST https://api.flipsidedigital.com.au/v1/messages \
  -H "Authorization: Bearer $FLIPSEND_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "channel":         "fax",
    "to":              "+61370000000",
    "document_base64": "<base64 PDF>",
    "document_name":   "referral-2211.pdf",
    "page_count":      2,
    "reference":       "REF-2211"
  }'

Fax is charged per page, so page_count is required.

Response

{
  "id":        "a495fa09-7f22-4677-b582-1be88c8c30fc",
  "channel":   "sms",
  "status":    "queued",
  "reference": "APPT-8891"
}

Idempotency

Send an Idempotency-Key header on any send. The first request with a given key is processed normally. Any repeat within 24 hours returns the original response instead of sending again, with an Idempotent-Replayed: true header.

Idempotency-Key: order-1024
If your system retries on failure, or receives webhooks that can be delivered more than once, use this. Set the key to something stable and unique for the event, such as the incoming webhook id or the order id. It is what stops one order sending two messages.

Message status

Requires the messages:read scope. Fetch a single message by id, or list recent messages and filter by your own reference.

curl https://api.flipsidedigital.com.au/v1/messages/<id> \
  -H "Authorization: Bearer $FLIPSEND_API_KEY"

curl "https://api.flipsidedigital.com.au/v1/messages?reference=APPT-8891" \
  -H "Authorization: Bearer $FLIPSEND_API_KEY"

List accepts channel, reference and limit (default 50, maximum 200), newest first.

{
  "id":                  "a495fa09-7f22-4677-b582-1be88c8c30fc",
  "channel":             "sms",
  "status":              "sent",
  "to":                  "+61400111222",
  "reference":           "APPT-8891",
  "provider_message_id": "a9224fed-4703-4aee-b5e0-b684dc352348",
  "created_at":          "2026-07-18T10:29:29.328Z",
  "updated_at":          "2026-07-18T10:29:29.427Z"
}

Opt-outs

FlipSend handles opt-out for you. Every SMS carries an opt-out link and every email a one-click unsubscribe, and a recipient who opts out is suppressed on your account. Sending to a suppressed recipient returns 409 rather than delivering.

Read your opt-outs with the optouts:read scope, newest first and cursor-paginated. Use this to sync on first connect and to reconcile after any webhook downtime.

curl "https://api.flipsidedigital.com.au/v1/optouts?since=2026-08-01T00:00:00Z&channel=sms&limit=200" \
  -H "Authorization: Bearer $FLIPSEND_API_KEY"
{
  "optouts": [
    {
      "event_id":    "evt_01J8...",
      "event":       "optout.created",
      "tenant_id":   "...",
      "occurred_at": "2026-08-08T04:22:11Z",
      "phone":       "+61400111222",
      "email":       null,
      "channel":     "sms",
      "source":      "link",
      "reference":   "APPT-8891",
      "message_id":  "..."
    }
  ],
  "next_cursor": "eyJ0cyI6..."
}

Pass next_cursor back as cursor to page through. since filters on occurred_at. Check a single number with GET /v1/optouts/{phone}.

Webhooks

Rather than polling, have opt-outs pushed to you in real time. Set an endpoint URL in the FlipSend dashboard under Webhooks. When a recipient opts out, FlipSend POSTs an optout.created event to your URL with the same body as the feed above.

POST https://your-app.example.com/webhooks/flipsend
X-FlipSend-Event: optout.created
X-FlipSend-Event-Id: evt_01J8...
X-FlipSend-Timestamp: 1786166108
X-FlipSend-Signature: sha256=<hex>

Verify the signature

Compute HMAC-SHA256 over timestamp + "." + rawBodyusing your endpoint's signing secret, and compare it to the hex in X-FlipSend-Signature. Reject any request whose X-FlipSend-Timestamp is more than five minutes old. Return 2xx to acknowledge.

Delivery is retried on any non-2xx or timeout, backing off over 1m, 5m, 30m, 2h and 6h before being dead-lettered. The same event_id is sent on every attempt, so deduplicate on it.

Rate limits

60 requests per minute per key. Every response carries X-RateLimit-Limit and X-RateLimit-Remaining. Over the limit returns 429 with a Retry-After header (seconds) so you can back off precisely.

Errors

Errors return JSON with an error code and a human-readable message.

StatusMeaning
202Accepted, the message is queued
401Missing, invalid, revoked or expired key
402Not enough credits on that channel
403The key is missing the required scope
422Validation failed, for example a number that is not an Australian mobile
429Rate limited
{
  "error":   "insufficient_credits",
  "message": "Not enough sms credits.",
  "required": 1,
  "available": 0
}

Questions

Email support@flipsidedigital.com.au and one of our team will help. FlipSend by Flipside Digital, Australian-built, Australian-hosted, Australian-supported.