SDKs
Libraries for Node.js, PHP and Laravel that cover every endpoint, retry safely and verify webhooks.
Three libraries, maintained by SendKuy, cover every endpoint in this reference. Field names are the API's own, so each request in the reference maps one to one onto an SDK call.
Node.js
npm i sendkuy · Node.js 20.3+, Bun, Deno and edge runtimes
PHP
composer require sendkuy/sdk · PHP 8.2+
Laravel
composer require sendkuy/laravel · notifications, a facade and webhooks
Send your first message
import { SendKuy } from 'sendkuy';
const sendkuy = new SendKuy('sk_live_YOUR_API_KEY');
const [message] = await sendkuy.messages.send({
channel: 'whatsapp',
to: ['+6281234567890'],
body: 'Your order is on its way.',
});What the SDKs handle for you
- Retries without duplicates. Every write carries an
Idempotency-Key, and each retry of that call reuses it, so a retry after a timeout or a dropped connection gets the first answer instead of sending again. The SDKs retry network errors, timeouts,5xx,idempotency_request_in_progress, and429whenRetry-Afteris a minute or less, up to twice. See Idempotency. - Pagination.
autoPaginate()followsnext_cursoruntil the last page. See Pagination. - Typed errors, one class per
error.type, carryingcode,param, the documentation link and the request id. - Webhook signatures, checked in one call. See Webhooks.
- Types. The Node.js SDK ships TypeScript types generated from this API's contract; the PHP SDK gives your editor every field of every object.
Errors
error.type | Node.js | PHP |
|---|---|---|
authentication_error | AuthenticationError | AuthenticationException |
authorization_error | AuthorizationError | AuthorizationException |
invalid_request_error | InvalidRequestError | InvalidRequestException |
rate_limit_error | RateLimitError | RateLimitException |
api_error | ApiError | ApiException |
| no response at all | ConnectionError | ConnectionException |
Every class extends SendKuyError in Node.js and SendKuyException in PHP, so one catch covers them all. Branch on the code, never on the message: error.code in Node.js, $e->getErrorCode() in PHP. The full list is on Errors.
Each error also carries the HTTP status (error.status, $e->getHttpStatus()) and, on a 429, the seconds to wait (error.retryAfter, $e->getRetryAfter()). A webhook that fails verification raises SignatureVerificationError or SignatureVerificationException, whose reason is one of malformed_header, timestamp_out_of_tolerance, signature_mismatch or invalid_payload.
Configure the client
The API key is the first argument. In Node.js you may leave it out, and SENDKUY_API_KEY is read from the environment. The other options go in the second argument:
const sendkuy = new SendKuy('sk_live_YOUR_API_KEY', { timeout: 10_000, maxRetries: 1 });| Node.js | PHP | Default | Sets |
|---|---|---|---|
timeout | timeout | 30000 milliseconds; 30 seconds | how long one attempt may take |
maxRetries | max_retries | 2 | retries after the first attempt |
fetch | http_client | the runtime's fetch; Guzzle | the HTTP client, for a proxy or a fake in tests |
baseUrl | base_url | https://app.sendkuy.com/api/v1 | the API address; change it only to reach a proxy or a mock server in tests |
With your own http_client in PHP, set the timeout on that client: the SDK's timeout does not reach it. The Node.js SDK refuses to run in a browser, where anyone who opens the page could read your key; dangerouslyAllowBrowser: true overrides that. In Laravel, every option is an environment variable; see Configuration.
One call can override the timeout and carry its own idempotency key. Node.js also takes an AbortSignal:
await sendkuy.messages.send(params, { timeout: 5_000, idempotencyKey: 'order-1042-shipped' });Versions
Version 1.x of each SDK covers API v1. Every release is listed in the CHANGELOG for Node.js, PHP and Laravel.
Methods
Every endpoint in this reference has a method. An endpoint newer than your installed version is still one call away with request(): sendkuy.request({ method: 'GET', path: '/account' }) in Node.js, $sendkuy->request('GET', '/account') in PHP.
| Endpoint | Node.js, then PHP |
|---|---|
| Messages | |
| List messages you have sent | sendkuy.messages.list()$sendkuy->messages()->list() |
| Send one message to one or more recipients | sendkuy.messages.send()$sendkuy->messages()->send() |
| Send up to 500 independent messages in one call | sendkuy.messages.sendBatch()$sendkuy->messages()->sendBatch() |
| Read one message | sendkuy.messages.get()$sendkuy->messages()->get() |
| Cancel a message that has not gone out yet | sendkuy.messages.cancel()$sendkuy->messages()->cancel() |
| Send a failed message again | sendkuy.messages.resend()$sendkuy->messages()->resend() |
| Numbers | |
| Check which numbers are on WhatsApp | sendkuy.numbers.check()$sendkuy->numbers()->check() |
| Verify | |
| Send a one-time code | sendkuy.verifications.create()$sendkuy->verifications()->create() |
| Read one verification | sendkuy.verifications.get()$sendkuy->verifications()->get() |
| Check a code | sendkuy.verifications.check()$sendkuy->verifications()->check() |
| Contacts | |
| List your contacts | sendkuy.contacts.list()$sendkuy->contacts()->list() |
| Create a contact | sendkuy.contacts.create()$sendkuy->contacts()->create() |
| Import up to 1000 contacts in the background | sendkuy.contacts.bulkImport()$sendkuy->contacts()->bulkImport() |
| Find a contact by phone number or by your own id | sendkuy.contacts.lookup()$sendkuy->contacts()->lookup() |
| Read one contact | sendkuy.contacts.get()$sendkuy->contacts()->get() |
| Change a contact | sendkuy.contacts.update()$sendkuy->contacts()->update() |
| Delete a contact | sendkuy.contacts.delete()$sendkuy->contacts()->delete() |
| List the attributes defined on your contacts | sendkuy.contacts.listAttributes()$sendkuy->contacts()->listAttributes() |
| Groups | |
| List contact groups | sendkuy.groups.list()$sendkuy->groups()->list() |
| Create a group | sendkuy.groups.create()$sendkuy->groups()->create() |
| Read one group | sendkuy.groups.get()$sendkuy->groups()->get() |
| Rename a group | sendkuy.groups.update()$sendkuy->groups()->update() |
| Delete a group | sendkuy.groups.delete()$sendkuy->groups()->delete() |
| Add contacts to a group | sendkuy.groups.addContacts()$sendkuy->groups()->addContacts() |
| Take contacts out of a group | sendkuy.groups.removeContacts()$sendkuy->groups()->removeContacts() |
| Templates | |
| List message templates | sendkuy.templates.list()$sendkuy->templates()->list() |
| Create a template | sendkuy.templates.create()$sendkuy->templates()->create() |
| Read one template | sendkuy.templates.get()$sendkuy->templates()->get() |
| Change a template | sendkuy.templates.update()$sendkuy->templates()->update() |
| Delete a template | sendkuy.templates.delete()$sendkuy->templates()->delete() |
| Campaigns | |
| List campaigns | sendkuy.campaigns.list()$sendkuy->campaigns()->list() |
| Create a campaign | sendkuy.campaigns.create()$sendkuy->campaigns()->create() |
| Read one campaign, with its numbers | sendkuy.campaigns.get()$sendkuy->campaigns()->get() |
| Change a campaign | sendkuy.campaigns.update()$sendkuy->campaigns()->update() |
| Delete a campaign | sendkuy.campaigns.delete()$sendkuy->campaigns()->delete() |
| List what a campaign is sending, per contact | sendkuy.campaigns.listDispatches()$sendkuy->campaigns()->listDispatches() |
| Start a campaign | sendkuy.campaigns.start()$sendkuy->campaigns()->start() |
| Pause a running campaign | sendkuy.campaigns.pause()$sendkuy->campaigns()->pause() |
| Resume a paused campaign | sendkuy.campaigns.resume()$sendkuy->campaigns()->resume() |
| Cancel a campaign | sendkuy.campaigns.cancel()$sendkuy->campaigns()->cancel() |
| Inbox | |
| List conversations in your inbox | sendkuy.conversations.list()$sendkuy->conversations()->list() |
| Read one conversation | sendkuy.conversations.get()$sendkuy->conversations()->get() |
| Read the messages in a conversation | sendkuy.conversations.listMessages()$sendkuy->conversations()->listMessages() |
| Mark a conversation as read | sendkuy.conversations.markRead()$sendkuy->conversations()->markRead() |
| Reply in a conversation | sendkuy.conversations.reply()$sendkuy->conversations()->reply() |
| Automation | |
| List automation workflows | sendkuy.workflows.list()$sendkuy->workflows()->list() |
| Read one workflow | sendkuy.workflows.get()$sendkuy->workflows()->get() |
| List the runs of one workflow | sendkuy.workflows.listExecutions()$sendkuy->workflows()->listExecutions() |
| Trigger a workflow | sendkuy.workflows.trigger()$sendkuy->workflows()->trigger() |
| Read one workflow run | sendkuy.executions.get()$sendkuy->executions()->get() |
| Webhooks | |
| List your webhook endpoints | sendkuy.webhooks.list()$sendkuy->webhooks()->list() |
| Register a webhook endpoint | sendkuy.webhooks.create()$sendkuy->webhooks()->create() |
| Read one webhook endpoint | sendkuy.webhooks.get()$sendkuy->webhooks()->get() |
| Change a webhook endpoint | sendkuy.webhooks.update()$sendkuy->webhooks()->update() |
| Delete a webhook endpoint | sendkuy.webhooks.delete()$sendkuy->webhooks()->delete() |
| Read the delivery history of an endpoint | sendkuy.webhooks.listDeliveries()$sendkuy->webhooks()->listDeliveries() |
| Gateways | |
| List the gateways your messages can leave through | sendkuy.gateways.list()$sendkuy->gateways()->list() |
| Read one gateway | sendkuy.gateways.get()$sendkuy->gateways()->get() |
| Account | |
| Read the account behind this key | sendkuy.account.get()$sendkuy->account()->get() |
| Read this period's usage per channel | sendkuy.account.usage()$sendkuy->account()->usage() |
| Jobs | |
| Read the status of background work | sendkuy.jobs.get()$sendkuy->jobs()->get() |