Getting started
Receiving messages
Replies, delivery receipts, read receipts and reactions all arrive the same way: we POST them to you. Three mechanisms, for three different questions.
Webhooks — “tell me about everything on this line”
The one to start with. Register an endpoint and we send every event on the project’s numbers: inbound messages, delivery, read receipts, tapbacks.
curl -X POST https://api.missblue.dev/v1/projects/$PROJECT/webhooks \
-H "Authorization: Bearer $MISS_BLUE_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com/hooks/missblue"}'Must be https, and must not resolve to a private address — an endpoint pointing at your own network would make us a way to reach it.
What an inbound message looks like
{
"event": "message.received",
"project_id": "b3c2...",
"number": "+16465550142",
"message": {
"id": "0b5ed7e8-f7a1-4f6e-9c2a-2a1f0d9e8b77",
"chat_id": "iMessage;-;+15555550100",
"from": "+15555550100",
"text": "Can I move it to 8?",
"service": "imessage",
"created_at": "2026-08-23T09:12:04Z"
}
}Proving it came from us
Every delivery is signed with the secret returned when you registered the endpoint. Verify it before trusting the body — a public URL that accepts anything posted to it is not a webhook, it is an open door.
Retries, and being switched off
A failed delivery is retried with backoff. An endpoint that keeps failing is switched off rather than retried forever, and you are told — a queue draining into a server that stopped listening a week ago helps nobody. Turn it back on with POST /v1/projects/{id}/webhooks/{endpoint_id}/enabled.
When your endpoint is up but you are not seeing events, read the delivery log first. It distinguishes “we never sent it” from “we sent it and your server said 500”, which are different problems with different owners.
curl https://api.missblue.dev/v1/projects/$PROJECT/webhooks/$ENDPOINT/deliveries \
-H "Authorization: Bearer $MISS_BLUE_KEY"status_callback — “tell me about this one message”
For a script that sends one message and wants its outcome, without standing up a project-wide endpoint and filtering it. Pass a URL when you send; we POST that message’s terminal status there once the Mac reports it.
curl -X POST https://api.missblue.dev/v1/messages \
-H "Authorization: Bearer $MISS_BLUE_KEY" \
-H "Content-Type: application/json" \
-d '{
"number_id": "8f14e45f-ceea-467a-9a1b-1b1e5f9e2c3d",
"recipient": "+15555550100",
"text": "Your table is confirmed for 7pm.",
"status_callback": "https://example.com/hooks/one-message"
}'Polling — the one you still want
Take webhooks, and still poll this on a schedule:
curl "https://api.missblue.dev/v1/messages/problems" \
-H "Authorization: Bearer $MISS_BLUE_KEY"It returns what failed and what is still waiting for a Mac. A webhook that never fired is exactly the case a webhook cannot tell you about, and a message stuck in a queue produces no event at all — so the only way to notice is to ask.
NextMessages referenceEvery field on every message endpoint.