- A Courier account. Start free.
- A Test API key from Settings → API Keys. Set it as
COURIER_API_KEY. - PHP 8.1 or later, and Composer.
- A user in Courier with an email or phone number. Step 2 creates one through the API.
1. Install the SDK
php-http/discovery, so add guzzlehttp/guzzle if you do not have one. The client reads COURIER_API_KEY from the environment, so there is nothing to configure for the first send.
2. Create a user
Courier is built around users, not addresses. A user profile holds the email, phone number, push tokens, and chat handles for one person, plus their notification preferences. Once it exists, every send names the user and Courier works out where to reach them. Your code never handles a contact detail again.create merges into the profile and leaves keys you omit untouched. Use $courier->profiles->replace() when you want the request body to become the whole profile.
3. Send a notification
A send names a template and a user, and passes the data specific to this event. The template lives in Design Studio, where it holds the content for every channel and the routing rules, so a copy change or a new channel never needs a deploy. The idempotency key means a retried request returns the original response instead of sending twice.4. Route across channels
Routing normally lives in the template, but a send can override it when the code knows something the template does not.single tries channels in order and stops at the first that delivers; all sends on every listed channel. The user’s preferences still apply on top, so a user who has opted out of SMS gets the email, and a user with no phone number on file does too.
5. Start a journey
Some notifications are sequences: a welcome email now, a reminder tomorrow if setup is not finished, a different path for team plans. A journey is that sequence built in a visual editor as steps that send, wait, branch on user data, or digest a burst of events into one message. You publish it once, and your code only has to start it. When the sequence changes, the editor changes; theinvoke call does not.
invoke returns before any message is sent. Runs are retained for 95 days.
Confirm delivery
A request fans out to one message per recipient and channel, and each message moves through its own lifecycle: enqueued, sent to the provider, delivered, opened, clicked. Look a message up by ID to read where it is.Next steps
- Working example: this guide as a runnable project.
- Add an in-app inbox with the React or web component SDK.
- Let users set preferences.
- Send API reference: every field.
- PHP SDK reference.