Review / Hosted API
Photon review
Built for agents first — gRPC streaming, open-source kits, and a free tier.
Photon is the most developer-shaped vendor in the category. Rather than a plain REST endpoint it exposes a persistent gRPC stream (its Spectrum SDK) between your backend and its managed infrastructure, which removes the webhook endpoint you would otherwise have to host and secure. It publishes pricing, ships open-source tooling — an iMessage kit, an n8n community node, a Vercel Chat SDK adapter — and has a free tier that can run against your own Mac and Apple ID before you pay for managed lines.
What it is good at
- Persistent gRPC stream means no public webhook endpoint to host, secure and debug.
- Genuinely open-source client tooling, including an n8n node and a Vercel Chat SDK adapter.
- A free tier you can evaluate on without talking to anyone.
- Published, flat pricing with no per-message billing.
- Agent-oriented features — mini apps, group messaging — rather than bulk-send framing.
Where it will bite you
- A streaming connection is a different operational model from webhooks; your infrastructure has to hold a long-lived connection open.
- Newer name than Sendblue or LoopMessage, with a correspondingly shorter public track record.
- The free tier running on your own Mac is not the same product as the managed lines — do not benchmark one and buy the other.
- Cold outreach and dedicated lines sit on the $250/line tier, not the $25 one.
What Photon claims
Reported as the vendor's own marketing claims. We have not independently reproduced these numbers, and neither should you treat them as benchmarks.
- Enterprise-grade iMessage API for agents
- No Mac, no local relay, no webhook to maintain
The shape of the API
Illustrative — parameter names and endpoints change. Treat this as the flavour of the integration, and copy the real thing from the official docs.
import { Photon } from "@photon-ai/advanced-imessage"; const photon = new Photon({ projectId: process.env.PHOTON_PROJECT_ID!, apiKey: process.env.PHOTON_API_KEY!,}); await photon.messages.send({ to: "+15551234567", text: "Your table is ready — https://acme.co/t/91?utm_source=imessage&utm_medium=sms&utm_campaign=table_ready",}); // Inbound arrives on the same stream rather than a webhook you host.for await (const event of photon.events.stream()) { if (event.type === "message.received") await handle(event);}Tracking links with Photon
UTM note
The streaming model makes it easy to correlate a delivered message id with a click later — put the message id in your own store at send time and join on it rather than trying to encode it in the URL.
Whatever you send with, build the URL from one helper so tagging is consistent across every job and campaign. Open the UTM builder to generate one now.
Still weighing options?
The comparison table puts all five side by side.