senderkit/senderkit-php). For framework
integrations see the dedicated pages:
Laravel
Service provider, notification channel, mail transport, and webhook middleware.
Symfony
Bundle with autowiring and a webhook request verifier.
Requirements
- PHP 8.1+
- A PSR-18 HTTP client — Guzzle or
symfony/http-clientare auto-discovered; you can also inject your own.
Install
Quickstart
Client construction
string
required
Your API key — must start with
sk_live_ (live mode) or sk_test_ (test
mode). The constructor throws \InvalidArgumentException for any other
prefix. See Authentication.string
default:"https://api.senderkit.com"
Override the API base URL. Useful for proxies or self-hosted gateways.
int
default:"30000"
Per-request timeout in milliseconds.
int
default:"2"
Max retry attempts for transient failures — network errors, timeouts,
429,
and 5xx. Retries use exponential backoff with jitter.?ClientInterface
Inject a PSR-18 HTTP client. Defaults to auto-discovery via
php-http/discovery (Guzzle or symfony/http-client if either is
installed).$client->mode property ('live' or 'test') is set as a read-only
value after construction, derived from the API key prefix.
send()
Send a templated message, substituting
variables at send time.
string
required
Template slug, e.g.
'welcome'.string
required
Recipient address — email, phone number, or push token.
array<string,mixed>
Template variables. Defaults to
[].Channel
Force a channel (
Channel::Email, Channel::Sms, Channel::Push,
Channel::WebPush). Defaults to the template’s primary channel.?int
Pin a specific template version. Omit to use the
current published version for the environment.
array<string,string|int|bool|float>
Free-form metadata attached to the message. Indexed server-side, so you can
later filter with
messages->list(new ListMessagesParams(metadata: [...])).DateTimeInterface|string|null
Defer delivery to a future time — a
DateTimeInterface or an ISO 8601
string. Must be in the future and within 30 days. See
Sending.?string
Idempotency key. If omitted, the SDK auto-generates one so a retried
request never duplicates a send. Reusing a key returns the original message.
list<string>|null
Cc / Bcc recipients. Email only.
?string
Reply-To address. Email only.
list<Attachment>|null
File or inline attachments (email only). Each
Attachment takes filename,
contentType, content (base64-encoded bytes), and optional
inline/contentId. Provider caps total across all attachments at 10 MB.Response
SendResult has three properties: id (e.g. "msg_…"), status
("queued" or "scheduled"), and livemode (bool).
sendRaw()
Send inline content without a registered template. Pass one of the typed
content classes — the channel is inferred from the content type.
string
required
Recipient address.
EmailContent|SmsContent|PushContent|WebPushContent
required
Typed content object — determines the channel.
?string
Email only. Must match a
verified custom sending domain
when using the managed email sender.
?bool
Set
true to run server-side variable substitution over the raw content
using the vars values.- email
- sms
- push
- web-push
sendBatch()
Send many messages sequentially with per-item error isolation. A failure on
one item never throws — each result carries a success flag so the rest of the
batch is not affected.
?string
Base idempotency key. Each item is dispatched with
{key}-{index} unless
the item already carries its own key.BatchResult:
$result->ok—trueon success,falseon failure.$result->index— position in the input array.$result->result—SendResultwhenok === true.$result->error—SenderKitExceptionwhenok === false.
context()
Fetch the workspace the API key belongs to and the active send mode.
Context object with workspace (id, slug, name) and mode
('live' or 'test'). Mirrors
GET /v1/context.
Templates
list() returns templates without their version body. get($slug) includes
currentVersion (versionNumber, variables, publishedAt). A Template
has slug, channel, description, status, and updatedAt.
The
content (raw HTML/blocks) field is intentionally omitted from list()
and get() responses to keep payloads lean. Use the dashboard or the
/v1/templates/{slug}/render endpoint when you need the rendered output.Messages
cancel() only works on scheduled or queued messages — later states
return a 409 (ApiException). list() returns data (array of Message)
and nextCursor (string or null).
Error handling
All exceptions extendSenderKitException (which extends \RuntimeException).
API errors carry $status, $apiCode, $issues, and $requestId (quote
$requestId in support requests).
The SDK retries
429, 5xx, network, and timeout failures up to $maxRetries
with backoff, so a thrown exception means retries were exhausted.
A 403 insufficient_scope error (scoped key used outside its grant) comes back
as ApiException with $status = 403 and $apiCode = "insufficient_scope".
See Authentication → Scopes.
Webhooks
verify() checks the HMAC-SHA256 signature and validates that the timestamp
is within 300 seconds (configurable via $toleranceSeconds). It throws
SignatureVerificationException on any failure — empty secret, malformed
header, stale timestamp, or signature mismatch.
See Webhooks for the full event-type list and payload schema.
Laravel
Notification channel, mail transport, and webhook middleware.
Symfony
Bundle autowiring and webhook verifier.
Sending
Channels, scheduling, and delivery lifecycle.
API Reference
The underlying REST endpoints.