Spun has a REST API built for exactly this kind of automation, and n8n needs nothing special to use it: an HTTP Request node with a Bearer token sends WhatsApp messages, uploads media, creates and updates contacts, applies labels and checks whether a number is on WhatsApp. A Webhook trigger node receives real WhatsApp events back, signed so you can prove they came from Spun.
This page is the working-today path, written against the live API rather than a roadmap. Where something is not self-serve yet, it says so instead of pretending otherwise.
1. Create an API key
- 1
Open API Keys
In your Spun inbox: Settings, then Webhooks, then Manage API Keys, then New Key.
- 2
Name it and pick scopes
Name it something like "n8n Production". Enable only what the workflow needs: Send Messages for text and media, Check Phone Numbers, Manage Contacts, Read Contacts, Manage Labels, Read Labels. Each endpoint below names the scope it requires.
- 3
Copy it once
The key starts with wap_ and is shown once. Store it in n8n as a credential, never pasted into a node parameter where it ends up in the execution log.
- 4
Optional: lock the key to your n8n server
A self-hosted n8n has a stable outbound IP, which makes an API key far safer than usual. Set Allowed IPs on the key to your n8n egress address or CIDR range and a stolen key is useless from anywhere else. Leave it empty and the key works from anywhere. Getting it wrong never locks you out of Settings, which uses your Spun login rather than the key.
In n8n, add the key as a Header Auth credential: header name Authorization, header value Bearer wap_YOUR_KEY. Reuse that one credential across every Spun node in every workflow.
2. Send WhatsApp messages from a workflow
Add an HTTP Request node, set the method and URL, attach the Header Auth credential, and send JSON. Every endpoint lives under the same base URL, https://api.spun.com/api/integrations.
- send-message (scope: Send Messages): a text message. If the WhatsApp channel happens to be offline the API answers 202 with a queue_id instead of failing, and the message goes out when the channel reconnects.
- send-media (Send Messages): an image, video, audio file, voice note or document, from a public URL or a base64 upload, with an optional caption on images, videos and documents.
- check-phone (Check Phone Numbers): does this number have WhatsApp. Accepts up to 20 numbers in one call, so batch instead of looping.
- create-contact and update-contact (Manage Contacts): keep a lead record in sync from a form, a CRM or a spreadsheet. Passing a phone number updates the existing contact rather than creating a duplicate.
- contacts (Read Contacts): look a contact up by phone number or id.
- apply-label and remove-label (Manage Labels): tag a chat from an external trigger, for example label a chat "New Lead" the moment a form is submitted.
- labels (Read Labels): list the labels in the account, which is also the cheapest way to confirm a key works.
POST https://api.spun.com/api/integrations/send-message
Authorization: Bearer wap_YOUR_KEY
Content-Type: application/json
{
"to": "972501234567",
"text": "Hi {{ $json.first_name }}, thanks for getting in touch.",
"idempotency_key": "{{ $execution.id }}"
}Pass an idempotency_key on sends and set it to something stable for the run, such as {{ $execution.id }}. If n8n retries the node, Spun recognises the key instead of sending the message twice.
3. Send a file, image or voice note
Media goes to a separate endpoint. Supply exactly one of media_url, which Spun fetches, or media_base64, which Spun uploads for you first.
- type is one of image, video, audio, voice or document.
- A caption is carried on image, video and document. Audio and voice notes have no caption in WhatsApp.
- A voice note sent as base64 is converted to the format WhatsApp expects automatically. A voice note passed as a URL is sent exactly as it is, so it has to be ogg or opus already, otherwise send it as base64 and let Spun convert it.
- Media is deliberately not queued when the channel is offline. Text is queued, media answers 409 channel_offline instead, because replaying a queued media message would deliver it as text. Handle 409 with n8n retry rather than treating it as a permanent failure.
POST https://api.spun.com/api/integrations/send-media
Authorization: Bearer wap_YOUR_KEY
Content-Type: application/json
{
"type": "document",
"to": "972501234567",
"media_url": "https://example.com/invoice-1043.pdf",
"filename": "invoice-1043.pdf",
"caption": "Your invoice"
}4. Trigger a workflow from a WhatsApp event
- 1
Create the Webhook node first
Add a Webhook trigger node to a new workflow and copy its Production URL. n8n only serves that URL while the workflow is active, so activate it before testing.
- 2
Paste the URL into Spun
Settings, then Webhooks, then Add Webhook. Paste the n8n URL, choose which events should fire it, and save. Spun signs every delivery with the secret shown for that subscription.
- 3
Send a test message
Message the connected WhatsApp number from your phone. The Webhook node picks up the real payload, which is the sample you then build the rest of the workflow against.
- Events you can subscribe to: incoming message, outgoing message, contact created, contact updated, contact deleted, label assigned, chat flow completed, queued message processed, lead qualified, chat archived, and call completed.
- X-Webhook-Signature is an HMAC-SHA256 of the exact raw request body, written as sha256 followed by the hex digest. Verify it against the raw body bytes, not against a re-serialised copy of the parsed JSON, because key order is not guaranteed to survive a parse and a re-encode.
- A delivery is retried up to three times, immediately then after 5 seconds then after 30 seconds, and each attempt waits 10 seconds for a response. Any 2xx counts as delivered.
- Because of those retries the same event can arrive twice. event_id stays the same across the retries of one event, so use it to skip duplicates.
POST https://your-n8n.example.com/webhook/abc123
X-Webhook-Event: message.inbound
X-Webhook-Delivery: 550e8400-e29b-41d4-a716-446655440000
X-Webhook-Signature: sha256=<hmac of the raw body>
{
"event_id": "550e8400-e29b-41d4-a716-446655440000",
"event": "message.inbound",
"timestamp": "2026-08-18T10:30:00.000Z",
"org_id": "123",
"data": {
"message_id": "[email protected]_ABC123",
"chat_id": "[email protected]",
"from": "972501234567",
"type": "text",
"text": "Hello!"
}
}Verifying the signature matters more than it looks: the webhook URL is the only thing protecting the workflow, and n8n webhook URLs are guessable enough to be worth signing against.
5. The full API description
The complete machine-readable description of the API is published as an OpenAPI 3.1 document, free to fetch and with no API key needed. Every endpoint, request field, response shape, error code and the webhook envelope are in it, which is usually faster than reading a guide.
curl https://api.spun.com/api/integrations/openapi.jsonn8n can import an OpenAPI description directly when generating a custom node or a declarative HTTP node, so this is the shortest route from zero to a working set of operations.
A native Spun node for n8n
Everything above uses the generic HTTP Request node, which is why it works today with no waiting. A dedicated Spun community node is built and going through publishing: it turns the same endpoints into named operations with proper fields, adds a Spun credential with a built-in connection test, and gives the trigger side a node that subscribes and unsubscribes on its own when you activate or deactivate the workflow, verifying each delivery signature for you.
It is not on the n8n community node registry yet, so there is nothing to install at the moment and this page does not pretend otherwise. Two capabilities arrive with it: the self-subscribing trigger, and polling the message history on a schedule for the case where an n8n instance cannot receive inbound webhooks at all. Both depend on API key permissions that are not yet offered in the key editor, so both are described here rather than given as instructions.
Until it lists, the HTTP Request path on this page is the supported way to use Spun with n8n, and it stays supported afterwards.
What to know before you build on it
- Rate limit is 60 requests per minute per API key across all endpoints. Batch phone checks up to 20 per call, and put a Wait node inside any loop that fans out over a large list.
- remove-label needs the label id, unlike apply-label which also accepts a label name. Call the labels endpoint once at the start of a workflow and keep the ids.
- Webhook subscriptions are created inside Spun Settings today. A workflow tool cannot yet create its own subscription with a key you can mint from the key editor.
- This is a key-based API. There is no OAuth "connect your Spun account" screen for it, which is deliberate: AI assistant connections use a separate, consent-based mechanism and separate keys, and the two cannot be mixed on one key.
- Everything is scoped to the WhatsApp number the key belongs to. An account with several numbers has a key per number rather than one key spanning all of them.
Related: WhatsApp + Zapier and Make · WhatsApp + Google Sheets (fully native, no API key needed) · WhatsApp + HubSpot CRM