# WeZend — full documentation for LLMs > WeZend is the Customer Engagement Platform that unifies CPaaS, CDP and AI automation — omnichannel messaging, real-time customer profiles and intelligent journeys in one place. This file contains the complete WeZend documentation as plain text, plus wiki guides, migration guides, playbooks, solutions, vendor comparisons and the full price list. Base API URL: https://api.wezend.com — authenticate with the `X-API-Key` header (server-side only). Human-readable docs: https://wezend.com/en/docs · Site map for LLMs: https://wezend.com/llms.txt --- # Section: Getting started ## Quickstart: send your first message _Go from zero to a delivered message in about five minutes with the WeZend API._ (https://wezend.com/en/docs/quickstart) This guide sends your first message in about five minutes. ## 1. Get your API key Sign in to the dashboard, open **Settings → API keys**, and create a key. It authenticates every request you send and should never be exposed in a browser or mobile app — call it from your own backend. ## 2. Send a message ```bash curl https://api.wezend.com/v1/messages/send \ -H "X-API-Key: $WEZEND_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "to": "+4512345678", "channel": "sms", "sender": "WeZend", "message": "Hello from WeZend" }' ``` A successful call returns `201` with the message record: ```json { "message_id": "3fa1e2c0-...", "status": "queued", "channel": "sms", "to": "+4512345678", "cost": 0.045, "currency": "EUR", "created_at": "2026-07-08T10:00:00.000Z" } ``` ## 3. Check delivery Poll `GET /v1/messages/:message_id`, or — better at any real volume — pass a `webhook_url` in the send request and receive delivery updates as they happen. See [Webhooks](/en/docs/webhooks). ## Next steps - [Authentication](/en/docs/api-authentication) — API keys vs. dashboard sessions - [Sending messages](/en/docs/sending-messages) — every field `/v1/messages/send` accepts, and channel fallback - [Rate limits](/en/docs/rate-limits) — the real, current limits per endpoint --- ## Authentication _API keys, dashboard JWTs, and how the platform accepts either on most endpoints._ (https://wezend.com/en/docs/api-authentication) WeZend uses two credential types, and most account-level endpoints accept either one. ## API keys (server-to-server) Send your key in the `X-API-Key` header. Keys are scoped to your account and meant for backend-to-backend calls. ```bash curl https://api.wezend.com/v1/account/me \ -H "X-API-Key: $WEZEND_API_KEY" ``` ## JWT bearer token (dashboard sessions) Interactive sessions authenticate with a JWT obtained from `POST /v1/auth/login`, optionally followed by `POST /v1/auth/mfa/verify` when TOTP MFA is enabled on the account. ```bash curl https://api.wezend.com/v1/account/me \ -H "Authorization: Bearer $WEZEND_JWT" ``` ## Endpoints that accept either A number of endpoints — sending messages, reading account data, creating an integration — run "flexible auth": they try `X-API-Key` first and fall back to a `Bearer` JWT, so the same integration code works whether it's called from your backend or triggered from the dashboard. Endpoints under `/v1/admin/*` and partner/agency endpoints are the exception — those are internal and staff/agency-only, not part of the customer-facing API surface. ## Rotating keys Rotate a key from **Settings → API keys → Rotate** (`POST /v1/account/keys/:id/rotate`). The old key stays valid for a **24-hour grace period**, so you can redeploy with the new key without a service interruption. > Never ship an API key to a browser or mobile app — anything running on a device you don't control can be inspected. Call WeZend from your own backend, or use the public tracking key described in [Tracking events](/en/docs/tracking-events), which is deliberately write-only and safe for the browser. --- ## Rate limits _The actual, current per-endpoint rate limits — not rounded estimates._ (https://wezend.com/en/docs/rate-limits) Rate limits are enforced per customer account (falling back to IP for unauthenticated endpoints), on a rolling 1-minute window unless noted otherwise. | Endpoint group | Limit | Notes | |---|---|---| | `POST /v1/messages/send` | 1,000 requests / minute | Per account. Use bulk for higher throughput. | | `POST /v1/messages/bulk` | 100 requests / minute | Each request may contain up to 10,000 messages. | | `POST /v1/auth/login` | 20 attempts / 15 minutes | Brute-force protection. | | Most other authenticated endpoints | 500 requests / minute | Dashboard and general API traffic. | | Public, unauthenticated endpoints (e.g. push registration) | 120 requests / minute per IP | No API key or login required on these. | ## Handling a 429 A rate-limited request returns `429` with `limit`, `window` and `retry_after` (seconds) in the body, plus standard `RateLimit-*` response headers. Back off for at least `retry_after` seconds before retrying — don't retry immediately in a tight loop. ```json { "error": "Rate limit exceeded", "message": "You can send up to 1,000 messages per minute. Please slow down or use the bulk endpoint.", "limit": 1000, "window": "1 minute", "retry_after": 12 } ``` ## Sending more than 1,000 messages a minute Use `POST /v1/messages/bulk` instead of looping individual `/send` calls — it's rate-limited per *request* (100/min), not per message, and each request can carry up to 10,000 messages. --- ## Build with AI (Claude, ChatGPT & friends) _Paste one context block into your AI assistant and it can wire WeZend into whatever it's building for you — forms, notifications, CDP events, journeys._ (https://wezend.com/en/docs/build-with-ai) If you're building your product with Claude, ChatGPT, Cursor or any other AI assistant, you don't need to read our docs — **your assistant does**, and we've made that trivial. ## The two URLs your assistant should know - `https://wezend.com/llms.txt` — a compact map of everything on this site ([llms.txt convention](https://llmstxt.org)). - `https://wezend.com/llms-full.txt` — the **entire documentation as one plain-text file**: every endpoint, every field, every example. Small enough for a modern context window, complete enough to build against without browsing. If your assistant can fetch URLs, one instruction suffices: *"Read https://wezend.com/llms-full.txt and integrate WeZend."* ## The copy-paste context pack No URL fetching? Paste this block into the conversation instead — it's the minimum an LLM needs to integrate correctly: ```text WEZEND API — INTEGRATION CONTEXT Base URL: https://api.wezend.com (all paths below are under /v1) Auth: header X-API-Key: (server-side only — NEVER in browser code) SEND A MESSAGE (any channel: sms | email | whatsapp | voice | push | inapp) POST /v1/messages/send { "to": "+4512345678" | "a@b.com", "channel": "sms", "sender": "Acme", "message": "text", "subject": "(email)", "html": "(email)", "template_id": "tpl_… (optional)", "variables": { }, "webhook_url": "(optional)" } → 201 { "message_id", "status": "queued", "cost", "currency" } Status: GET /v1/messages/:id Bulk: POST /v1/messages/bulk { "messages": [ … ] } CONTACTS (CDP) POST /v1/contacts { "email", "phone", "first_name", …custom fields } PATCH /v1/contacts/:id (partial update; matched/deduped on email/phone) POST /v1/contacts/fields { "key", "type": "text|number|date|boolean", "label" } POST /v1/contacts/import (CSV) BEHAVIOURAL EVENTS (feeds segments & journeys) POST /v1/events { "contact": { "email": "a@b.com" }, "event": "order_completed", "properties": { "value": 499, "currency": "DKK" } } LEAD FORMS (public — safe in browser code, no API key) POST https://api.wezend.com/forms//submit { "email", …fields } Hosted page: GET https://api.wezend.com/forms/ DELIVERY WEBHOOKS (configure URL in dashboard or per-send webhook_url) You receive: POST { "message_id", "status": "delivered|failed|…", "timestamp", … } Verify the X-WeZend-Signature header with your webhook secret (GET /v1/webhook-secret). RULES FOR GENERATED CODE 1. API key lives in an env var (WEZEND_API_KEY), called from backend code only. 2. Public browser code may only call /forms//submit — nothing else. 3. Marketing sends require consent; transactional sends set "category": "transactional". 4. Use E.164 phone numbers (+4512345678). Handle 402 (insufficient balance) and 429 (rate limit). Full reference: https://wezend.com/llms-full.txt ``` ## Prompts that work > "Add a newsletter signup to my site's footer that submits to my WeZend form `site-footer` with a success state." > "When a user completes checkout in this Express app, send an order-confirmation email via WeZend and track an `order_completed` event with the order value." > "Build a /webhooks/wezend endpoint that verifies the signature and marks messages delivered in my DB." The assistant has everything it needs in the pack above — endpoints, shapes, and the security rules that keep it from putting your API key in a browser bundle. ## Getting your credentials 1. [Create an account](https://app.wezend.com) and grab a key under **Settings → API keys**. 2. Create a form under **Audience → Forms** if the assistant is building signup UI. 3. Set `WEZEND_API_KEY` in your project's environment — and let the assistant do the rest. ## Want to operate, not just build? With [Connect AI (MCP)](/en/docs/connect-ai) your assistant doesn't just write code against WeZend — it runs your account directly: 34 customer-scoped tools for segments, campaigns, journeys, domains and budgets, with real sends behind an explicit confirmation. --- ## Connect AI (MCP) — run your account from Claude or ChatGPT _Connect Claude or ChatGPT to your WeZend account: 44 customer-scoped tools that read, configure and — behind an explicit confirmation — operate the platform in plain language._ (https://wezend.com/en/docs/connect-ai) The [Build with AI](/en/docs/build-with-ai) page makes your assistant able to **write code against** WeZend. Connect AI goes further: your assistant **operates your account directly** — no code, just conversation. ## What it can do **Read & diagnose** — plan & usage, contacts (search), segments, journeys, campaigns, templates, forms, flows, integrations, senders, email domains, analytics, ROI, deliverability, budget — and `explain_message`: "why did message X fail?" **Understand your CDP data** — which events are flowing in (types, volumes, sample properties), any contact's unified profile (identity, custom fields, lifecycle stage, engagement score, churn risk, predicted CLV, recent events), computed traits, and behavioural analytics: funnels between event steps and weekly retention cohorts. **Configure** — create segments (explicit rules *or* a plain-English description we translate to rules), add contacts (JSON array or raw pasted CSV), migrate from Klaviyo/Mailchimp/Brevo (suppressions + contacts, consent intact), create templates, campaign drafts, journey drafts and lead forms, request sender IDs, add + verify email domains (SPF/DKIM/DMARC), set sending policy, set budget caps. **Act — confirm-gated** — `send_campaign`, `launch_journey` and `send_test` are real, billable actions. They refuse to run unless the call carries `confirm: true`, so your assistant must explicitly confirm before anything is sent. Confirmed or not, every dashboard guard still applies: suppression lists, quota, budget caps, card-on-file and the audit log. **Deliberately excluded** — connecting integrations, WhatsApp/Voice/Push credentials and billing. Anything involving secrets or money stays in the dashboard, behind your login. In total: **44 tools**, each mapped 1:1 to the same customer-scoped services the dashboard uses. The account identity always comes from your API key — never from the model. ## Get your key Dashboard → **Connect AI** (`/connect-ai`). Create a key there; you can revoke it at any time. Treat it like a password. ## Connect from Claude **claude.ai / Claude Desktop (remote connector):** add a custom connector pointing at ```text https://api.wezend.com/v1/mcp ``` with your API key as the `X-API-Key` header. **Claude Desktop / Claude Code (stdio bridge):** if your client prefers a local MCP server, use the npm bridge: ```json { "mcpServers": { "wezend": { "command": "npx", "args": ["-y", "@wezend/mcp"], "env": { "WEZEND_API_KEY": "zc_live_sk_..." } } } } ``` The bridge speaks MCP over stdio and forwards to `/v1/mcp` (override with `WEZEND_MCP_URL` for staging). ## Connect from ChatGPT Create a GPT → **Actions** → *Import from URL*: ```text https://api.wezend.com/v1/mcp/openapi.json ``` That spec describes a single endpoint, `POST /v1/mcp/act`, taking `{ "tool": "...", "arguments": { ... } }` — with the full tool list embedded so the model knows what it can call. Set authentication to an API key in the `X-API-Key` header. ## Try it Ask your assistant, in your own words: - *"What plan am I on and how much of my quota is left this month?"* - *"Create a segment of customers who haven't opened anything in 60 days."* - *"Here's a CSV of leads from our fair — import them and add them to a 'Fair 2026' list."* (paste the CSV) - *"I'm moving from Klaviyo — here's my suppression export, then my profile export."* (paste both, in that order) - *"Draft a two-step win-back journey for that segment — don't activate it yet."* - *"What events are we actually receiving, and what do they contain?"* - *"Show me the full profile for anna@example.com — is she churn-risk?"* - *"Create an ltv trait that sums order revenue, then a segment of everyone above 5,000."* - *"How does our signup → first purchase funnel look over the last 30 days?"* - *"Why did message msg_1a2b fail?"* - *"Send campaign X."* → the assistant will be asked to confirm before anything leaves. ## Migrate from Klaviyo, Mailchimp or Brevo — in chat Two source-aware tools reuse the same mapping engine as the [migration wizard](/en/migrate), so field mapping, lists and consent survive the move: 1. `import_migration_suppressions(source, csv)` — **always first.** Imports the unsubscribe/suppression export, so no one who opted out at your old provider can ever be mailed from WeZend. 2. `import_migration_contacts(source, csv, list_name?)` — then the profile export, with the source's field mapping and consent applied. The tools enforce the order: contact import for a source is refused until its suppressions have been imported. Paste each export straight into the chat — for very large files, use the [migration wizard](/en/migrate) in the dashboard instead. ## Understand & shape your CDP data Six read tools and two configuration tools cover the [CDP](/en/features/customer-data-platform): - `list_event_types()` — the event types your account receives, with volumes and sample properties, so the assistant knows what your data actually looks like before building on it. - `get_events(contact?, event_type?, limit?)` — the recent event stream, filterable. - `get_profile(contact)` — one contact's unified profile: identity, custom fields, lists, consent, lifecycle stage, engagement score, churn risk, predicted CLV and the latest events. - `list_computed_traits()` / `create_computed_trait(key, source, agg, event_type?, field?)` / `refresh_traits()` — traits aggregate events, messages or orders per contact (count, sum, avg, max, min or days_since). "Create an `ltv` trait summing order revenue" or "add `days_since_purchase`" — then segment on them immediately. - `get_funnel(steps, days?)` — conversion between event steps, e.g. `product_viewed → checkout_started → order_completed`. - `get_retention(weeks?)` — weekly cohort retention. Ask "what does our signup-to-purchase funnel look like?", get the numbers, then say "create a segment of everyone stuck at checkout and draft a nudge campaign" — the assistant chains it end to end. ## The 44 tools `get_plan_usage`, `list_segments`, `list_journeys`, `list_campaigns`, `get_recent_messages`, `list_contacts`, `list_templates`, `list_forms`, `list_flows`, `list_integrations`, `list_senders`, `list_email_domains`, `list_migration_sources`, `get_analytics`, `get_roi`, `get_deliverability`, `get_budget`, `explain_message`, `list_event_types`, `get_events`, `get_profile`, `list_computed_traits`, `get_funnel`, `get_retention` — read. `create_segment`, `add_contacts`, `import_contacts_csv`, `import_migration_suppressions`, `import_migration_contacts`, `create_computed_trait`, `refresh_traits`, `create_template`, `create_form`, `create_journey`, `create_campaign`, `create_sender`, `add_email_domain`, `verify_email_domain`, `set_sending_policy`, `set_budget`, `pause_campaign` — configure. `send_campaign`, `launch_journey`, `send_test` — act, **confirm required**. --- # Section: Core APIs ## Sending messages _Every field POST /v1/messages/send accepts, channel fallback, and how per-category frequency caps work._ (https://wezend.com/en/docs/sending-messages) `POST /v1/messages/send` is the single endpoint for every channel. ## Required fields `to`, `channel` (one of `sms`, `rcs`, `whatsapp`, `email`, `voice`) and `message` are required — or pass a `channels` array instead of `channel`/`fallback` (see below). ## Channel fallback Provide an ordered `fallback` list, or the newer `channels` array with the primary channel first: ```json { "to": "+4512345678", "channels": ["whatsapp", "sms"], "message": "Your order has shipped." } ``` If WhatsApp delivery fails, the platform automatically retries on SMS — no separate API call. ## Channel-specific fields - **Email**: set `subject`, and `htmlmessage` (or the legacy `html` alias) for the HTML body. `message` is the plain-text fallback. - **WhatsApp**: pass a `whatsapp` object, e.g. `{ "template": "order_shipped" }`, for template messages outside the 24-hour session window. - **Voice**: pass a `voice` object (e.g. `{ "voice": "female", "language": "da-DK" }`) for TTS parameters. - **Sender ID**: `sender` must be a sender ID approved in **Settings → Sender IDs** for SMS/RCS — unless your account has `allow_unverified_sender` enabled for system integrations. ## Scheduling and per-message webhooks `scheduled_at` (ISO timestamp) delays dispatch. `webhook_url` receives delivery status updates for **this specific message** — see [Webhooks](/en/docs/webhooks). ## Marketing frequency caps Pass a `category` (e.g. `"newsletter"`) to have this send count against that category's frequency cap, configured account-wide in messaging policy — independent of the global cross-channel cap and any per-channel cap. ## Response ```json { "message_id": "3fa1e2c0-...", "status": "queued", "channel": "sms", "to": "+4512345678", "cost": 0.045, "currency": "EUR", "created_at": "2026-07-08T10:00:00.000Z" } ``` A `402` means insufficient balance or a missing payment method; `403` means the account is suspended, pending activation, or the sender ID isn't approved; `409` means the recipient has opted out of that channel. --- ## Bulk sending _Send up to 10,000 messages in a single request with POST /v1/messages/bulk._ (https://wezend.com/en/docs/bulk-sending) `POST /v1/messages/bulk` accepts an array of up to **10,000** messages per request, processed in parallel batches of 50. ```json { "messages": [ { "to": "+4512345678", "channel": "sms", "message": "Hi Mette, your table is ready." }, { "to": "+4587654321", "channel": "sms", "message": "Hi Jonas, your table is ready." } ], "webhook_url": "https://yourapp.com/hooks/wezend" } ``` Per-message `sender`, `webhook_url`, `scheduled_at` and `fallback` override the request-level defaults. ## Response ```json { "batch_id": "b6e2...", "queued": 1987, "failed": 13, "estimated_cost": 89.415, "currency": "EUR", "created_at": "2026-07-08T10:00:00.000Z" } ``` `estimated_cost` is computed from live pricing at request time, in your account's billing currency. A message can still fail after being queued (e.g. a bad number) — this endpoint reports what was *accepted for delivery*, not final delivery. Track outcomes via `webhook_url` or [message history](/en/docs/message-status-and-history). This endpoint is rate-limited at **100 requests/minute** (not 100 messages) — see [Rate limits](/en/docs/rate-limits). --- ## Message status, history & resend _Look up a message, search delivery history, resend or cancel a queued message._ (https://wezend.com/en/docs/message-status-and-history) ## Get a single message ```bash curl https://api.wezend.com/v1/messages/msg_01H8... \ -H "X-API-Key: $WEZEND_API_KEY" ``` ```json { "message_id": "msg_01H8...", "status": "delivered", "channel": "sms", "to": "+4512345678", "fallback_used": false, "sent_at": "2026-07-08T10:00:01.000Z", "delivered_at": "2026-07-08T10:00:04.000Z", "cost": 0.045, "currency": "EUR" } ``` ## Search history `GET /v1/messages/history` supports `search` (matches recipient, body or vendor message ID), `status`, `channel`, `page` and `limit` (max 100/page) query parameters. ## Resend `POST /v1/messages/:id/resend` creates a **new** message to the same recipient with the same content — it runs through the same balance, suppression and budget checks as a fresh send. ## Cancel a scheduled message `DELETE /v1/messages/:id` cancels a message that's still `queued` (i.e. scheduled ahead via `scheduled_at` and not yet dispatched). Returns `409` if it has already been sent. --- ## Send-by-tag (hiding PII from public pages) _Trigger a send to a saved recipient by tag, so a phone number or email never has to appear in your own HTML._ (https://wezend.com/en/docs/send-by-tag) Some integrations — a booking confirmation page, a returns portal — need to trigger a message without exposing the recipient's phone number or email in the page's own HTML or client-side JavaScript. ## The pattern 1. Create a named recipient once: `POST /v1/recipients` with `{ tag, channel, recipient }`. 2. From your backend, trigger a send by tag instead of by raw address: ```bash curl -X POST https://api.wezend.com/v1/messages/send-by-tag \ -H "X-API-Key: $WEZEND_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "recipient_tag": "booking-42891", "subject": "Your booking is confirmed", "message": "See you Thursday at 14:00." }' ``` Only the tag ever needs to reach the browser or a third-party page builder — the platform resolves it to the real recipient server-side. ## Attachments (email only) Pass `attachment: { filename, content (base64), contentType }` to attach inline, or `media_url` pointing at a file you've already uploaded via [Media](/en/docs/media). Attachments aren't supported on SMS/WhatsApp — include a link in the message text instead. This endpoint requires an API key (not a dashboard JWT) — it's designed for server-to-server calls. --- ## Webhooks _How per-message delivery webhooks actually work: the webhook_url field, real headers, and the real retry schedule._ (https://wezend.com/en/docs/webhooks) WeZend's webhook model is **per-message**, not a global event subscription. There's no dashboard screen where you register "notify me about every future delivery" — instead, you pass `webhook_url` directly on the send request (or per-message inside a bulk request), and status updates for *that message* are POSTed there as they happen. ```json { "to": "+4512345678", "channel": "sms", "message": "Your order has shipped.", "webhook_url": "https://yourapp.com/hooks/wezend" } ``` ## Payload and headers Every delivery includes: - `X-ZafeConnect-Event` — the event name - `X-ZafeConnect-Timestamp` — Unix ms timestamp used in the signature - `X-ZafeConnect-Signature` — HMAC-SHA256 of `${timestamp}.${JSON.stringify(payload)}`, using the webhook signing secret from **Settings → Webhook secret** > These headers currently carry the platform's original "ZafeConnect" name rather than "WeZend" — a branding detail in the backend that hasn't been renamed yet, not something you need to work around. Verify the signature the same way regardless of the header prefix. ## Verify the signature ```javascript const crypto = require("crypto"); function verify(rawBody, timestamp, signature, secret) { const expected = crypto .createHmac("sha256", secret) .update(`${timestamp}.${rawBody}`) .digest("hex"); return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature)); } ``` ## Retries If your endpoint doesn't respond `2xx`, delivery is retried **3 times** — after 30 seconds, 5 minutes, then 30 minutes — and retries survive a restart or deploy (they're durable, backed by the database, not an in-memory queue). Respond quickly and process asynchronously rather than doing slow work in the request handler. ## Inbound vendor delivery receipts The `/v1/webhooks/messente`, `/v1/webhooks/twilio`, `/v1/webhooks/vonage` and `/v1/webhooks/whatsapp` endpoints are how upstream carriers report delivery back to the platform — they're platform-internal and not something you configure; they exist so WeZend itself can populate the statuses you see via `webhook_url` and the [message history API](/en/docs/message-status-and-history). --- # Section: Channels ## Email: domains, DNS & sending _Verify your sending domain with SPF, DKIM and DMARC, then send email through the same API as every other channel._ (https://wezend.com/en/docs/email-domains-and-sending) Before WeZend sends email in your name, you prove that you own the domain. This is what keeps your mail out of the spam folder — inbox providers trust mail that is cryptographically tied to a verified domain. ## 1. Add your domain In the dashboard, open **Settings → Email domains** and add the domain you send from (for example `mail.yourcompany.com`). The API equivalent: ```bash curl -X POST https://api.wezend.com/v1/account/email-domains \ -H "X-API-Key: $WEZEND_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "domain": "mail.yourcompany.com" }' ``` The response lists the exact DNS records to create: an **SPF** record (which servers may send for you), a **DKIM** key (a signature receivers verify) and a **DMARC** policy (what receivers should do when a message fails the first two). ## 2. Create the DNS records Copy each record into your DNS provider exactly as shown. DNS changes can take from minutes to a few hours to propagate. ## 3. Verify Click **Verify** in the dashboard or call `POST /v1/account/email-domains/:id/verify` — the platform runs live DNS checks and marks each record green or red, telling you precisely which record is wrong if one fails. ## 4. Send Once verified, email is just another channel on the same endpoint you already use: ```bash curl -X POST https://api.wezend.com/v1/messages/send \ -H "X-API-Key: $WEZEND_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "to": "customer@example.com", "channel": "email", "sender": "hello@mail.yourcompany.com", "subject": "Welcome!", "html": "

Hi there

Thanks for signing up.

" }' ``` Opens and clicks are tracked automatically (a tracking pixel and rewritten links), bounces and complaints feed the [suppression list](/en/docs/consent-and-unsubscribes), and your sender reputation is monitored continuously — see [Deliverability](/en/docs/deliverability-and-inspector). --- ## WhatsApp (Cloud API) _Connect Meta's WhatsApp Cloud API: session messages, media, approved templates, and inbound replies straight into your Inbox._ (https://wezend.com/en/docs/whatsapp-cloud) WeZend speaks to WhatsApp through **Meta's official Cloud API** — no third-party middleman. You bring your own Meta Business account; WeZend handles sending, receiving, delivery receipts and conversation threading. ## What you need from Meta 1. A **Meta Business** account with a WhatsApp Business App. 2. A **phone number ID** and a **permanent access token** (created in Meta's developer console under WhatsApp → API Setup). ## Connect the channel Open **Settings → Channels → WhatsApp** and paste the phone number ID and access token. Via API: ```bash curl -X PUT https://api.wezend.com/v1/channels/whatsapp \ -H "X-API-Key: $WEZEND_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "phone_number_id": "1045…", "access_token": "EAAG…" }' ``` Then set WeZend's webhook URL (shown on the same settings page) in Meta's console so inbound messages and status updates reach the platform. ## The 24-hour rule (important!) WhatsApp distinguishes two kinds of messages: - **Session messages** — free-form text and media, allowed only within 24 hours after the customer last wrote to you. - **Template messages** — pre-approved by Meta, required to *start* a conversation or re-engage after 24 hours. WeZend enforces this automatically: outside the session window, sends must reference an approved template. ## Sending ```bash curl -X POST https://api.wezend.com/v1/messages/send \ -H "X-API-Key: $WEZEND_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "to": "+4512345678", "channel": "whatsapp", "message": "Your order #1042 has shipped 🎉" }' ``` Media attachments use `media_url` (upload via `POST /v1/media` first). Inbound replies appear in **Inbox → Conversations** and fire your [webhooks](/en/docs/webhooks), so support tools and bots can react in real time. --- ## Voice & text-to-speech calls _Place automated voice calls that read your message aloud — for alerts, OTPs and reminders that must not be missed._ (https://wezend.com/en/docs/voice-messages) Some messages are too important to sit unread in an inbox. The voice channel calls the recipient and reads your message aloud with natural text-to-speech — ideal for critical alerts, on-call escalation, appointment reminders for less digital audiences, and OTP fallback. ## Setup Open **Settings → Channels → Voice** and connect your telephony credentials (Twilio-compatible). One-time setup via `PUT /v1/channels/voice`. ## Sending a call Voice uses the exact same send endpoint as SMS and email — only the `channel` differs: ```bash curl -X POST https://api.wezend.com/v1/messages/send \ -H "X-API-Key: $WEZEND_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "to": "+4512345678", "channel": "voice", "message": "This is an automated alert from Acme. Your server EU-1 is unreachable. Press any key to acknowledge." }' ``` ## What you get back Call status flows through the same lifecycle as any message (`queued → sent → delivered/failed`), where *delivered* means the call was answered. Delivery webhooks fire exactly like for SMS, so your escalation logic ("no answer in 2 minutes → call the next person on rotation") is a small [journey](/en/docs/building-a-journey) rather than custom code. ## When to prefer voice - **OTP fallback** — if the SMS wasn't delivered within N seconds, call instead (built as a two-step journey with a `wait_event` node). - **Critical ops alerts** — voice interrupts; push and email do not. - **Audiences that don't read SMS** — reminders for healthcare and public-sector use cases. --- ## Web & mobile push _Free, instant notifications: a one-script web push SDK (VAPID) plus FCM for your mobile apps, with broadcasts and click tracking._ (https://wezend.com/en/docs/push-notifications) Push is the cheapest channel you have — delivery costs nothing — and WeZend treats it as a first-class citizen next to SMS, email and WhatsApp. ## Web push in one script Add the SDK to your site: ```html ``` The SDK registers a service worker, asks the visitor for permission (you control when — call `wezendPush.prompt()` after a meaningful action, not on page load), and registers the device via `POST /v1/push/subscribe`. Devices are automatically linked to the contact profile when you [identify](/en/docs/tracking-events) the visitor. Web push uses the open **VAPID** standard — it works in Chrome, Edge, Firefox and Safari without any app-store involvement. ## Mobile push (FCM) For iOS/Android apps, connect your Firebase Cloud Messaging server key under **Settings → Channels → Push**, then register device tokens with the same `POST /v1/push/subscribe` endpoint from your app code. ## Sending Individual pushes go through the universal send endpoint with `"channel": "push"`. For one-to-many, create a **broadcast**: ```bash curl -X POST https://api.wezend.com/v1/push/broadcasts \ -H "X-API-Key: $WEZEND_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "title": "Flash sale ⚡", "body": "25% off everything until midnight.", "url": "https://shop.example.com/sale", "segment_id": "seg_active_shoppers" }' ``` Clicks are reported back via `POST /v1/push/event` (the SDK does this for you), so broadcast analytics show delivered → shown → clicked, and click-through feeds journey goals just like email clicks. --- ## In-app inbox _A persistent message center inside your own product — messages that wait for the user instead of interrupting them._ (https://wezend.com/en/docs/in-app-inbox) Not every message deserves an interruption. The in-app inbox is a message center you embed in your own web app — announcements, feature news and account notices land there and wait until the user logs in. ## Why an inbox channel - **Zero fatigue** — it never buzzes a phone. Perfect for "nice to know" content that would hurt your push opt-in rate. - **Guaranteed reach** — no spam filter, no notification permission needed; every active user sees it. - **A journey step like any other** — journeys can deliver to `inapp` exactly like SMS or email, so "announce in-app, escalate to email if unread after 3 days" is a standard pattern. ## Embedding Fetch messages for the signed-in user from your backend and render them in your own UI: ```bash curl "https://api.wezend.com/v1/inapp/messages?contact_id=c_123" \ -H "X-API-Key: $WEZEND_API_KEY" ``` Mark read state back so unread badges stay correct: ```bash curl -X POST https://api.wezend.com/v1/inapp/messages/msg_456/read \ -H "X-API-Key: $WEZEND_API_KEY" ``` ## Sending Use the universal endpoint with `"channel": "inapp"`, or add an in-app step in a [journey](/en/docs/building-a-journey). Messages support Markdown, a call-to-action URL and an expiry date (after which they disappear from the inbox on their own). --- ## SMS sender IDs & compliance _Alphanumeric sender names, per-country rules, and the validation API that stops a non-compliant send before it costs you money._ (https://wezend.com/en/docs/sms-senders-and-compliance) Every country regulates SMS sender names ("Sender IDs") differently: some allow any alphanumeric name, some require pre-registration, some force a numeric sender. Getting this wrong means silently dropped messages — you pay, nothing arrives. WeZend encodes these rules into the platform so you cannot make that mistake. ## Register your sender names Add the names you send as (e.g. `Acme`, max 11 characters alphanumeric) under **Settings → Senders** or via `POST /v1/senders`. Where a destination country requires registration (e.g. several telco markets), the request is routed to the operator process and you can follow its approval status in the dashboard. ## Check the rules programmatically ```bash curl "https://api.wezend.com/v1/sender/rules?country=DK" -H "X-API-Key: $WEZEND_API_KEY" ``` Returns what the destination allows: alphanumeric yes/no, registration required, max length, and fallback behaviour. ## Validate before sending ```bash curl -X POST https://api.wezend.com/v1/sender/validate \ -H "X-API-Key: $WEZEND_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "sender": "Acme", "to": "+4670123456" }' ``` The response tells you whether the send would be compliant and, if not, what the platform would substitute (for example a registered numeric sender). The same check runs automatically inside `/v1/messages/send` — validation is a pre-flight convenience so your UI can warn users early. ## Marketing traffic Marketing SMS additionally respects [consent, quiet hours and frequency caps](/en/docs/frequency-caps-and-quiet-hours) — transactional traffic (OTPs, receipts) is exempt by design. --- ## SMS keyword opt-in _Define a keyword — JOIN, VIP — so texting it to your number subscribes the sender with consent captured automatically._ (https://wezend.com/en/docs/sms-keyword-optin) Keyword opt-in turns any surface — a poster, a receipt, a shop window — into a subscribe point. When someone texts your keyword to your number, they're subscribed and the opt-in is recorded, timestamped and documented. ## Create a keyword ```bash curl https://api.wezend.com/v1/sms-keywords \ -H "X-API-Key: " -H "Content-Type: application/json" \ -d '{ "keyword": "vip", "reply_text": "Welcome to VIP! You'\''ll hear about drops first.", "tag": "vip" }' ``` - `keyword` — 1–40 letters/numbers, no spaces (case-insensitive). - `action` — `subscribe` (default) or `unsubscribe`. - `reply_text` — optional auto-reply confirming the opt-in. - `tag` — optional tag applied to contacts who join, so you can segment on it. List your keywords with `GET /v1/sms-keywords`. ## After they join The opt-in is a documented consent signal (who, what, when). Route new subscribers straight into a welcome [journey](/en/docs/building-a-journey) so they get an instant first message. Set up a matching `unsubscribe` keyword (e.g. STOP) to honour opt-outs. --- # Section: Customer Data Platform ## Contacts, custom fields & lists _The contact profile: standard and custom fields, CSV import, deduplication, and how lists differ from segments._ (https://wezend.com/en/docs/contacts-and-custom-fields) Everything in WeZend hangs off the **contact** — one profile per human, holding identifiers (email, phone), attributes, consent state, event history, messages and scores. ## Standard + custom fields Contacts ship with the standard fields you'd expect (name, email, phone, country, language…). Everything else is a **custom field** you define once: ```bash curl -X POST https://api.wezend.com/v1/contacts/fields \ -H "X-API-Key: $WEZEND_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "key": "loyalty_tier", "type": "text", "label": "Loyalty tier" }' ``` Types: text, number, date, boolean. Once defined, the field is available everywhere — in template variables (`{{loyalty_tier}}`), in the segment builder, on the contact card in the dashboard, and in CSV imports. ## Creating & updating ```bash # Create curl -X POST https://api.wezend.com/v1/contacts \ -H "X-API-Key: $WEZEND_API_KEY" -H "Content-Type: application/json" \ -d '{ "email": "anna@example.com", "phone": "+4512345678", "first_name": "Anna", "loyalty_tier": "gold" }' # Update (partial — only the fields you send change) curl -X PATCH https://api.wezend.com/v1/contacts/c_123 \ -H "X-API-Key: $WEZEND_API_KEY" -H "Content-Type: application/json" \ -d '{ "loyalty_tier": "platinum" }' ``` Contacts are matched on email/phone, so importing the same person twice updates rather than duplicates. ## CSV import **Audience → Contacts → Import** (or `POST /v1/contacts/import`). Upload the file, map your columns to fields (unmapped columns can become new custom fields on the spot), choose the target list, and confirm. Imports run in the background with a progress indicator and a per-row error report — a bad phone number on row 3,481 doesn't kill the other 50,000 rows. ## Lists vs. segments — when to use which - A **list** is *static*: contacts are in it because you put them there (import, form signup, manual add). Membership only changes when something adds/removes them. - A **[segment](/en/docs/segments-and-traits)** is *live*: a rule ("spent > €500 AND inactive 30 days") that contacts flow in and out of automatically as their data changes. Rule of thumb: lists for provenance ("Spring fair leads 2026"), segments for state ("currently at churn risk"). Campaigns and journeys accept both. --- ## Product catalog & recommendations _Sync your products, let the affinity model learn what sells together, and drop per-contact recommendations into any message._ (https://wezend.com/en/docs/product-catalog-and-recommendations) "Customers who bought X also bought Y" — inside your own messages, from your own data, with no external recommendation service. ## 1. Load the catalog ```bash curl -X POST https://api.wezend.com/v1/catalog/products \ -H "X-API-Key: $WEZEND_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "products": [ { "sku": "TSHIRT-BLK-M", "name": "Black tee (M)", "price": 29.0, "currency": "EUR", "url": "https://shop.example.com/p/tshirt-blk", "image_url": "https://…/tshirt.jpg", "category": "apparel" } ] }' ``` Bulk import accepts your full feed; re-posting a SKU updates it. Most shops sync nightly from their commerce platform. ## 2. Feed it behaviour The model learns from the events you already track — `product_viewed`, `added_to_cart`, `order_completed` (see [Tracking events](/en/docs/tracking-events)). Rebuild the affinity model on your schedule: ```bash curl -X POST https://api.wezend.com/v1/catalog/affinity/rebuild -H "X-API-Key: $WEZEND_API_KEY" ``` It computes co-occurrence: which products appear together in real baskets and browsing sessions. ## 3. Use recommendations Per contact: ```bash curl "https://api.wezend.com/v1/catalog/recommendations/c_123?limit=4" -H "X-API-Key: $WEZEND_API_KEY" ``` In the email builder, add a **product grid** block set to "personalised" and each recipient gets their own four products at send time. In journeys, the post-purchase cross-sell ("order delivered → wait 7 days → send recommendations") is a template you can enable in one click. Contacts with no history get graceful fallbacks: bestsellers in the categories they've browsed, or overall bestsellers — never an empty grid. --- ## Two-way conversations & Inbox _Replies from SMS, WhatsApp and email land in one shared Inbox, threaded per contact — with an API to build your own support flows._ (https://wezend.com/en/docs/conversations-and-inbox) Messaging is not fire-and-forget. When a customer replies — to an SMS, a WhatsApp message, an email — the reply lands in the **Inbox**, threaded onto the same conversation and the same contact profile as everything you've sent them. ## The Inbox **Inbox → Conversations** shows every open thread across channels. Each conversation displays the full history (outbound and inbound, all channels interleaved chronologically), the contact card alongside (profile, consent, recent orders), and a reply box that sends on the same channel the customer used. Conversations have a status (open/closed) so a team can work through them like a queue. ## Inbound routing - **SMS replies** arrive via the numbers/keywords configured on your account. - **WhatsApp replies** arrive through the [Cloud API webhook](/en/docs/whatsapp-cloud). - **STOP/unsubscribe keywords** are intercepted before the Inbox: the contact is unsubscribed instantly and the compliance event is recorded — no human in the loop, see [Consent](/en/docs/consent-and-unsubscribes). Everything else can also be forwarded to your own systems: set an inbound webhook URL (`PUT /v1/webhook-secret/inbound-url`) and every inbound message POSTs to your endpoint — this is how booking systems, help desks and bots plug in. ## The API ```bash # List conversations (filter by status) curl "https://api.wezend.com/v1/conversations?status=open" -H "X-API-Key: $WEZEND_API_KEY" # Read a thread curl "https://api.wezend.com/v1/conversations/cv_42/messages" -H "X-API-Key: $WEZEND_API_KEY" # Reply (goes out on the conversation's channel) curl -X POST "https://api.wezend.com/v1/conversations/cv_42/reply" \ -H "X-API-Key: $WEZEND_API_KEY" -H "Content-Type: application/json" \ -d '{ "message": "Thanks — your new appointment is Tuesday at 10:00." }' ``` Inbound messages also fire as events on the contact, so a [journey](/en/docs/building-a-journey) can branch on "customer replied" — the foundation for confirmation flows ("reply YES to confirm"). --- ## Tracking events _Stream behavioral events into the CDP with the public, write-only tracking endpoint._ (https://wezend.com/en/docs/tracking-events) `POST /v1/events/track` is a public, write-only endpoint built to be called directly from a customer's own website — it can accept events but can't read anything back, so it's safe to call with just a public key, unlike your main API key. ## Track a single event ```bash curl -X POST https://api.wezend.com/v1/events/track \ -H "Content-Type: application/json" \ -d '{ "public_key": "pk_live_...", "event": "product_viewed", "customer_ref": "cus_8823", "properties": { "sku": "DK-1180", "price": 499 } }' ``` A single event returns `202 { "ok": true }`. ## Batch events ```json { "public_key": "pk_live_...", "events": [ { "event": "product_viewed", "customer_ref": "cus_8823", "properties": { "sku": "DK-1180" } }, { "event": "add_to_cart", "customer_ref": "cus_8823", "properties": { "sku": "DK-1180", "qty": 1 } } ] } ``` returns `202 { "accepted": 2, "rejected": 0 }`. ## Origin restriction You can pass the key as `X-ZC-Key` instead of in the body. Each public key can optionally be restricted to an allowlist of origins, so a leaked key can only be used to post events from your own domain(s) — an empty allowlist means any origin. ## What happens next Once events land, computed traits recompute and segment membership updates in real time — any [journey](/en/docs/building-a-journey) watching that trigger or segment can fire immediately, no batch job involved. --- ## Segments & computed traits _Build segments with a live-preview count and define computed traits over events, messages and orders._ (https://wezend.com/en/docs/segments-and-traits) ## Segments `GET /v1/segments` lists every segment with a live contact count. `GET /v1/segments/schema` returns the fields and operators the rule builder can offer, so a custom UI can be built against the same schema the dashboard uses. Before saving a segment, preview how many contacts a rule set matches: ```bash curl -X POST https://api.wezend.com/v1/segments/preview \ -H "X-API-Key: $WEZEND_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "rules": [{ "field": "trait:churn_score", "op": "gt", "value": 0.7 }] }' ``` `GET /v1/segments/:id/contacts` resolves a saved segment to the actual member contacts. ## Computed traits Traits (`/v1/traits`) are customer-defined aggregations over events, messages and orders — e.g. "orders in the last 90 days" or "average order value" — materialized directly onto each contact so they're queryable as `trait:` in segment rules, exactly like the churn-score example above. --- ## Audience activation (reverse-ETL) _Push CDP segments out to Meta, Google, TikTok and LinkedIn ad audiences — PII hashed before it ever leaves the platform._ (https://wezend.com/en/docs/activation-reverse-etl) Activation pushes CDP segments and lists **out** to ad platforms as custom audiences — the reverse direction of importing ad-platform data in. ## Connect a destination ```bash curl -X POST https://api.wezend.com/v1/activation/destinations \ -H "X-API-Key: $WEZEND_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "provider": "meta", "name": "Meta — lapsed customers", "credentials": { "access_token": "..." } }' ``` Supported connectors: **Meta Custom Audiences**, **Google Customer Match**, **TikTok**, **LinkedIn**, and a generic **webhook** destination for anything else. Meta/Google/TikTok/LinkedIn connectors require your own ad-platform API access and app review with that platform — the webhook connector works immediately with no external approval. ## Create and run a sync ```bash curl -X POST https://api.wezend.com/v1/activation/syncs \ -H "X-API-Key: $WEZEND_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "destination_id": "dest_..." , "segment_id": "seg_..." }' curl -X POST https://api.wezend.com/v1/activation/syncs/sync_.../run \ -H "X-API-Key: $WEZEND_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "dryRun": true }' ``` `dryRun: true` previews the sync (record counts, matched fields) without actually pushing anything. ## What leaves the platform Emails and phone numbers are normalized and SHA-256 hashed **locally, before egress** — the ad platform never receives raw PII, only the hashes it needs to match its own user base. Destination credentials are encrypted at rest. --- ## Warehouse sync _Export profiles and events to your own data warehouse or a webhook — what's built in vs. what needs your own driver._ (https://wezend.com/en/docs/warehouse-sync) `/v1/warehouse/connections` manages export destinations; `.../run` triggers a sync on demand (in addition to any scheduled runs). ## What works out of the box **Webhook** and **Postgres** destinations work immediately with no extra setup. ## What needs your own driver **BigQuery**, **Snowflake** and **S3** connections need the corresponding client library/driver installed on the host running the platform — they're supported destinations, but the platform doesn't bundle every cloud vendor's SDK by default. Talk to whoever manages your deployment about adding the driver before configuring one of these destinations. --- # Section: Automation ## Building a journey _The real node types, trigger types and pre-built templates behind the visual journey builder._ (https://wezend.com/en/docs/building-a-journey) Journeys are node graphs: a `trigger` node feeds into `send`, `delay`, `wait_event`, `branch`, `split`, `update_contact`, `goal` and `exit` nodes. ## Node types | Type | What it does | |---|---| | `send` | Send a message on any channel | | `delay` | Wait a fixed number of minutes | | `wait_event` | Wait for an event, with a timeout that branches separately | | `branch` | If/else based on segment membership | | `split` | A/B split by weight | | `update_contact` | Write a field back to the contact | | `goal` | Marks the journey as converted (terminal) | | `exit` | Ends the journey without a goal (terminal) | ## Trigger types `event` (any tracked event), `segment_enter` (a contact enters a segment), or `manual` (added by hand or via API). ## Start from a real template Three templates ship with the platform and can be installed as a starting point rather than built from scratch: - **Welcome Journey** — triggers on `signup`; sends a welcome email, waits 48 hours, then waits up to 72 hours for a `purchase` event before sending a follow-up SMS. - **Abandoned Cart Recovery** — triggers on `add_to_cart`; waits 60 minutes, then A/B splits 50/50 between an email and an SMS reminder. - **Win-back Lapsed Customers** — triggers on entering a "lapsed" segment; sends a discount email, waits up to 168 hours (7 days) for a `purchase`, then sends a last-chance SMS. ```bash curl https://api.wezend.com/v1/journeys/templates \ -H "Authorization: Bearer $WEZEND_JWT" ``` ## Test before you launch Every journey supports `.../test-enroll` to run one real profile through the graph and see exactly which path it takes, before you `.../activate` it for everyone matching the trigger. --- ## Flows: one-click automation templates _A simpler alternative to journeys for teams that want a working automation in one click, not a graph to design._ (https://wezend.com/en/docs/flows-and-templates) `/v1/flows` is a lighter-weight automation layer alongside journeys: `GET /v1/flows/templates` lists ready-made, one-click templates you install and turn on, rather than a graph you design node by node. Use flows when you want a standard, well-understood automation (like a birthday message or a re-order reminder) running today; reach for a full [journey](/en/docs/building-a-journey) when you need custom branching, A/B tests, or multi-step timing logic specific to your business. `GET /v1/flows/:id/stats` reports performance once a flow is live. --- ## Predictive: churn, CLV & propensity _Trained churn, lifetime-value and propensity scores via an optional ML sidecar, with a built-in heuristic fallback._ (https://wezend.com/en/docs/predictive-ml) `GET /v1/ml/summary` and `POST /v1/ml/score` expose churn, customer-lifetime-value (CLV) and purchase-propensity scoring. ## Two ways it runs - **With the ML sidecar** (a separate Python service, configured via `ML_SIDECAR_URL`): scores come from trained models on your actual data. - **Without it**: the platform falls back to in-stack heuristics automatically — predictive segmentation still works, just with a simpler model, no separate service to run. ## Using the scores Scores are written back onto the contact as `ml_churn_score`, `ml_clv` and `ml_propensity` — from there they're just traits, segmentable exactly like any [computed trait](/en/docs/segments-and-traits) (`trait:ml_churn_score`), so a high-churn-risk segment can feed straight into a win-back [journey](/en/docs/building-a-journey) without any custom integration code. --- ## AI Studio — prompt to campaign or journey _Turn a plain-language brief into a reviewable draft: a campaign (segment + email + A/B subject + send time) or a full journey graph._ (https://wezend.com/en/docs/ai-studio) AI Studio composes a complete, editable draft from one prompt. It's exposed on two endpoints — one for campaigns, one for journeys. Both create **drafts**; nothing sends until you review and act. ## Draft a campaign ```bash curl https://api.wezend.com/v1/studio/compose \ -H "X-API-Key: " -H "Content-Type: application/json" \ -d '{ "prompt": "A win-back email for customers who haven'\''t ordered in 60 days" }' ``` Returns a draft campaign with a **segment** (translated from the prompt), an **email** as builder blocks, an **A/B subject-line** variant and a **suggested send time**. Open it in the dashboard to edit, then send. ## Draft a journey ```bash curl https://api.wezend.com/v1/studio/journey \ -H "X-API-Key: " -H "Content-Type: application/json" \ -d '{ "prompt": "A two-step welcome flow for new subscribers" }' ``` Returns a **validated journey graph** (nodes + edges: triggers, delays, sends, splits) persisted as a draft journey — open it in the visual builder, refine, and activate with `launch_journey`. ## Notes - Both require a key with the `write` scope. - With no AI key configured, Studio still returns a sensible editable starting point. - The same generation is available from your own assistant via [Connect AI](/en/docs/connect-ai). --- # Section: Campaigns & content ## Campaigns, A/B tests & holdouts _One-off sends to a list or segment, with built-in A/B variants, automatic winner selection and holdout groups that prove real uplift._ (https://wezend.com/en/docs/campaigns-and-ab-testing) A **campaign** is a one-off send to an audience — a newsletter, a sale announcement, a product launch. Where [journeys](/en/docs/building-a-journey) react to individual behaviour over time, campaigns go out to everyone at once (or on a schedule). ## Creating a campaign In the dashboard: **Campaigns → New campaign**. Pick the channel, the audience (a list or a live segment), the content (write it inline or start from a [template](/en/docs/templates-and-email-builder)), and send now or schedule. Via API: `POST /v1/campaigns`. ## A/B testing, properly Add up to several variants — different subject lines, different content, even different send times. You choose: - **Split size** — e.g. test on 20% of the audience (10% see A, 10% see B). - **Winning metric** — opens, clicks, or conversions (a tracked goal event). - **Decision window** — how long to wait before declaring a winner. After the window closes, the platform sends the winning variant to the remaining 80% automatically. No spreadsheet, no manual second send. ## Holdout groups A holdout is a random slice of the audience that deliberately receives **nothing**. Why would you pay for an audience and not message them? Because it is the only honest way to measure incremental effect: if the messaged group converts at 4.1% and the holdout at 3.9%, your campaign added 0.2 points — not 4.1. Configure a holdout percentage on any campaign and the [ROI report](/en/docs/analytics-and-roi) shows messaged vs. holdout conversion side by side. ## Guard rails Campaign sends respect [frequency caps and quiet hours](/en/docs/frequency-caps-and-quiet-hours), suppression lists, and consent per channel — a contact who unsubscribed from email but not SMS is excluded from the email audience automatically. You can cancel an in-flight campaign with `POST /v1/campaigns/:id/cancel`; already-queued messages are recalled where the channel allows it. --- ## Templates & the email builder _Reusable message templates with variables, a visual drag-and-drop email builder, and a shared media library._ (https://wezend.com/en/docs/templates-and-email-builder) Templates keep your content in one place so campaigns, journeys and API sends all reuse the same approved wording and design. ## Creating templates **Content → Templates → New**. A template belongs to a channel (email, SMS, WhatsApp, push, in-app) and supports **variables** in double curly braces: ```text Hi {{first_name}}, your order {{order_id}} ships tomorrow. ``` Variables resolve from the contact profile (standard fields, [custom fields](/en/docs/contacts-and-custom-fields) and [computed traits](/en/docs/segments-and-traits)) plus any per-send payload you pass in the API call. A missing variable falls back to the default you define on the template — never an embarrassing `{{first_name}}` in a real send. ## The email builder Email templates open in a visual builder: drag in sections (text, image, button, divider, product grid), style them, and preview on desktop and mobile widths. The builder outputs battle-tested responsive HTML — you never touch table markup. Prefer full control? Switch any template to raw HTML mode and paste your own. Images come from the **media library** (**Content → Media** or `POST /v1/media`), which stores your uploads once and serves them from the platform CDN host. ## Using a template - Dashboard: pick the template inside a campaign or journey step. - API: `POST /v1/messages/send` with `"template_id": "tpl_…"` plus a `"variables": { … }` object. - Management: `GET/POST/PUT /v1/templates`, duplicate with `POST /v1/templates/:id/duplicate`. Every send records which template version it used, so a template edit never rewrites history in [message analytics](/en/docs/message-status-and-history). --- ## Lead-capture forms _Hosted signup forms with a public submit API — new leads become contacts, get tagged, and can trigger a welcome journey instantly._ (https://wezend.com/en/docs/lead-forms) Forms are the front door of your audience. WeZend forms exist in two shapes — a **hosted page** you can link to from anywhere, and a **public submit endpoint** you can POST to from your own website — both feeding the same pipeline: contact created/updated → consent recorded → tags applied → journeys triggered. ## Create a form **Audience → Forms → New form.** Choose the fields (email and/or phone plus any custom fields), the consent text, the tags to apply, and what happens next (double opt-in on/off, redirect URL, welcome journey). Every form gets a key, say `spring-fair`: - **Hosted page:** `https://api.wezend.com/forms/spring-fair` — a ready styled page, perfect for QR codes, bio links and paid landing pages. - **Submit endpoint:** `POST https://api.wezend.com/forms/spring-fair/submit` — wire your own HTML form to it: ```html
``` No API key in the browser — the form key is public by design and rate-limited server-side. ## Double opt-in With [double opt-in](/en/docs/consent-and-unsubscribes) enabled, the submit triggers a confirmation email/SMS and the contact is only marked subscribed after clicking the link — the gold standard under GDPR and the single best thing you can do for long-term deliverability. ## Where submissions land Each submission upserts a contact (matched on email/phone), records the consent event with timestamp, form key and IP, applies your tags, and — if configured — enrolls the contact in a welcome [journey](/en/docs/building-a-journey) within seconds. --- ## Web layers & on-site personalisation _Popups, banners and embedded blocks targeted by segment — decided server-side in real time by the same profiles that drive your messaging._ (https://wezend.com/en/docs/web-layers-and-onsite) Your website is a channel too. Web layers are popups, banners, slide-ins and embedded content blocks that appear for the *right* visitor — decided by the same CDP profile and segments used for messaging. ## How it works 1. Build a layer in **Content → Web layers**: pick a layout, write the content, style it (it inherits nothing from your site's CSS, so it looks the same everywhere). 2. Target it: which [segment](/en/docs/segments-and-traits) sees it, on which URLs, after how many seconds/scroll depth, and how often (e.g. max once per week per visitor). 3. Publish. The site snippet (the same one used for [event tracking](/en/docs/tracking-events)) asks the decision endpoint what to show. ## The decision call The browser asks, the server decides — targeting logic and segment membership never leak to the client: ```text POST /v1/web/decide { "anonymous_id": "anon_8f3…", "url": "https://shop.example.com/cart" } → { "layers": [ { "id": "wl_exit_10", "html": "…", "trigger": "exit_intent" } ] } ``` An anonymous visitor who later [identifies](/en/docs/tracking-events) keeps their history — the profile is merged, and segment targeting applies retroactively. ## What teams build with it - **Exit-intent offer** for visitors with a non-empty cart who are *not* in the "purchased last 30 days" segment. - **Newsletter bar** shown only to visitors not yet subscribed (why nag your subscribers?). - **VIP banner** for the high-CLV segment, hidden for everyone else. Impressions, closes and clicks are recorded as events, so a layer can trigger a [journey](/en/docs/building-a-journey) — e.g. "clicked the offer but didn't buy within 2 hours → send the reminder SMS". --- ## Short links & click tracking _Branded short links for SMS, automatic link rewriting in email, per-contact click history, and how opens are measured._ (https://wezend.com/en/docs/links-and-tracking) Clicks are the strongest engagement signal you get, and in SMS every character costs money. The links module solves both. ## Short links Create a link once, use it everywhere: ```bash curl -X POST https://api.wezend.com/v1/links \ -H "X-API-Key: $WEZEND_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "https://shop.example.com/spring-sale?utm_source=sms" }' # → { "slug": "x7Kp2", "short_url": "https://wznd.link/x7Kp2" } ``` When a message containing the link is sent, the platform mints a **per-recipient** variant — so a click is attributed to the exact contact, message and campaign, not just counted anonymously. Click data is available per link (`GET /v1/links/:id/clicks`), on the message record, and as a `link_clicked` event on the contact profile, where [segments](/en/docs/segments-and-traits) and [journeys](/en/docs/building-a-journey) can react to it ("clicked but didn't purchase within 24h → follow up"). ## Email link rewriting & open tracking In email you don't need to do anything: every link in the HTML is rewritten to a tracking redirect at send time, and a 1×1 pixel measures opens. Honesty note, straight from how the platform works: **open rates are an undercount**. Apple Mail Privacy Protection pre-fetches pixels and many clients block images, so treat opens as a directional signal and use clicks for decisions — this is why A/B winner selection defaults to clicks, not opens. ## Deliverability tip for SMS Some carriers distrust public URL shorteners (bit.ly and friends). Using the platform's link domain — or your own branded domain (configure under **Settings → Link domain**) — keeps your SMS out of URL-based spam filtering and your brand in the link the customer sees. --- ## Smart send-time optimization _Schedule each contact's message for the hour they personally tend to engage, derived from their event history._ (https://wezend.com/en/docs/smart-send-time) Instead of one blast time for the whole list, smart send-time schedules each contact's message for their **modal active hour** — the time of day they open, click and browse, derived from their event stream. Contacts without enough signal fall back to a sensible default. ## Enabling it Turn it on per campaign or journey send in the dashboard. AI Studio also proposes it automatically on every draft. There's no separate endpoint — it's a send option applied at schedule time. ## How the hour is chosen The platform reads the contact's recent [behavioural events](/en/docs/customer-data-platform) and picks the hour they're most active. The maths is deterministic, so the choice is explainable — no black box. ## When to use it Best for non-urgent marketing (newsletters, nudges) where a few hours' timing shift lifts opens. Skip it for time-critical sends (OTPs, order updates) that must go immediately. --- ## Unique discount codes _Load a pool of single-use codes and use {{discount_code}} in a message — each recipient gets a unique code, claimed atomically._ (https://wezend.com/en/docs/discount-code-pools) A pool holds many single-use codes; the `{{discount_code}}` placeholder claims one per recipient at send time, so a shared code never leaks to a coupon site. ## Create a pool ```bash curl https://api.wezend.com/v1/discount-pools \ -H "X-API-Key: " -H "Content-Type: application/json" \ -d '{ "name": "Summer 2026" }' ``` ## Add codes (from your store) ```bash curl https://api.wezend.com/v1/discount-pools//codes \ -H "X-API-Key: " -H "Content-Type: application/json" \ -d '{ "codes": "SUMMER-A1B2, SUMMER-C3D4, SUMMER-E5F6" }' ``` `codes` accepts an array or a string split on commas / spaces / newlines. Generate the codes as single-use in your e-commerce or POS system first, so your checkout validates them. ## Or generate random codes ```bash curl https://api.wezend.com/v1/discount-pools//generate \ -H "X-API-Key: " -H "Content-Type: application/json" \ -d '{ "count": 5000, "prefix": "SUMMER" }' ``` ## Use in a message Put `{{discount_code}}` in an email, SMS or RCS body. At send time each recipient claims one unused code atomically — no double-issue even at high volume. List pools with `GET /v1/discount-pools`. Size the pool to your audience and top it up before large sends. --- ## Inbox-placement seed testing _Send a real email to your own seed inboxes across providers and track delivery and opens per address before a big campaign._ (https://wezend.com/en/docs/inbox-placement-seed-test) Seed testing sends a real email to a small list of **seed inboxes** you control (across Gmail, Outlook, Apple and more) so you can catch a delivery problem on a test list, not your whole audience. ## Add seed addresses ```bash curl https://api.wezend.com/v1/seed-test/addresses \ -H "X-API-Key: " -H "Content-Type: application/json" \ -d '{ "address": "seed.gmail@yourdomain.com" }' ``` List them with `GET /v1/seed-test/addresses`. ## Run a test ```bash curl https://api.wezend.com/v1/seed-test/run \ -H "X-API-Key: " -H "Content-Type: application/json" \ -d '{ "subject": "Preview", "html_body": "

Hello

" }' ``` Requires the `send` scope. Delivery and opens are tracked **per address, automatically**. Review results with `GET /v1/seed-test/runs` and `GET /v1/seed-test/runs/:id`. ## Scope note Automated inbox-vs-spam **folder** detection needs IMAP access to your seed inboxes (an ops integration). Until that's wired, delivery and open tracking are automatic and folder placement is recorded manually. Pair this with the [DNS checker](/en/tools/dns-checker) and [domain warm-up](/en/blog/email-domain-warmup) before large sends. --- ## Product recommendations in email _Add a recommendations block to any template — each recipient sees products picked from their behaviour and your catalog, rendered at send time._ (https://wezend.com/en/docs/product-recommendations) The recommendations **email block** personalises per recipient. You build one email; at send time each recipient's copy is filled with products chosen for them from their [CDP](/en/docs/customer-data-platform) behaviour, matched against your product catalog. ## How to use it 1. Keep your **product catalog** current in the platform (synced from your store or added directly). 2. In the email builder, add a **recommendations block** to the template. 3. Send the campaign (or use the block inside a [journey](/en/docs/building-a-journey)). Each recipient's version renders at send time, so picks stay fresh — not frozen when you scheduled. ## What drives the picks Browsing and purchase **events** on the contact's profile, matched to catalog items. The more behavioural signal a contact has, the sharper the recommendations; new contacts get sensible catalog defaults. Because it renders per recipient, one campaign becomes thousands of personalised versions — strongest in post-purchase and win-back flows where the right next product matters. --- # Section: Consent & deliverability ## Consent, double opt-in & unsubscribes _Per-channel consent, double opt-in confirmation, one-click unsubscribe (RFC 8058), STOP keywords, and the suppression list._ (https://wezend.com/en/docs/consent-and-unsubscribes) Consent is tracked **per channel, per contact** — a contact can happily receive your SMS while having unsubscribed from email. The platform enforces it at send time so no code path can accidentally message someone without a legal basis. ## Recording consent Consent is written automatically when contacts arrive through [forms](/en/docs/lead-forms) (with timestamp, source and IP), and can be set explicitly via `POST /v1/consent` when you import audiences you've collected elsewhere. Every change is kept as an auditable history, not just a current flag — when a regulator asks *when and how* someone consented, the answer is one API call away. ## Double opt-in With double opt-in enabled (per form or per list), a new signup gets a confirmation message and only counts as subscribed after clicking. Yes, you'll "lose" the fake and mistyped addresses — that's the point. Those addresses were future bounces and spam-trap hits that would have dragged down deliverability for everyone else on your list. ## Unsubscribing — every door open - **Email**: every marketing email carries a `List-Unsubscribe` header with **one-click unsubscribe (RFC 8058)** — Gmail and Yahoo require this at volume, and the platform adds it automatically — plus a visible link in the footer. - **SMS**: reply **STOP** (and local variants). Intercepted and processed instantly, before anything reaches your Inbox. - **Hosted page**: the unsubscribe link leads to a hosted confirmation page (`GET /v1/account/unsubscribes/:token`) where the contact can also choose to only leave certain topics — see [Preference center](/en/docs/preference-center). ## The suppression list Unsubscribed and bounced addresses land on the suppression list: sends to them are blocked platform-wide, whatever the source (API, campaign, journey). Manage it under **Audience → Suppressions** — you can bulk-import suppressions from a previous provider (`POST /v1/account/unsubscribes/api/import`) on day one, which is strongly recommended before your first campaign. --- ## Preference center _A hosted, token-signed page where contacts choose their channels and topics — turning would-be unsubscribes into tuned subscriptions._ (https://wezend.com/en/docs/preference-center) Most people who hit "unsubscribe" don't hate you — they hate the *frequency* or the *topic*. The preference center gives them a third option between "everything" and "nothing". ## What the contact sees A hosted page at `GET /preferences?token=…` where they can: - toggle **channels** (email yes, SMS no), - pick **topics** from your catalogue (newsletter, offers, product updates…), - or unsubscribe from everything — it must always be easy, and it is. The link is signed per contact (no login needed, no way to open someone else's preferences) and belongs in every email footer, which the default templates already handle. ## Setting up topics Define your topic catalogue under **Settings → Preferences** (API: `/v1/preferences/topics`). Keep it short and honest — three to six topics a human can tell apart. Changes save via `POST /v1/preferences/save` and take effect immediately: campaign and journey sends check topic membership at send time. ## Targeting by topic When creating a campaign you pick the topic it belongs to; contacts who opted out of that topic are excluded automatically. In the [segment builder](/en/docs/segments-and-traits), topic membership is a filterable property, so "subscribed to offers AND inactive 60 days" is a perfectly normal segment. ## Why this is worth an afternoon Deliverability compounds: every unsubscribe you convert into "fewer topics" keeps list size, and every send to people who actually chose the topic raises engagement — which is exactly what [inbox providers score you on](/en/docs/deliverability-and-inspector). --- ## Frequency caps & quiet hours _Global and per-channel caps on marketing pressure, per-category limits, and quiet hours in the contact's own timezone._ (https://wezend.com/en/docs/frequency-caps-and-quiet-hours) The fastest way to burn a list is to over-message it. WeZend's sending policy is a platform-level guard: however many campaigns, journeys and API calls target a contact, the policy decides what actually goes out. ## What you can cap Under **Settings → Sending policy**: - **Global marketing cap** — e.g. max 4 marketing messages per contact per week, across all channels. - **Per-channel caps** — e.g. max 2 SMS per week (SMS fatigue is real and expensive), max 5 emails. - **Per-category caps** — using the same categories as the [preference center](/en/docs/preference-center): max 1 "offers" message per day even if three different campaigns fire. - **Quiet hours** — a nightly window (e.g. 21:00–09:00) where marketing messages are **held, not dropped**: they queue and go out when the window opens, in the *contact's* timezone when known, falling back to your account timezone. ## What is exempt Transactional messages — OTPs, receipts, delivery notices, password resets — bypass caps and quiet hours by design. A 3 a.m. login code must arrive at 3 a.m. The transactional/marketing flag is set per send (`"category": "transactional"`) and per journey step. ## How conflicts resolve When a contact hits a cap, further marketing sends that period are suppressed and recorded as such (visible in [message history](/en/docs/message-status-and-history) with the suppression reason — never a silent drop). Journeys handle it gracefully: a suppressed step is skipped or retried after the window depending on the step's setting. ## Why bother Beyond politeness: complaint rates are the deadliest deliverability signal there is, and complaints spike when people feel bombarded. A cap costs you a few sends today and buys you inbox placement for quarters. --- ## Deliverability & the Delivery Inspector _Per-channel delivery health, the Delivery Inspector that explains any failed message in plain language, vendor health and automatic failover._ (https://wezend.com/en/docs/deliverability-and-inspector) "It says delivered — but did it arrive?" is the question this module answers, continuously, for every channel. ## The deliverability report `GET /v1/account/channel-deliverability` (dashboard: **Analytics → Deliverability**) shows delivery rate, failure rate and click rate per channel over time, plus the email reputation report (`/v1/account/deliverability`): bounce rate, complaint rate, spam-trap indicators and domain authentication status, with thresholds marked so you can see *how close to trouble* you are, not just where you are today. ## The Delivery Inspector Every failed or delayed message can be opened in the Inspector — a plain-language timeline of exactly what happened: ```text 10:41:02 Accepted (API) — queued for route DK-1 10:41:03 Submitted to vendor 10:41:19 Vendor status: REJECTED — code 33: sender not registered for destination → Explanation: Denmark requires alphanumeric sender registration. → Fix: register "Acme" under Settings → Senders, or send from a numeric sender. ``` No decoding cryptic carrier error codes at midnight. The Inspector translates vendor and carrier responses into the *reason* and the *fix*. ## Vendor health & failover The platform monitors each downstream vendor's live delivery performance per destination. If a route degrades — a vendor starts failing Danish traffic, say — sends automatically fail over to the next-best route, and the incident appears in **Operations → Vendor health**. Messages that ultimately fail land in a **dead-letter queue** for inspection and one-click retry (`POST /v1/messages/ops/:id/retry`) rather than vanishing. ## Deliverability autopilot Optionally, the platform acts on its own findings: pausing a campaign whose bounce rate spikes above a threshold, throttling volume to a domain showing deferrals, and alerting you with the reason. You define the guard rails; it pulls the brake faster than a human watching dashboards ever could. --- ## GDPR: export, erasure & retention _Answer data-subject requests in minutes: full JSON export, one-call anonymisation, automatic retention policies and the audit log._ (https://wezend.com/en/docs/gdpr-and-retention) GDPR requests have legal deadlines. These endpoints turn "a week of database archaeology" into minutes. ## Right of access — export ```bash curl "https://api.wezend.com/v1/gdpr/export?contact_id=c_123" -H "X-API-Key: $WEZEND_API_KEY" ``` Returns everything the platform holds on the contact as structured JSON: profile fields, consent history, events, messages (content and delivery metadata), list/segment memberships, form submissions and scores. Hand it to the data subject as-is or reformat it — the completeness is the platform's job, and it covers every module, including ones added later. ## Right to erasure — anonymise ```bash curl -X POST https://api.wezend.com/v1/gdpr/anonymise \ -H "X-API-Key: $WEZEND_API_KEY" -H "Content-Type: application/json" \ -d '{ "contact_id": "c_123" }' ``` Anonymisation (rather than row deletion) is deliberate: identifiers and free-text content are irreversibly scrubbed across all modules, while anonymous statistical rows survive so your historical campaign metrics don't silently change. The email/phone also lands on an internal blocklist so a later import can't resurrect the profile. ## Retention policies Under **Settings → Data retention** you set how long each data class lives — e.g. events 24 months, message bodies 12 months, inactive profiles 36 months. A scheduled job enforces the policy continuously. This is GDPR's storage-limitation principle turned into configuration instead of quarterly cleanup projects. ## Audit log Every export, anonymisation and retention run is recorded (`GET /v1/gdpr/audit-log`) — who requested it, when, and what was touched. When the regulator asks, the paper trail already exists. For deleting an entire customer account, see your account manager or the Super Admin flow (`DELETE /v1/gdpr/account/:customerId`). --- # Section: Account & insights ## Analytics, ROI & cohorts _Channel and campaign analytics, revenue attribution against goals, cohort retention views and the weekly digest._ (https://wezend.com/en/docs/analytics-and-roi) Sending is a cost; the analytics module is where you find out what it *bought*. ## The dashboards **Analytics** in the dashboard (API: `GET /v1/account/analytics`) covers: - **Channel performance** — sent, delivered, failed, opened, clicked per channel over any period, with period-over-period comparison. - **Campaign results** — per campaign: funnel from sent to converted, A/B variant comparison, and holdout uplift where configured. - **List growth** — subscribes vs. unsubscribes over time (`GET /v1/account/list-growth`), split by source, so you can see *which* forms and imports actually grow the list. ## Revenue & ROI Attach a **goal** to journeys and campaigns — typically an `order_completed` event with a revenue property. The ROI view then attributes conversions and revenue to the message that drove them (last-touch within your attribution window) and sets it against message cost: *this flow costs €84/month and drives €3,900/month*. That sentence is what budget meetings run on. ## Cohorts The cohort view groups contacts by signup month and shows how each cohort's engagement and purchases decay over time — the honest way to see whether retention is improving, because it separates "new contacts behave differently" from "everyone is drifting away". ## The weekly digest A Monday-morning email to your team: sends, engagement, list growth, revenue attributed, and anything that needs attention (a failing route, a spiking complaint rate). Configure recipients under **Settings → Digest**. Most teams run on the digest and open the dashboard only when a number looks off. ## Export Raw usage data exports as CSV (`GET /v1/export/usage`) for your BI stack — or push everything continuously with [Warehouse sync](/en/docs/warehouse-sync). --- ## Billing, balance & pay-as-you-go _Prepaid balance, auto-topup, invoices, multi-currency billing, plan quotas and the pay-as-you-go tier._ (https://wezend.com/en/docs/billing-and-payg) WeZend billing is prepaid: you hold a balance, sends draw on it at your per-channel, per-destination rates, and you can see both at any moment. ## Balance & topping up - **Check**: `GET /v1/account/balance` — balance, currency and recent movements. - **Top up**: **Billing → Top up** in the dashboard (Stripe-backed), or `POST /v1/billing/topup`. - **Auto-topup**: the setting that prevents 2 a.m. outages — "when balance drops below €50, charge €200 to the default card" (`PATCH /v1/billing/auto-topup`). Strongly recommended for anything transactional. ## Your prices `GET /v1/account/pricing` returns your current sell rates per channel and destination. Rates depend on your plan and any negotiated pricing; what the API returns is exactly what sends deduct, so you can compute costs before sending (`estimated = rate × recipients`). ## Plans & quotas Subscription plans include monthly message quotas per channel; usage against quota is visible under **Billing → Plan & usage** (API: `GET /v1/account/usage`). When a quota is spent, further sends draw on your balance at your per-message rates — nothing stops working mid-month. **Pay-as-you-go** is the no-subscription tier: no monthly fee, no included quota, every message billed from balance. It fits spiky senders (election night, ticket on-sales) and low-volume starters; you can move between PAYG and a plan without any integration change. ## Invoices & currency Invoices live under **Billing → Invoices** (`GET /v1/billing/invoices`) as PDFs. Company details on the invoice come from `PUT /v1/account/billing-details`. You choose your billing currency (`PUT /v1/account/billing-currency`) — EUR, DKK, SEK, NOK, USD and more; an existing balance converts at the day's rate when you switch. --- ## Team, roles & two-factor auth _Invite teammates with scoped roles, enforce TOTP-based MFA, rotate API keys safely and read the audit trail._ (https://wezend.com/en/docs/team-and-roles) One login per human, least privilege per login. Shared passwords are how audit trails die. ## Inviting your team **Settings → Team → Invite.** Each member gets their own login with a role: - **Admin** — everything, including billing and team management. - **Editor** — build and send: campaigns, journeys, templates, audiences. - **Viewer** — read-only: analytics and content, no sending, no exports of PII. Invites expire after 7 days and can be re-sent. Changing someone's role applies on their next request; removing a member kills their sessions immediately (session-epoch revocation — no "still logged in on the old laptop" problem). ## Two-factor authentication TOTP-based MFA (Google Authenticator, 1Password, etc.): **Account → Security → Enable MFA** shows a QR code; confirming one code activates it (`POST /v1/auth/mfa/setup` → `/confirm`). Admins can require MFA for the whole account — with it on, no member can sign in without a second factor. ## API keys are not people Machines use [API keys](/en/docs/api-authentication), humans use logins. Keys can be **rotated** with a 24-hour grace window (`POST /v1/account/keys/:id/rotate`) — the new key works immediately, the old one keeps working for a day while you roll deployments, then dies. Rotate on any suspicion and on every offboarding of someone who had production access. ## Audit trail Account changes — role edits, key creation, pricing changes, GDPR actions — are logged with actor and timestamp. When something changed and nobody remembers changing it, the answer is in **Settings → Audit log**. --- ## Integrations & inbound sources _Connect CRMs and shops, import audiences in the background, test webhook wiring, and stream events in from any system._ (https://wezend.com/en/docs/integrations-and-sources) The CDP is only as good as what flows into it. The integrations module manages the pipes. ## Creating an integration **Settings → Integrations → New**, or: ```bash curl -X POST https://api.wezend.com/v1/integrations \ -H "X-API-Key: $WEZEND_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "type": "shopify", "name": "Main store", "config": { "shop_domain": "acme.myshopify.com", "access_token": "shpat_…" } }' ``` An integration defines *what* connects (CRM, shop, custom system), *which events* flow, and *how contacts map* to profiles. Credentials are encrypted at rest. ## Importing an existing audience `POST /v1/integrations/:id/import-audience` starts a background job that pulls the connected system's contacts (with consent state where the source provides it), deduplicates against existing profiles and reports progress — poll `GET /v1/integrations/import-jobs/:jobId` or watch the progress bar in the dashboard. Big audiences import without blocking anything else. ## Testing the wiring Before trusting an integration, click **Send test event** (`POST /v1/integrations/:id/test`). A synthetic event runs the full pipeline and shows you exactly what arrived and how it mapped — debugging with a flashlight instead of guessing in the dark. ## Custom systems: the events firehose Anything that can send an HTTP request is an integration. Stream behavioural events from your backend or site to `POST /v1/events` (see [Tracking events](/en/docs/tracking-events)), and expose the [inbound webhook](/en/docs/conversations-and-inbox) to receive replies in your own tools. Between those two and the [reverse-ETL activation](/en/docs/activation-reverse-etl) out to ad platforms, WeZend sits in the middle of the stack rather than at the end of it. --- ## AI: writer, coach, autopilot & copilot _The four AI surfaces in the platform: generate emails from a brief, get data-grounded advice, let guarded automation act, and drive it all in chat._ (https://wezend.com/en/docs/ai-features) Four distinct AI capabilities, each with a clear job. The writer and coach are paid add-ons enabled per account; autopilot and copilot ship with the platform. ## AI Email Writer *(add-on)* Give it a brief, get a complete email — subject, preheader, structured body in your brand's builder blocks: ```bash curl -X POST https://api.wezend.com/v1/account/ai-write \ -H "X-API-Key: $WEZEND_API_KEY" -H "Content-Type: application/json" \ -d '{ "brief": "Spring sale, 25% off apparel, ends Sunday, playful tone, one CTA to /sale" }' ``` The output lands as an editable draft — you always review before anything sends. Request access with `POST /v1/account/ai-writer-request`. ## AI Coach *(add-on)* Personalised marketing advice computed daily from *your* account data (`POST /v1/account/ai-recommendations`): "Your Tuesday sends outperform Friday by 31%", "Segment X hasn't been messaged in 60 days and is drifting". Recommendations are actionable — each links to the screen where you'd act on it. ## Autopilot *(built in)* Guarded automation: within limits you define, the platform acts on its own findings — pausing a campaign whose complaint rate spikes, rebalancing send times, throttling a degrading route ([deliverability autopilot](/en/docs/deliverability-and-inspector)). Every action is logged with its reason and is reversible. You set the rails; it never exceeds them. ## Copilot *(built in)* The conversational layer over the dashboard: ask "how did last week's campaigns perform?" or say "create a segment of Danish contacts inactive 30 days" and it queries the data or drafts the object for your confirmation. Destructive actions always require an explicit confirm. ## Where the boundaries are The AI reads your account's own data. It doesn't send anything autonomously (autopilot *stops* sends; it never initiates marketing), and generated content is always a draft until a human approves it — or until you wire your own approval flow through the [API](/en/docs/build-with-ai). --- # Wiki guides (step-by-step walkthroughs) ## Send your first SMS (https://wezend.com/en/wiki/send-your-first-sms) From a fresh account to a delivered SMS in five clicks — no code required. 1. **Open Messages** — After signing in you land on the dashboard. In the left menu, choose Messages → New message. Everything you can do in the API you can also do here. 2. **Pick channel & recipient** — Choose SMS as the channel and type the recipient in international E.164 format — country code first, like +45 for Denmark. New accounts can send to their own verified number right away. 3. **Write the message** — Type your text. The counter shows SMS segments — one segment is 160 characters, and emojis/special characters reduce that. The price preview updates live. 4. **Sent!** — The message is queued and handed to the best route for the destination within seconds. 5. **Watch it deliver** — Under Messages → History you follow the status live: queued → sent → delivered. Click any message to open the Delivery Inspector and see the full carrier timeline. ## Verify your email domain (https://wezend.com/en/wiki/verify-your-email-domain) Set up SPF, DKIM and DMARC so your email lands in the inbox — the single most important setup step for email. 1. **Open Email domains** — Go to Settings → Email domains. Until a domain is verified, email sends are limited — this is what unlocks real volume. 2. **Add your domain** — Use a subdomain dedicated to sending, like mail.yourcompany.com — it isolates your sending reputation from your main domain. 3. **Create the DNS records** — The platform lists the exact records: SPF (who may send), DKIM (cryptographic signature) and DMARC (policy). Copy each one into your DNS provider exactly as shown. 4. **Run verification** — Click Verify. The platform runs live DNS checks — each record turns green, or tells you precisely what's wrong (a typo, a missing quote, propagation still pending). 5. **Verified — send away** — Your domain is live. Every email is now DKIM-signed automatically, and the reputation report under Analytics → Deliverability starts tracking your inbox placement. ## Import contacts & build your first segment (https://wezend.com/en/wiki/import-contacts-and-build-a-segment) Upload a CSV, map the columns, and carve out a live segment that updates itself as your data changes. 1. **Open Audience → Import** — Choose Audience → Contacts → Import and drop your CSV. Files from any previous tool work — you'll map the columns in the next step. 2. **Map your columns** — Each CSV column maps to a field. Unknown columns can become custom fields on the spot — 'loyalty_tier' here becomes a real field you can segment and personalise on. 3. **Import runs in the background** — Big files don't block anything. Duplicates (same email/phone) update the existing contact instead of creating a copy, and bad rows land in an error report you can download. 4. **Build the segment** — Under Audience → Segments → New, stack rules with AND/OR. The live counter on the right shows how many contacts match before you save — no guessing. 5. **It stays fresh by itself** — A segment is a rule, not a snapshot: contacts flow in and out automatically as their data changes. Campaigns and journeys targeting it always hit the current members. ## Create a lead form with double opt-in (https://wezend.com/en/wiki/create-a-lead-form) Build a hosted signup form, turn on double opt-in, and connect it to a welcome journey — the compliant way to grow a list. 1. **New form** — Go to Audience → Forms → New form. A form gives you both a hosted page (link it anywhere, QR codes included) and a public submit endpoint for your own website. 2. **Choose fields & consent text** — Keep it short — every extra field costs signups. The consent text is what the subscriber legally agrees to, so say plainly what you'll send and how often. 3. **Turn on double opt-in** — With double opt-in, the signup only counts after the subscriber clicks a confirmation link. You lose the fake addresses — which is exactly what protects your deliverability. 4. **Share it** — The form is live at its hosted URL, and the embed snippet posts to the same endpoint from your own site — no API key needed in the browser, it's public and rate-limited by design. 5. **Watch the pipeline work** — Every confirmed signup becomes a contact with recorded consent, gets tagged, and starts the welcome journey within seconds. The whole funnel is visible under the form's stats. ## Build a welcome journey (https://wezend.com/en/wiki/build-a-welcome-journey) The classic three-step welcome series on the visual canvas: instant hello, a nudge two days later — but only for those who didn't click. 1. **New journey, pick the trigger** — Journeys → New. The trigger is what enrolls a contact — here, joining the 'Newsletter' list. Triggers can also be an event (like order_completed) or entering a segment. 2. **Step 1: the instant welcome** — Drag a Send email node onto the canvas and pick your welcome template. It fires the moment the trigger matches — welcome emails get the highest open rates you'll ever see, so make it count. 3. **Step 2: wait, then branch** — Add a Delay of 2 days, then a Branch: did the contact click the welcome email? The 'yes' path exits quietly — never nag people who already engaged. The 'no' path continues. 4. **Step 3: the nudge, on SMS** — On the 'no' branch, add Send SMS with a short nudge. Cross-channel is the point of a journey: the follow-up reaches people who don't live in their inbox. Quiet hours are respected automatically. 5. **Test-enroll yourself** — Before activating, use Test enroll with your own contact — you'll receive the real messages and see your dot move through the canvas. Then hit Activate. 6. **Read the results per node** — The stats view shows every node's numbers: sent, delivered, clicked, converted — and the goal you attach (like first purchase) attributes revenue to the journey in the ROI report. ## Connect WhatsApp Cloud API (https://wezend.com/en/wiki/connect-whatsapp) Link your Meta Business account, point the webhook at WeZend, and send your first template message. 1. **Get your Meta credentials** — In Meta's developer console (WhatsApp → API Setup) you need two values: the phone number ID and a permanent access token. WeZend uses Meta's official Cloud API — no middleman. 2. **Paste them into WeZend** — Under Settings → Channels → WhatsApp, paste both values and save. The channel card flips to 'connected' once the credentials check out against Meta's API. 3. **Point Meta's webhook at WeZend** — Copy the webhook URL and verify token shown on the settings page into Meta's console. This is how inbound replies and delivery statuses reach your Inbox. 4. **Mind the 24-hour rule** — Free-form messages are only allowed within 24h after the customer last wrote to you. To start a conversation you use a Meta-approved template — WeZend enforces this automatically so nothing bounces. 5. **Send & receive** — Send via the same endpoint as SMS with channel 'whatsapp'. Replies land in Inbox → Conversations, threaded on the contact — and your team answers from there. ## Set up delivery webhooks (https://wezend.com/en/wiki/set-up-webhooks) Receive delivery statuses in your own system, verify the signature, and never poll again. 1. **Expose an endpoint** — Create a POST route in your backend — it must respond 200 quickly (do the heavy work async). During local development, a tunnel like ngrok gives Meta-style services a reachable URL. 2. **Register the URL** — Set it once account-wide under Settings → Webhooks, or per message with the webhook_url field in the send call. Per-send overrides account-wide. 3. **Verify the signature** — Every delivery carries an X-WeZend-Signature header — an HMAC of the body with your webhook secret. Verify it, or anyone who finds your URL can fake delivery events. 4. **Replay & debug from the log** — Every webhook attempt is logged with the response your server gave (GET /v1/webhooks/log). Failed deliveries retry with backoff — and you can replay any of them manually while debugging. ## Let Claude or ChatGPT integrate WeZend for you (https://wezend.com/en/wiki/integrate-with-claude-or-chatgpt) Hand your AI assistant our context pack and watch it wire signup forms, notifications and events into the app it's building for you. 1. **Grab your API key** — In WeZend: Settings → API keys → Create key. This is the one secret in the whole flow — it goes in your project's environment variables, never in the chat and never in browser code. 2. **Give the assistant context** — Paste one line if your assistant fetches URLs — or the full context pack from our Build-with-AI doc if it can't. Either way it now knows every endpoint, field and security rule. 3. **Ask for the feature, not the code** — Describe the outcome. The assistant knows from the pack that browser code may only touch the public form endpoint, and that sends belong server-side. 4. **Verify like a human** — Trust, then check: trigger a signup, watch the message arrive in Messages → History, and confirm the API key isn't in any client bundle. Two minutes, worth it every time. ## Draft a campaign with AI Studio (https://wezend.com/en/wiki/draft-a-campaign-with-ai-studio) Describe the campaign you want in one sentence and let AI Studio compose the segment, the email, an A/B subject and a send time — then review and ship. 1. **Open AI Studio and describe it** — Create → AI Studio. Type what you want in plain language — the audience, the offer, the goal. One sentence is enough to start. 2. **Review the draft it built** — Studio returns a full draft campaign — the segment translated from your prompt, an editable email, an A/B subject variant and a send time. Nothing sends yet. 3. **Edit, then send** — Tweak the copy and audience if you like, then send or schedule. Every guardrail still applies — suppression, quota and budget. Prefer your own assistant? The same is available via Connect AI. ## Grow your SMS list with a keyword (https://wezend.com/en/wiki/grow-your-sms-list-with-a-keyword) Set up a keyword like VIP so 'text VIP to subscribe' turns posters, receipts and social posts into a consented SMS list. 1. **Add a keyword** — Audience → SMS keywords → New. Pick a short word (letters/numbers, no spaces), an auto-reply that confirms the opt-in, and a tag so you can segment on who joined. 2. **Put it on your surfaces** — Print it anywhere: 'Text VIP to 12345 for early access.' When a customer texts it, they're subscribed and the consent is recorded, timestamped and documented — the cleanest opt-in there is. 3. **Welcome them automatically** — Feed the 'vip' tag into a [welcome journey](/en/wiki/build-a-welcome-journey) so new subscribers get an instant first message. Set up a STOP keyword too, to honour opt-outs. --- # Migration guides (switching from another provider) ## How to switch from Klaviyo (https://wezend.com/en/migrate/from-klaviyo) The complete, honest procedure: suppressions first, profiles with consent intact, flows rebuilt as journeys, and a gradual cutover that protects your deliverability. Concept mapping: - Klaviyo "Profiles" → WeZend "Contacts" - Klaviyo "Lists" → WeZend "Lists" - Klaviyo "Segments" → WeZend "Segments (live rules)" - Klaviyo "Flows" → WeZend "Journeys" - Klaviyo "Campaigns" → WeZend "Campaigns" - Klaviyo "Metrics / Events" → WeZend "Events (POST /v1/events)" - Klaviyo "Profile properties" → WeZend "Custom fields" - Klaviyo "Sign-up forms" → WeZend "Lead forms" - Klaviyo "Suppressed profiles" → WeZend "Suppression list" - Klaviyo "Predictive analytics (CLV)" → WeZend "Predictive scores (churn/CLV)" ## The one rule that makes this safe **Run both platforms in parallel until WeZend has proven itself on real volume.** You are not flipping a switch — you are moving house while living in it. Keep Klaviyo sending until your domain is verified, warmed up and delivering, then cut over flow by flow. ## Step 1 — Suppressions first. Always first. Before a single contact is imported, move the do-not-contact data. In Klaviyo, export your suppressed profiles (under your account's suppression settings, or via Klaviyo's API if the list is large). Then bulk-import the file into WeZend under **Audience → Suppressions** (`POST /v1/account/unsubscribes/api/import`). Why first? Because the moment suppressions are in, it is *impossible* to accidentally message someone who already unsubscribed — no matter what you import later or in what state. Skipping this step is how migrations turn into spam complaints. ## Step 2 — Export profiles with consent intact In Klaviyo, open **Audience → Lists & segments**, select each list you want to keep, and export to CSV. Export segments you rely on the same way — you'll get their *members* (the rules themselves can't be exported; you'll recreate those in step 6). The CSVs include consent-relevant columns (email marketing consent, timestamps). Keep them — they're your legal audit trail for how each contact was collected. ## Step 3 — Import into WeZend **Audience → Contacts → Import.** Map Klaviyo's columns: standard fields map automatically; every "profile property" becomes a [custom field](/en/docs/contacts-and-custom-fields) you can create right in the mapping screen. Import list by list so provenance survives ("Newsletter", "VIP", …). Duplicates merge on email/phone instead of multiplying. > **Prefer chat?** With [Connect AI (MCP)](/en/docs/connect-ai) you can do steps 1–3 straight from Claude or ChatGPT: paste your suppression export first, then your profile export — the assistant imports both with Klaviyo's field mapping and consent intact. ## Step 4 — Verify your domain before real volume Add your sending domain under **Settings → Email domains**, create the SPF/DKIM/DMARC records, and let the [live DNS checker](/en/docs/email-domains-and-sending) confirm them. Then **warm up honestly**: your DKIM domain is new to inbox providers, so ramp volume gradually — start with your most engaged segment (they open, which builds reputation) and grow send sizes over 2–3 weeks rather than blasting the full list on day one. ## Step 5 — Rebuild templates Klaviyo templates don't export as portable objects, but their HTML does: open a template, copy the generated HTML, and paste it into a WeZend [template](/en/docs/templates-and-email-builder) in raw-HTML mode — or rebuild it cleanly in the drag-and-drop builder (an hour well spent for your top 5 templates). Swap personalisation tags as you go: Klaviyo's `{{ first_name }}` becomes WeZend's `{{first_name}}` mapped to your imported fields. ## Step 6 — Flows become journeys Flows can't be exported from Klaviyo — this is manual, and it's also your chance to prune. List your flows, sort by revenue, and rebuild the ones that earn their keep as [journeys](/en/docs/building-a-journey): trigger → delay → branch → send maps one-to-one to the canvas. The classics (welcome, abandoned cart, win-back, post-purchase) also exist as [one-click templates](/en/docs/flows-and-templates) you can start from. Wire your shop's events into `POST /v1/events` first so triggers like `added_to_cart` fire — see [Tracking events](/en/docs/tracking-events). Use **test-enroll** with your own contact on every journey before activating it. ## Step 7 — Switch the entry points Replace Klaviyo signup forms with WeZend [lead forms](/en/docs/lead-forms) (hosted page or your own HTML posting to the public submit endpoint), with double opt-in on. From this moment, new signups land in WeZend; Klaviyo's audience is now frozen in time, which makes the final diff easy. ## Step 8 — Cut over, then close down Move campaigns to WeZend first (they're one-offs — easy), then activate journeys one at a time while pausing the corresponding Klaviyo flow. After 2–4 weeks of clean parallel running: do a final delta export from Klaviyo (anyone who unsubscribed there during the transition!), import it, and archive the account. Keep the final CSVs — they're part of your GDPR documentation. ## What does NOT come along (so nothing surprises you) - **Historical campaign stats** — Klaviyo's past opens/clicks stay in Klaviyo. Export reports to CSV for your records. - **Flow analytics history** — journeys start their statistics fresh. - **Segment definitions** — members come along; the rules you rebuild (usually better) in the [segment builder](/en/docs/segments-and-traits). - **Benchmark data** — WeZend's own benchmarks build up as you send. --- ## How to switch from Mailchimp (https://wezend.com/en/migrate/from-mailchimp) Audience export with subscribed/unsubscribed/cleaned intact, merge tags mapped to custom fields, and Customer Journeys rebuilt on a canvas that also speaks SMS and WhatsApp. Concept mapping: - Mailchimp "Audience" → WeZend "Contacts + lists" - Mailchimp "Tags & groups" → WeZend "Tags & lists" - Mailchimp "Merge fields (*|FNAME|*)" → WeZend "Custom fields ({{first_name}})" - Mailchimp "Segments" → WeZend "Segments (live rules)" - Mailchimp "Customer Journeys" → WeZend "Journeys" - Mailchimp "Campaigns" → WeZend "Campaigns + A/B & holdout" - Mailchimp "Signup forms / landing pages" → WeZend "Lead forms (hosted + API)" - Mailchimp "Unsubscribed + cleaned" → WeZend "Suppression list" ## What makes the Mailchimp exit easy Mailchimp's audience export is genuinely good: one export gives you subscribed, unsubscribed and cleaned contacts as separate files with consent timestamps. That's everything WeZend needs — the whole migration hinges on importing those three files in the right order. ## Step 1 — Export the audience In Mailchimp: **Audience → All contacts → Export Audience.** You'll receive a ZIP containing separate CSVs for **subscribed**, **unsubscribed** and **cleaned** (hard-bounced) contacts, including merge fields, tags and opt-in timestamps. If you use multiple audiences, export each one. ## Step 2 — Import in the safe order 1. **Unsubscribed + cleaned first** → **Audience → Suppressions → Import** in WeZend (`POST /v1/account/unsubscribes/api/import`). Cleaned addresses are hard bounces — importing them as suppressions means WeZend will never waste a send (or your reputation) on them. 2. **Subscribed second** → **Audience → Contacts → Import**, one import per Mailchimp audience so provenance survives. With suppressions in place *before* the subscriber import, no ordering mistake later can message someone who opted out. ## Step 3 — Merge fields become custom fields In the import mapping screen, Mailchimp's merge fields (`FNAME`, `LNAME`, and your custom `MMERGE*` fields) map to WeZend [custom fields](/en/docs/contacts-and-custom-fields) — create missing ones on the spot. Tags come along as tags; groups usually translate best to lists or a tag per group, and interests you actively target should become topics in the [preference center](/en/docs/preference-center) — a straight upgrade from Mailchimp's group checkboxes. ## Step 4 — Domain, then warm-up Mailchimp may have sent from its shared infrastructure or your authenticated domain. Either way: verify your domain in WeZend (**Settings → Email domains**, [live DNS checks](/en/docs/email-domains-and-sending)) and ramp volume over 2–3 weeks starting with engaged contacts. If you sent from Mailchimp's shared domains until now, this is where your deliverability starts being *yours* — a real long-term win that costs a little patience up front. ## Step 5 — Templates and content Copy each template's HTML out of Mailchimp's editor and paste into a WeZend [template](/en/docs/templates-and-email-builder) in raw-HTML mode, or rebuild in the visual builder. Replace `*|FNAME|*`-style merge tags with `{{first_name}}`-style variables as you paste — search for `*|` to catch them all. Set a default value per variable so a missing field never renders as an empty gap. ## Step 6 — Customer Journeys → journeys (and further) Mailchimp automations are rebuilt manually on the [journey canvas](/en/docs/building-a-journey). The mapping is direct — trigger, delay, condition, send — but you gain what Mailchimp's email-first canvas can't do: branch to **SMS or WhatsApp** for the people who don't open email, respect [frequency caps and quiet hours](/en/docs/frequency-caps-and-quiet-hours) automatically, and attach a revenue goal so the [ROI report](/en/docs/analytics-and-roi) prices every journey. ## Step 7 — Forms, then cutover Swap Mailchimp embedded forms and landing pages for WeZend [lead forms](/en/docs/lead-forms) with double opt-in. Then run both platforms for 2–3 weeks: campaigns from WeZend, journeys activated one at a time while the matching Mailchimp automation is paused. Finish with a delta export of late unsubscribes, import it, archive the account. ## What does NOT come along - **Past campaign reports** — export the CSVs you want to keep before closing. - **Automation history** — journeys start counting fresh. - **Landing pages** — rebuild on your own site with a WeZend form; the form endpoint is public and safe in browser code. --- ## How to switch from ActiveCampaign (https://wezend.com/en/migrate/from-activecampaign) Contacts, tags and custom fields via CSV, the exclusion list moved first, and automations translated to journeys — plus what to do about deals and site tracking. Concept mapping: - ActiveCampaign "Contacts" → WeZend "Contacts" - ActiveCampaign "Tags" → WeZend "Tags" - ActiveCampaign "Custom fields" → WeZend "Custom fields" - ActiveCampaign "Automations" → WeZend "Journeys" - ActiveCampaign "Site tracking" → WeZend "Event tracking + web snippet" - ActiveCampaign "Forms" → WeZend "Lead forms" - ActiveCampaign "Exclusion list" → WeZend "Suppression list" - ActiveCampaign "Deals (CRM)" → WeZend "Events + custom fields (or keep your CRM)" ## Scope it honestly first ActiveCampaign is two products in one: marketing automation and a light CRM (Deals). WeZend replaces the automation side outright. For Deals you choose: model what you need as [events and custom fields](/en/docs/tracking-events) (fine for "deal won → start onboarding journey"), or keep a dedicated CRM and connect it as an [integration](/en/docs/integrations-and-sources). Decide this before you start — it defines what "done" means. ## Step 1 — Exclusion list first Export ActiveCampaign's exclusion list (their do-not-send registry) and any unsubscribed-contact exports, and import them into WeZend under **Audience → Suppressions** before anything else. Same logic as every migration: once suppressions are in, no later mistake can message an opted-out contact. ## Step 2 — Contacts, tags and fields In ActiveCampaign, export contacts to CSV (from the Contacts overview; include tags and custom fields in the export). In WeZend, import via **Audience → Contacts → Import**, creating [custom fields](/en/docs/contacts-and-custom-fields) in the mapping screen as needed. Tags survive as tags — and since ActiveCampaign workflows often encode state in tags (`welcome-done`, `vip`), having them intact means your rebuilt journeys can branch on them immediately. ## Step 3 — Site tracking → event tracking Replace ActiveCampaign's site-tracking snippet with WeZend's [tracking snippet](/en/docs/tracking-events). You gain granularity: instead of page-visit tracking, you send named events with properties (`product_viewed`, `order_completed` with revenue) that drive [segments](/en/docs/segments-and-traits), [journey triggers](/en/docs/building-a-journey) and [ROI attribution](/en/docs/analytics-and-roi). Map your most-used "visited URL" automation conditions to explicit events — it's more work than copying a snippet, and it pays back every day after. ## Step 4 — Domain and warm-up Verify your sending domain (**Settings → Email domains**) and ramp volume over 2–3 weeks, engaged contacts first. If SMS is part of your ActiveCampaign setup, register your [sender IDs](/en/docs/sms-senders-and-compliance) now — some countries need pre-registration lead time. ## Step 5 — Automations become journeys, deliberately ActiveCampaign automations can't be exported in a portable form; you rebuild them on the [journey canvas](/en/docs/building-a-journey). Practical translation guide: - *Start triggers* (subscribes, tag added, event) → journey triggers (`event`, `segment_enter`, list join). - *If/Else* → branch nodes on profile fields, tags or events. - *Wait until* → `wait_event` nodes ("wait until customer replies / clicks / purchases, max N days"). - *Goal blocks* → journey **goals** — with the upgrade that goals also attribute revenue. - *Tag operations* → `update_contact` nodes. Rebuild in revenue order, test-enroll yourself in each, and prune the automations nobody can explain anymore — every mature ActiveCampaign account has a few. ## Step 6 — Forms and cutover Swap ActiveCampaign forms for [lead forms](/en/docs/lead-forms) with double opt-in, run both platforms in parallel for 2–3 weeks, activate journeys one at a time while pausing the matching automation, then delta-export late unsubscribes and archive the account. ## What does NOT come along - **Automation history and contact timelines** — export what you need for records; journeys start fresh. - **Deal pipelines** — by design (see scope note above). - **Email opens/clicks history** — stays in ActiveCampaign's reports. --- ## How to switch from Twilio (https://wezend.com/en/migrate/from-twilio) A code swap, not a data migration: the send-call diff, sender IDs re-registered, opt-outs carried over, and status callbacks remapped — with a phased rollout so nothing critical breaks. Concept mapping: - Twilio "Messages API (POST /Messages)" → WeZend "POST /v1/messages/send" - Twilio "Account SID + Auth Token" → WeZend "X-API-Key header" - Twilio "Messaging Services / sender pool" → WeZend "Automatic routing + registered senders" - Twilio "Status callbacks" → WeZend "Delivery webhooks (signed)" - Twilio "Advanced Opt-Out lists" → WeZend "Suppression list + STOP handling" - Twilio "Inbound webhooks (MO)" → WeZend "Inbound webhook + Inbox" - Twilio "Twilio Verify (OTP)" → WeZend "Transactional sends + voice fallback journey" - Twilio "Programmable Voice (TTS)" → WeZend "Voice channel" ## What kind of migration this is Twilio holds very little of your *data* — it's infrastructure your code calls. So this migration is 90% a controlled code swap and 10% regulatory logistics (sender registration). The golden rule: **route by feature flag, not by big bang**, so you can shift traffic gradually and roll back instantly. ## Step 1 — Start the slow clock: sender IDs Registration lead time is the only thing you can't compress, so do it first. List every sender you use (alphanumeric names, numeric senders) and every destination country, then register them under **Settings → Senders** (`POST /v1/senders`). Check per-country requirements programmatically: ```bash curl "https://api.wezend.com/v1/sender/rules?country=DK" -H "X-API-Key: $WEZEND_API_KEY" ``` Countries with operator registration take days to weeks — start now, code later. ## Step 2 — Carry the opt-outs over If you use Twilio's Advanced Opt-Out (or track STOPs yourself), export those numbers and import them as [suppressions](/en/docs/consent-and-unsubscribes). WeZend intercepts STOP/START keywords automatically going forward, but history must come with you — a recipient who said STOP on Twilio must stay stopped on WeZend. ## Step 3 — The code diff Twilio (Node): ```js const twilio = require("twilio")(ACCOUNT_SID, AUTH_TOKEN); await twilio.messages.create({ to: "+4512345678", messagingServiceSid: "MG…", body: "Your code is 493202", statusCallback: "https://api.yourapp.com/sms-status", }); ``` WeZend — plain HTTP, no SDK required: ```js await fetch("https://api.wezend.com/v1/messages/send", { method: "POST", headers: { "X-API-Key": process.env.WEZEND_API_KEY, "Content-Type": "application/json" }, body: JSON.stringify({ to: "+4512345678", channel: "sms", sender: "Acme", message: "Your code is 493202", category: "transactional", webhook_url: "https://api.yourapp.com/sms-status", }), }); ``` Differences that matter: - **Auth** is one header (`X-API-Key`), no SID/token pair. Keys [rotate with a 24-hour grace window](/en/docs/team-and-roles). - **`messagingServiceSid` disappears** — routing to the best vendor per destination is the platform's job, with automatic failover when a route degrades. - **`category: "transactional"`** marks OTPs and receipts so they bypass marketing caps and quiet hours. - **Status callbacks** arrive on your `webhook_url` with an `X-WeZend-Signature` HMAC — [verify it](/en/docs/webhooks). Map statuses: Twilio's `queued/sent/delivered/undelivered/failed` correspond to `queued/sent/delivered/failed` (undelivered and failed both arrive as `failed`, with the reason attached). ## Step 4 — Inbound and two-way Point your reply handling at WeZend: set the [inbound webhook URL](/en/docs/conversations-and-inbox) and inbound messages POST to your endpoint just like Twilio's MO webhooks did — plus they land threaded in the Inbox, which your support team gets for free. ## Step 5 — Phased rollout Put the provider choice behind a flag and shift traffic in stages: 5% → verify [delivery rates](/en/docs/deliverability-and-inspector) against Twilio's baseline → 50% → 100%. Keep the Twilio account alive (it costs nearly nothing idle) until every webhook consumer is migrated and a full billing cycle has passed. When something fails during the transition, the [Delivery Inspector](/en/docs/deliverability-and-inspector) shows the carrier-level reason in plain language — no more decoding error 30008. ## What about Verify, Voice and numbers? - **OTP flows**: send with `category: "transactional"`; add the "no delivery in N seconds → [voice call](/en/docs/voice-messages)" fallback as a two-step journey. - **Voice/TTS**: the [voice channel](/en/docs/voice-messages) covers automated TTS calls and alerts. - **Dedicated long codes/short codes**: number porting is handled case by case — [contact us](/) with your numbers and destinations before you schedule the cutover. --- ## How to switch from SendGrid (https://wezend.com/en/migrate/from-sendgrid) Move transactional email without dropping a single receipt: suppression groups over first, parallel domain authentication, the v3 mail/send diff, and event-webhook remapping. Concept mapping: - SendGrid "POST /v3/mail/send" → WeZend "POST /v1/messages/send (channel: email)" - SendGrid "API key (Bearer)" → WeZend "X-API-Key header" - SendGrid "Domain authentication" → WeZend "Email domains + live DNS verify" - SendGrid "Dynamic templates ({{handlebars}})" → WeZend "Templates + variables" - SendGrid "Suppression groups + global suppressions" → WeZend "Suppression list + preference topics" - SendGrid "Event Webhook" → WeZend "Delivery webhooks (signed)" - SendGrid "Marketing Campaigns" → WeZend "Campaigns + journeys" ## The stakes, stated plainly Transactional email is unforgiving: a dropped password reset is a support ticket, a dropped receipt is a legal problem. So this guide is built around one principle — **both providers stay fully operational until WeZend has delivered your real traffic for days, not minutes**. ## Step 1 — Suppressions and bounces first Export SendGrid's suppression data: global unsubscribes, per-group unsubscribes, bounces, spam reports and invalid addresses (all downloadable under Suppressions in the SendGrid console, or via their API). Import the lot into WeZend (**Audience → Suppressions**, `POST /v1/account/unsubscribes/api/import`). Bounced and complaining addresses must never be retried from a fresh platform — that's how new domains get burned. If you use suppression *groups* (newsletter vs. product updates), recreate them as [preference-center topics](/en/docs/preference-center) — same concept, and subscribers manage them on one hosted page. ## Step 2 — Authenticate your domain in parallel Add your domain under **Settings → Email domains**. WeZend's DKIM selector coexists with SendGrid's — **you do not remove SendGrid's DNS records yet**. Both platforms stay fully authenticated side by side, which is what makes a gradual, reversible cutover possible. The [live DNS checker](/en/docs/email-domains-and-sending) confirms each record. ## Step 3 — The code diff SendGrid: ```js await fetch("https://api.sendgrid.com/v3/mail/send", { method: "POST", headers: { Authorization: `Bearer ${SENDGRID_KEY}`, "Content-Type": "application/json" }, body: JSON.stringify({ personalizations: [{ to: [{ email: "anna@example.com" }], dynamic_template_data: { name: "Anna" } }], from: { email: "receipts@mail.acme.com" }, template_id: "d-abc123", }), }); ``` WeZend — flatter body, same idea: ```js await fetch("https://api.wezend.com/v1/messages/send", { method: "POST", headers: { "X-API-Key": process.env.WEZEND_API_KEY, "Content-Type": "application/json" }, body: JSON.stringify({ to: "anna@example.com", channel: "email", sender: "receipts@mail.acme.com", template_id: "tpl_receipt", variables: { name: "Anna" }, category: "transactional", webhook_url: "https://api.yourapp.com/email-events", }), }); ``` Port your dynamic templates first: copy each template's HTML into a WeZend [template](/en/docs/templates-and-email-builder) — Handlebars `{{name}}` syntax carries over almost unchanged (conditionals become template defaults or separate templates; most transactional templates use none). ## Step 4 — Remap the Event Webhook SendGrid's Event Webhook events map onto WeZend's [delivery webhooks](/en/docs/webhooks): `processed→queued`, `delivered→delivered`, `bounce/dropped→failed` (reason attached), `open→opened`, `click→clicked`, `spamreport→complaint`, `unsubscribe→unsubscribed`. Verify the `X-WeZend-Signature` header instead of SendGrid's signed-webhook ECDSA — the [webhooks doc](/en/docs/webhooks) has the five-line check. Bounces and complaints also feed the suppression list automatically, so your own bookkeeping can shrink. ## Step 5 — Cut over by mail stream Migrate one stream at a time, lowest risk first: internal notifications → user-facing but recoverable (digests) → critical (receipts, password resets). At each step compare delivery and bounce rates in the [deliverability report](/en/docs/deliverability-and-inspector) against your SendGrid baseline. Transactional volume warms up much faster than marketing volume — recipients expect and open these mails — so a week of phased cutover is typically enough. Keep SendGrid alive for a full week after 100% cutover, then remove its DNS records and close. ## If you also use Marketing Campaigns Follow the [Mailchimp-style playbook](/en/migrate/from-mailchimp) for the marketing side: contacts in the safe order, campaigns as [campaigns](/en/docs/campaigns-and-ab-testing), automations as [journeys](/en/docs/building-a-journey). The pleasant surprise: transactional and marketing then share one suppression list, one domain reputation view and one balance. --- ## How to switch from Braze (https://wezend.com/en/migrate/from-braze) An engineering-led migration: user export via API, custom events remapped to the events endpoint, Canvases rebuilt as journeys, and Currents replaced by warehouse sync. Concept mapping: - Braze "Users / external_id" → WeZend "Contacts (matched on email/phone)" - Braze "Custom attributes" → WeZend "Custom fields" - Braze "Custom events" → WeZend "Events (POST /v1/events)" - Braze "Segments" → WeZend "Segments (live rules)" - Braze "Canvas" → WeZend "Journeys" - Braze "Frequency capping / quiet hours" → WeZend "Sending policy (built in)" - Braze "Currents (event export)" → WeZend "Warehouse sync + webhooks" - Braze "Content Cards" → WeZend "In-app inbox" - Braze "Intelligence Suite" → WeZend "Predictive scores + AI coach" ## Read this first Braze migrations are engineering projects, not marketing projects — your Braze value lives in SDK instrumentation and event pipelines, and that's what actually moves. The good news: WeZend's surface is deliberately simpler (plain REST, no SDK required), so the destination is less code than the origin. ## Step 1 — Map the identity model Braze keys users on `external_id`; WeZend matches contacts on email/phone and accepts your own IDs as custom fields. Decide the mapping up front: export `external_id → email/phone` pairs, and store `external_id` as a custom field (`braze_external_id`) so historical references never go dark during the transition. ## Step 2 — Export users, import contacts Export your user base via Braze's user-export APIs (segment-scoped exports work well — export segment by segment to keep provenance). Global unsubscribes and email bounces come first, into **Audience → Suppressions** — same iron rule as every migration on this site. Then import users with attributes mapped to [custom fields](/en/docs/contacts-and-custom-fields). ## Step 3 — Re-point the event stream Wherever your backend calls Braze's track endpoints, call `POST /v1/events` instead — or in parallel during the transition; dual-writing events for two weeks is the safest pattern: ```js await fetch("https://api.wezend.com/v1/events", { method: "POST", headers: { "X-API-Key": process.env.WEZEND_API_KEY, "Content-Type": "application/json" }, body: JSON.stringify({ contact: { email: user.email }, event: "order_completed", properties: { value: 499, currency: "DKK" }, }), }); ``` Keep event names identical to your Braze taxonomy — rebuilt segments and journeys read naturally, and your analysts keep their vocabulary. ## Step 4 — Canvases become journeys Canvas steps translate directly to [journey](/en/docs/building-a-journey) nodes: entry rules → triggers, Delay/Decision Split/Action Paths → delay and branch nodes, message steps → send nodes (all six channels). Frequency capping and quiet hours move from per-Canvas configuration to a [platform-wide sending policy](/en/docs/frequency-caps-and-quiet-hours) — one place, every send, no per-Canvas drift. Rebuild in revenue order, test-enroll each journey, and let the parallel period judge: pause a Canvas only after its journey twin has run cleanly on real traffic. ## Step 5 — Replace Currents If Currents feeds your warehouse or BI, replace it with [warehouse sync](/en/docs/warehouse-sync) (profiles + events to your own database) plus [delivery webhooks](/en/docs/webhooks) for real-time consumers. Most teams find those two cover every Currents consumer they actually had. ## What does NOT come along - **Message engagement history** — export reports for your records; WeZend analytics start fresh. - **Braze's ML segments** (predicted churn etc.) — recompute with the built-in [predictive scores](/en/docs/predictive-ml) once events flow; they're segmentable the same way. - **Content Cards content** — recreate as [in-app inbox](/en/docs/in-app-inbox) messages; the embed model is comparable. --- ## How to switch from HubSpot Marketing Hub (https://wezend.com/en/migrate/from-hubspot) Keep the CRM if you like it — move the messaging. Contacts and opt-outs over safely, workflows rebuilt as journeys, and a two-way integration so sales still sees everything. Concept mapping: - HubSpot "Contacts" → WeZend "Contacts" - HubSpot "Contact properties" → WeZend "Custom fields" - HubSpot "Active lists" → WeZend "Segments (live rules)" - HubSpot "Static lists" → WeZend "Lists" - HubSpot "Workflows" → WeZend "Journeys" - HubSpot "Marketing emails" → WeZend "Campaigns + templates" - HubSpot "Forms / landing pages" → WeZend "Lead forms" - HubSpot "Subscription types" → WeZend "Preference-center topics" - HubSpot "Opted-out contacts" → WeZend "Suppression list" - HubSpot "CRM (deals, tickets)" → WeZend "Keep it — connect as integration" ## The strategic choice first HubSpot is a suite; most teams leaving it are leaving *Marketing Hub's price tag*, not the CRM their sales team lives in. Both paths work: - **Keep the CRM** (most common): sales stays in HubSpot; WeZend takes over messaging, automation and audience. Connect HubSpot as an [integration](/en/docs/integrations-and-sources) so profile changes and key events flow both ways. - **Leave entirely**: also fine — contacts and consent move as below, and deal-stage logic gets remodelled as [events](/en/docs/tracking-events). The rest of this guide works for both; skip the integration step if you're leaving outright. ## Step 1 — Opt-outs first Export contacts who opted out of email (filter on the opt-out property, export CSV) plus hard bounces, and import them into **Audience → Suppressions**. HubSpot's *subscription types* deserve care: a contact opted out of "Marketing information" but subscribed to "Product updates" should be recreated with [preference-center topics](/en/docs/preference-center) — not flattened into one big opt-out. ## Step 2 — Contacts and properties Export contacts to CSV (from the contacts view, include every property you actually use). In WeZend's import mapper, contact properties become [custom fields](/en/docs/contacts-and-custom-fields). Active lists don't export as rules — note their filters down and rebuild them as [segments](/en/docs/segments-and-traits); static lists import directly as lists. ## Step 3 — Website plumbing Replace the HubSpot tracking code with WeZend's [event snippet](/en/docs/tracking-events), swap embedded HubSpot forms for [lead forms](/en/docs/lead-forms) (double opt-in on), and rebuild the landing pages you actually use on your own site — a WeZend form endpoint is public and safe in plain HTML. ## Step 4 — Workflows become journeys Workflow actions map cleanly: enrollment triggers → journey triggers, if/then branches → branch nodes, delays → delays, "send email" → send nodes that can also be **SMS, WhatsApp or push**. Internal-notification actions ("email the sales rep") become [webhook](/en/docs/webhooks) steps into your own systems or the CRM. Rebuild by revenue, test-enroll, run parallel. ## Step 5 — Domain, warm-up, cutover Verify your domain (**Settings → Email domains**), keep HubSpot sending while you [warm up](/en/docs/email-domains-and-sending) on engaged contacts, then shift campaigns first and workflows one at a time. Delta-export late opt-outs before you downgrade the Marketing Hub subscription. ## What does NOT come along - **Email engagement history** — export reports; analytics restart in WeZend. - **Landing pages and CTAs hosted on HubSpot** — rebuild on your own site (and enjoy owning them). - **Attribution reports** — WeZend's [ROI attribution](/en/docs/analytics-and-roi) rebuilds from goal events, with holdout groups HubSpot never gave you. --- ## How to switch from Brevo (Sendinblue) (https://wezend.com/en/migrate/from-brevo) The EU-to-EU move: contacts and blocklist over in an afternoon, transactional and marketing mail split cleanly, and SMS that finally shares a profile with email. Concept mapping: - Brevo "Contacts" → WeZend "Contacts" - Brevo "Contact attributes" → WeZend "Custom fields" - Brevo "Lists & folders" → WeZend "Lists (+ tags)" - Brevo "Blocklist (unsubscribed)" → WeZend "Suppression list" - Brevo "Automations" → WeZend "Journeys" - Brevo "Email campaigns" → WeZend "Campaigns + A/B & holdout" - Brevo "Transactional (SMTP / API)" → WeZend "POST /v1/messages/send (transactional)" - Brevo "SMS campaigns" → WeZend "SMS on the same profile" - Brevo "Signup forms" → WeZend "Lead forms" ## Why this one is the easy move Brevo and WeZend share the same instincts — EU roots, email + SMS in one product, sane pricing — so the concepts map almost one-to-one and nothing needs re-architecting. What you gain is the layer above: a real CDP (events, live segments, traits), journeys across six channels, and deliverability tooling with an actual [inspector](/en/docs/deliverability-and-inspector). ## Step 1 — Blocklist first Export Brevo's blocklisted/unsubscribed contacts (filter your contact export on blocklist status, or export the unsubscribed segment) and import into **Audience → Suppressions** before anything else. One import, permanent safety. ## Step 2 — Contacts, attributes, lists Export contacts to CSV from Brevo's contact overview — attributes and list memberships come along. Import per list in **Audience → Contacts → Import**; attributes map to [custom fields](/en/docs/contacts-and-custom-fields) in the mapping screen. Folder structure flattens to tags — tag on import (`brevo-folder-x`) if you want the grouping preserved. ## Step 3 — Split transactional and marketing cleanly If you send transactional mail through Brevo's SMTP or API, follow the [SendGrid-style playbook](/en/migrate/from-sendgrid): authenticate your domain in parallel (don't touch Brevo's DNS records yet), port templates, then cut over stream by stream with `"category": "transactional"` on every send. Marketing traffic follows the classic path: [warm up](/en/docs/email-domains-and-sending) on engaged contacts over 2–3 weeks. ## Step 4 — SMS comes home Register your [sender IDs](/en/docs/sms-senders-and-compliance) (start early — some countries need operator registration), and enjoy the actual upgrade: in WeZend, SMS and email live on the *same contact profile*, so "email first, SMS to non-openers after 2 days" is a standard [journey](/en/docs/building-a-journey) branch instead of two disconnected lists — and [frequency caps](/en/docs/frequency-caps-and-quiet-hours) count across both channels. ## Step 5 — Automations, forms, cutover Rebuild automations as journeys (trigger → delay → branch → send maps directly; test-enroll each), swap signup forms for [lead forms](/en/docs/lead-forms) with double opt-in, run parallel for 2–3 weeks, delta-export late unsubscribes, close. ## What does NOT come along - **Campaign statistics** — export the reports you want to keep. - **Automation history** — journeys count from zero. - **Brevo's Meetings/Conversations modules** — out of scope; two-way messaging replies land in WeZend's [Inbox](/en/docs/conversations-and-inbox), and meeting scheduling stays in your calendar tool. --- # Playbooks (campaign & journey recipes, step by step) ## Abandoned cart recovery (https://wezend.com/en/playbooks/abandoned-cart) **Goal:** Recover lost revenue from abandoned carts **Trigger:** cart_updated with no purchase within an hour **Channels:** Email, SMS · **Effort:** 30 minutes Most abandoned carts aren't rejections — they're interruptions. A phone rings, a train arrives, a toddler needs something. Abandoned-cart recovery catches those buyers before the intent fades, and it's reliably one of the highest-ROI automations in commerce because the audience has already told you what they want. The craft is in the timing and the exit: nudge soon enough that the intent is warm, escalate only if they don't act, and stop the instant they purchase so no one gets "come back and buy" after they already did. This playbook builds exactly that in WeZend. 1. **Send the cart_updated event** — Your store fires a `cart_updated` event to WeZend with the items and cart value. Most shop integrations do this out of the box. 2. **Trigger a journey on the event** — Create a journey with an event trigger on `cart_updated`, and set the goal event to `purchase` so buyers exit automatically. 3. **Wait 1 hour, then email** — A short delay keeps you from pestering someone still shopping. Then send an email showing the exact items — pull them in with a recommendations or cart block. 4. **Wait for purchase (up to 24h)** — Add a wait-for-event step. If they buy, the goal fires and they leave. If not, continue. 5. **Escalate with SMS + a unique code** — For those still holding out, send a short SMS with a single-use discount from a code pool — real scarcity, no coupon-site leakage. Tips: **Don't lead with a discount.** The first touch should just remind — save the code for people who need a second push, or you train customers to abandon on purpose. **Cap it at two or three messages.** Recovery has sharply diminishing returns; chasing longer mostly earns unsubscribes. **Respect quiet hours** so the SMS never lands at 2 a.m. --- ## Welcome series (https://wezend.com/en/playbooks/welcome-series) **Goal:** Convert new subscribers to first purchase **Trigger:** New contact / opt-in **Channels:** Email · **Effort:** 45 minutes A new subscriber is never more interested than the moment they sign up. A welcome series capitalises on that window — it consistently earns the highest open and click rates of any email you send, because the person actively asked to hear from you. The goal isn't to sell hard on message one; it's to set expectations, deliver on any signup promise, and guide them to a first purchase over a few well-paced touches. Get this right and every other program inherits a warmer, better-primed audience. 1. **Trigger on opt-in** — Start the journey when a contact joins — from a form, a keyword opt-in, or an import segment of "joined this week". 2. **Message 1 — welcome + deliver the promise** — Send immediately. If you promised a discount for signing up, deliver it here — from a code pool if it's a unique code. 3. **Message 2 — the story (day 2)** — Who you are and why you're different. Add a recommendations block so even the story email shows relevant products. 4. **Message 3 — nudge to purchase (day 4)** — Bestsellers or a gentle reminder of the welcome offer, with a clear call to action. Exit anyone who's already purchased. Tips: **Send message one instantly.** Any delay wastes the peak-interest moment. **Use smart send-time** for messages two and three so each lands when that contact usually reads. **Don't discount if you don't have to.** A strong brand story converts plenty of first purchases without eroding margin. --- ## Win-back lapsed customers (https://wezend.com/en/playbooks/win-back) **Goal:** Reactivate lapsed customers, provably **Trigger:** days_since_last_order between 60 and 120 **Channels:** Email, SMS · **Effort:** 45 minutes Winning back a lapsed customer is cheaper than acquiring a new one — but only if the revenue you attribute to the campaign is real. The discipline that separates a win-back that looks good from one that pays is a **holdout**: a small control group that receives nothing, so you can measure the true incremental lift. This playbook builds the flow and the proof together. (For the strategy in depth, see our guide on [win-back journeys with holdouts](/en/blog/win-back-journey-with-holdout).) 1. **Define lapsed with a computed trait** — Create a `days_since_last_order` trait and segment on 60–120 days quiet — the trait keeps the segment current automatically. 2. **Reserve a 10% holdout** — Before anything sends, hold out a random slice of the segment. They get nothing and become your control group. 3. **Soft nudge, no discount (day 0)** — Remind them what they liked — "we saved your favourites". Many come back without any incentive at all. 4. **Incentive (day 4)** — For those who didn't return, a time-boxed offer — SMS with a unique code works well for high-value lapsed customers. 5. **Read the holdout, then decide** — Compare revenue-per-customer, treated vs. holdout. If the lift beats the cost, scale it. If not, fix the offer before spending more. Tips: **Always reserve the holdout.** Without it, you can't tell recovered revenue from revenue that would have arrived anyway. **Segment by value.** Save discounts for lapsed customers worth winning back; a blanket offer trains your best customers to wait for one. **Stop at day 7.** Beyond that, you're mostly generating unsubscribes. --- ## Back-in-stock alerts (https://wezend.com/en/playbooks/back-in-stock) **Goal:** Convert sold-out demand when stock returns **Trigger:** Restock event for a watched product **Channels:** Email, SMS · **Effort:** 30 minutes Someone who tried to buy a sold-out item is a buyer with proven intent and no product to give them — the easiest sale you're not making. A back-in-stock alert closes that gap: capture interest while the item is out, then notify exactly those people the moment it returns. Because the demand is pre-qualified, these alerts convert far above a normal promo, and speed matters — the first hour after restock is where limited inventory sells out again. 1. **Capture interest while out of stock** — A "notify me" form or button records the contact and the product they want as an event — consent captured. 2. **Trigger on the restock event** — When your store signals the product is back, trigger a journey scoped to the contacts who asked about that product. 3. **Notify immediately, both channels** — Send email and SMS right away — for scarce restocks, SMS's speed is the difference between a sale and a second sell-out miss. Tips: **Speed beats polish.** A plain, fast alert outsells a beautiful, slow one when stock is limited. **Deep-link to the product,** not the homepage — every extra click loses buyers. **Send once.** These are high-intent; a single timely alert is enough, and repeats annoy. --- ## Post-purchase flow (https://wezend.com/en/playbooks/post-purchase) **Goal:** Increase repeat rate and reduce support load **Trigger:** purchase event **Channels:** Email, SMS · **Effort:** 40 minutes The moment after purchase is peak goodwill — and most brands waste it on a bare receipt. A post-purchase flow uses that window to reassure, inform and gently set up the next order. It's a quiet workhorse: it lifts repeat rate, and it deflects support tickets by answering "where's my order?" before anyone asks. The second purchase is the hardest and most valuable one to earn; this flow is where you earn it. 1. **Trigger on purchase** — Start the journey on the `purchase` event, with the order details available for personalisation. 2. **Order confirmation + what's next** — Immediately: confirm the order and set delivery expectations. Clear expectations are the cheapest way to cut "where's my order?" tickets. 3. **Get-the-most-out-of-it (day 3)** — Care tips, how-tos or a setup guide for what they bought — value first, no ask. This builds the trust the next sale rides on. 4. **Set up the second order (day 10)** — A recommendations block with complementary products — the things people who bought this tend to buy next. Tips: **Lead with service, not selling.** The first two messages should ask for nothing — earn the second purchase, don't demand it. **Personalise to the product bought,** so care tips and recommendations are actually relevant. **Feed a review request** off the back of this flow once the product has had time to arrive and be used. --- ## Browse abandonment (https://wezend.com/en/playbooks/browse-abandonment) **Goal:** Convert product interest that didn't reach the cart **Trigger:** product_viewed with no cart_updated **Channels:** Email · **Effort:** 30 minutes Browse abandonment sits one step earlier than cart abandonment: the customer looked at products but never added anything. It's a bigger audience with softer intent, so the winning move is a lighter touch — helpful, not pushy — or you'll train browsers to feel watched. Done well, it recovers interest that would otherwise evaporate, and it feeds your CDP with the behavioural signal that sharpens every other program's targeting. 1. **Capture product_viewed events** — Your site sends `product_viewed` to the CDP as customers browse — the raw signal for this flow. 2. **Trigger only on repeat interest** — Fire when someone views a product (or category) more than once and hasn't added to cart — real interest, not a bounce. 3. **One helpful email (a few hours later)** — Show what they looked at plus a recommendations block — framed as "still thinking it over?", not "we're watching you". Tips: **Require a stronger signal than one glance.** A single page view is noise; a repeat view is intent. **Keep it to one message.** Browse intent is soft — more than one touch tips into creepy. **Never mention the exact price they saw** in a way that feels surveillance-y; keep it helpful. --- ## Review & UGC request (https://wezend.com/en/playbooks/review-request) **Goal:** Generate reviews and social proof at scale **Trigger:** Purchase + estimated delivery + use time **Channels:** Email, SMS · **Effort:** 25 minutes Reviews are the social proof that lifts everyone else's conversion — but timing is everything. Ask too early and the product hasn't arrived; ask too late and the moment's gone. The trick is to wait until the customer has actually received and used what they bought, then make giving feedback effortless. This flow automates that timing, so reviews accumulate steadily without anyone remembering to send the ask. 1. **Trigger after estimated use** — Start from the `purchase` event with a delay that covers delivery plus a few days of use — tune it to your fulfilment time. 2. **Ask, and make it one tap** — A short email or SMS with a direct link to the review form — every extra step loses responses. 3. **One gentle reminder (day 4)** — Only to non-responders. Exit anyone who's left a review so no one is asked twice. Tips: **Match the wait to your product.** A consumable needs less use-time than durable goods before a fair review is possible. **Don't incentivise dishonestly.** A small thank-you is fine; paying for five stars corrupts the proof you're building and can breach platform rules. **Route unhappy replies to support** before they become public one-stars. --- ## Replenishment reminders (https://wezend.com/en/playbooks/replenishment) **Goal:** Drive predictable repeat orders on consumables **Trigger:** Purchase + typical consumption interval **Channels:** Email, SMS · **Effort:** 30 minutes If you sell anything people run out of — coffee, supplements, skincare, pet food — replenishment is the closest thing to free recurring revenue. The customer already chose you; you just have to reach them at the moment their supply runs low, before they default to whatever's nearest. The whole game is timing the reminder to the product's real consumption cycle. Land it right and reorders become a habit; land it wrong and it's noise. 1. **Estimate the consumption interval** — Decide how long a typical unit lasts — 30 days of coffee, 60 of supplements. This sets the wait before you remind. 2. **Trigger on purchase, wait the interval** — Start on `purchase` and delay to just before they'd run out — a few days of buffer so it arrives while supply is low, not gone. 3. **Remind with one-tap reorder** — Send a friendly "running low?" email or SMS with a direct reorder link to the exact product. Exit anyone who reorders. Tips: **Tune per product,** not per customer average — a 30-day and a 90-day item need different waits. **Offer a subscription as the graduation** for repeat reorderers; the reminder proved the habit, a subscription locks it in. **Deep-link to reorder,** ideally pre-filling the cart, so it's one tap. --- ## Birthday & anniversary (https://wezend.com/en/playbooks/birthday) **Goal:** Build goodwill and drive a dated purchase **Trigger:** Birthday / signup anniversary date **Channels:** Email, SMS · **Effort:** 20 minutes A birthday message is personal by definition, so it earns attention almost no promo can. Pair the warmth with a small, dated gift — a discount valid for a week around the day — and you get goodwill *and* a reason to buy now. No birthday on file? A signup anniversary works just as well and is data you already have. It's a set-and-forget automation: build it once and it quietly greets every customer, every year. 1. **Collect the date (or use anniversary)** — Ask for a birthday in your preference center or a form. No date? Fall back to the signup anniversary you already store. 2. **Trigger a few days before** — Send ahead of the day so the gift is usable *on* the birthday, not after it — a date-based journey handles the yearly recurrence. 3. **Warm message + a dated gift** — A genuine greeting and a discount (from a code pool for uniqueness) that expires a week later — the deadline creates the nudge. Tips: **Make the greeting real,** not a coupon with a cake emoji. The warmth is why it outperforms. **Give the gift a short window** so it drives action, but long enough to actually use. **Skip it for brand-new customers** who joined days ago — a birthday gift lands better once there's a relationship. --- ## VIP & loyalty flow (https://wezend.com/en/playbooks/vip-loyalty) **Goal:** Retain and grow your highest-value customers **Trigger:** Computed LTV / order-count trait crosses a threshold **Channels:** Email, SMS · **Effort:** 40 minutes A small share of customers drives most of the revenue — and losing one of them costs far more than losing an average buyer. A VIP flow protects that base: it identifies your best customers automatically from their behaviour, welcomes them into a tier, and gives them reasons to stay that a discount never could. The most durable loyalty isn't points; it's feeling recognised. This flow makes recognition automatic and scalable. 1. **Define VIP with a computed trait** — Create an `ltv` or order-count trait and set the bar — top spenders, or customers past N orders. The trait tags them automatically. 2. **Trigger when they cross the threshold** — The moment a customer becomes a VIP, start the journey — timing the welcome to the achievement makes it feel earned. 3. **Welcome to the tier** — Tell them they're now a VIP and what that means — early access, a dedicated perk, priority support. Make the status concrete. 4. **Keep the perks flowing** — Feed VIPs into a segment your launches and early-access campaigns target — ongoing recognition, not a one-time email. Tips: **Perks over points.** Early access and genuine recognition retain better than a loyalty-points ledger nobody tracks. **Watch for slipping VIPs.** A VIP whose activity drops is your highest-priority win-back — segment on it. **Don't over-discount your best customers** — they already buy; protect the margin and lead with status. --- # Solutions (channel x industry) ## SMS marketing for e-commerce (https://wezend.com/en/solutions/sms-for-ecommerce) In e-commerce, SMS is read within minutes and its open rates leave email far behind — which makes it perfect for the moments that are time-sensitive: an order shipped, a cart abandoned, a two-hour flash sale. The catch is that SMS is precious and expensive per message, so it rewards restraint and consent over volume. WeZend gives e-commerce teams SMS on the same platform as email, RCS and WhatsApp — one profile, one journey builder, one consent record — with a regional pricing model built for sending from Europe. That means you can run cart recovery and back-in-stock alerts as multi-channel journeys, and measure the revenue each one actually drove. - **Cart recovery that stops on purchase** — Trigger an SMS nudge after a cart is abandoned, escalate with a unique discount code, and exit the instant they buy — no "come back" after they already did. - **Order updates that cut support tickets** — "Shipped", "out for delivery", "back in stock" by SMS answers "where's my order?" before anyone asks — transactional messages your customers actually want. - **Grow the list compliantly** — Keyword opt-in ("text VIP to join") turns receipts, packaging and posters into subscribe points — with consent captured at the source. **Q: What does SMS cost for a Danish shop?** Danish SMS is 0.33 kr per message on WeZend — below the general European rate. Use the pricing calculator to model your real volume, and the SMS calculator to see how encoding affects segment count. **Q: Do I need separate consent for SMS?** Yes — treat SMS consent as its own opt-in, not inherited from an email or a purchase. Keyword opt-in and forms both capture and document it for you. --- ## WhatsApp Business for retail (https://wezend.com/en/solutions/whatsapp-for-retail) For retail, WhatsApp is where conversations already happen. It carries images, buttons and two-way replies, so it's less a broadcast channel and more a storefront in the customer's pocket — great for product questions, order updates and personal service at scale. In WeZend, WhatsApp shares the same customer profile, segments and journeys as your other channels, so a customer's WhatsApp thread and their email history are one story, not two systems. That's how you keep a conversation feeling personal even when it's automated. - **Rich, two-way conversations** — Images, quick-reply buttons and real replies turn a notification into a conversation — ideal for product questions and order support. - **One profile across channels** — WhatsApp reads and writes the same unified profile as email and SMS, so context follows the customer wherever they reply. - **Automated, still personal** — Drive WhatsApp from journeys with product recommendations and brand voice, so scaled messages still sound like your shop. **Q: Do I need WhatsApp Business approval?** Yes — WhatsApp requires a verified business sender and approved message templates for outbound. Connecting the channel and its credentials is done in the dashboard; talk to us and we'll guide the setup. --- ## Lifecycle email for SaaS (https://wezend.com/en/solutions/email-for-saas) SaaS growth lives and dies on lifecycle email: the onboarding that gets a new signup to their aha-moment, the nudges that pull dormant users back, the renewal reminders that protect revenue. What makes it work isn't the emails — it's reacting to what users actually do in the product. WeZend's CDP ingests your product events, so journeys can trigger on real behaviour — "created a project but never invited a teammate", "hasn't logged in for 14 days" — and computed traits like churn risk let you reach at-risk accounts before they cancel. It's the difference between a static drip and a lifecycle program that adapts to each user. - **Onboarding that drives activation** — Trigger the next step on what the user has (and hasn't) done, so onboarding adapts instead of blindly sending email three on schedule. - **Behaviour-triggered retention** — Product events feed segments and journeys, so a feature adopted or a login gone quiet can each start the right message. - **Churn-risk win-backs** — A computed churn-risk trait surfaces accounts trending toward cancellation early — reach them while you still can. **Q: How do product events get into WeZend?** Your app sends events to the CDP via the API (or an integration). They build unified profiles and drive segments and journeys — the same events you'd track for analytics do double duty for lifecycle. --- ## OTP & secure alerts for banking (https://wezend.com/en/solutions/otp-and-alerts-for-banking) In banking and finance, messaging is infrastructure: a login OTP that arrives in seconds, a transaction alert the customer trusts, a security notice that's provably delivered. The bar is reliability, speed and compliance — not creativity. WeZend is built for that bar: EU data residency by default, a real audit log on every send, per-message delivery status, and routing tuned for fast OTP delivery. Marketing and transactional live on one platform with one suppression and consent model, so the compliance story is coherent across everything you send. - **OTPs that arrive fast** — Routing tuned for speed and reliability, with per-message delivery status so you know each code landed. - **EU data residency + audit trail** — Customer data stays in the EU and every send is logged — the first platform your compliance team can actually sign off on. - **One model, marketing to transactional** — Suppression, consent and audit apply to every message, so security alerts and marketing obey the same rules. **Q: Is data kept in the EU?** Yes — EU data residency is the default, with GDPR tooling (consent, suppression, erasure, audit log) built in. See the security page for the concrete mechanisms. --- ## RCS Business Messaging for retail (https://wezend.com/en/solutions/rcs-for-retail) RCS is the upgrade retail has been waiting for: your verified logo at the top, product carousels, and buttons like "Track order" or "Reorder" — all in the phone's default messaging app, no download. It turns a text into a mini-storefront. The honest caveat is reach: not every device supports RCS yet, so you need a fallback. WeZend sends RCS with automatic SMS fallback on the same send, so you get the rich experience where it's available and reliable delivery everywhere else — and you can test whether the richer format actually beats plain SMS for your campaigns before committing. - **Verified branding + rich cards** — Your logo, product carousels and tap-through buttons make retail promos feel like a storefront, not a plain text. - **Automatic SMS fallback** — Devices that can't receive RCS get an SMS instead, on the same send — rich where possible, reliable everywhere. - **Prove the uplift first** — Test RCS against SMS with A/B arms and compare conversion to the price difference before you roll it out. **Q: Is RCS more expensive than SMS?** Yes — RCS costs more per message, and rich RCS more than basic. It pays off when the format changes behaviour; test it against SMS and let the numbers decide. The pricing calculator shows both. --- ## Voice & IVR for financial services (https://wezend.com/en/solutions/voice-for-finance) Some financial moments are too important for a text: confirming a large transfer, flagging suspected fraud, a payment-due reminder that needs to land. A voice call carries weight and reaches people who don't check messages — and programmable voice with IVR lets you automate it without a call centre for every case. WeZend's voice sits on the same platform, profile and compliance model as your other channels, so a fraud alert can cascade SMS then voice, and every attempt is logged. EU data residency and audit trails apply here too — the same standard your regulators expect across the board. - **For moments that need weight** — Verification, fraud alerts and payment reminders reach people a text won't, with the seriousness a call conveys. - **Cascade across channels** — Try SMS first, escalate to a voice call if there's no response — one journey, every attempt logged. - **Compliant by default** — EU data residency and audit trails cover voice like every other channel — one coherent compliance story. **Q: Can voice be part of an automated journey?** Yes — a journey can cascade channels, so a critical alert can start as SMS and escalate to a voice call if unanswered, all orchestrated and logged in one place. --- # Vendor comparisons (when WeZend fits better — and when it does not) ## The Klaviyo alternative that doesn't tax your list (https://wezend.com/en/alternatives/klaviyo-alternative) Klaviyo earned its place as the e-commerce email platform, and if it still fits your economics, keep it. But the most common reason people search for an alternative is the pricing model: plans priced on stored contacts mean your bill grows every time your list does — whether or not you send more. If that's the wall you've hit, WeZend's model will feel like fresh air: contacts are free up to 20,000 (60,000 on Scale), and you pay for the volume you actually send. The second reason is channels. Email plus US-centric SMS covers less of the customer journey every year. WeZend puts email, SMS, RCS, WhatsApp, voice and push on one API, one profile and one journey builder — with a regional SMS price model built for sending from Europe, and EU data residency as the default, not an enterprise add-on. - **No contact tax** — Growing your list costs nothing until 20,000 contacts — and even then the add-on is a small flat fee, not a plan jump. You're billed for sends, which you control. - **Six channels, not one and a half** — Email, SMS, RCS, WhatsApp, voice and push share one API, one template system and one journey builder — with flat regional SMS rates across 130+ countries. - **EU data residency by default** — Your customer data lives in the EU with GDPR tooling built in: consent tracking, suppression lists, erasure workflows and a real audit log. - **A migration path that keeps consent** — The migration wizard imports your suppressions first, then profiles with consent intact — or do the whole thing from Claude/ChatGPT via Connect AI. **Q: Can I move my Klaviyo flows?** Flows are rebuilt as WeZend journeys — the concepts map 1:1 (triggers, delays, conditional splits, goals). The migration guide walks through each standard flow type, and the AI copilot can draft them from a plain-language description. **Q: What does the switch actually cost?** The import itself is free on every plan, including Free. Most teams run both platforms in parallel for one billing cycle while warming the new email domain — the pricing calculator shows exactly what your volume costs on WeZend. --- ## The Mailchimp alternative for teams that outgrew newsletters (https://wezend.com/en/alternatives/mailchimp-alternative) Mailchimp is where half the internet learned email marketing, and for a simple newsletter it's still fine. The trouble starts when you grow: audience-based pricing that climbs with every signup, automation that tops out at simple sequences, and duplicated contacts counted twice. If your roadmap says "behavioural segmentation", "SMS" or "customer data platform", you're shopping in the wrong aisle. WeZend is built for that next stage: a real-time CDP that unifies profiles across email and phone, event-driven segments that update in seconds, visual journeys with experiments and holdouts, and six channels on one API. Billing follows what you send, not how many people know you — so a growing audience is a good thing again. - **Priced for growth, not against it** — 20,000 contacts free on every paid tier, no duplicate counting, and your bill follows send volume you control. - **Automation that branches and proves itself** — Visual journeys with conditional splits, multi-channel steps, A/B arms and holdout groups — so you can see the lift an automation actually produced. - **A CDP underneath, not a contact list** — Behavioural events, unified profiles, computed traits (LTV, days-since-purchase) and segments that react to what customers do — not just what they signed up for. - **Six channels when you're ready** — Start with email, add SMS or WhatsApp as a parameter — same API, same templates, same journey builder, flat regional rates. **Q: Is it harder to use than Mailchimp?** The basics are the same: import contacts, pick a template, send. The depth (CDP, journeys, experiments) is there when you need it, with guided flows and product tours — and you can run the whole platform in plain language via Connect AI. **Q: What happens to my signup forms?** Rebuild them as WeZend lead forms (hosted or embedded) with double opt-in built in, and switch the endpoints your site posts to. The migration guide covers the cut-over order so no signup is lost. --- ## The Twilio alternative with the marketing layer built in (https://wezend.com/en/alternatives/twilio-alternative) Twilio is a superb set of communication primitives — and that's exactly the problem for most teams: primitives. You get the send API; everything else (audience management, templates, campaign scheduling, consent, suppression, analytics, retry logic) is yours to design, build and maintain. That's a fine trade if messaging is your product. It's a tax if messaging is your marketing. WeZend gives you the same channel breadth as an API — one endpoint for SMS, WhatsApp, RCS, voice, email and push — but wraps it in the platform your marketers actually need: campaigns, visual journeys, a real-time CDP, deliverability tooling, quiet hours, frequency caps and GDPR workflows. Developers keep clean APIs and webhooks; marketers stop filing tickets. - **The layer you'd otherwise build** — Campaigns, journeys, segmentation, templates, consent and analytics ship on day one — no internal tooling project. - **Predictable regional pricing** — One flat rate per region instead of a per-country, per-carrier price sheet — budget a campaign before you send it. - **Compliance is not your codebase's job** — Suppression lists, opt-out handling, quiet hours, frequency caps and audit logs are enforced by the platform on every send path, including the API. - **Developers still get an API-first platform** — REST API, webhooks with signatures, event ingestion and warehouse sync — plus an MCP server so even your AI assistant can operate it. **Q: We have Twilio code in production — how big is the rewrite?** Small: the send call maps nearly field-for-field (the migration guide has side-by-side examples), and delivery webhooks follow the same pattern. Most teams swap the client in a day and spend the rest of the week deleting the tooling they no longer need. **Q: Can we keep our sender IDs and numbers?** Alphanumeric sender IDs are re-registered on WeZend (a quick approval step). Number porting depends on the number type and country — ask us before you migrate and we'll map it out. --- ## The Braze alternative you can start using this week (https://wezend.com/en/alternatives/braze-alternative) Braze is genuinely good at what it does — enterprise customer engagement at enterprise scale, with an enterprise process to match: sales cycles, onboarding partners, and pricing that assumes a seven-figure marketing budget. If you have all that, Braze is a fair choice. If you don't, you shouldn't need it to get world-class orchestration. WeZend delivers the same category of capability — event-driven journeys, unified profiles, experiments with holdouts, six channels — as a self-serve platform. Sign up free, import your data the same afternoon, and send your first journey before the week is out. When you outgrow self-serve, the Enterprise tier and white-label track are there, on your timeline instead of a procurement calendar. - **Days to value, not quarters** — Self-serve signup, guided onboarding, migration wizard and product tours — no implementation partner required. - **The same core loop** — Events in, profiles unified, segments updated live, journeys reacting in real time, experiments proving lift — the workflow enterprise teams buy Braze for. - **Pricing a CFO can read** — Public tiers from free to 999 kr/mo, volume bands you pick yourself, and a contact add-on with published brackets. No quote required. - **EU-first, not EU-eventually** — Data residency in the EU, GDPR workflows and a Danish SMS override rate — built from Europe for sending from Europe. **Q: Is WeZend really comparable at enterprise scale?** For most mid-market workloads, yes — same event-driven architecture, same experiment discipline. If you're orchestrating billions of messages monthly across dozens of brands, run a pilot first; the Enterprise tier exists for exactly that conversation. **Q: Can we migrate mid-contract?** Technically any time — the import is a data export away. Commercially, most teams start the pilot a quarter before renewal so the switch decision lands with real numbers on the table. --- ## The SendGrid alternative that grows past email (https://wezend.com/en/alternatives/sendgrid-alternative) SendGrid is a solid email API, and if all you'll ever send is email, it does the job. But teams rarely stay email-only: the day someone asks for an order-update SMS or a WhatsApp notification, you're integrating a second vendor, reconciling two dashboards and duplicating suppression logic. WeZend is the single integration that covers the whole arc: transactional email through the same API as marketing campaigns, plus SMS, WhatsApp, RCS, voice and push when you need them. Deliverability is first-class — guided SPF/DKIM/DMARC setup, warm-up plans, inbox-placement insight — and underneath sits a CDP and journey engine, so the platform grows from "send this receipt" to "orchestrate this lifecycle" without a re-platforming project. - **One key, every channel** — The send endpoint takes a channel parameter — adding SMS or WhatsApp to your product is a field, not a vendor evaluation. - **Deliverability with guardrails** — Domain verification wizard, DNS checker, warm-up guidance and a deliverability autopilot that flags problems before they hit revenue. - **Marketing and transactional together** — One suppression model, one template system and one analytics view across both — no more "which system sent this?". - **A CDP when you're ready** — Events, unified profiles and computed traits are already under the hood — turn engagement data into segments and journeys without new infrastructure. **Q: Will my transactional templates work?** Templates port over as HTML with variable substitution — the migration guide maps SendGrid's substitution syntax to WeZend's. Test sends against a seed list before switching the API key. **Q: How disruptive is the DNS change?** Not at all if you sequence it: verify your domain on WeZend (new selectors, so nothing collides), warm it up alongside SendGrid, then move traffic gradually. The DNS checker validates every record live. --- ## The Brevo alternative with real depth under the hood (https://wezend.com/en/alternatives/brevo-alternative) Brevo (ex-Sendinblue) got one thing right that most of the industry didn't: pricing on sends rather than contacts. If you're on Brevo, you already believe what we believe about billing. The question is what you get for it as your program matures. WeZend takes the same fair pricing philosophy and builds further up: a real-time CDP with behavioural events and computed traits, journeys with experiments and holdout measurement, six channels including RCS and voice, deliverability autopilot, and an agency/white-label track when you start running this for clients. Same billing instincts, considerably deeper machine. - **Same billing philosophy, more machine** — Volume-based pricing plus a CDP, computed traits, experiments and six channels — the upgrade path without the pricing-model regret. - **Channels beyond email + SMS** — RCS with rich cards, WhatsApp Business, voice and push join email and SMS on the same API and journey builder. - **Proof, not just sends** — A/B arms, holdout groups and ROI attribution per campaign and journey — see the lift, not just the open rate. - **Built for agencies too** — Multi-client console, white-label UI on your domain and consolidated billing — run every client from one login. **Q: Is the import really one afternoon?** For contacts, suppressions and lists, yes — the migration wizard maps Brevo's export directly. Templates and automations are rebuilt (usually the same week), and the guide sequences the cut-over so nothing sends twice. **Q: Do you have a free tier like Brevo?** Yes — Free includes unlimited contacts and a monthly send allowance, no credit card required. Paid tiers start at 79 kr/month. --- ## The ActiveCampaign alternative with channels to match the automation (https://wezend.com/en/alternatives/activecampaign-alternative) ActiveCampaign taught a generation of marketers what automation could be, and its recipe library is genuinely excellent. The friction shows up in two places: pricing tied to contact count (and to feature tiers that move the good stuff upward), and a channel model where email is native while SMS and everything else feel bolted on. WeZend starts from the channels: six of them, native, on one API — then gives your automations a CDP to react to. Journeys trigger on behavioural events, branch on profile traits, send on whichever channel the moment calls for, and measure themselves with holdouts. Billing follows volume, so an automation that touches your whole list doesn't require a plan upgrade first. - **Automation with real channel reach** — Journeys send email, SMS, RCS, WhatsApp, voice and push natively — the right channel per step, not email with add-ons. - **Events, not just tags** — A real event stream with properties and revenue, unified profiles and computed traits — segmentation on what customers do, live. - **No feature-tier ladder** — Volume bands within a tier share the same features — you pick a band for capacity, not to unlock capabilities. - **AI in the driver's seat if you want** — Draft journeys and segments in plain language — in the app's copilot or from your own Claude/ChatGPT via Connect AI. **Q: Can I recreate my automation recipes?** The standard ones (welcome, abandoned cart, win-back, post-purchase) exist as journey patterns you can adapt, and the AI copilot drafts custom ones from a description. The migration guide maps ActiveCampaign concepts to WeZend's. **Q: What about the CRM part?** WeZend is a messaging and customer-data platform, not a sales CRM. Keep your CRM (or ActiveCampaign's, or HubSpot's free tier) and connect it as an inbound source — deals and stages flow in as events and fields. --- ## The HubSpot Marketing Hub alternative for messaging that scales (https://wezend.com/en/alternatives/hubspot-alternative) Nobody leaves HubSpot's CRM — and you don't have to. The pain point is usually the Marketing Hub: pricing that scales with "marketing contacts", messaging channels that arrive via add-ons, and automation that's priced as a premium feature. When the marketing side of the bill starts rivalling the sales side, it's worth separating concerns. The pattern that works: HubSpot stays your CRM and sales system of record; WeZend becomes your messaging and customer-data layer. Contacts, deals and lifecycle stages sync in as events and fields; WeZend runs segmentation, journeys and sending across six channels on volume-based billing. Each tool does what it's actually best at, and your marketing costs follow campaigns instead of database size. - **Keep the CRM, fix the economics** — HubSpot stays the system of record; WeZend takes over messaging on pricing that follows sends, not database size. - **Channels HubSpot doesn't lead with** — Native SMS, RCS, WhatsApp, voice and push beside email — with flat regional rates and one journey builder across all of them. - **A CDP built for behaviour** — Website and product events, unified profiles, computed traits and live segments — marketing reacts to what people do, not just their CRM stage. - **Sync, don't migrate** — Connect HubSpot as an inbound source: contacts and lifecycle changes flow into WeZend continuously, so both systems stay truthful. **Q: Do we lose attribution by splitting tools?** No — WeZend attributes revenue to campaigns and journeys from its own event stream, and conversions can be posted back to HubSpot as events, so both report the same truth from their own angle. **Q: Is this all-or-nothing?** Not at all. Most teams move one program first — often SMS or the newsletter — prove the economics, then migrate the rest at their own pace. The sync keeps both sides consistent throughout. --- # Pricing & regional rates (authoritative, generated from the pricing engine) ## Pricing (DKK-anchored; EUR shown at fixed 7.45 peg — full local price list on /en/pricing) Model: pay for volume SENT, never for stored contacts. Email quota is a hard cap (no paid email overage). SMS/RCS overage and pay-as-you-go are billed at the destination region's per-message rate (see Regions below). - **Free** — free: 1,000 emails + 50 SMS/RCS per month. unlimited contacts. 1 user(s). - **Growth** — 79 kr (€11)/mo: 20,000 emails + 200 SMS/RCS per month; 199 kr (€27)/mo: 50,000 emails + 500 SMS/RCS per month; 299 kr (€40)/mo: 75,000 emails + 750 SMS/RCS per month. 20,000 contacts included before the contact add-on applies. 2 user(s). - **Business** — 399 kr (€54)/mo: 100,000 emails + 750 SMS/RCS per month; 599 kr (€80)/mo: 150,000 emails + 1,125 SMS/RCS per month; 799 kr (€107)/mo: 200,000 emails + 1,500 SMS/RCS per month. 20,000 contacts included before the contact add-on applies. 5 user(s). - **Scale** — 999 kr (€134)/mo: 400,000 emails + 2,500 SMS/RCS per month. 60,000 contacts included before the contact add-on applies. 8 user(s). - **Enterprise** — custom volume, pricing and SLA; white-label/partner track available. Contact sales. Annual billing: pay 12x the monthly fee and get +10% included volume (no discount games). Contact add-on per month (applies above the included contacts; Free tier exempt): - 20,001–40,000 contacts: +99 kr (€13)/mo - 40,001–80,000 contacts: +249 kr (€33)/mo - 80,001–200,000 contacts: +499 kr (€67)/mo - 200,001–400,000 contacts: +899 kr (€121)/mo - 400,001+ contacts: Enterprise pricing Frozen local entry price points (Growth-1 / Business-1 / Scale): SEK 119/599/1499, NOK 119/599/1499, GBP 9/45/115, CHF 10/49/125, JPY 1990/9900/24900. ## Regional SMS/RCS rates (flat per-message, by destination region) - North America: 0.15 kr (€0) per SMS/RCS-basic, 0.35 kr (€0) per RCS-rich — included in plan quota, overage per message. - Europe: 0.45 kr (€0) per SMS/RCS-basic, 1 kr (€0) per RCS-rich — included in plan quota, overage per message. - Oceania: 0.45 kr (€0) per SMS/RCS-basic, 1 kr (€0) per RCS-rich — included in plan quota, overage per message. - Latin America & Caribbean: 0.6 kr (€0) per SMS/RCS-basic, 1.35 kr (€0) per RCS-rich — pay-as-you-go from message one. - Asia: 0.95 kr (€0) per SMS/RCS-basic, 2.15 kr (€0) per RCS-rich — pay-as-you-go from message one. - Middle East & North Africa: 1.85 kr (€0) per SMS/RCS-basic, 4.15 kr (€1) per RCS-rich — pay-as-you-go from message one. - Sub-Saharan Africa: 2.35 kr (€0) per SMS/RCS-basic, 5.3 kr (€1) per RCS-rich — pay-as-you-go from message one. - Central Asia & Caucasus: 2.7 kr (€0) per SMS/RCS-basic, 6.1 kr (€1) per RCS-rich — pay-as-you-go from message one. - Denmark (country override, beats the Europe rate): 0.33 kr per SMS, 0.75 kr per RCS-rich. - Not available (sanctioned): Russia, Belarus, Iran, North Korea, Libya, Myanmar, Palestinian Territory. - 140+ countries mapped; full country table: https://wezend.com/en/regions # Platform features (marketing overview) - **Omnichannel Messaging** (https://wezend.com/en/features/omnichannel-messaging): Reach customers on SMS, RCS, WhatsApp, email, voice and push through a single API with automatic failover. - **SMS API** (https://wezend.com/en/features/sms-api): A carrier-grade SMS API with smart routing, delivery receipts and two-way messaging across 190+ countries. - **WhatsApp Business** (https://wezend.com/en/features/whatsapp-business): Official WhatsApp Cloud API access with templates, interactive buttons, media and conversational automation. - **Email API & Marketing** (https://wezend.com/en/features/email-api): High-deliverability email with double opt-in, one-click unsubscribe, open/click tracking and A/B testing. - **Customer Data Platform** (https://wezend.com/en/features/customer-data-platform): Ingest behavioural events in real time and resolve them into unified, queryable customer profiles. - **Segmentation & Audiences** (https://wezend.com/en/features/segmentation): Create real-time segments from any event, trait or behaviour, and activate them across every channel. - **Journey Orchestration** (https://wezend.com/en/features/journey-orchestration): A visual, drag-and-drop builder for multi-step, cross-channel journeys triggered by real-time events. - **AI Agents & Automation** (https://wezend.com/en/features/ai-automation): AI agents that answer conversations, copilots that draft campaigns, and predictive models that pick the next best action. - **Analytics & Attribution** (https://wezend.com/en/features/analytics): Funnels, cohorts, attribution and revenue reporting unified across all channels and journeys. - **RCS Business Messaging** (https://wezend.com/en/features/rcs-messaging): Send branded, interactive RCS messages with carousels, buttons and verified sender identity, falling back to SMS. - **Programmable Voice** (https://wezend.com/en/features/voice-api): Place and receive calls, run IVR flows, send voice OTPs and text-to-speech alerts via a simple API. - **Mobile & Web Push** (https://wezend.com/en/features/push-notifications): Send targeted mobile (FCM/APNs) and web push notifications driven by behaviour and segments. - **Consent & Preference Center** (https://wezend.com/en/features/preference-center): A self-serve center where customers manage channels, topics and consent — enforced on every send. - **Warehouse Sync & Reverse-ETL** (https://wezend.com/en/features/warehouse-export): Stream profiles and events to your data warehouse, and activate warehouse-built audiences back across every channel. - **Experimentation & A/B Testing** (https://wezend.com/en/features/experimentation): Run A/B tests and holdout experiments across channels and journeys, and measure true incremental impact. - **AI Connector (MCP)** (https://wezend.com/en/features/ai-connector): Connect your own AI assistant to your WeZend account: 44 customer-scoped tools that read, configure and (with explicit confirmation) operate the platform — segments, campaigns, journeys, templates, domains, budgets and more. - **AI Studio** (https://wezend.com/en/features/ai-studio): Type what you want — "a win-back email for customers who haven't ordered in 60 days" — and AI Studio returns a full draft: the audience segment, a written email, an A/B subject line and a suggested send time. You review and ship. - **Smart Send-Time** (https://wezend.com/en/features/smart-send-time): Every contact has a rhythm — the hours they actually engage. Smart Send-Time reads each person's event history, finds the hour they're most active, and schedules their message for then. Better open and click rates, no guesswork, no spreadsheets. - **AI Brand Voice** (https://wezend.com/en/features/ai-brand-voice): Set your brand's voice once — tone, phrases to use, words to avoid — and every AI-written email, SMS and subject line sounds like your brand instead of a default assistant. The voice profile is folded into every AI prompt across the platform. - **Product Recommendations** (https://wezend.com/en/features/product-recommendations): Drop a recommendations block into any email and each recipient sees products picked for them — from their behaviour and your catalog. One campaign, thousands of personalised versions, rendered at send time. - **Unique Discount Codes** (https://wezend.com/en/features/discount-code-pools): Upload a pool of single-use codes and put {{discount_code}} in your message. Each recipient gets a unique code handed out atomically — never reused, never leaked to a coupon site. Real scarcity, real urgency. - **AI Performance Analyst** (https://wezend.com/en/features/ai-performance-analyst): Every week the analyst turns your digest numbers into a short, readable narrative — what changed, why it matters, and one concrete thing to do next. When AI is configured it's written by Claude; otherwise a rules-based version, so it always works. - **SMS Keyword Opt-In** (https://wezend.com/en/features/sms-keyword-optin): Set up a keyword — JOIN, VIP, SUMMER — and when someone texts it to your number, they're opted in with consent captured automatically. Put it on a poster, a receipt, a shop window; grow SMS the compliant way. - **Inbox-Placement Testing** (https://wezend.com/en/features/inbox-placement-testing): Send a real test to your own seed inboxes across providers and track delivery and opens per address. Catch a deliverability problem on a seed list — not on your whole audience. - **Hosted Landing Pages** (https://wezend.com/en/features/hosted-landing-pages): Build a landing page in the platform and publish it to a hosted URL instantly — for a lead form, an offer, an event RSVP. No developer, no deploy pipeline, connected to the same forms and CDP as everything else. - **Campaign approval** (https://wezend.com/en/features/campaign-approval): Members can build and submit campaigns, but a send goes to pending approval for an owner or admin to release. Governance for teams and agencies, built into roles — no accidental sends to the whole list. - **Template gallery** (https://wezend.com/en/features/email-template-gallery): A gallery of ready-made starter templates — newsletter, promo, transactional, welcome — that you drop into the builder and make yours. Faster first send, consistent design, no HTML. - **DMARC monitoring** (https://wezend.com/en/features/dmarc-monitoring): Upload your DMARC aggregate reports and WeZend parses them into a readable picture: which sources pass authentication, which fail, and where someone may be spoofing you. The visibility you need to tighten DMARC safely. - **Spam pre-flight & BIMI** (https://wezend.com/en/features/spam-preflight-bimi): A pre-flight spam check scores your subject and content against known spam signals and tells you what to fix. Pair it with BIMI to show your verified logo next to your emails in supporting inboxes — trust before the open. - **Outbound webhooks** (https://wezend.com/en/features/outbound-webhooks): Subscribe an endpoint to platform events — contact created, message delivered or failed, campaign sent, form submitted — and WeZend posts them to you in real time, HMAC-signed so you can verify they're genuine.