The @senderz/sdk package is the official TypeScript client for the senderZ API. It wraps every REST endpoint in typed methods, handles authentication, retries failed requests, and verifies webhook signatures — so you write less boilerplate and ship faster.
Installation
npm install @senderz/sdk pnpm add @senderz/sdk yarn add @senderz/sdk The SDK requires Node.js 18 or later and supports both ESM and CommonJS imports.
Quick Start
import { SenderZ } from '@senderz/sdk'
const client = new SenderZ({
apiKey: process.env.SENDERZ_API_KEY!,
})
// Send a message
const message = await client.messages.send({
to: '+15551234567',
channel: 'auto',
body: 'Hello from senderZ!',
})
console.log(message.id) // "01JCNS789GHI"
console.log(message.status) // "queued"
Constructor Options
| Option | Type | Default | Description |
|---|---|---|---|
apiKey | string | Required | Your senderZ API key (sz_live_... or sz_test_...) |
baseUrl | string | https://api.senderz.com | Custom API URL for self-hosted instances |
timeout | number | 30000 | Request timeout in milliseconds |
retries | number | 2 | Number of automatic retries on 5xx errors |
Methods Overview
Messages
// Send a message
const msg = await client.messages.send({
to: '+15551234567',
channel: 'auto', // 'auto' | 'imessage' | 'sms'
body: 'Hello!',
})
// Send using a template
const otp = await client.messages.send({
to: '+15551234567',
channel: 'auto',
template: 'otp_verify',
data: { code: '483920' },
})
// Get message status
const status = await client.messages.get('01JCNS789GHI')
// List messages with filters
const recent = await client.messages.list({
status: 'failed',
since: '7days',
limit: 50,
})
Templates
// Create a template
const tmpl = await client.templates.create({
name: 'appointment_reminder',
body: 'Hi {{name}}, your appointment is on {{date}} at {{time}}.',
type: 'alert',
channel: 'both',
})
// List templates
const templates = await client.templates.list({ type: 'marketing' })
Contacts
// Add a contact
const contact = await client.contacts.create({
phone_number: '+15551234567',
name: 'Jane Smith',
group: 'VIP Clients',
})
// List contacts
const contacts = await client.contacts.list({
search: 'Smith',
limit: 25,
})
Webhooks
// Register a webhook
const hook = await client.webhooks.register({
url: 'https://myapp.com/hooks/senderz',
events: ['message.delivered', 'message.failed', 'message.received'],
})
// List webhooks
const hooks = await client.webhooks.list()
// Remove a webhook
await client.webhooks.remove('webhook_01ABC')
Compliance
// Log consent
await client.compliance.logConsent({
phone_number: '+15551234567',
consent_type: 'express_written',
consent_source: 'web_form',
ip_address: '203.0.113.42',
})
// Check opt-out status
const optOut = await client.compliance.checkOptOut('+15551234567')
console.log(optOut.opted_out) // true or false
// List opt-outs
const optOuts = await client.compliance.listOptOuts({ limit: 100 })
Billing
// Get current usage
const usage = await client.billing.usage()
console.log(usage.new_contacts.used_this_month) // 487
console.log(usage.new_contacts.limit_this_month) // 1250
Capabilities
// Check iMessage support (Growth and Scale plans)
const caps = await client.capabilities.check('+15551234567')
console.log(caps.imessage) // true
Pagination
List methods return paginated results. Use the page and limit parameters to navigate through pages.
// Page 1
const page1 = await client.messages.list({ limit: 25, page: 1 })
// Page 2
const page2 = await client.messages.list({ limit: 25, page: 2 })
// Check if more pages exist
if (page1.meta.total > page1.meta.page * page1.meta.limit) {
// More pages available
}
Every list response includes a meta object with total, page, and limit fields so you can calculate pagination state.
Webhook Signature Verification
When senderZ sends a webhook to your server, it includes an X-Senderz-Signature header containing an HMAC-SHA256 signature. The SDK provides a built-in verification method:
import { SenderZ } from '@senderz/sdk'
const client = new SenderZ({ apiKey: process.env.SENDERZ_API_KEY! })
// In your webhook handler (Express example)
app.post('/hooks/senderz', (req, res) => {
const signature = req.headers['x-senderz-signature'] as string
const rawBody = req.body // raw string, not parsed JSON
const isValid = client.webhooks.verify(rawBody, signature)
if (!isValid) {
return res.status(401).send('Invalid signature')
}
const event = JSON.parse(rawBody)
// Process the event...
res.status(200).send('OK')
})
Always verify webhook signatures before processing events. This prevents spoofed requests from triggering actions in your application.
Retry Handling
The SDK automatically retries requests that fail with 5xx server errors. By default, it retries up to 2 times with exponential backoff (1 second, then 2 seconds). You can customize this:
const client = new SenderZ({
apiKey: process.env.SENDERZ_API_KEY!,
retries: 3, // retry up to 3 times
})
The SDK does not retry 4xx client errors (bad request, unauthorized, not found) because these indicate a problem with your request that retrying will not fix.
Error Types
All API errors throw a SenderZError with a structured code field that you can switch on:
import { SenderZ, SenderZError } from '@senderz/sdk'
try {
await client.messages.send({
to: '+15551234567',
channel: 'auto',
body: 'Hello!',
})
} catch (err) {
if (err instanceof SenderZError) {
switch (err.code) {
case 'OPTED_OUT':
console.log('Recipient has opted out')
break
case 'QUOTA_EXCEEDED':
console.log('New contact limit reached')
break
case 'TRIAL_EXPIRED':
console.log('Subscribe to a plan to continue')
break
case 'INVALID_API_KEY':
console.log('Check your API key')
break
case 'MISSING_TEMPLATE_VAR':
console.log(`Missing variable: ${err.message}`)
break
default:
console.log(`API error: ${err.message}`)
}
}
}
The SenderZError object includes:
code— Machine-readable error code (e.g.OPTED_OUT,QUOTA_EXCEEDED)message— Human-readable error descriptionstatus— HTTP status code (e.g. 400, 401, 429)