# Documentation (/docs) WASync puts WhatsApp numbers, QR or Business API, inside your CRM: conversations in the inbox and on the record, automatic flows, calls, and rules for who sees what. The same numbers are reachable from your own software through a REST API, a remote MCP server and an n8n node. ## Choose your path [#choose-your-path] ## Three things to know first [#three-things-to-know-first] **Two kinds of numbers.** A **QR number** is the WhatsApp you already have, paired by scanning a code; no templates, no Meta limits, but WhatsApp's rules on bulk messaging apply. A **Business API number** is registered with Meta: templates, calls, higher volumes, and a 24-hour rule. The [connection types](/docs/concepts/connection-types) page compares them. **The 24-hour window.** On a Business API number you may send free text only to a customer who wrote to you in the last 24 hours. Outside that window, only an approved **template** goes through; WASync locks the composer and offers the template picker instead of losing your message. [Templates on Business API numbers](/docs/product/wasync-chat#templates-on-business-api-numbers). **Records follow rules you set.** Who becomes the responsible of a new chat, whether each number gets its own lead, what a flow creates or binds to, who may see which conversation: all of it is in **Chat rules** and documented under [CRM records](/docs/product/crm-records) and [Chat Flows](/docs/product/chat-flows). ## Keeping up [#keeping-up] The [changelog](/docs/changelog) is the dated record of what shipped, with a line per change pointing at the product page that now documents it. Inside the app, **What's new** shows the same releases per user, in your language. ## For developers [#for-developers] * [Quickstart](/docs/quickstart): account, key, first message in under five minutes. * [Guides](/docs/guides): webhooks, OAuth2, n8n, MCP, WhatsApp templates, bringing a number from another provider. * [API reference](/docs/api-reference): every endpoint, generated from the OpenAPI contract. * [Security](/docs/security): API keys and the developer console. Base URL `https://developers.wasync.app/api/v1`. Every page of this site is also available as Markdown (append `.md` to the URL) and listed in [llms.txt](/llms.txt) for AI agents. # Plans, trial and invoices (/docs/administration/billing) ## What is licensed [#what-is-licensed] Each WhatsApp **number** has its own licence, bought and renewed on the number's row in **Connections**. The app itself, the team, the flows and the settings are free; a number with no active licence stops sending and receiving. | Plan | Covers | Price | | ----------------------- | ---------------------------------------------------------------------- | ------------- | | **WAPP** | A QR number: the WhatsApp you already have, paired by scanning a code. | $19 per month | | **WABA** | A WhatsApp Business API number: templates, calls, higher volumes. | $29 per month | | **API & agents** add-on | REST API, remote MCP server and n8n node on the number. | $12 per month | Prices are in USD and exclude VAT, which Stripe adds according to your country and VAT status at checkout. Partners resell at 60 % of the list price; see [Partners](https://wasync.app/partners). ## The trial [#the-trial] Every new number starts with a **7-day trial** with everything enabled; numbers brought by a partner get 15 days. One trial per phone number: a number that already had its trial, on any portal, goes straight to a paid licence. Three days before the end you receive an email and a Bitrix24 notification; when the trial ends the number is paused until a licence is activated, and nothing is deleted. ## Paying [#paying] **Connections → the number → Activate** opens the Stripe checkout. Card and PayPal are accepted; the subscription renews monthly on the same card. A refused card is almost always the issuing bank's decision; try another card or write to [support@wasync.app](mailto:support@wasync.app) for a Revolut payment link and a manual activation. Add-ons and extra numbers are added on the same page; the subscription is adjusted pro rata. ## Invoices and company details [#invoices-and-company-details] Stripe emails an invoice for every payment. **Connections → the number → Manage subscription** opens the Stripe customer portal with every invoice, the card on file and the company details: fill in the legal name, address and VAT number **before** paying, because an invoice carries the details at the moment of payment. Companies outside Romania also receive a fiscal invoice from TDACRM Solutions SRL for each payment. ## Expiry and grace [#expiry-and-grace] A subscription that fails to renew enters a short grace period during which the number keeps working and administrators are notified; after it, the number is paused. Reactivating a paused number restores everything, including conversations and flows. ## Related [#related] * [Licences and trial](/docs/concepts/licences-and-trial) for the API side * Help Center: [Do I get an invoice?](/docs/help-center/api-and-billing/invoices), [My card is refused](/docs/help-center/api-and-billing/card-refused-by-stripe) # Data and security (/docs/administration/data-and-security) ## What is stored [#what-is-stored] For each number, WASync keeps the conversations (messages, delivery status, the linked CRM record), the contacts WhatsApp knows (number, name, photo link), the files exchanged, the Chat Flow runs with the answers collected, call records, and an audit trail of administrative actions. Bitrix24 keeps its own copy of what WASync writes on timelines and in Open Channels. ## Retention [#retention] | Data | Kept | | ------------------------------------- | ----------- | | Messages and media | 90 days | | Sessions, events, email log, alerts | 180 days | | Audit trail of administrative actions | Not deleted | | Unused Bitrix24 user tokens | 60 days | Media files are stored in the EU and served through short-lived signed links; the links in exports expire after 24 hours. ## Deleting [#deleting] * **A connection**: the number, its conversations in WASync and the flows bound to it are removed; the CRM keeps everything written on it. [What do I lose when deleting a connection?](/docs/help-center/connections/what-do-i-lose-when-deleting-a-connection) * **The app**: uninstalling from Bitrix24 pauses the portal; the data is kept for 90 days in case you come back, with a warning email on day 83, then purged, including messages, media and settings. Audit records of the purge itself are kept. ## Who can read what [#who-can-read-what] Access follows Bitrix24: a person reads only the numbers and conversations given in [Team](/docs/administration/team-and-access), administrators read everything, and the APIs behind the app enforce the same limits. WASync staff access customer data only for support, on request, and every such access is logged. ## Agreements [#agreements] The [Data Processing Agreement](https://wasync.app/dpa) is available to every customer; the [Terms](https://wasync.app/terms) and the [Privacy policy](https://wasync.app/privacy) cover the rest. WhatsApp traffic itself is subject to Meta's terms for the Business API and, on QR numbers, to WhatsApp's terms for the application. ## Related [#related] * [Security: API keys](/docs/security/api-keys) * [Developer console](/docs/security/developer-console) # Administration (/docs/administration) The pages for the person who installed WASync: money, people and data. # Team and access (/docs/administration/team-and-access) ## Access to numbers [#access-to-numbers] **Team** (sidebar) lists every Bitrix24 user with the numbers they may use. A person with access to a number can read and answer its conversations in WASync Chat and in the CRM tab, send files and templates, and is rung for its calls. **Edit access** picks the numbers; one of them is the **primary** number, used when the person starts a conversation from a CRM record without choosing a number. A person with no access sees no WhatsApp at all in Bitrix24. The Open Channel's own queue in Bitrix24 is separate: a number bound to an Open Channel delivers to that queue as well, by Bitrix24's rules. ## Console access [#console-access] For each person, **Console access** decides what they may do in the WASync app itself, area by area: read, or read and change. A sales agent typically needs numbers and nothing else; a team lead gets Chat Flows and Quick replies; connections, team, settings and reports stay with administrators. ## Visibility of conversations [#visibility-of-conversations] Independent of access to a number, each person has a visibility level: **all chats** of the numbers they may use, their **department**, or **only the records they are responsible for**. It is set on their row in Team; the default for everyone else is in [Chat rules](/docs/product/settings#who-sees-what). The level applies in WASync Chat, in the "Assigned to" filter and in the export. ## Administrators [#administrators] Bitrix24 administrators are administrators in WASync: they see every conversation, change every setting, manage licences and the team. Nothing has to be granted to them. Everybody else is limited to the numbers and areas given above, and the APIs behind the app refuse what the interface hides. ## Changing user or portal [#changing-user-or-portal] WASync acts in Bitrix24 as the user who installed the app. If that person leaves, reinstall from the Marketplace as another administrator, or write to support; records created by WASync land on that user when no rule says otherwise ([Chat rules](/docs/product/settings#new-chats-from-unknown-numbers)). ## Related [#related] * [Settings and Chat rules](/docs/product/settings) * Help Center: [Can I restrict employees to their own chats?](/docs/help-center/wasync-chat/restrict-employees-to-their-own-chats) # API Reference (/docs/api-reference) {/* Generated by scripts/generate-api-reference.mjs — do not edit. */} Base URL `https://developers.wasync.app/api/v1`. Every request carries `Authorization: Bearer `; an OAuth access token goes in the same header. The machine-readable contract these pages are built from is [openapi.json](https://developers.wasync.app/openapi.json), served with open CORS so you can generate a client straight from it. ## Connections [#connections] ## Account [#account] ## Messages [#messages] ## Webhook [#webhook] # 19 June 2026 (/docs/changelog/2026-06-19) ## WhatsApp Platform API launch [#whatsapp-platform-api-launch] **New feature.** First public release. REST v1 at `https://cloudapi.wasync.app/api/v1`: `GET /connections`, `GET /messages` (cursor-paginated) and `POST /messages` (text, idempotent via `idempotencyKey`). Auth is OAuth 2.0 Authorization Code + PKCE (S256 required, `client_secret_post`) with discovery under `/.well-known/`. A remote MCP server at `/api/mcp` exposes `list_whatsapp_connections`, `send_whatsapp_message` and `read_whatsapp_messages`. Webhooks deliver `message.received` with HMAC-SHA256 signatures (`X-WASync-Signature`). App registration lives at [https://developers.wasync.app](https://developers.wasync.app); the AI integration kit (`/docs`, `/openapi.json`, `/llms.txt`) shipped the same day. # 2 July 2026 (/docs/changelog/2026-07-02) ## 402 responses with a payment link when the API add-on is inactive [#402-responses-with-a-payment-link-when-the-api-add-on-is-inactive] **Improvement.** Sending through a connection whose Platform API add-on is not active now returns `HTTP 402` with an actionable body instead of a bare 403: `{ error: "license_inactive", code, message, payment_url }`. The original core code (`addon_required` or `license_inactive`) is preserved in `code`, and `payment_url` points where the connection owner can activate the add-on. MCP tool results return the same information as plain text so an AI agent can relay it to the human. Every other error status is still relayed verbatim — branch on the `error` code, never on message text. See [Errors & idempotency](/docs/concepts/errors-and-idempotency). # 13 July 2026 (/docs/changelog/2026-07-13) ## Webhooks reference page + docs payload fix [#webhooks-reference-page--docs-payload-fix] **New feature · Improvement.** A dedicated [Webhooks reference](/docs/guides/webhooks) now documents the full delivery contract: event catalog, exact payload, signature verification with a complete receiver example, retry policy (3 attempts, exponential backoff, 10 s per-attempt timeout, no long redelivery queue — backfill via `GET /messages`), duplicate and ordering semantics, and a troubleshooting checklist. Docs fix: the webhook example previously showed `message.timestamp` as an ISO string — deliveries actually carry epoch **milliseconds** (a number). The payload itself is unchanged; only the documentation was wrong. ## Machine-readable docs surface: llms-full.txt + CORS-open spec [#machine-readable-docs-surface-llms-fulltxt--cors-open-spec] **Improvement.** The complete documentation is now published as a single markdown file at [https://developers.wasync.app/llms-full.txt](https://developers.wasync.app/llms-full.txt) for LLM ingestion, alongside the existing [https://developers.wasync.app/llms.txt](https://developers.wasync.app/llms.txt) index. `/openapi.json`, `/llms.txt` and `/llms-full.txt` are now served with `Access-Control-Allow-Origin: *`, so browser-based spec viewers, SDK generators and AI agents can fetch them cross-origin. This changelog is also new. # 25 July 2026 (/docs/changelog/2026-07-25) ## Read receipts — POST /messages/read gives your customers blue ticks [#read-receipts--post-messagesread-gives-your-customers-blue-ticks] **New feature.** If your operators read WhatsApp inside your own CRM, nobody ever opens the chat in WhatsApp — the customer's messages stay on double grey ticks and the conversation feels ignored. `POST /messages/read` sends the WhatsApp read receipt for you. Body: `{ connectionId, phone?, messageId? }` — at least one of `phone` / `messageId` (the latter is WASync's cuid of an *incoming* message, not `waMessageId`). It uses the existing `whatsapp.send` scope, because marking read transmits a receipt to the customer's device — no re-consent needed. Idempotent by nature: no `idempotencyKey`, no rate limit, safe to retry. Response `{ ok: true, marked }`, where `marked` counts the stored inbound messages newly flagged as read. ## messageId is now WASync's stable id — WhatsApp's id moves to waMessageId [#messageid-is-now-wasyncs-stable-id--whatsapps-id-moves-to-wamessageid] **Breaking change · Improvement.** `POST /messages` previously returned WhatsApp's own message id (`true_…@c.us_3EB0…`) as `messageId`, while `GET /messages` and the `message.received` / `message.status` webhooks used WASync's id — so status events could never be matched back to a send. They are now the SAME id everywhere: `messageId` (POST) = `id` (GET) = `message.id` (webhooks), a WASync cuid. WhatsApp's own id is still returned, alongside, as `waMessageId` (REST), `wa_id` (webhooks) and `wa_message_id` (media send) — use it for support tickets, never as a join key (it can be `null`). `GET /messages` rows now also carry `waMessageId`, so you can map both ways. **Action required** if you stored the value of `messageId` to match webhooks: it now changes format — join on the new value, and read `waMessageId` if you specifically needed the WhatsApp id. One new edge case: if a send reaches WhatsApp but cannot be persisted, the 200 body is `{ messageId: null, waMessageId, status, persisted: false }` — the message was delivered, so do not retry it. # 8 August 2026 (/docs/changelog/2026-08-08) ## Connection lifecycle events + GET /account slot quota [#connection-lifecycle-events--get-account-slot-quota] **New feature.** Two webhook events were added for partners who run our connections inside their own product: `connection.disconnected` (a number stopped working and its owner must pair again) and `connection.connected` (it recovered). Both fire once per real transition, on `qr` connections, and the QR is deliberately NOT in the payload — it is a scan-to-login credential, so fetch it from your authenticated `GET /connections/{id}`. `GET /account` (scope `whatsapp.read`) answers "can I onboard another number right now?" before you take the order: `{ slots: { total, used, available, nextExpiry }, connections: { total, connected, needsReconnect } }`. A slot is capacity, not a phone number — it attaches when a number actually pairs and returns to your pool with whatever time is left on it when the connection is deleted, so a paid slot moves from a departing customer to a new one without paying twice. You map our connection `id` to your own customer record; we mint the id, you map it. Subscriptions created before 10 August 2026 must re-consent to receive the `connection.*` events. Also from this date, the connection `provider` field speaks the public vocabulary: `qr` and `cloud_api`. See [Connection types](/docs/concepts/connection-types). # 17 August 2026 (/docs/changelog/2026-08-17) ## developers.wasync.app is the canonical host — cloudapi.wasync.app keeps working forever [#developerswasyncapp-is-the-canonical-host--cloudapiwasyncapp-keeps-working-forever] **Improvement.** The developer portal, the docs and the REST API are now documented under `https://developers.wasync.app`, and the REST base URL is `https://developers.wasync.app/api/v1`. **Nothing you already built has to change.** `https://cloudapi.wasync.app/api/v1` is a permanent alias serving exactly the same API — same keys, same paths, same responses — and it remains valid indefinitely. This is a documentation change, not a migration: there is no cut-off date and no deprecation. The OAuth endpoints, the `/.well-known/` discovery documents and the MCP server URL are protocol identifiers your clients have already registered, so they are **unchanged** and still read `cloudapi.wasync.app`. Keep using them exactly as issued. ## Idempotency-Key on POST /connections — a retried create no longer costs you a second slot [#idempotency-key-on-post-connections--a-retried-create-no-longer-costs-you-a-second-slot] **New feature.** Creating a connection provisions a WhatsApp session and consumes a paid slot, so a client that timed out and retried used to end up with two connections and two slot charges for one customer. `POST /connections` now accepts an optional `Idempotency-Key` header — the only endpoint that does; omit it and behaviour is exactly as before. Within a 24 h TTL: the same key with the same body returns the SAME connection with `200` and the response header `Idempotency-Replayed: true`; the same key with a different body is `400 idempotency_key_reuse`; a retry while the first call is still in flight is `409 idempotency_in_progress` with `Retry-After: 1`; a key over 255 characters is `400 idempotency_key_invalid`. Keys are namespaced per workspace, and the body comparison is over a canonical hash, so JSON key order is irrelevant. **Mint one fresh UUID per customer-onboarding attempt** — never one per process, per API key, per day, or a constant, or the second customer you onboard is handed the first customer's connection. On a replay the `qr` is re-fetched fresh, because pairing codes rotate roughly every 20 seconds and a stale one would not scan. ## API keys are the default credential — plus IP allowlists and webhook self-service [#api-keys-are-the-default-credential--plus-ip-allowlists-and-webhook-self-service] **New feature.** `Authorization: Bearer wsk_live_…` now works on every endpoint. Create and revoke keys at [https://developers.wasync.app/keys](https://developers.wasync.app/keys) — the key is shown once and stored only as a hash, scopes are per key, and scopes plus the reachable connection list are resolved live on every request. If you are automating your own account this replaces the entire OAuth flow: no redirect URI, no PKCE, no consent screen, no token refresh. OAuth 2.0 remains, unchanged, for apps that OTHER WASync customers install and consent to. A key can create a workspace's FIRST connection, so the old "make the first one in the portal UI" bootstrap step is gone. Optional hardening: pin a key to IPv4/IPv6 addresses or CIDR ranges — a call from an address that is not on the list is refused with `403 ip_not_allowed`, deliberately distinct from `401 invalid_key` (unknown or revoked key), because the fix is to add an address, not to rotate a good key. New endpoints `GET /webhook`, `PUT /webhook` and `POST /webhook/rotate` let you point WASync at your endpoint and manage its signing secret without registering an app: `PUT` issues the secret, `GET` never returns it (it reports `secretSet` only), and rotation kills the old secret immediately. Nothing changed for existing OAuth clients, and the webhook signature scheme is unchanged. # 18 August 2026 (/docs/changelog/2026-08-18) ## Pairing codes — connect a number without scanning a QR [#pairing-codes--connect-a-number-without-scanning-a-qr] **New feature.** New endpoint `POST /connections/{id}/pairing-code` (scope `whatsapp.manage`). Body `{ "phoneNumber": "40740267964" }` — E.164 without the leading `+`, digits only — returns `{ "code": "7S59-1KZP" }`. Your customer types it into WhatsApp → Settings → Linked devices → **Link with phone number**. This is the path for the customer who is completing your onboarding on the same phone that runs WhatsApp: there is no second screen to photograph, so the QR simply cannot be used. **A pairing code is not always available** — the engine can decline with `502 pairing_code_unavailable`, so keep the QR flow on screen as a fallback. Requesting another code on the same connection is allowed (a new code, same session) and capped at 5 per connection per 15 minutes, then `429 rate_limited` with `Retry-After`. Nothing extra is consumed: the same paid slot and the same 7-day trial as QR pairing, claimed when the number actually pairs. Monitoring is unchanged — poll `GET /connections/{id}` and/or listen for `connection.connected`. `qr` connections only; a `cloud_api` number answers `409 not_supported_for_provider`. Full guide: [Pairing code & QR](/docs/guides/pairing-and-qr). # 8 September 2026 (/docs/changelog/2026-09-08) ## `422 recipient_not_on_whatsapp` on `POST /messages` [#422-recipient_not_on_whatsapp-on-post-messages] **Improvement.** When WhatsApp reports that it has no account for the recipient, the send now answers `422` with the code `recipient_not_on_whatsapp` and a message that says what to check: the number must be in international format (country code first, no leading zero) and the person must use WhatsApp. Until today this case came back as a generic `502 send_failed`, which read like an outage on our side. It is permanent for that number — fix the input rather than retrying. `502 send_failed` is now reserved for failures that are not about the recipient (session or provider), where a short back-off and a retry make sense. Both codes are listed in [Errors & idempotency](/docs/concepts/errors-and-idempotency). ## Purchased slots apply themselves [#purchased-slots-apply-themselves] **Improvement.** In a developer workspace, a new connection now takes a free purchased slot immediately instead of starting a trial, and a connection still on trial is upgraded as soon as a slot is free. On the Connections & Billing page you can also move capacity by hand: "Assign a slot" on a trial or expired connection, "Release slot" on a slot-backed one (the slot returns to your pool with its remaining time), and a "free slots" counter on the Slots card. # 14 September 2026 (/docs/changelog/2026-09-14) ## API keys from inside Bitrix24 [#api-keys-from-inside-bitrix24] **New feature.** Settings → **API & Agents** now has an **API keys** card. An admin names the integration and gets the full key shown once, with Copy, plus the portal's existing keys — prefix, created, last used, revoked — and can revoke any of them with a confirmation. Below the list: the API base URL (`https://cloudapi.wasync.app/api/v1`), a curl example, a link to these docs and a pointer to the n8n node. Creating a key needs at least one connection with the API add-on active ($12 per number per month); without one, the button is disabled with the reason and the server answers `403 addon_required`. Keys made this way carry the standard scopes `whatsapp.read whatsapp.send`. The developer console still exists for IP allowlists, webhooks, and several portals under one account — the card links to it. ## Checkout self-heals a stale Stripe customer [#checkout-self-heals-a-stale-stripe-customer] **Fix.** A customer id that no longer exists in Stripe live mode is now replaced automatically instead of failing the checkout. # 15 September 2026 (/docs/changelog/2026-09-15) ## Delete a number, close a workspace [#delete-a-number-close-a-workspace] **New feature.** The developer console can now remove what it creates. Each connection row on **Billing** has a **Delete** button, and a workspace with no connections left can be closed from the same card. Deleting a number closes its WhatsApp session, removes every message stored for it, and returns its slot to the workspace pool if it was on a paid one. Closing a workspace removes it together with its API keys and webhook configuration, so anything still calling the API with those keys stops working. Both actions ask for confirmation and neither can be undone. Two refusals are deliberate. A workspace that still has numbers cannot be closed — delete them first, so the phones are actually unlinked instead of leaving orphaned sessions behind. A workspace with a live slot subscription cannot be closed either; cancel the subscription first, or it keeps billing a workspace that no longer exists. The same actions are available over the API: `DELETE /v1/connections/{id}` with a key carrying the `whatsapp.manage` scope. What survives on purpose: the record that a number already had its free trial. Closing a workspace and opening another does not hand the same phone a second trial. ## Click-to-WhatsApp attribution retries the CRM write [#click-to-whatsapp-attribution-retries-the-crm-write] **Fix.** Bitrix24 lists a freshly created deal seconds before it will answer a write for that same id, replying `400 Not found` in between. Ad attribution written in that window was lost, leaving the contact attributed and the deal with empty UTM fields. Each write is now retried, and a write that still fails raises an alert on our side instead of failing quietly. # 17 September 2026 (/docs/changelog/2026-09-17) ## Call permission, end to end [#call-permission-end-to-end] **New.** When a customer answers the WhatsApp "may we call you?" card, the answer is now recorded on the contact and written to the CRM timeline: allowed permanently, allowed until a date (temporary grants last seven days), declined, or revoked. In the CRM widget and in WASync Chat the phone icon turns green while the permission is active, and a chip next to the customer's name reads "Calls allowed" or "Calls declined". Until now the only way to learn the answer was to place a call and hit Meta's error. The template picker has a new checkbox, *Also ask permission to call after sending*: the permission card follows the template automatically. Official WhatsApp Business API connections only — QR numbers have no call permission. The request sentence itself now goes out in the operator's language, twenty languages, instead of always English, and the call window has an optional field for a custom sentence. ## Tapped template buttons reach chat flows [#tapped-template-buttons-reach-chat-flows] **Fix.** A quick-reply button tapped on a template, or an interactive button or list choice, used to arrive as an empty message: flows could not branch on it and the inbox showed nothing. The button label is now the message text, and flows branch on it with the usual keyword matching. ## Two new chat-flow nodes [#two-new-chat-flow-nodes] **New.** *Ask permission to call* sends the permission card from inside a flow. *Create Bitrix24 activity* adds a to-do on the lead or deal, assigned to the record's responsible person, with a configurable deadline (default 60 minutes) and a notification. A new variable, `{{RESPONSIBLE_NAME}}`, is available in messages and templates. Together these enable the re-engagement pattern after the 24-hour window: an approved template with three buttons, one branch per button, a permission request for the customers who want a call, and a to-do for the recruiter when they accept. ## Buttons and the call-permission card in templates [#buttons-and-the-call-permission-card-in-templates] **New.** The template builder adds buttons: up to three quick replies, one link button and one call button, with a preview. A template can also carry Meta's call-permission card as part of the message — tick *Include a WhatsApp call-permission request* — which is the only way to ask a customer whose 24-hour window has closed. The picker marks such templates and hides the follow-up checkbox for them. When the follow-up checkbox is used on a closed window, the request is no longer refused: it is parked and sent automatically at the customer's next message, and the header reads *Asking…* until then. Meta allows one permission request per customer per 24 hours and two per seven days. ## Known limit [#known-limit] Call logging in Bitrix24's *Call details* requires the `telephony` permission, which ships with app version 3, in Bitrix24 moderation since 17 September. Existing portals will need to update the app from Market once it is approved. # 18 September 2026 (/docs/changelog/2026-09-18) ## Late delivery failures reach the Open Channel [#late-delivery-failures-reach-the-open-channel] **Fix.** On the official WhatsApp Business API, a message sent outside the 24-hour window is accepted by Meta and fails a few seconds later, in a separate delivery status. Bitrix24 had already marked the message as sent, and the connector API offers no way to change that, so the operator believed the customer received it. The CRM widget showed the error; the Open Channel showed nothing. Every such late failure now posts a note into the same Open Channel dialog, once per message, in the portal's language. For the 24-hour case the note reads: *This message was not delivered: the 24-hour window with this customer has closed. To reach them again, send an approved template.* Other Meta error codes get the reason in plain words, with the code in parentheses. The note respects the portal's Open Channel mirroring switch and is never posted twice when Meta retries the webhook. ## Ad attribution always reaches the deal [#ad-attribution-always-reaches-the-deal] **Fix.** Bitrix24 creates the contact when a conversation opens and the deal a little later. When the deal arrived more than about 30 seconds after the ad referral, the campaign data was written to the contact only and the deal stayed empty. The lookup now keeps waiting for the deal for up to five minutes, and an hourly pass copies the attribution from the contact onto any deal created in the last 48 hours that came too late. Nothing is lost: the contact always has it, and the deal inherits it within an hour at most. # 19 September 2026 (/docs/changelog/2026-09-19) ## Passkeys, two-step sign-in and a security page for the developer console [#passkeys-two-step-sign-in-and-a-security-page-for-the-developer-console] **New.** The developer console at [developers.wasync.app](https://developers.wasync.app) now offers three ways to sign in — password, a 6-digit email code, or a passkey (Face ID, Touch ID, Windows Hello or a hardware key) — and a mandatory second step for accounts that hold API keys: a passkey (which satisfies both steps at once), an authenticator app, or one of ten single-use recovery codes. New accounts set up the second step right after creating the account. Existing accounts get a 14-day heads-up before it becomes mandatory; account admins have no grace period. A new **Security** page lists your signed-in devices (revoke any of them), your last 12 months of account activity, and lets you manage your passkeys, authenticator app and recovery codes. Sensitive actions — creating or revoking an API key, rotating a webhook secret, deleting a connection, closing a workspace, or changing your two-step setup — now ask you to reconfirm your second step if it has been more than a few minutes since you last did. Repeated failed sign-in attempts bring up a Cloudflare Turnstile challenge, and ten wrong passwords in 15 minutes apply a temporary 15-minute lock to the account (password sign-in only — a passkey or email code always still gets you in). See [Developer console sign-in](/docs/security/developer-console) for the full picture. # 21 September 2026 (/docs/changelog/2026-09-21) ## Deleting a deal no longer orphans the conversation [#deleting-a-deal-no-longer-orphans-the-conversation] **Fix.** Every WhatsApp conversation is bound to one Bitrix24 record — usually the deal or lead it was last worked from. That binding is what the CRM tag on the chat points at, what the assignee and stage controls act on, and where the chat notes are written. Deleting that deal in Bitrix24 left the binding pointing at a record that no longer existed. The chat kept showing the old tag, the assignee and stage in the chat header went blank — and, invisibly, every chat note from then on was addressed to the deleted deal and reached nothing at all, instead of falling back to the contact. The binding now repairs itself. When the app reads the record it is bound to and finds it missing, it confirms the record really was deleted rather than merely unreadable at that moment, drops the stale binding, and re-matches the conversation the same way an incoming conversation is matched: an open deal first, then an open lead, then the contact. The message that discovered the deletion is written to the CRM too, so no history is lost in between. Nothing to switch on, and no effect on conversations whose records still exist. A record you simply do not have permission to read is never mistaken for a deleted one. # 24 September 2026 (/docs/changelog/2026-09-24) ## Insert field, on every chat-flow message [#insert-field-on-every-chat-flow-message] **New.** Every Message card in Chat Flows (and the escalate/handoff message) has an *Insert field* button under the text. It opens the CRM field list — Deal or Lead, Contact, Company — with search, and a click drops `{{CODE}}` at the cursor. At send time the code is replaced by the record's value. Placeholders were already substituted at send time (`{{NAME}}`, `{{RESPONSIBLE_NAME}}`, any field of the lead or deal); what was missing was a way to discover them. New in the same release: `{{CONTACT_*}}` and `{{COMPANY_*}}` resolve in flows too, including inside a WhatsApp Business template's parameters, and a question step's answer can be inserted as `{{LABEL}}`. A flow that is not attached to a lead or deal offers its own collected answers instead of CRM fields. ## Attach the file stored on the deal or lead [#attach-the-file-stored-on-the-deal-or-lead] **New.** The attachment picker of a chat-flow message step (and of an Automation) has a third source next to *upload* and *link*: **From CRM field**. It lists the file-type fields of the flow's lead or deal; picking one attaches the field, not a file. At send time WASync reads the file stored on that record and sends it, so each customer receives their own contract, invoice or CV. A multiple field sends all its files, five per message at most, in the step's order. If the field is empty on a record, or the file cannot be fetched, the message text still goes out without the file and a short note is written to the record's timeline. Nothing fails silently and nothing is sent half-resolved. ## Values written the way a person would [#values-written-the-way-a-person-would] **Improvement.** Wherever a person reads a CRM value — flow messages, robot messages, Automations text, AI prompts, timeline comments, notifications — it is now formatted: list fields show the item's label instead of its id (a customer had received "282, 284, 286"), dates read `dd.mm.yyyy` (with `hh:mm` for date-time fields), money fields read "100 EUR", yes/no fields read Yes/No in the message's language, file fields read "1 file" or "3 files". Values written back into Bitrix24 by a flow (set-field steps, router conditions) stay raw on purpose. ## Robot panel: custom fields show their name [#robot-panel-custom-fields-show-their-name] **Fix.** In the robot panel's field picker, custom fields (`UF_*`) showed their technical code instead of their name. Bitrix24 reports the code as the field's title and keeps the name in a separate label; the picker now reads the label. The inserted placeholder is unchanged, so saved automations keep working. # 25 September 2026 (/docs/changelog/2026-09-25) ## Who sees which chats [#who-sees-which-chats] **New.** A "WASync Chat" page in the app's sidebar lets an administrator decide what each employee sees in the WASync Chat inbox and in the WhatsApp tab of the CRM: **all chats** of the numbers they may use (the default, and today's behaviour), **their department** (the records of everyone who shares a Bitrix24 department with them — a team leader's view), or **only their own records** (the leads, deals and contacts they are responsible for). The scope is set per person on the Staff page, with a portal-wide default; Bitrix24 administrators always see everything. The rule is enforced on the server, not just hidden in the interface: the conversation list, search, the conversation itself, every action on it and every send are checked. If Bitrix24 cannot say who owns a record, a scoped employee sees nothing rather than everything. Nothing changes for existing portals until an administrator sets a rule. ## New chats from unknown numbers [#new-chats-from-unknown-numbers] **New.** On the same page, a portal can decide what happens when a message arrives from a number that is not yet in the CRM: nothing (the default), or WASync creates the lead and assigns it **round-robin** to an employee from a chosen list, or to one fixed person. The chat is then visible to that employee and their department. Numbers already in the CRM are linked to their existing record instead; connections bound to a Bitrix24 Open Line are left to Bitrix24, which creates the record there. ## Slot subscriptions: no more reminders that do not apply [#slot-subscriptions-no-more-reminders-that-do-not-apply] **Fix.** Workspaces on a slot subscription renew automatically, yet their connections were receiving "your licence expires" reminders, and a renewal extended the slots without extending the connections holding them. Both are fixed: reminders skip every connection covered by a live slot, and a renewal carries the attached connections to the new period end. # 29 September 2026 (/docs/changelog/2026-09-29) ## One thread per contact, whichever number they wrote to [#one-thread-per-contact-whichever-number-they-wrote-to] **Improved.** When a customer has written to two or more of a workspace's WhatsApp numbers, WASync Chat keeps a single conversation with the whole history of that person. It now says which number each message belongs to: a small "via +number" badge on messages that came through a number other than the one selected for replying. The composer always shows the number a reply will go out from and, with two or more numbers, becomes a picker — it defaults to the number the customer wrote to last, and marks a WhatsApp Business number as "templates only" while it is outside the 24-hour window. Every send path follows the chosen number: text, files, templates, voice notes, notes, takeover and the stage or assignee changes written to the CRM. ## New users saw their first two hours of messages as read [#new-users-saw-their-first-two-hours-of-messages-as-read] **Fix.** An employee opening WASync Chat for the first time had every incoming message of the following two hours counted as already read, in any conversation they had not opened themselves; on workspaces with team-shared read status, the team badge inherited it. The cause was a database session time-zone shift on the moment the inbox was first opened. It is fixed for all workspaces with nothing to configure. The rule is unchanged: whatever existed before a person's first visit is read, and unread accrues from that visit onward. The same correction applies to the **chat export** — its date range was two hours off at each end — and to the **Bot** tab's activity window. # 30 September 2026 (/docs/changelog/2026-09-30) ## Media in EU object storage, served through signed links [#media-in-eu-object-storage-served-through-signed-links] **Changed.** Images, voice notes, videos and documents exchanged over WhatsApp are now stored in an EU-jurisdiction object store (Cloudflare R2) and handed out only through **short-lived signed links** (15 minutes for the CRM widget and WASync Chat, 30 minutes for a send in progress, 24 hours for a chat export). The same 90-day retention applies, and deletion removes the object store copy too. Nothing changes for what you see in Bitrix24, Pipedrive or WASync Chat; links you copied earlier keep working until they expire. ## Deleted and edited WhatsApp messages on QR connections [#deleted-and-edited-whatsapp-messages-on-qr-connections] **Fix.** When a customer deleted a message for everyone or edited it, the change reached us with a short message id we did not recognise, so the conversation in WASync kept the original. Both now apply within seconds: a deleted message shows as deleted and an edited one shows the new text with an "edited" label. ## Health checks that reach the database [#health-checks-that-reach-the-database] **Improved.** The `/api/health` endpoint now runs a real database query and reports the deployed build; a deploy only takes traffic once both agree. Background jobs run on a single leader, which is what lets a second application host come next. ## Voice notes through the WhatsApp Business API [#voice-notes-through-the-whatsapp-business-api] **Fix.** A voice note recorded in the CRM widget or WASync Chat and sent through a WhatsApp Business API number reached the customer as a plain audio attachment, without the waveform bubble. It now arrives as a real voice note, the same way it already did on QR-connected numbers. ## A number that is already connected cannot be connected twice [#a-number-that-is-already-connected-cannot-be-connected-twice] **Changed.** Scanning the QR code with a phone whose number is already connected on the same workspace used to create a second connection that took over the first one, and both imported the conversation history — which showed up as duplicated notes in the CRM. The second scan is now refused with a clear message, in every language of the app, and the existing connection keeps working. If the existing connection shows as disconnected, open it and click Reconnect instead of creating a new one. # 6 October 2026 (/docs/changelog/2026-10-06) ## Required fields before a stage change [#required-fields-before-a-stage-change] **New.** Bitrix24 enforces its "required on this stage" fields only in its own form, never when a stage is changed through the API, so closing a lead from the chat could leave fields such as the reason for closing empty. An administrator now defines, in WASync Chat rules → "Before moving to a stage, ask for these fields", which fields must be filled for each pipeline and stage (leads and every deal pipeline). When an operator changes the stage from WASync Chat, a panel asks for those fields, pre-filled from the record; the stage changes only once they are filled, in a single CRM update, and Cancel leaves it as it was. Chat Flows are not affected, and the CRM widget has no stage picker, so Bitrix24's own card applies its rule there. ## Templates keep their header image [#templates-keep-their-header-image] **Improved.** WhatsApp Business API templates with an image, video or document header now keep the file uploaded when they were created. Every send — CRM widget, WASync Chat, Chat Flows, Automations and the template robot — uses it by default: the operator sees "Template image" preselected with a preview and can still change it before sending. For templates approved earlier or created in Meta's own interface, "Set default image" in the template list sets it once. Meta keeps the sample only for approval and asks for the file again at every send, which is why this was needed. ## Chat visibility after a lead or deal is closed [#chat-visibility-after-a-lead-or-deal-is-closed] **New.** A new administrator option in WASync Chat rules, "Closed leads and deals", removes a conversation from its former responsible employee N days after the lead or deal is closed (0 = immediately). It can optionally ignore the contact's responsible, so only open leads and deals decide who sees a chat. The chat reappears for whoever receives the customer's next lead or deal. Administrators and people who see all chats are not affected. Under "New chats from unknown numbers" there is also a new option, "Also create a lead when the number is already a contact but has no open lead or deal": the lead is linked to the existing contact and assigned by the same rule (fixed person or round-robin). The "Create lead" button in WASync Chat now appears on conversations linked only to a contact as well. Both options are off by default. ## Chat Flows editor: first step of the redesign [#chat-flows-editor-first-step-of-the-redesign] **Changed.** The Start step is now unique and cannot be deleted. It describes in plain sentences when the flow starts — for example "Starts when a customer writes first on +…, with any message" or "Once per customer. Stops when a colleague replies" — with a "Change when it starts" button. Steps are edited in a side panel while the canvas stays visible, instead of a modal. The Branch step takes conditions as Field · Condition · Value, with a searchable field picker grouped by customer answers, deal or lead, contact, company and ad fields, and list values (stage, source, user, yes/no) chosen by name. Every step that used to ask for an ID now uses pickers with names, and the legacy "Action" step is no longer in the palette. The palette is grouped and searchable, and the top bar has an editable name, a live "N problems" pill that jumps to the step, Undo/Redo and a "Flow settings" panel. The whole editor is available in all 20 languages. Draft and published versions are not part of this step. ## "Customer writes first" no longer starts on a reply to your team [#customer-writes-first-no-longer-starts-on-a-reply-to-your-team] **Fix.** If someone on the team wrote to a customer in the previous 72 hours — from the CRM widget, WASync Chat, the Open Line or the business phone — the customer's answer is now treated as a reply, and the inbound flow does not start. Messages sent by flows, automations or robots do not count, so a flow still starts when the customer truly writes first. This is on by default for every existing flow; the trigger's "Don't start when we wrote first" option turns it off or changes the window (1–168 hours). ## Leads created by WASync come with a contact and the form data [#leads-created-by-wasync-come-with-a-contact-and-the-form-data] **Improved.** Every lead WASync creates — automatically at the first message, when the operator writes first, or from the "Create lead" button — now gets a linked contact: an existing one found by phone or email, otherwise a new one. When the first message is a Meta lead-form message from a Click-to-WhatsApp ad, its data is mapped: full name to first and last name and the lead title, email to email, a different phone to a secondary phone, and every other question and answer to a comment on the lead's timeline. On existing leads only empty fields are filled; nothing is overwritten. ## Every contact of a lead or deal links to that record [#every-contact-of-a-lead-or-deal-links-to-that-record] **Improved.** When a lead or deal has several contacts, the WhatsApp conversation of any of them is now linked to that lead or deal, not only the primary contact's. An open deal wins over an open lead, and a closed lead never wins over a contact. This applies to new conversations and to the daily re-check of existing links. ## Ad attribution reaches every open deal [#ad-attribution-reaches-every-open-deal] **Fix.** When a customer's first message arrives without Meta's ad data and the referral only comes with a later message, the campaign and ad fields are now written to the contact and to every open deal without attribution opened in the previous 24 hours, not only the first one. An older deal already attributed to a previous ad no longer blocks the new one. An existing attribution is never overwritten. ## Pipedrive: subscribing from the WASync panel [#pipedrive-subscribing-from-the-wasync-panel] **Fix.** Pipedrive customers can subscribe again from the WASync panel. Pay opens Stripe Checkout in a new tab — WhatsApp QR $19 or WhatsApp Business API $29 per number per month, for 1, 3, 6 or 12 months, the same prices as on Bitrix24 — and the panel updates itself when the payment completes. Account & Plans shows each number's plan and billing state, with "Manage billing" for the card, invoices and cancellation at the end of the period. Paying does not reconnect a number that was disconnected when its trial ended; scan the QR code again. # 7 October 2026 (/docs/changelog/2026-10-07) ## Create or link a lead from WASync Chat [#create-or-link-a-lead-from-wasync-chat] **Improved.** "Create lead" in WASync Chat first shows what the CRM already has for that person under "Already in the CRM": existing leads (open and closed, closed ones tagged "Closed") found by phone number and by the linked contact, plus the contact's open deals, each with a "Link" button. "Create new lead" sits below the list. On conversations linked only to a contact the button reads "Create or link lead", and "Link to record" is available there too. Operators see only the records their Bitrix24 role allows. Nothing is created or linked automatically. ## Chat Flows: "Assign to" can rotate within a group [#chat-flows-assign-to-can-rotate-within-a-group] **New.** The "Assign to a colleague" step has two modes: "One person", as before (existing flows are unchanged), or "Rotate within a group". In rotation mode the administrator ticks up to 50 employees in the step's side panel, and each new conversation that reaches the step goes to the next person in the list. Every step keeps its own rotation, and saving the flow again does not restart it. Employees deactivated in Bitrix24 are skipped; if nobody in the group is active, the record keeps its current responsible and a timeline note explains why. A customer who passes the same step twice in one conversation stays with the same person, and a test run shows who is next without using up a real turn. ## Long messages on the WhatsApp Business API [#long-messages-on-the-whatsapp-business-api] **Fix.** WhatsApp's official API accepts at most 4,096 characters in one text message, so longer texts written by an operator were not delivered at all. They are now sent as several WhatsApp messages in order, cut at the end of a paragraph (or else a line, a sentence or a word), with the operator's name only on the first one and delivery ticks on each. This works from the Open Line, the CRM widget, WASync Chat, Chat Flows and Automations; in Bitrix24 the operator still sees the single original message. The limit is 10 messages (about 40,000 characters) — beyond that the operator is told the message is too long and nothing is sent. Templates and file captions keep their own limits. The developer API does not split: a text over 4,096 characters is answered with the error `text_too_long`. ## Calls you place: "Ringing…" until the customer answers [#calls-you-place-ringing-until-the-customer-answers] **Fix.** When an operator calls a customer from the CRM on a WhatsApp Business API number, the call window shows "Ringing…" with the customer's name and number while the phone rings, and switches to "In call" only when the customer picks up. The timer starts then, so the duration is talk time. The call saved in Bitrix24 follows the same rule, and a call that was not picked up is saved as an unanswered outgoing call with no duration. The operator is told why a call was not answered: "No answer", "Call declined" or "Line busy" (the last two only when WhatsApp reports them). Incoming calls are unchanged. ## Incoming calls: the team is rung when the responsible is offline [#incoming-calls-the-team-is-rung-when-the-responsible-is-offline] **Fix.** When a known customer called and their responsible employee was offline in Bitrix24, the call was saved as missed straight away. It is now offered to the other online operators of the number's Open Line, all at once, and if none is online, to the online employees with access to the number in Connections → Staff. Only when nobody is online is the call saved as missed, on the responsible employee, as before. An online responsible employee is still rung alone, and only people already allowed to handle the number are ever rung. ## The customer's WhatsApp photo and name in Bitrix24 [#the-customers-whatsapp-photo-and-name-in-bitrix24] **Improved.** On QR-connected numbers, WASync now asks for the customer's WhatsApp profile photo as their message arrives, so the Open Channel chat is created with the photo from the first message. The message is never held for it: if the photo is not available within about a second and a half, it is used from the next message on. New QR conversations also arrive in the Open Channel under the customer's WhatsApp name instead of their phone number. **New.** Settings → "CRM contact name and photo" → "Copy the WhatsApp name and profile photo to the CRM contact when they are empty" is off by default. When an administrator turns it on, WASync fills the name and photo on the linked Bitrix24 contact only when they are missing, never over anything the team entered, once per contact, with an audit log entry. On WhatsApp Business API numbers only the name is available, because Meta does not provide customer photos. A lead or deal without a contact is not affected, and a name the customer changes later in WhatsApp is not re-synced. # 8 October 2026 (/docs/changelog/2026-10-08) ## Answer WhatsApp calls in Bitrix24's call card [#answer-whatsapp-calls-in-bitrix24s-call-card] **New.** A WhatsApp call now rings in Bitrix24's own call card as an ordinary incoming call: the customer's name and number as the title, "WhatsApp" and the line under it, and Bitrix24's Answer and Ignore buttons. Answer takes the call right there — the card switches to connected, Bitrix24's timer runs, and Mute and End work from the card. Ignore declines the call. If another operator answers first, the other cards show "Taken by" with that person's name and close. When the call ends the card shows why for a few seconds. The call lives in the browser tab where it was answered; the card says so, and the browser asks before the tab is closed or reloaded. If the browser refuses the microphone, the WASync panel opens and offers the call window as before. The separate call window still exists for that case, when the card does not appear within 3 seconds, and for calling a customer back from the CRM widget. Calling back from the card's own Call button is not available yet; use the widget's Call button. Card texts are in the operator's language. ## The conversation inside the call card [#the-conversation-inside-the-call-card] **New.** The call card's tab for a WhatsApp call is now named "WASync" (it was "WhatsApp"). It shows a status line (incoming, connected with a timer, ended) and, under it, the WhatsApp conversation with the caller on the number they called: read the history and write while the phone rings or during the call. Messages sent there go exactly where messages from the CRM widget go, and new messages from the customer appear by themselves. An operator without access to the called number sees only the call status. The conversation stays in the tab after the call until the card is closed. ## Who is rung for an incoming call [#who-is-rung-for-an-incoming-call] **Changed.** Everyone who handles a number can now be rung for its calls: the operators of its Open Line or the employees with access to it in Connections → Staff — either is enough. Until now a responsible manager with Staff access but not in the Open Line queue could miss a call while online. When a known customer calls, their responsible employee is still rung alone first if they handle the number and are online. New: if nobody answers within 8 seconds — or straight away if the responsible is missing, offline or does not handle the number — everyone online who handles the number is rung at once, up to 5 people, while the responsible's card keeps ringing. The first to answer takes the call. Bot users are never rung, and if nobody who handles the number is online the call is saved as missed, as before. The 8 seconds are fixed. ## Each WhatsApp number creates its own lead [#each-whatsapp-number-creates-its-own-lead] **New.** Under "New chats from unknown numbers" (when that rule is on), a new option, off by default, makes an open lead or deal count for a conversation only if it was created or linked from the same WhatsApp number. If a customer writes to number X while their open deal came from another number or another tool, WASync creates a new lead for X — assigned by the rule, attached to the customer's existing CRM contact, carrying the Click-to-WhatsApp ad when there is one — and leaves the old record untouched. Later messages on X go to that same lead. With the option on, the CRM timeline, the record shown on the conversation row and the stage filter follow the record of the number the last message came through. Records created before 8 October 2026 have no number and count as coming from another number. ## The employee filter follows what each person may see [#the-employee-filter-follows-what-each-person-may-see] **Changed.** The "All employees" filter above the WASync Chat list now offers only the colleagues whose conversations the person is allowed to see. Someone set to "Only my records" no longer gets the filter, and someone set to "My department" sees only colleagues from their department. Administrators and people who see all chats get the same list as before. Nothing to configure: it follows the visibility set in WASync Chat rules. # 9 October 2026 (/docs/changelog/2026-10-09) ## A chat flow per Meta ad [#a-chat-flow-per-meta-ad] **New.** The Start step of an inbound flow gains "From a specific ad": list the Meta ad ids the flow should answer (for a campaign, list all of its ad ids; an empty list means any ad). A number can now have several inbound flows, and the one that starts is chosen by how specific it is: the matching ad first, then keywords, then "any message". A flow bound to the number beats a workspace-wide one, and within the same level the older flow wins. A message from an unlisted ad, or from no ad, falls back to the keyword or any-message flow. A human reply stops every inbound flow set to stop on it. The editor does not yet warn when the same ad id is listed in two active flows, and the simulator cannot yet pretend a message came from an ad. ## Insert a step on a connection line [#insert-a-step-on-a-connection-line] **New.** In the Chat Flows editor, hovering a line between two steps shows a "+" next to the "×". It opens the same step picker as the "+" on a step and inserts the new step in between, keeping the branch or answer option the line carried. The new step lands halfway along the line with its panel open. ## Flows no longer advance on a re-delivered message [#flows-no-longer-advance-on-a-re-delivered-message] **Fix.** WhatsApp can deliver the same incoming message twice, for example after a session re-sync or a retry. The copy was treated as a new answer from the customer, so a flow could move on by itself. Copies are now ignored by flows, lead creation and automations; the conversation already showed the message once. ## Choose who is rung first for incoming calls [#choose-who-is-rung-first-for-incoming-calls] **New.** Settings → "Incoming calls" (administrators) sets who is rung first when a known customer calls: "The contact's responsible person" (the default, as before), "The responsible person of the most recent open deal or lead" (falling back to the contact's responsible when there is none), or "Both at once". The rest is unchanged: only people online in Bitrix24 who handle the number are rung, and after 8 seconds without an answer everyone online who handles the number is rung too. # 10 October 2026 (/docs/changelog/2026-10-10) ## Quick replies with "/" [#quick-replies-with-] **New.** Quick replies are saved answers with a short command name, either for the whole team or personal. They work in every chat: WASync Chat and the WhatsApp tab in the CRM. Type `/` at the start of the message box or after a space, and a picker opens with every reply **already filled in for the open customer**. Keep typing to filter (`/cuo`), choose with ↑ and ↓, and press Enter or Tab to insert — a reply is never sent by itself, so you can edit it first. Esc closes the picker. The ⚡ button next to the box does the same for mouse and phone users, and a pencil in the picker edits a reply in place. **Variables** are filled in on the server when the reply is inserted: * `{{greeting}}` — Good morning, Good afternoon or Good evening in the customer's language and at the customer's local time, both taken from the country of their phone number (UTC when the country is unknown). * `{{contact.first_name}}`, `{{contact.name}}` — the customer. * `{{me.first_name}}`, `{{me.name}}` — the person sending. * `{{record.title}}`, `{{record.stage}}`, `{{record.responsible}}` — the lead or deal linked to the conversation. * `{{crm.FIELD}}` — any CRM field of that lead or deal, for example `{{crm.OPPORTUNITY}}`. A reply can carry **versions in other languages**, and the picker chooses the version that matches the country of the customer's phone number. **Save from the conversation.** "⋯ → Save as quick reply" on any message you sent turns it into a quick reply, with the customer's name, the greeting and the record title replaced by variables automatically. **Improve as you go.** Insert a reply, change it and send it, and WASync asks "Update «/x» with this version?", so the saved text keeps up with how you actually write. **The Quick replies page** (⚡ in the app menu, for administrators and anyone with write access to Settings) lists Team and Mine replies, with add, edit and delete, language versions, how often and when each was last used, and "promote to team" for a personal reply. Everything is available in all 20 languages. Quick replies are not the canned responses of Bitrix24 Open Lines, which live in the Contact Center and do not fill in CRM data. AI suggestions for replies are not part of this release. ## Learning quick replies inside the product [#learning-quick-replies-inside-the-product] **New.** Getting started needs no tutorial: * **Hover card on ⚡** — "Type / in the box or click here. Enter inserts, then edit before sending", with an example. The empty message box reads "Write a message… (/ for quick replies)". * **Empty states that teach** — an empty picker shows the two ways to get a first reply (⋯ → Save as quick reply, or "Create one now"). Typing `/xyz` with no match offers "Create «/xyz»" and inserts the new reply right after it is saved. A key legend sits in the picker footer (hidden on touch screens). * **Quick replies page** — a two-line introduction and a three-step "How it works" (Create → Use → Improve) with "?" explanations. * **Starter kit** — while the list is empty, "Add these 4" offers four suggested replies with variables: a greeting, a thank-you, a follow-up and a request for details. * **Live preview** — the reply form shows the text with sample values as you type. * **Placeholder chips** — when a reply contains hand-typed placeholders such as "\[nombre]", "\[asesor]" or "\[saludo]", a chip offers the matching variable in one click. * **One-time tip** — after the third hand-typed message in a session, a tip above the box suggests saving it ("Save this one?" / "Got it"); once dismissed, it does not come back for that person. * **Checklist** — the Getting started checklist on Connections gains "Create your first quick reply". ## "Each number creates its own lead": no duplicate for existing records [#each-number-creates-its-own-lead-no-duplicate-for-existing-records] **Fix.** With the option on, a customer whose open lead had been created by Bitrix24's Open Channel, or before the option was switched on, got a second lead on their next message, assigned to the fixed person. Now, when a contact has only ever written to one of the workspace's numbers and their open lead or deal was created after their first message there, that record counts and nothing new is created. A record older than the first message, such as a deal from another channel, still gets its own new lead, as designed. ## The "WhatsApp disconnected" alert now says why [#the-whatsapp-disconnected-alert-now-says-why] **Improved.** When WhatsApp removes a linked device right after the number has messaged many new contacts in a short time, the "WhatsApp disconnected" e-mail and Bitrix24 notice now include the reason: how many new contacts were messaged, that WhatsApp usually removes a linked device for this (especially for a new number or when the recipients had not written first), and what to do next — reply to people who write to you, add only a few new contacts a day, and send bulk or promotional messages from a WhatsApp Business API number, otherwise WhatsApp can block the number. Available in the eight languages of the alert. ## A QR number moved to the Cloud API no longer alerts as "disconnected" [#a-qr-number-moved-to-the-cloud-api-no-longer-alerts-as-disconnected] **Fixed.** When a number that was connected by QR code is later connected through the WhatsApp Business API on the same workspace, the old QR connection is retired automatically: no more "WhatsApp disconnected" alerts for it and no endless reconnection attempts. Scanning the number by QR again revives it. # 11 October 2026 (/docs/changelog/2026-10-11) ## No more doubled timeline comments [#no-more-doubled-timeline-comments] **Fixed.** A reply sent from the Open Channel chat was written to the CRM timeline twice: once when it was sent, and once more when WhatsApp echoed the same message back. A message WhatsApp delivered twice could do the same. Both copies are now ignored; a message typed on the phone or in WhatsApp Web is still logged once, as before. ## One comment per message, on the conversation's record [#one-comment-per-message-on-the-conversations-record] **New option.** Until now every WhatsApp message was logged on every lead, deal, contact and company that carries the customer's number, which on a busy workspace can mean three or four copies of the same comment. Settings → **Log WhatsApp messages in the CRM timeline** gains a second checkbox, **Write the comment only on the conversation's record**. With it on, WASync writes one comment per message, on the record the conversation is linked to: the open deal or lead, otherwise the contact. With "Each number creates its own lead" on, that is the record of the number the message went through. The default is unchanged. ## Sent messages are credited to the operator [#sent-messages-are-credited-to-the-operator] **Changed.** Bitrix24 credits a timeline comment to the user whose authorisation wrote it, and ignores any author we pass, so every comment used to appear under the person who installed WASync, and "last activity" on a record always showed that person. For messages **sent** by an operator, from the Open Channel chat, WASync Chat or the WhatsApp tab in the CRM, the comment is now written with that operator's own authorisation, so Bitrix24 shows them as the author. This works for everyone who has opened WASync at least once; otherwise, and for every received message, robot send and automation, the comment is written by the application's user as before. If you want that user to be a dedicated service account, create it as a portal administrator and open WASync once with it. ## Move a conversation to another record [#move-a-conversation-to-another-record] **New.** In WASync Chat, a conversation that is already linked to a lead or a deal gets a **Change record** button next to the responsible person. It opens the same search as "Link to record"; pick the lead, deal or contact, confirm, and the conversation moves. Only WASync's link changes: the old record keeps its history and nothing in Bitrix24 is edited. New messages are logged on the new record. With "Each number creates its own lead" on, the link of that number is replaced too, and the target must be a lead or a deal. # 12 October 2026 (/docs/changelog/2026-10-12) ## "Any message" flows wait for a new conversation [#any-message-flows-wait-for-a-new-conversation] **Fixed.** When several inbound flows run on one number (one per Meta ad plus a general one), the general flow, set to *Any message — the first message of a new contact*, could start the moment another flow finished: a customer who came from an ad, answered the ad flow's questions and was handed to a person received the general flow's greeting on his next "Ok". Now the general flow starts only when no flow on that conversation ended in the last 72 hours (the same window as *Don't start if we wrote first*, adjustable per flow). A flow that was completed, handed to a person or cancelled counts; one that was closed for inactivity does not. Flows started by an ad referral or a keyword are unaffected: those are explicit intents and still start. # 13 October 2026 (/docs/changelog/2026-10-13) ## MCP: send a file from an AI assistant [#mcp-send-a-file-from-an-ai-assistant] **New.** The [MCP server](/docs/guides/mcp) has a sixth tool, `send_whatsapp_file`. An assistant can send a document, image, audio or video (up to 5 MB, with an optional caption) from one of the authorized numbers, the same way `send_whatsapp_message` sends text. Give the file as a direct `https` link in `url`, or as base64 in `data` with its `mimetype`. A link is preferred: WASync downloads it, and links that point at private networks, at WASync itself or at a web page rather than a file are refused. Like the text tool, it needs the send permission and the assistant is told to confirm the recipient and the file first, because a delivered file cannot be recalled. Nothing changes for existing integrations: `send_whatsapp_message` and the other four tools are untouched, and the REST `POST /messages` media send keeps its larger limit. # 14 October 2026 (/docs/changelog/2026-10-14) ## Chat Flows: HTTP request step [#chat-flows-http-request-step] **New.** A flow can ask an external system over HTTPS and use the answer: method, URL and body with `{{VARIABLES}}`, headers (secret ones stored encrypted), and a mapping from JSON paths to flow variables. Two outgoing edges: success and error. The request is performed by a dedicated Cloudflare Worker, never by WASync's servers, under a fixed policy (https only, public hosts, 10 s, 256 KB). See [HTTP request step in Chat Flows](/docs/guides/chat-flows-http-request). No change to the REST API or the MCP tools. ## Guide: bring a number from another provider [#guide-bring-a-number-from-another-provider] **New page.** [Bring a number from another provider](/docs/guides/bring-your-own-number) walks through the in-app wizard for moving a WhatsApp Business API number you already run elsewhere onto WASync: what comes with the number and what stays behind, the checks the wizard runs before the move, exactly what to choose in Meta's own window, and what to do right after (templates, the new two-step PIN, when to cancel the old provider). No API change. # 15 October 2026 (/docs/changelog/2026-10-15) ## Smart Processes (SPA) [#smart-processes-spa] **New.** WASync now works on Bitrix24 Smart Process items as it does on leads and deals. Rolled out in four steps between 14 October 23:30 and 15 October (Bucharest). * **Robots on SPA automation rules.** *Send WhatsApp message*, *Send WhatsApp template*, *Start a Chat Flow* and the AI robot run from a process's automation rules; the recipient is the item's client (primary contact, other contacts, company). Before this release the robots were listed there but failed with "no phone". * **WASync tab in the item card**, added automatically for existing processes, for processes created later, and on *Reinstall placements*. A process without the *Client* field gets an explanation instead of an error. * **Conversations linked to items** in WASync Chat (type selector, search as the operator), item responsible honoured by "Assigned to" and "only my records", timeline comments on the item, closed items (final stages) treated like won or lost deals. * **Chat Flows on a process**: fields read and filled (custom fields included), *Set stage → Move item*, activities, assignment; `{{record.stage}}` renders the stage name. * **Ad attribution** fills the item's native UTM fields when a click-to-WhatsApp conversation is linked to it. Guide: [Smart Processes (SPA) in WASync](/docs/guides/smart-processes). No change to the REST API or the MCP tools; linked items appear as record type `dynamic_` in WASync's data. ## Re-contact window after a closed lead [#re-contact-window-after-a-closed-lead] **New option** under *Chat rules → New chats from unknown numbers*: **Re-contact window after a closed lead (hours)**, 0 (off) to 720. When a customer writes again within that many hours after their lead was marked **lost**, the conversation goes back to that lead instead of a new lead being created. A second switch, **Reopen the lost lead when the client writes back**, moves the lead back to an open stage so it shows up again in the agent's list: the first open status of your lead pipeline (usually *New*) or a stage you pick in **Stage the lead returns to**. Without it the lead stays closed and the messages land in its timeline. The window applies to leads created from new chats (fixed person or round-robin), to the "already a contact but no open lead" option, and to Chat Flows that create leads. Leads that were **won** (converted) are not affected: the conversation already follows the deal made from them. Off by default on every portal. Guide: [Leads from WhatsApp chats](/docs/guides/leads-from-whatsapp-chats). # 16 October 2026 (/docs/changelog/2026-10-16) ## Stage picker in WASync Chat [#stage-picker-in-wasync-chat] **New option** under *Chat rules → Stage picker in WASync Chat*, for Bitrix24 administrators: choose who may change the CRM stage of a conversation from the WASync Chat header. * **All operators** (default, unchanged behaviour). * **Admins only**: other operators see the current stage as a read-only label. * **Hidden (read-only for everyone)**: nobody changes the stage from WASync Chat; the current stage stays visible. The restriction is enforced on the server, not only in the interface, and Bitrix24 CRM permissions still apply on top of it. Required-fields rules for stage changes are unaffected. No change to the REST API or the MCP tools. Guide: [Leads from WhatsApp chats](/docs/guides/leads-from-whatsapp-chats). ## Bring a number without a WABA connection [#bring-a-number-without-a-waba-connection] **Improved.** The **Bring a number** wizard no longer needs an existing WABA connection. Open it from the link inside **Connect WhatsApp Business API** or from the link on the Connections page. Without a WABA connection, the five prerequisite checks become a checklist you confirm yourself; once a number is connected, later moves get the automatic checks. Guide: [Bring a number from another provider](/docs/guides/bring-your-own-number). # 18 October 2026 (/docs/changelog/2026-10-18) ## What's new, inside the app [#whats-new-inside-the-app] **New.** The sidebar of the WASync app in Bitrix24 has a **What's new** entry. It opens the list of product releases, newest first, each with a version such as `2026.10.18`, the date, and a few lines on what changed, with a *Learn more* link to the matching page here when a change needs more than a sentence. A small dot on the entry means there are releases you have not opened yet; it disappears when you open the list, separately for each person. Entries that only an administrator can act on (a Chat rules setting, for example) are shown to administrators only. The list is translated into every language the app offers.
Version numbers are dates: `2026.10.18` is the release of 18 October 2026, the same date as this page. A second release on the same day would be `2026.10.18.2`. Nothing on your side needs an update; the app is always the current version. ## Choose the source of the record a flow creates [#choose-the-source-of-the-record-a-flow-creates] **New.** In the Start card's *When it starts* section, lead and deal flows now have a **Source** selector listing your CRM sources. The chosen source is written on the contact, lead or deal the flow creates, so a flow can, for example, leave the source on a placeholder such as "not selected" for your team to fill in later, or stamp a campaign source of its own. The default, *Automatic*, keeps today's behaviour: the record takes the source of the WhatsApp Open Channel it came through. Nothing changes on existing flows until you pick a source. A record the flow reuses instead of creating keeps its own source.
## No second lead for a customer you are already working [#no-second-lead-for-a-customer-you-are-already-working] **Fixed.** A lead flow that creates its record when it starts used to add a new lead even when the customer's contact already had an open lead or deal. The flow now binds to that open record instead (an open lead as a lead, an open deal as a deal) and creates a lead only when there is none. This is the same rule the "new chats from unknown numbers" lead follows, and the mirror of what deal flows already did with an open deal in their pipeline.
## Records created by a flow follow your "new chats" rule [#records-created-by-a-flow-follow-your-new-chats-rule] **Fixed.** A contact, lead or deal created by a flow when it started was owned by the person who installed WASync, because Bitrix24 assigns a record to the app's user when no responsible is given. With an Open Channel that routes to the CRM responsible, that person then received every conversation of that customer. Flow-created records now take the responsible from the same *New chats from unknown numbers* rule in Chat rules (a fixed person or round-robin); with the rule off, nothing changes. ## Find a step, and lines that light up [#find-a-step-and-lines-that-light-up] **New, in the flow editor.** A **Find a step** box in the top bar searches every step by name, message text, question options and keywords, branch names, assignee and step type. Enter jumps to the next match and Shift+Enter to the previous one; the card is selected, centred and flashes for a moment. Ctrl+F (⌘F on a Mac) while on the canvas focuses the box. When a step is selected, its incoming and outgoing lines turn green and come to the front while the other lines fade, so a long connection can be followed on a large canvas. # 19 October 2026 (/docs/changelog/2026-10-19) ## WhatsApp from CRM Marketing and automation rules [#whatsapp-from-crm-marketing-and-automation-rules] **New.** WASync registers itself as a Bitrix24 message provider, **WASync WhatsApp**. Choose it in a CRM Marketing campaign under *Send using*, in the **Send message** automation rule, or in the message button of a lead, deal, contact or company (Bitrix24 labels that button *SMS*). The customer receives a WhatsApp message from your WASync number, and it lands on the record's timeline. How it chooses the number and what happens on a Business API number outside the 24-hour window: [WhatsApp from CRM Marketing and automation rules](/docs/product/crm-records#whatsapp-from-crm-marketing-and-automation-rules). Existing portals get the provider when the app is next updated from the Market, or on request. ## Campaign and ad set on conversations from ads [#campaign-and-ad-set-on-conversations-from-ads] **New.** Give WASync a Meta Ads token (System User, `ads_read`) in Settings and every conversation from a Click-to-WhatsApp ad carries the campaign id in `UTM Campaign`, the ad set id in `UTM Term` and the ad id in `UTM Content`, with their names on the timeline note. Without a token nothing changes. [Campaign and ad set on conversations from ads](/docs/guides/meta-ads-campaign-attribution). ## Flows and "Each number creates its own lead" [#flows-and-each-number-creates-its-own-lead] **Fixed.** With the option on, a flow that starts for a known customer reused any open lead or deal of the contact, including one from another channel. It now reuses only the record that belongs to the number the customer wrote to, otherwise it creates the number's own lead. [Which record a flow creates or binds to](/docs/product/chat-flows#which-record-a-flow-creates-or-binds-to). ## Reliability [#reliability] * **Fixed.** On portals with many advisors online at once, the WASync Chat list asked Bitrix24 for the responsible person of every conversation on every refresh and hit Bitrix24's request limit at the start of the day, which also refused sign-ins and new leads for a few minutes. The list now reads from its cache. * **Fixed.** Automation rules (*Send WhatsApp Message*, *Send WhatsApp Template*) stopped working on portals where the portal's first user had been deactivated. They now run under the user who installed WASync. * **Fixed.** An incoming WhatsApp message that arrived in the few seconds of a WASync deployment could be lost. The message is now kept and saved as soon as the deployment settles. # 20 October 2026 (/docs/changelog/2026-10-20) ## A refused send outside the 24-hour window says why [#a-refused-send-outside-the-24-hour-window-says-why] **Fixed.** On a WhatsApp Business API number, typing to a contact who had never written (or whose only "incoming" item was a missed call) left the composer open; the send was refused by the 24-hour rule and the message simply disappeared. Now the composer locks for such contacts with the explanation and the **Pick a template** button, in WASync Chat and in the CRM tab alike, and if a send is still refused the reason stays on screen until the customer replies. [Templates on Business API numbers](/docs/product/wasync-chat#templates-on-business-api-numbers). ## A closing message when a run stops for inactivity [#a-closing-message-when-a-run-stops-for-inactivity] **New.** **If no reply** has a fourth field, **When the run closes, send this message**, both in Flow settings and on each question. Write something like "We didn't hear back, so this conversation was closed. Whenever you want to continue, just send us a new message here." and the customer receives it the moment the run closes. Leave it empty to close silently, as before. The preview simulator plays it after the close. [Inactivity reminders and closing](/docs/product/chat-flows#inactivity-reminders-and-closing). ## The reminder is the bot's message, not your team's [#the-reminder-is-the-bots-message-not-your-teams] **Fixed.** The inactivity reminder was stored like a message typed by a person. For a customer who answered only after the run had closed, that made their reply look like an answer to your team, and **Flows do not start on a reply to your team** kept the flow from starting again. Reminders and closing messages are now recorded as the flow's own messages: they never count as a colleague taking over, and a late reply starts a new run as the documentation always said. ## No second lead when an open lead already holds the number [#no-second-lead-when-an-open-lead-already-holds-the-number] **Fixed.** A **Customer writes first** lead flow found the customer's CRM contact and that contact's open lead or deal, but an open lead that carries the number without any CRM contact on it, typically a lead imported from another tool, stayed invisible, so the flow created a second lead next to it. The flow now also binds to such a lead. [Which record a flow creates or binds to](/docs/product/chat-flows#which-record-a-flow-creates-or-binds-to). ## Edits and deletions in a group stay in the group chat [#edits-and-deletions-in-a-group-stay-in-the-group-chat] **Fixed.** When a member edited or deleted a message inside a WhatsApp group synced to a Bitrix24 group chat, the "message edited" / "message deleted" note was sent to the Open Line as if the group were a person, which opened a one-to-one chat and a lead whose phone number was the group id. The note now goes to the bridged group chat, and a group id is refused as a phone number when sending from a CRM record. Leads created this way can be deleted; they carry a phone of 18 digits starting with `1203`. ## Videos and documents sent from Bitrix24 no longer fail at 15 seconds [#videos-and-documents-sent-from-bitrix24-no-longer-fail-at-15-seconds] **Fixed.** On a WhatsApp QR number, a file sent from an Open Channel or from the WASync tab is downloaded and uploaded to WhatsApp in one step, and a large video can take 20 to 30 seconds. Our side gave up after 15 seconds and marked the message as failed in Bitrix24 and in the thread, while the file still reached the customer, so operators sometimes sent it a second time. Media sends now wait up to 90 seconds; short text messages keep their quick timeout. # 21 October 2026 (/docs/changelog/2026-10-21) ## One run per customer, even when the first messages come in a burst [#one-run-per-customer-even-when-the-first-messages-come-in-a-burst] **Fixed.** When a customer sent two or three messages within a few seconds before the bot answered ("hi", "good evening", "where are you?"), each message arrived as its own request and each could start the flow. The second run replaced the first, but the first had already begun its opening sequence and kept sending it, so the customer saw every opening message twice, sometimes three times. Now the first message of a burst is the only trigger, and a run that has been replaced or cancelled stops at its next step instead of finishing its sequence. [When a flow starts](/docs/product/chat-flows#when-a-flow-starts). # 22 October 2026 (/docs/changelog/2026-10-22) ## Lead per number: a new contact gets its own lead, not another tool's old one [#lead-per-number-new-contact-gets-its-own-lead] **Fixed.** With **Each number creates its own lead** switched on, a flow run for a contact that did not exist yet could bind to an older open lead that merely held the phone number, typically a lead created by another WhatsApp tool running in parallel. That lead was not this number's record, so when the customer answered the agent, the "new conversations" rule created a second lead and assigned it again. Now, under that option, a first-time contact gets the number's own lead at the start of the flow, and the next reply lands on it. Portals without the option are unchanged. [Which record a flow creates or binds to](/docs/product/chat-flows#which-record-a-flow-creates-or-binds-to). # 23 October 2026 (/docs/changelog/2026-10-23) ## Pick which number to message from a CRM record [#pick-which-number-to-message-from-a-crm-record] **New.** The WASync tab of a lead, deal, contact or company used to chat with the first phone of the record only. It now lists every number the record can reach, including the phones of each contact of a deal, and shows a picker when there is more than one. It opens on the number you used last on that record. [Records with several phone numbers](/docs/product/crm-records#records-with-several-phone-numbers). ## Start a conversation with a number that has no chat yet [#start-a-conversation-with-a-number-that-has-no-chat-yet] **New.** WASync Chat only listed existing conversations, so a number nobody had written to yet could not be reached from there. Search the full number; when nothing matches, the list offers to start the conversation, with your sending number of choice and a template on Business API numbers. An employee limited to their own records can start one with a number that is on a record assigned to them. [Starting a conversation with a number that has no chat yet](/docs/product/wasync-chat#starting-a-conversation-with-a-new-number). # 27 October 2026 (/docs/changelog/2026-10-27) ## Options of a question as buttons [#options-of-a-question-as-buttons] **New.** A question step can show its options to the customer: as buttons (up to 3) or a list (up to 10) on WhatsApp Business API numbers, and as a numbered list on QR numbers, where the customer can answer with the number. Until now the customer only saw the question text. [Showing the options as buttons](/docs/product/chat-flows#showing-the-options-as-buttons). ## Keywords separated with commas [#keywords-separated-with-commas] **Fixed.** In the keywords of an option, a typed comma disappeared at once, so several keywords could not be entered. Commas and semicolons now both separate keywords, and keywords already saved with semicolons (`continuar;1;si`) are read as separate keywords. ## Send a message later [#send-a-message-later] **New.** Next to **Send** in WASync Chat and the WASync tab of a CRM record, a clock schedules the message for a date and time up to 30 days ahead; it can be cancelled until it goes out. On WhatsApp Business API numbers it goes out only if the customer wrote in the 24 hours before. [Sending a message later](/docs/product/wasync-chat#sending-a-message-later). ## Voice notes transcribed to text [#voice-notes-transcribed-to-text] **New.** An administrator can turn on transcription of WhatsApp voice notes in Settings. The text appears under the player in WASync Chat and the CRM tab, and in the export. It runs on the workspace's own OpenAI, Groq or ElevenLabs account. [Voice-note transcription](/docs/product/wasync-chat#voice-note-transcription). ## WhatsApp forms in Chat Flows [#whatsapp-forms-in-chat-flows] **New.** A Chat Flows step sends a form the customer fills in inside WhatsApp, with up to 8 fields; each answer can land in a CRM field. WhatsApp Business API numbers only. [WhatsApp forms](/docs/product/chat-flows#whatsapp-forms). ## Carousel templates [#carousel-templates] **New.** Marketing templates with 2 to 10 swipeable cards, each with an image or video, a short text and buttons, created in the WASync template builder and sent from the chat, flows and robots. [Carousel templates](/docs/product/wasync-chat#carousel-templates). ## Link click tracking [#link-click-tracking] **New.** With link tracking on, links sent from WASync become short links; the message and the CRM timeline show when the customer opened them. [Link click tracking](/docs/product/wasync-chat#link-click-tracking). ## Re-contact window covers lost deals [#re-contact-window-lost-deals] **Fix.** With one lead per number, a reply to a deal marked lost inside the re-contact window goes back to that deal instead of creating a new lead. [Re-contact window](/docs/guides/leads-from-whatsapp-chats#re-contact-window-after-a-closed-lead). ## Allow the flow again restarts the flow at once [#allow-flow-again-restarts] **Fix.** **Allow the flow again** in WASync Chat now also clears the wait after a finished flow, so the next message starts an *Any message* flow right away. [Chat Flows](/docs/product/chat-flows). # 28 October 2026 (/docs/changelog/2026-10-28) ## Ad attribution on leads created from the chat [#ad-attribution-on-leads-created-from-the-chat] **Fixed.** When a customer wrote from a click-to-WhatsApp ad and no lead or deal existed yet (for example on a number without an Open Line), a lead created later with **Create lead** in WASync Chat stayed without UTM fields. The lead or deal you create or link from the chat now receives the ad's UTM fields, campaign and timeline note, when the ad message is from the last 7 days. [Ad attribution](/docs/product/crm-records#ad-attribution). # 29 October 2026 (/docs/changelog/2026-10-29) ## Templates no longer get a phone number as the name [#templates-no-longer-get-a-phone-number-as-the-name] **Fixed.** The template window fills `{{1}}` with the contact's first name. For a contact with no name, that "name" was its phone number, and it went into `{{1}}` even when `{{1}}` was a date. The window now fills `{{1}}` only with a real name and only when the template describes `{{1}}` as a name; otherwise it stays empty for you to type. [Templates on Business API numbers](/docs/product/wasync-chat#templates-on-business-api-numbers). ## Reports for people who are not administrators [#reports-for-people-who-are-not-administrators] **New.** In **Staff → Access**, the new **Reports** area gives a non-administrator the Reports page and its export, and nothing else from the console. [Reports for non-administrators](/docs/product/connections#reports-for-non-administrators). # 31 October 2026 (/docs/changelog/2026-10-31) ## Customer videos and large files always reach the Open Channel [#customer-videos-and-large-files-always-reach-the-open-channel] **Fixed.** A large video or file a customer sent could be refused by Bitrix24 when it tried to fetch it, and the operator never saw the message. Files are now handed over from a link that is ready at once; a file sent without a caption gets a short one in the portal's language (for example “🎬 Video” or “📎 Document · offer.pdf”); and if Bitrix24 still refuses the file, the message is sent again with the caption and a link to the file. [Bitrix24 Open Channels](/docs/product/settings#bitrix24-open-channels). ## A message made only of empty CRM fields no longer stops the flow [#a-message-made-only-of-empty-crm-fields-no-longer-stops-the-flow] **Fixed.** A Chat Flows message made only of a CRM field, such as a promo text kept in a deal field, stopped the whole conversation when that field was empty on the record, and every later step was lost. The step is now skipped and the flow continues, and the editor warns you when a message is made only of fields. [Messages built from CRM fields](/docs/product/chat-flows#messages-built-from-crm-fields). ## Fill in a field can write only when the field is empty [#fill-in-a-field-can-write-only-when-the-field-is-empty] **New.** The Chat Flows step **Fill in a field** has a new switch, **Only if the field is empty**, off by default so existing flows behave as before. When it is on and the field already has a value, nothing is written and the flow continues, so a later flow can no longer overwrite a lead's origin or UTM values. [Fill in a field](/docs/product/chat-flows#fill-in-a-field). ## A flow can save a lead's origin before the lead exists [#a-flow-can-save-a-leads-origin-before-the-lead-exists] **New.** A **Fill in a field** step has a second switch, **If there is no CRM record yet, save as pending origin**. On a conversation without a lead, the value (for example a UTM source or the lead source) waits on the contact, WASync Chat shows it under the header, and it is written into the lead when someone creates it from the chat. Linking an existing record never changes its origin. [Save the origin when there is no lead yet](/docs/product/chat-flows#pending-origin). ## Call-permission templates only on numbers with calls on [#call-permission-templates-only-on-numbers-with-calls-on] **Fixed.** WhatsApp approves a template with a call-permission request even for a number without WhatsApp calls, then refuses every send of it. The template builder now offers the call-permission request only when calls are on for the number, the template picker marks such templates **Needs calling** and greys them out on a number without calls, and a send from the chat, an automation rule or a Chat Flow is refused before it reaches WhatsApp, with the reason shown. [Turning calls on for a number](/docs/product/calls#turning-calls-on-for-a-number). ## When a contact changes their WhatsApp number [#when-a-contact-changes-their-whatsapp-number] **New.** When a contact moves to a new WhatsApp number on a Business API number, the conversation gets a note, the new number is added to the CRM record (the old one stays) with a timeline comment, and the old conversation shows a banner that opens the new one. The CRM update can be turned off in the Chat rules. [When a contact changes their number](/docs/product/wasync-chat#when-a-contact-changes-their-number). ## Open Channel chats named from CRM fields [#open-channel-chats-named-from-crm-fields] **New.** A chat title template in Settings, such as `WA: {{company.UF_CRM_CODE}} - {{contact.name}}`, names every Open Channel chat when an operator first answers and again when its CRM record changes; the **Set WhatsApp chat title** automation step sets it at any stage. A chat someone renamed by hand is kept. [Chat title from CRM fields](/docs/product/settings#chat-title-from-crm-fields). ## Chat files open with a fresh link and can be downloaded [#chat-files-open-with-a-fresh-link-and-can-be-downloaded] **Fixed.** In a chat left open for a while, clicking an older photo or file could show an "expired" page instead of the file. Photos, videos and files now open with a link made at the moment you click, photos open full size inside the app, and each file has a **Download** button that saves it with its original name. [Opening and downloading files](/docs/product/wasync-chat#opening-and-downloading-files). ## See when a contact uses disappearing messages [#see-when-a-contact-uses-disappearing-messages] **New.** On QR connections, the conversation header in WASync Chat and in the WASync tab of a CRM record shows a label such as **Disappearing: 24 h**, **7 days** or **90 days** when the contact has disappearing messages on, so you know a quote may vanish from their phone. Your history in WASync and Bitrix24 is kept. [Disappearing messages](/docs/product/wasync-chat#disappearing-messages). ## My conversations only through the number they are on [#my-conversations-only-through-the-number-they-are-on] **New.** With **Each number creates its own lead**, a new switch in the Chat rules makes an employee who sees only their own (or their department's) conversations see a conversation only through the lead or deal of the number it is on. A colleague's lead on another number no longer opens it, and sending from a number whose record belongs to a colleague is refused. Off by default; with it off, the conversation header explains when you see a conversation because of your record on another number. [Who sees which conversations](/docs/product/wasync-chat#who-sees-which-conversations). ## Warning when Meta routes a number to your old provider [#warning-when-meta-routes-a-number-to-your-old-provider] **New.** A number brought from another provider can look connected while Meta's Conversation routing still sends its conversations to the old provider: no messages arrive and every send fails with error 131070. WASync now checks this after the move and several times a day, shows a red warning on the number in **Connections** and in the Templates window with the exact steps in Meta Business Suite, and a failed message shows what to do instead of Meta's code. [Conversation routing at Meta](/docs/product/connections#conversation-routing-at-meta). ## Customers who write from a WhatsApp username [#customers-who-write-from-a-whatsapp-username] **New.** Customers who write from a WhatsApp username with a hidden number now reach WASync Chat and the Open Channel as **@username** on WhatsApp Business API numbers; replies, templates and the Open Channel work without a phone number. Their messages used to be dropped. When the same customer later writes from their phone number, both conversations get a note pointing to each other. [Contacts without a phone number](/docs/product/wasync-chat#contacts-without-a-phone-number). ## Sequential stages in WASync Chat [#sequential-stages-in-wasync-chat] **New.** A new chat rule, **Sequential stages**, off by default: from WASync Chat, an operator can move a lead or deal only to the next stage of its pipeline, with one step back and the won or lost stages allowed by default. A jump is refused with "Move to *next stage* first". Moves made directly in Bitrix24 are not affected. [Sequential stages](/docs/product/wasync-chat#sequential-stages). **Changed.** The closing option is now two: **Allow "Lost" from any stage** (on by default) and **Allow "Won" from any stage** (off by default), so a lost record closes from any stage while "Won" still follows the pipeline. # 2 November 2026 (/docs/changelog/2026-11-02) ## More control over chat titles from CRM fields [#more-control-over-chat-titles-from-crm-fields] **New.** The chat title template in Settings can now be limited to the Open Channels you tick, and it has two new fields, `{{line.name}}` (the channel's name) and `{{line.phone}}` (the WhatsApp number). With **Skip the rename when a field is empty** on, a chat keeps its current title until every field in the template has a value, instead of leaving the empty ones out. Each rename WASync makes adds the note “WASync set the chat title: «…»” to the conversation's CRM record (on by default, can be switched off in the same card). The **Set WhatsApp chat title** automation step also works on companies, renaming the chats of the company's contacts. [Chat title from CRM fields](/docs/product/settings#chat-title-from-crm-fields). ## New AI step in Chat Flows [#new-ai-step-in-chat-flows] **New.** Chat Flows have an **AI reply** step: the flow answers the customer with your own AI key (Chat Flows → AI assistant), from the context you choose — the last messages of the conversation, the CRM fields you pick and its own earlier answers. The AI takes no actions; messages that look like prompt injection are caught before the call, links to other sites are removed from the answer, and when anything goes wrong the conversation goes to a person by default. Pro (paid) numbers only. [AI step](/docs/product/chat-flows#ai-step). ## AI step: choose from a list [#ai-step-choose-from-a-list] **New.** The AI step has a second mode, **Choose from a list**: the AI picks one of the options you list (2–12) and the flow continues on that option's line. Nothing the AI writes is sent; an answer that is not one of your options goes to **Anything else** or to your fallback. The step can ask the customer a question first and classify the reply. [Choose from a list](/docs/product/chat-flows#ai-choose-from-a-list). ## Knowledge for the AI step [#knowledge-for-the-ai-step] **New.** Add texts, PDFs and web pages once in **Chat Flows → AI assistant**, then pick in each AI step which of them it may use. Before every answer the AI gets the passages closest to the customer's message; with **Answer only from the knowledge** on, a question the knowledge does not cover goes to your fallback instead of getting an invented answer. [Knowledge base](/docs/product/chat-flows#knowledge-base). ## Automation-started flows check the country code [#automation-started-flows-check-the-country-code] **Improved.** A chat flow started by a Bitrix24 automation rule no longer starts on a phone without a country code (for example a 10-digit national number). The lead or deal gets a timeline comment that explains how to fix it. A message to a number that is not on WhatsApp now says “This number is not on WhatsApp” under the bubble. [When a flow starts](/docs/product/chat-flows#when-a-flow-starts). ## Set up and test the AI in one place [#set-up-and-test-the-ai-in-one-place] **New.** Chat Flows has an **AI assistant** tab with your AI key and model, the knowledge and a **Try a question** box that shows the answer and the passages it used. The AI step now lists what is missing (key, licence) with a fix on the spot, lets you paste knowledge without leaving the editor and can test a question with the changes you have not saved yet. The cards moved out of Settings, which keeps a shortcut. [The AI assistant tab](/docs/product/chat-flows#ai-assistant-tab). ## PDFs and videos open inside the app [#pdfs-and-videos-open-inside-the-app] **Improved.** A PDF or a video in a conversation now opens in a window over the chat, with **Open** and **Download** next to it, instead of a new browser tab. Some browsers add an extra code to addresses opened in a new tab, and the file storage then refused the link. A PDF over 25 MB, or on a browser that cannot show PDFs in a page, offers Open and Download only. [Opening and downloading files](/docs/product/wasync-chat#opening-and-downloading-files). # 3 November 2026 (/docs/changelog/2026-11-03) ## Large batches from automation rules no longer fail [#large-batches-from-automation-rules-no-longer-fail] **Fixed.** When an automation rule ran the **Send WhatsApp message**, **Send WhatsApp template (WABA)** or **Start chat flow** robot on hundreds of records at once, Bitrix24 limited how fast WASync could read the records and many runs failed with “Bitrix24 did not answer while we looked up the phone number”. WASync now queues those runs and sends them at a steady pace, about one per second for your portal, in order. Bitrix24 shows the robot as *queued* and the message follows within minutes. [Large batches](/docs/product/crm-records#large-batches). ## Replies to robot messages stay on their record [#replies-to-robot-messages-stay-on-their-record] **Fixed.** With one lead per number turned on, a WhatsApp message sent by the **Send WhatsApp message** or **Send WhatsApp template (WABA)** robot did not bind the conversation to the lead or deal it ran on, so the customer's reply opened a new lead. The conversation is now bound to that record, exactly like a message sent from the record's widget. [Robot messages and the record](/docs/product/crm-records#robot-messages-and-the-record). # 4 November 2026 (/docs/changelog/2026-11-04) ## Sending from an open record moves the chat off a closed one [#sending-from-an-open-record-moves-the-chat-off-a-closed-one] **Fixed.** With one lead per number turned on, a conversation whose record on that number was already won or lost stayed on it, even when an advisor sent a message from the customer's open deal. The reply then opened a new lead for the unknown-numbers rule. Now a message sent from an open lead, deal or Smart Process item moves the conversation to that record, and a reply to a closed record first looks for the contact's open deal or lead before creating one. Off by default: write to support to turn it on for your portal. [When the number's record is closed](/docs/product/crm-records#when-the-numbers-record-is-closed). ## Mexican numbers typed with +52 stay in one conversation [#mexican-numbers-typed-with-52-stay-in-one-conversation] **Fixed.** WhatsApp files a Mexican mobile as `521` followed by the 10-digit number, while people usually type `+52` and the 10 digits. A message sent to a number typed the second way reached the customer but opened a second, empty conversation, and the customer's reply arrived in the first one. Both spellings now open the same conversation; duplicates created before the fix will be merged on our side. [Default country](/docs/product/settings#default-country). ## Lead flows can create the lead without a new contact [#lead-flows-can-create-the-lead-without-a-new-contact] **New.** A lead flow that creates the lead when the customer writes first can now skip creating a CRM contact. Tick **Create only the lead (no new contact)** on the Start card: the lead is created on its own, and linked to a contact only when one with the customer's phone already exists. [Create only the lead, without a new contact](/docs/product/chat-flows#lead-only-without-a-new-contact). ## One CRM timeline comment per day per record [#one-crm-timeline-comment-per-day-per-record] **New.** A busy conversation no longer fills a deal's timeline with one comment per WhatsApp message. Turn on **One comment per day per record** under **CRM Timeline Log** in Settings: each record then gets one comment per day, and every message is added to it as a line with the time, the direction and the operator's name. [One comment per day per record](/docs/product/crm-records#one-comment-per-day-per-record). # Changelog (/docs/changelog) This is the dated record: when something arrived. How each feature works today is documented under [Product](/docs/product) for the Bitrix24 app and under [Guides](/docs/guides) and the [API reference](/docs/api-reference) for the API, and the entries below link there. Breaking changes to the API are always announced here before they ship. New event types are announced here too, which is why unknown `event` values in a webhook payload should be ignored rather than treated as errors. # Connection types (/docs/concepts/connection-types) Every connection reports a `provider`, and it is one of two values: | `provider` | What it is | How it is onboarded | | ----------- | ---------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | | `qr` | An ordinary WhatsApp number (sold as **WAPP**), paired by linking a device. | `POST /connections`, then scan a QR or type a pairing code. Entirely self-serve through the API — no Meta Business account. | | `cloud_api` | A WhatsApp Business number (sold as **WABA**) registered with Meta, on the official Cloud API. | Meta embedded signup, not this API. | Both types send and receive through the same endpoints, with the same request bodies and the same two message ids. If you assumed QR-from-your-own-app was impossible: it is not. ## Where they actually differ [#where-they-actually-differ] **Webhooks.** Events fire for `qr` connections only. `cloud_api` connections emit no webhooks today — poll `GET /messages` and `GET /connections/{id}` for those. **Pairing.** `POST /connections/{id}/pairing-code` is a `qr` concept. A `cloud_api` number answers `409 not_supported_for_provider`; that is a permanent refusal, so do not retry it. **Send latency.** A `qr` send normally takes 1–7 s (up to \~20 s for a long text) and can take \~2.5 minutes on the self-heal path. A `cloud_api` send is about 1 s. Size your HTTP timeout for the slow one: **at least 180 s**. **Marking read.** `POST /messages/read` marks the whole chat on a `qr` connection. A `cloud_api` connection can only mark one specific message, so a `phone`-only request resolves your most recent inbound message from that number automatically. **Volume.** A newly paired `qr` number has 72-hour warm-up caps on hourly volume; exceeding one returns `429 warmup_limited`. See [Licences & trial](/docs/concepts/licences-and-trial). **Session health.** A `qr` connection is bound to a phone that has to stay reachable, so it can drop and be asked to re-pair — that is what `connection.disconnected` / `connection.connected` and the `needs_reconnect` flag are for. A `cloud_api` connection never scans anything and does not have that failure mode. `provider` maps to `null` rather than passing through an unrecognised value. If a new connection kind is ever added it will be named here deliberately, so branching on `qr` / `cloud_api` today is safe — but treat `null` as "a kind this client does not know about" rather than crashing on it. # Errors & idempotency (/docs/concepts/errors-and-idempotency) ## Branch on the code, not the status [#branch-on-the-code-not-the-status] Errors come back as `{ "error": "" }`. The status alone is not enough to decide what to do — two `403`s can need opposite fixes. | Status | Code | What it means, and what to do | | ------ | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | 401 | `invalid_key` | Unknown or revoked key. Create a new one; retrying will never help. | | 403 | `ip_not_allowed` | The key has an IP allowlist and this address is not on it. **The key is fine** — add the address at `developers.wasync.app/keys`. Do not rotate. | | 403 | `insufficient_scope` | The credential lacks the scope this endpoint needs. | | 403 | `forbidden_portal_kind` | `POST /connections` on a Bitrix24 portal. Connections there are created by the portal admin. | | 400 | `invalid_phone_number` | `phoneNumber` must be digits only, no leading `+`. | | 400 | `invalid_webhook` | The URL must be HTTPS on a publicly reachable host. | | 402 | — | The connection's licence has lapsed. See [Licences & trial](/docs/concepts/licences-and-trial). | | 409 | `already_connected` | The session is live; there is nothing to pair. | | 409 | `not_supported_for_provider` | A `qr`-only operation on a `cloud_api` number. Permanent — do not retry. | | 422 | `recipient_not_on_whatsapp` | WhatsApp could not find an account for the recipient. Check the number is in international format (country code first, no leading zero) and that the person uses WhatsApp. Permanent for that number — do not retry unchanged. | | 502 | `send_failed` | WhatsApp could not deliver for a reason that is not about the recipient (session or provider). Retry after a short delay; if it persists, check the connection's status. | | 429 | `warmup_limited` | Hourly warm-up cap on a new `qr` number. Back off in minutes. | | 429 | `rate_limited` | Abuse limiter. Honour `Retry-After` when present; keep a default back-off regardless. | | 502 | `pairing_code_unavailable` | An ordinary outcome, not an outage — fall back to the QR. | `Retry-After` is not guaranteed on every 409/429, so never make your back-off depend on it. ## Idempotency on `POST /connections` [#idempotency-on-post-connections] Creating a connection provisions a WhatsApp session and consumes a paid slot. A client that times out and retries would otherwise create a *second* connection — and you would silently pay for two slots for one customer. The optional `Idempotency-Key` header closes that hole. It is supported on `POST /connections` **only**; leave it off and behaviour is exactly as before. A key is any opaque string up to 255 characters, namespaced to your workspace (two partners using the same literal string never collide), and it lives **24 hours** from the first request that used it. **New key** — the connection is provisioned as normal → `201 Created` . **Same key, same body, within the TTL** — the same connection is returned, nothing is provisioned again: `200 OK` plus the response header `Idempotency-Replayed: true` . The `qr` in that response is freshly fetched, not the code stored at first creation: pairing codes rotate roughly every 20 seconds, so a replayed stale QR would simply fail to scan. **Treat 200 as success, not as an error.** **Same key, different body, within the TTL** — `400 { "error": "idempotency_key_reuse" }` . The comparison is a hash of the canonical body, so JSON key order does not matter. **Same key, first request still in flight** — `409 { "error": "idempotency_in_progress" }` with `Retry-After: 1` . Honour it and retry with the *same* key. A key longer than 255 characters is rejected with `400 { "error": "idempotency_key_invalid" }` — never truncated. A blank or whitespace-only header counts as absent. The response body shape is unchanged in all cases. A fresh UUID (`crypto.randomUUID()`) minted right before the call and reused only by that call's retries. Do **not** use one key per process, per API key, per day, or a constant. A key that coarse means the second customer you onboard is handed the *first* customer's connection back instead of his own. ## Idempotency on sends [#idempotency-on-sends] `POST /messages` takes an `idempotencyKey` in the **body** (not a header). Always send one — a UUID per logical send. * On any error **or timeout**, retry with the *same* key. A new key means a second real WhatsApp message on someone's phone. * On `409 in_progress`, poll with the same key: honour `Retry-After` when present, otherwise back off about 5 s. * A slow send is not a failed send. Set your HTTP timeout to at least 180 s. # Concepts (/docs/concepts) The model behind the API: workspaces, connection kinds, licences, scopes and failure handling. # Licences & trial (/docs/concepts/licences-and-trial) Each WhatsApp **number** needs an active licence to send and receive through the API. There is no free tier; there is a **7-day free trial** on every new number. ## Prices [#prices] One price, in USD, per number, per month — the same whether the number is a `qr` connection or a `cloud_api` connection, and whatever you send through it. | | Price | | ------------------------------------------------------------------- | ------- | | A WhatsApp number in a standalone workspace | **$12** | | API access to a number that lives on a Bitrix24 portal (API add-on) | **$12** | No seats, no message caps, no per-request fees on our side. Meta's own conversation charges for `cloud_api` numbers are billed by Meta to your WhatsApp Business Account, not by us. Activation and invoices live at [https://developers.wasync.app/billing](https://developers.wasync.app/billing). ## Slots [#slots] A **slot** is capacity, not a phone number, and not something you bind to a customer: * It attaches when a number actually pairs — creating a connection record does not consume one until then. * Deleting a connection returns its slot to the pool carrying whatever time is left on it. The next number you connect picks it up automatically. * That is what lets you move a paid slot from a departing customer to a new one without paying twice or asking anybody to intervene. Check `GET /account` before you promise capacity: `slots.available` is what `POST /connections` can still consume with an active licence, and `slots.nextExpiry` is the date you have to renew before. ## Deleting a number, closing a workspace [#deleting-a-number-closing-a-workspace] Both are yours to do, from the **Billing** screen of the developer console or over the API. * **Delete a number** — `DELETE /v1/connections/{id}`, or the **Delete** button on the connection row. Its WhatsApp session is closed, every message stored for it is removed, and a paid slot returns to the pool as described above. * **Close a workspace** — the **Close workspace** button on a workspace with no connections left. It removes the workspace together with its API keys and its webhook configuration, so anything still calling the API with those keys stops working. A workspace that still has numbers cannot be closed: delete them first, so the phones are unlinked instead of leaving sessions behind. A workspace with a live slot subscription cannot be closed either — cancel the subscription first. Neither action can be undone. What does survive is the record that a number already used its free trial: closing a workspace and opening a new one does not give the same phone a second trial. ## The trial [#the-trial] A new number starts on a 7-day trial the moment it pairs — whether it paired by scanning a QR or by typing a pairing code. Pairing by code consumes nothing extra: same slot, same trial. When the licence lapses, the connection stops being reachable: it disappears from `GET /connections`, events stop being delivered, and sends answer `402`. ## Warm-up caps on new `qr` numbers [#warm-up-caps-on-new-qr-numbers] A freshly paired `qr` number carries **72 hours of warm-up caps** on hourly send volume. Exceeding one returns `429 warmup_limited` — an hourly cap, so back off in minutes and do not hot-loop. That is a separate limiter from the abuse limiter, which returns `429 rate_limited`. Honour `Retry-After` when it is present, but always keep a default back-off of your own: the header is not guaranteed on every 409/429. # Scopes (/docs/concepts/scopes) Scopes are per credential — per API key, or per OAuth grant. There are four. | Scope | Grants | | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | | `whatsapp.read` | `GET /connections`, `GET /connections/{id}`, `GET /account`, `GET /messages` | | `whatsapp.send` | `POST /messages`, `POST /messages/read` | | `whatsapp.events` | `GET /webhook`, `PUT /webhook`, `POST /webhook/rotate`, and receiving deliveries at all | | `whatsapp.manage` | `POST /connections`, `POST /connections/{id}/pairing-code`, `POST /connections/{id}/restart`, `POST /connections/{id}/logout`, `DELETE /connections/{id}` | ## Marking read is a send, not a read [#marking-read-is-a-send-not-a-read] `POST /messages/read` needs `whatsapp.send`. It looks like a read operation, but it **transmits** a receipt from your number to the customer's device — it is outbound. The upside is that any client which can already send can also mark read: no new scope, no re-consent. ## Resolution is live [#resolution-is-live] Scopes and the reachable connection list are resolved on **every** request. Nothing is cached in the token and nothing has to be refreshed. Two consequences: * Revoking a key, or narrowing its scopes, takes effect on the very next call. * A connection you just created is visible on the next call. There is no propagation delay and nothing to re-issue. ## Insufficient scope [#insufficient-scope] A credential that lacks the scope an endpoint needs gets `403 insufficient_scope`. Branch on the **code**, not the status — `403` is also what an IP-allowlist refusal returns (`ip_not_allowed`) and the two need opposite fixes: one means edit the key's scopes, the other means add an address. See [Errors & idempotency](/docs/concepts/errors-and-idempotency). ## Ask for less [#ask-for-less] The scope you do not grant is the one that cannot be abused if the key leaks. A read-only reporting job wants `whatsapp.read` and nothing else; a notification sender wants `whatsapp.send`; only a provisioning flow needs `whatsapp.manage`, which can delete connections. # Workspaces (/docs/concepts/workspaces) A **workspace** owns WhatsApp connections. An API key is issued against exactly one workspace, and everything the key can see or do is scoped to it — there is no way to ask about another one. ## One key, one workspace, many connections [#one-key-one-workspace-many-connections] For a multi-tenant application this is the shape you want: * **One API key**, not one per tenant. Do not mint a key per customer. * **One `POST /connections` per tenant**, including the very first one, each with its own fresh `Idempotency-Key`. * **Route inbound events by `connection_id`** — a stable cuid that appears on every REST response and every webhook payload. Map it to your own customer record; we mint the id, you map it. * New connections are usable immediately. The key's connection list is resolved live on each request, so there is nothing to refresh after a create. ## Two kinds of workspace [#two-kinds-of-workspace] The difference shows up in exactly two places, and they are worth knowing before you write code against the wrong one: **Creating connections.** `POST /connections` is standalone-only. On a Bitrix24 portal it answers `403 forbidden_portal_kind` — the portal admin creates connections in the WASync interface instead. Every other endpoint behaves identically on both. **What makes a connection reachable.** In a standalone workspace it is the connection's own licence (trial or paid). On a Bitrix24 portal the portal's subscription pays for the number in the CRM, and reaching that same number *through the API* additionally needs the **API add-on**, at $12 per number per month. Without it the connection is simply not in `GET /connections`. ## Bootstrapping [#bootstrapping] With an API key there is no bootstrap step: the key is issued against your workspace directly, so `POST /connections` creates the first connection as readily as the tenth. An OAuth grant is different by construction — it is only ever issued *over connections that already exist*, so an OAuth-only integration cannot create a workspace's first connection. That is the reason every quickstart here starts with a key. # Bring a number from another provider (/docs/guides/bring-your-own-number) Already using the WhatsApp Business API somewhere else, for example Gupshup, 360dialog, Twilio or Wati? You can move that number to WASync (sold as **WABA**) and keep your reputation with Meta. Your old provider keeps working right up to the final step, so there is no gap in service until you switch over. The wizard is called **Bring a number**. Where to find it, under **Connections** in the WASync app: * The menu of an existing WABA connection. * The link **Already using the WhatsApp Business API with another provider? Bring that number instead** inside **Connect WhatsApp Business API**. * The link **Bring a number from another provider** next to the buttons at the top of the Connections page. You do not need a WABA connection to start: the last two entries work on a portal that has none yet. ## What comes with you, what stays behind [#what-comes-with-you-what-stays-behind] | Comes with you | Stays behind | | ------------------------------------------------------------------ | ------------------------------------------ | | Your display name | Chat history | | Quality rating | Analytics and insights | | Official Business Account status | Rejected, pending or low-quality templates | | Messaging limits | | | Approved, high-quality message templates (Meta copies them across) | | Because the display name comes across with the number, there is nothing to re-enter and no new name review. ## Before you start [#before-you-start] * Switch off **two-step verification** for the number at your current provider. Meta refuses the move while it is on, and this is by far the most common reason a migration fails. In Business Manager: WhatsApp Manager, Phone numbers, the settings (gear) of the number's row, Two-step verification, Turn off. Meta emails a confirmation link that must be clicked before it takes effect. * **No Two-step verification tab?** Meta is retiring the six-digit PIN for eligible Cloud API numbers, number by number. When the tab is missing from a number you own with full control, the change has already reached that number: there is no PIN to switch off, and you can proceed with the move and tick the box in the wizard. Meta's note is in their [account model evolution](https://developers.facebook.com/documentation/business-messaging/whatsapp/account-model-evolution) page. * Your business must be verified with Meta, and the WhatsApp Business Account the number moves into must be in good standing. * You need to be able to receive a 6-digit code on the number, by SMS or by voice call. ## Steps [#steps] 1. **Intro.** Read what comes with you and what stays behind, then continue. 2. **Number.** Pick the country and enter the phone number exactly as it runs at your current provider, without the country code and without a leading 0. You type the same number again in Meta's window at the last step. Here it is only used to run the checks. 3. **Checks.** WASync reads your Meta business and WhatsApp Business Account (read-only, nothing is changed) and reports five checks: * Your business is verified with Meta. * The destination WhatsApp Business Account is in good standing. * Your account has room for another number. Meta does not publish the maximum, so WASync shows how many numbers the account has and you confirm the rest yourself. * The number is not already on this account. * Two-step verification is switched off at your current provider. Only you can confirm this, so you tick a box. You can continue only when no check fails and the box is ticked. Fix any failing check, then run the checks again. If the portal has no WhatsApp Business API connection yet, WASync has no account to read through, so it cannot run these checks. You get a checklist of five boxes instead: business verified with Meta, you are an admin of the Business portfolio that owns the number, the number is yours and not rented from the provider, two-step verification is off (and Meta's confirmation email opened), and no display-name change is pending. Tick all five to continue. Once a number is connected, later moves get the automatic checks. 4. **Meta's window.** Click **Open Meta sign-up**. The move happens in Meta's own window, which WASync cannot fill in for you. Choose: 1. Your existing Meta Business portfolio, the one that owns the number today. Do not create a new one. 2. **Create a new WhatsApp Business Account.** Meta always builds a fresh account for a number arriving from another provider. Your old account cannot be reused, and that is expected. 3. Enter your existing number, exactly as checked. Meta warns that it is already registered with another provider. Continue past it. 4. Verify with the code Meta sends, by SMS or voice call, and enter the 6-digit code. When setup finishes, close the window if it stays open. The move finalizes in WASync automatically. 5. **Done.** The number now runs on WASync. ## After the move [#after-the-move] * Meta created a new WhatsApp Business Account for the number under WASync and registered it for sending. Your old provider no longer sends or receives on it. * Templates can take up to **24 hours** to show a quality rating again, and may read as unrated until then. Templates that were rejected, pending or low-quality did not come across. Create them again under **Templates**. * WASync re-registers the number with a two-step verification PIN, because you had to switch it off to move. Save the PIN. You need it if you ever move the number again. It is always under **Connections**, **PIN**. * Your old provider's dashboard shows the number as migrated and its channel is dead. Send and receive a real message in WASync first, and cancel the old subscription only once messaging works. ## Conversation routing at Meta [#conversation-routing-at-meta] Meta has a setting, **Conversation routing**, that decides which partner app receives a number's conversations. When it is on and your previous provider is still the primary partner, the number looks connected in WASync but customer messages keep going to the old provider, and every message you send from WASync fails with error **131070** ("another app is controlling this thread"). Moving or re-registering the number does not change this. Only you can, at Meta. WASync checks this right after the move and again several times a day. When Meta still routes the number elsewhere, **Connections** shows a red warning on the number with these steps: 1. Open **Meta Business Suite**, **Settings**, **WhatsApp accounts**, and select the number. 2. Open **Conversation routing**. 3. Set **WASync** as **Primary** for every entry point: **Customer service**, **Click-to-WhatsApp ads**, **Utility**, **Marketing** and **Calls**. 4. Set **WASync** as the **Escalation** partner too. 5. Save. New messages from then on reach WASync. If you no longer use the previous provider at all, you can instead remove it under **Partners** or **Messaging accounts** in Business Suite. Then every conversation comes to WASync. The warning disappears on its own at the next check once WASync is the primary partner. If messages still do not arrive after that, write to support with the number. ## Troubleshooting [#troubleshooting] Meta locks a number for 72 hours after 10 failed attempts. Continue only when every check passes. If Meta refuses in its own window, read its message and fix the cause before trying again. | What you see | What to do | | -------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Business verification is pending or not verified | Complete verification in Business Manager, Business settings, Security centre, or wait for Meta to finish the review. The wizard does not start the move until this check passes. | | The account is not in good standing | Resolve the restriction on that WhatsApp Business Account first. Moving a healthy number into it does not lift the restriction. | | The number is already attached to this account | There is nothing to migrate. Use the connection it belongs to. | | Room for another number cannot be confirmed | If Meta rejects the move because the account is full, delete a number you no longer use in WhatsApp Manager, Phone numbers, or migrate into a different account. | | WASync could not reach Meta | Retry in a minute. If it keeps failing, reconnect the WhatsApp Business Account and try again. | | Meta refuses the move | The usual cause is two-step verification still on at the old provider, or the confirmation email not yet clicked. | | After the move, messages still go to the old provider, or sends fail with error 131070 | Meta's Conversation routing still makes the old provider the primary partner. See [Conversation routing at Meta](#conversation-routing-at-meta). | ## Billing [#billing] WASync's licence for the number is unchanged by the move. Meta's own message charges are billed by Meta per WhatsApp Business Account, and the move creates a new account for the number: open WhatsApp Manager, Billing & payments, for the new account and make sure it has a payment method before you send business-initiated messages. See [Licences & trial](/docs/concepts/licences-and-trial). # HTTP request step in Chat Flows (/docs/guides/chat-flows-http-request) A Chat Flow can ask an external system a question over HTTPS and use the answer in the conversation: look up an order, check a balance, fetch a delivery date. The step is called **HTTP request** (palette group *Integrate*) in the Chat Flows editor of the WASync app in Bitrix24. ## What the step does [#what-the-step-does] 1. Builds the request from the step's settings: method (GET or POST), URL, headers, and for POST a body. `{{VARIABLES}}` from earlier steps and from the lead or deal are substituted: in the URL they are URL-encoded, in a JSON body they are JSON-escaped. 2. Performs the request and waits up to 10 seconds for the answer. 3. Maps the JSON answer onto flow variables with the **response mapping**: a JSON path (`data.order.status`, `items[0].id`) on the left, a variable name (`ESTADO`) on the right. The next steps use these like any answer: `{{ESTADO}}` in a message, a condition in a Branch, a value in Fill in a field. Every call also sets three variables: | Variable | Value | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | | `HTTP_STATUS` | The HTTP status code the system answered with (`200`, `404`, …), empty if nothing answered. | | `HTTP_OK` | `true` for a 2xx answer, otherwise `false`. | | `HTTP_ERROR` | Empty on success; otherwise a short code: `http_404`, `timeout`, `blocked_url`, `upstream_unreachable`, `budget_exceeded`, `breaker_open`. | ## Two outgoing edges [#two-outgoing-edges] The node has a normal edge (success) and a red **error** edge. The error edge is taken when the call times out, the URL is refused, the system answers 4xx or 5xx, or the network fails. If the error edge is not connected, the flow continues on the normal edge with `HTTP_OK` = `false`, so a Branch on `HTTP_OK` can still react. ## Where the request is made from [#where-the-request-is-made-from] The request is **not** made from WASync's servers. It is performed by a dedicated Cloudflare Worker (`egress.wasync.app`) that has no access to WASync's internal systems. Two consequences: * The call reaches your system from Cloudflare's IP ranges, not from a fixed WASync address. If your API allows only listed IPs, use an API key or a signature instead; there is no WASync IP to allow-list. * A slow or failing API can never delay or duplicate WhatsApp messages: the call runs outside the message pipeline, and the flow waits on the step until the answer or the timeout. ## What the step may call [#what-the-step-may-call] | Rule | Value | | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Scheme and port | `https` on port 443 only | | Host | A public domain name. IP addresses, `localhost`, `.local`, `.internal`, single-label names and WASync's own domains are refused. | | Methods | GET, POST | | Headers | Up to 16. Transport and proxy headers (`Host`, `Transfer-Encoding`, `Proxy-*`, `Cookie`, `X-Forwarded-*`, …) are refused; `Authorization`, `X-Api-Key`, `Content-Type`, `Accept` and the like are fine. | | Request body | Up to 64 KB | | Response | Read up to 256 KB; longer bodies are cut, and `truncated` is reported in Test. | | Timeout | 10 seconds | | Redirects | At most 2, each checked against the same rules | | Budget | 600 calls per workspace per hour. A host that fails 5 times in a row is paused for 5 minutes (the error edge is taken meanwhile). | | Licence | The number's licence must be active; the step does not run on a trial. | The user agent is always `WASync-Flows/1.0 (+https://wasync.app)`. ## Secrets [#secrets] Mark a header as **secret** (an API key, a bearer token) and WASync stores it encrypted. It is never shown again in the editor, never exported with the flow, never written to logs or to the audit trail. To change it, type a new value; to keep it, leave the field empty when you save. ## Test before you save [#test-before-you-save] **Test request** in the step's panel performs the real call with sample values for the variables and shows the status, the time taken, the mapped variables and the body. **Use as sample response** stores that body on the step: the simulator uses it instead of calling the system, so the whole flow can be previewed offline. ## Example: order status [#example-order-status] * **Question**: "¿Cuál es tu número de pedido?" (saved as `PEDIDO`) * **HTTP request**: `GET https://erp.example.com/api/orders/{{PEDIDO}}`, header `X-Api-Key` (secret), mapping `data.status` → `ESTADO`, `data.eta` → `ENTREGA` * **Branch** on `HTTP_OK`: `true` → **Message** `Tu pedido está {{ESTADO}}, llega el {{ENTREGA}}.` · `false` → **Message** `No pude consultar tu pedido ahora, un asesor te escribe en breve.` → **Hand to a person** ## Not in this version [#not-in-this-version] PUT, PATCH and DELETE; OAuth towards the external system; automatic retries; file downloads; waiting for a callback from the system. For those, keep the sibling recipe: the flow writes a CRM field, a Bitrix24 automation rule notifies your system, your system writes the result back through the Bitrix24 REST API, and the **WASync: Send WhatsApp Message** rule sends it. Every call is recorded in the workspace audit trail (host and path, status, duration, which variables were set; never the body or the headers). # Guides (/docs/guides) End-to-end recipes: n8n, MCP, webhooks, pairing, and OAuth2 for third-party apps. # Leads from WhatsApp chats (/docs/guides/leads-from-whatsapp-chats) Everything on this page lives in one place: open the WASync app in Bitrix24 and choose **WASync Chat** in the left menu. The page is visible to people who can read Settings; saving needs write access to Settings. The rules below apply to numbers connected through WASync, both the ones paired by QR and the official WhatsApp Business API ones. They never touch leads or deals your team creates by hand. ## New chats from unknown numbers [#new-chats-from-unknown-numbers] A number that is not in your CRM writes to you for the first time. Pick what WASync does: | Option | What happens | | ---------------- | ----------------------------------------------------------------------------- | | **Off** | The chat is visible to people who see all chats. No CRM record is created. | | **Round-robin** | WASync creates a lead and assigns it to the next person in the list you tick. | | **Fixed person** | WASync creates a lead and assigns it to that person. | The lead carries the customer's name and phone, the CRM source of the WhatsApp line, and, when the message came from a click-to-WhatsApp ad, the ad's attribution (UTM fields and the ad name). The conversation is linked to the lead, so the lead's responsible sees the chat and the lead's stage shows on the conversation. Three switches refine the rule: * **Also on connections bound to an Open Line.** By default a number that is connected to a Bitrix24 Open Line is skipped, because Bitrix24 creates its own lead there. It does so only when an operator takes the chat, sometimes hours later. Turn this on and the lead exists from the first message. * **Also when an operator writes first.** A conversation started from WASync Chat to a number that is not in your CRM gets a lead right away, assigned to the operator who wrote. * **Also create a lead when the number is already a contact but has no open lead or deal.** Without it, a known contact is linked to their contact card only. With it, WASync creates a lead attached to the existing contact (no duplicate contact) and assigns it by the rule above. ## Numbers already in your CRM [#numbers-already-in-your-crm] When the number exists in Bitrix24, WASync looks for the customer's open record and links the conversation to it, in this order: an open deal, then an open lead, then the contact. A lead that was converted follows its deal. **Each number creates its own lead** changes what "open record" means for teams that run several WhatsApp numbers or another WhatsApp tool next to WASync. With it on, an open lead or deal counts only if it was created or linked from the same WhatsApp number the customer wrote to. A customer who reaches a new number from an ad gets a lead for that number, attached to their existing contact; the old record is not touched, and the customer's next messages on that number go to that same lead. ## Re-contact window after a closed lead [#re-contact-window-after-a-closed-lead] A customer's lead is marked **lost**. Minutes or hours later they write again: "thanks", "one more question", or they tap the same ad. Without a window, the rules above see a contact with no open record and create a new lead at once. Set **Re-contact window after a closed lead (hours)** to the number of hours during which a message from that customer goes back to the lost lead instead: * `0` (the default on every account) keeps today's behaviour: a new lead. * Any value up to `720` (30 days) is accepted. Most teams pick between 24 and 72. Inside the window: 1. No new lead is created. The conversation stays linked to the lost lead and the messages land in its timeline. 2. With **Reopen the lost lead when the client writes back** on, the lead also moves to an open stage, so it shows up again in the agent's list. The stage is **Stage the lead returns to**: the first open status of your lead pipeline (usually *New*) or any open stage you pick. If the chosen stage no longer exists or is a closed one, WASync falls back to the first open status. 3. After the window, the next message is handled by the rules above again, which usually means a new lead. **Lost deals, with one lead per number.** When **Each number creates its own lead** is on, the window also covers a lost deal the conversation on that number is linked to. Example: an agent sends a template from a deal and marks the deal lost a minute later. The customer's reply inside the window goes back to that deal, not to a new lead for the default responsible. A lost deal is never reopened, whatever the reopen option says: move it to a stage yourself if the conversation brings it back to life. What the window does not change: * **Won leads.** A converted lead has a deal; the conversation already follows that deal, so the window never applies to it. * **Chat Flows** that create a lead when they start use the same window: a customer re-entering from an ad inside the window lands on the lost lead, not on a second one. * **Records closed before you saved the setting.** The window reads the lead's close time, so it applies from the moment you save, including leads that were closed shortly before, but it does not merge duplicates created earlier. The field is enabled only while **Also create a lead when the number is already a contact…** or **Each number creates its own lead** is on; with both off, a known contact never gets a new lead, so there is nothing for the window to prevent. ### A typical setup for an ad-driven sales team [#a-typical-setup-for-an-ad-driven-sales-team] * **Fixed person** or **Round-robin** for new numbers. * **Also on connections bound to an Open Line** on, so leads exist from the first message. * **Also create a lead when the number is already a contact…** on, so returning customers get a fresh lead for the new inquiry. * **Re-contact window** 72 hours, **Reopen the lost lead** on, stage *New*. With that, a lost lead stays closed unless the customer comes back within three days; when they do, the agent sees the same lead reopened with the whole conversation on it. ## Closed leads and deals [#closed-leads-and-deals] The separate **Closed leads and deals** card decides who still sees a conversation after its record is closed: the former responsible keeps it for the number of days you set (0 = it disappears immediately), and the chat reappears for whoever receives the customer's next lead or deal. Admins and people who see all chats are not affected. ## Stage picker in WASync Chat [#stage-picker-in-wasync-chat] The **Stage picker in WASync Chat** card decides who may change the CRM stage of a conversation from the WASync Chat header. Open the WASync app in Bitrix24 and choose **WASync Chat** in the left menu. Only a Bitrix24 administrator can change it. * **All operators** (default): everyone who can open the chat sees the stage dropdown and can move the record. * **Admins only**: administrators keep the dropdown; everyone else sees the current stage as a read-only label. * **Hidden (read-only for everyone)**: nobody can change the stage from WASync Chat. The current stage is still shown, in its Bitrix24 colour. This setting only narrows access. Bitrix24 CRM permissions still apply on top: an operator who cannot edit a record in Bitrix24 cannot move its stage from WASync Chat either. The "required fields before a stage change" rules keep working for the people who can still change the stage. ## Related [#related] * [Smart Processes (SPA) in WASync](/docs/guides/smart-processes): the same rules link conversations to Smart Process items. * [Changelog, 15 October 2026](/docs/changelog/2026-10-15): when the re-contact window shipped. * [Changelog, 16 October 2026](/docs/changelog/2026-10-16): when the stage picker setting shipped. # MCP (/docs/guides/mcp) WASync runs a remote **MCP** server over Streamable HTTP. Add it to an MCP client and the agent gets WhatsApp tools with no code on your side. ```text title="MCP server URL" https://cloudapi.wasync.app/api/mcp ``` That host is deliberate. The REST base URL and every human-facing link use `developers.wasync.app`, but the MCP server URL, the OAuth endpoints and the `/.well-known/…` documents are protocol identifiers clients have already registered — they stay on `cloudapi.wasync.app` and must match byte-for-byte. Do not "normalise" them. ## Connect a client [#connect-a-client] For clients that read a config file (Claude Desktop, Cursor, …): ```json title="mcp config" { "mcpServers": { "wasync": { "url": "https://cloudapi.wasync.app/api/mcp" } } } ``` Authentication is **OAuth 2.0 with PKCE**, handled by the client: the first call opens a browser, you approve, and the client stores the tokens. There is no key to paste. A client without native remote-MCP support can bridge over stdio: ```bash npx mcp-remote https://cloudapi.wasync.app/api/mcp ``` ## Find it in the registry [#find-it-in-the-registry] WASync is listed in the official MCP Registry as: ```text app.wasync/whatsapp ``` Clients and directories that read the registry can find the server by name instead of pasting the URL. ## The tools [#the-tools] | Tool | What it does | Needs | | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- | | `list_whatsapp_connections` | Lists the connections the grant may use, with status and licence state. Every other tool takes a connection id from here. | read | | `get_whatsapp_connection` | The current state of one connection: online or not, licence status and expiry. Read-only. | read | | `read_whatsapp_messages` | Stored messages, newest first, across every shared connection or one of them; paged with `nextCursor`. Nothing is sent and no read receipt is shown. | read | | `send_whatsapp_message` | Sends a text message from one connection to one recipient. The tool's description tells the model to confirm recipient and wording first: a WhatsApp message cannot be recalled. | send | | `send_whatsapp_file` | Sends a file (document, image, audio or video, up to 5 MB) with an optional caption. Give a direct `https` link in `url` (preferred) or base64 in `data`. Same confirm-first rule: it cannot be recalled. | send | | `mark_whatsapp_messages_read` | Marks one customer's inbound messages as read (blue ticks), by phone number or by a message id. | send | They map onto `GET /connections`, `GET /connections/{id}`, `GET /messages`, `POST /messages` (text and media) and `POST /messages/read`, and they obey the same [scopes](/docs/concepts/scopes) — an agent can only do what the grant allows. ### Sending a file [#sending-a-file] `send_whatsapp_file` takes exactly one of `url` or `data`: ```json title="send_whatsapp_file arguments" { "connectionId": "conn_123", "to": "40700000000", "url": "https://files.example.com/offers/offer-2026.pdf", "filename": "offer-2026.pdf", "caption": "Here is the offer we discussed." } ``` * **`url`** must be a direct `https://` link to a file that anyone on the internet can open without logging in. WASync downloads it (up to 5 MB, 20 seconds) and takes the `mimetype` from the file server's answer unless you pass one. Links that point at private networks, at WASync itself, or at a web page instead of a file are refused. * **`data`** is the file as plain base64 (no `data:` prefix), at most 5 MB decoded, and then `mimetype` is required. Prefer `url`: moving file bytes through a model's conversation is slow and costly. * `filename` is what the recipient sees (no slashes); `caption` is optional, up to 1024 characters. Failures come back as tool errors with a stable code at the start of the message: `invalid_url`, `url_not_allowed`, `download_failed`, `file_too_large`, `invalid_media`, or `send_failed: ` when WASync refused the send. ## MCP or the REST API? [#mcp-or-the-rest-api] Use MCP when a **human-supervised agent** should be able to reach WhatsApp: answering from a chat client, drafting replies, looking things up. Use the [REST API](/docs/api-reference) when your own software owns the behaviour and needs webhooks, idempotency keys, files larger than 5 MB or provisioning — none of which MCP exposes. An OAuth grant is only ever issued over connections that **already exist**, so MCP cannot create a workspace's first connection. Create it with an API key first: [Quickstart](/docs/quickstart/first-call). # Campaign and ad set on conversations from ads (/docs/guides/meta-ads-campaign-attribution) When a customer writes to you from a Click-to-WhatsApp ad, WhatsApp tells WASync which **ad** it was, and nothing more. WASync writes that on the lead or deal: `UTM_SOURCE = facebook`, `UTM_MEDIUM = ctwa`, the ad id in `UTM Campaign` and the click id in `UTM Content`, plus the `UF_CRM_CTWA_*` fields. To report by **campaign** and **ad set** you need the two ids Meta does not send with the message. WASync can look them up in your ad account if you give it a token of your own Business Manager. With the token in place the UTM fields follow Meta's own convention: | Field | Value | | ------------ | ----------- | | UTM Campaign | campaign id | | UTM Term | ad set id | | UTM Content | ad id | The click id stays in `UF_CRM_CTWA_CLID`, and the timeline note on the record shows the names: *Campaign: «Préstamos octubre» (1202…)*, *Ad set: «Profes» (1202…)*, *Ad: «FACSIS IA» 1202…*. ## 1. Create a System User token with ads\_read [#1-create-a-system-user-token-with-ads_read] Five steps, once, about ten minutes. Everything happens in Meta's own interfaces; WASync only receives the token at the end. ### 1.1 An app with the Marketing API product [#1-1-an-app-with-the-marketing-api-product] Meta only issues a token through an app of your own portfolio, and the token dialog lists only the permissions that app can grant. If your portfolio already has an app with the **Marketing API** product, use it. If not, create one once at [developers.facebook.com/apps](https://developers.facebook.com/apps/): **Create app**. Meta's wizard first asks for a *use case*: pick **Other** (the last card at the bottom, labelled "this option is going away soon"), which opens the previous experience: type **Business** → pick your business portfolio → once the app exists, **Add product** → **Marketing API** → *Set up*. In the new experience, the use case under *Ads and monetisation* that creates and manages ads with the Marketing API leads to the same place. Do not pick "Create an app without a use case": it has no products. No code, no review: the app stays in development mode and that is enough for a system user token. ### 1.2 A system user [#1-2-a-system-user] In **Meta Business Suite → Business settings → Users → System users → Add**. Name it in lowercase, for example *wasync attribution* (Meta refuses names with several capital letters); the **Employee** role is enough. ### 1.3 Give it the ad account [#1-3-give-it-the-ad-account] Open the system user → **Assign assets → Ad accounts** → tick the ad account that runs your Click-to-WhatsApp ads → **View performance** (read is enough) → Save. ### 1.4 Give it the app [#1-4-give-it-the-app] Still on the system user → **Assign assets → Apps** → tick the app from step 1.1 → **Develop app** → Save. This is the step most people miss: without it, the token dialog shows only the WhatsApp permissions and **ads\_read** is not in the list. ### 1.5 Generate the token [#1-5-generate-the-token] System user → **Generate token** → choose the app from step 1.1 → expiry **Never** → tick **ads\_read** only → **Generate token** → copy it. Meta shows it once; if you close the dialog, generate a new one. ## 2. Paste it in WASync [#2-paste-it-in-wasync] Open the WASync app in Bitrix24 → **Settings** → the card **Campaign and ad set on conversations from ads**. Paste the token and click **Save token**. WASync stores it encrypted and never shows it again. To check it, paste the numeric id of one of your ads (from Ads Manager, the *Ad ID* column) and click **Test**: the card shows the campaign, the ad set and the ad that WASync would write.
Save token Test Remove token
## If something does not work [#if-something-does-not-work] * **ads\_read is not in the token dialog.** The system user has no role on the app (step 1.4), or the app has no Marketing API product (step 1.1). Fix one of the two and open *Generate token* again. * **The app is not offered in the token dialog.** The app belongs to another business portfolio. Create the app under the portfolio that owns the ad account, or assign it to the system user from that portfolio. * **Test says the token is invalid or expired.** The token was generated with an expiry, or from an app that was later removed. Generate a new one with expiry *Never* and save it again. * **Test says the ad was not found.** The ad belongs to an ad account the system user does not have (step 1.3), or the id is a campaign or ad set id. Use the *Ad ID* column of Ads Manager. * **Leads still show only the ad id.** The token applies to new conversations only; records attributed before the token keep what they have. ## What changes, and what does not [#what-changes-and-what-does-not] * Only new conversations from ads get the three ids; records attributed before the token keep what they have. * A record that already has a `UTM Source` from another channel is never overwritten; the `UF_CRM_CTWA_*` fields are always written. * Each ad is looked up once and remembered for a day, so a campaign with thousands of conversations costs one request to Meta. * If Meta refuses the lookup (expired token, an ad from another ad account), the conversation is attributed as before, with the ad id only, and nothing else breaks. * Remove the token at any time with **Remove token**; WASync goes back to writing the ad id only. Related: [CRM records and timeline](/docs/product/crm-records#ad-attribution). # n8n (/docs/guides/n8n) WASync ships a community node for [n8n](https://n8n.io), published on npm as [`n8n-nodes-wasync`](https://www.npmjs.com/package/n8n-nodes-wasync). It wraps the same REST API these docs describe, so anything the node does you can also do with curl — and anything it does not do yet, you can. ## Before you start: an account and a connected number [#before-you-start-an-account-and-a-connected-number] The node talks to your **WASync account**. If you do not have one yet, create it first — it takes a minute and costs nothing: ### Create a free developer account [#create-a-free-developer-account] Go to [developers.wasync.app/register](https://developers.wasync.app/register) — name, email, password. Every new account comes with its own **workspace**: the place your WhatsApp numbers and API keys live. ### Get a WhatsApp number into that workspace [#get-a-whatsapp-number-into-that-workspace] Two situations: * **You already use WASync inside Bitrix24** — sign in with the same email you use in Bitrix24. Your portal appears as a workspace and its connected numbers are ready to use. Sending through the API needs the **API add-on** on that number ($12 per number per month; without it the node's send step answers `addon_required`). * **You are new to WASync** — connect a number to your own workspace with one API call that returns a QR code (or a pairing code you type into WhatsApp). The exact steps are in [Connect a WhatsApp number](/docs/quickstart/first-call). Every number starts with a **7-day free trial**; plans are WAPP $19 or WABA $29 per number per month, USD. ### Create an API key [#create-an-api-key] Two ways to do this: * **Already using WASync inside Bitrix24?** Go to **Settings → API & Agents → API keys**, name the integration and click **Create key**. It needs a connection with the API add-on active, and it comes with the scopes this workflow needs (`whatsapp.read whatsapp.send`) — skip the scope picklist below. * **Otherwise**, sign in and open [developers.wasync.app/keys](https://developers.wasync.app/keys). Pick the workspace, give the key a name, tick the scopes below, create it. Either way, copy the key immediately — it is shown once. This is the value the n8n credential asks for. The node's **Connection → List** operation shows every number the key can reach. If the list is empty, the workspace has no connected number yet — go back to step 2. ## 1. Install the community node [#1-install-the-community-node] `n8n-nodes-wasync` is a **verified** community node — it carries the verified badge wherever n8n shows one. Two ways to install it, depending on where you run n8n: * **n8n Cloud or self-hosted — search the node panel.** Open the nodes panel, search for **"WASync"**, and add it. Verified nodes install straight from there, no extra setup. * **Self-hosted only — Community Nodes settings.** Go to **Settings → Community nodes → Install**, enter the package name and confirm: ```text n8n-nodes-wasync ``` This path works on any self-hosted instance, verified or not. After installing, the **WASync** and **WASync Trigger** nodes appear in the node panel. Ready-made starting points: the [free workflow templates](https://wasync.app/whatsapp-n8n-kit) cover the most common flows — import one and adjust the fields instead of building from a blank canvas. ## 2. Create the credential [#2-create-the-credential] Add a credential of type **WASync API**. It takes a single field: your API key, which is sent as `Authorization: Bearer …`. Paste the key you created above (see *Before you start*) — it is shown once. Give it only the scopes the workflow needs: * listing connections and reading messages → `whatsapp.read` * sending and marking read → `whatsapp.send` * the trigger → `whatsapp.events` See [Scopes](/docs/concepts/scopes). ## 3. Your first workflow [#3-your-first-workflow] The simplest useful workflow is two nodes: a manual trigger and a send. **Find the connection id.** Add a **WASync** node, choose resource **Connection** → operation **List**, and run it. Copy the `id` of the number you want to send from. **Send a message.** Add a second **WASync** node, resource **Message** → operation **Send**. Fill in: | Field | Value | | -------------- | ------------------------------------------------- | | `connectionId` | the id you just copied | | `to` | international digits, no `+` — e.g. `40712345678` | | `text` | the message body | **Execute.** The node returns the message id you can join on later — see [the two ids](/docs/quickstart/first-message). ## Operations the node supports [#operations-the-node-supports] | Resource | Operation | Parameters | | ---------- | ---------------- | ---------------------------- | | Connection | **List** | — | | Message | **Send** | `connectionId`, `to`, `text` | | Message | **Get Many** | `connectionId`, `limit` | | Message | **Mark as Read** | — | Text sending only. Sending a WhatsApp **template** and checking whether a number is on WhatsApp are not available through the API today, so the node does not offer them — do not build a workflow that assumes they exist. ## 4. The trigger [#4-the-trigger] **WASync Trigger** starts a workflow when something happens on your account. It supports four events: * `message.received` * `message.status` * `connection.connected` * `connection.disconnected` The payloads are exactly the ones in the [Webhooks guide](/docs/guides/webhooks) — same fields, same ids, same `timestamp`-in-milliseconds. The API has a **single** webhook URL per account (`PUT /webhook`, `POST /webhook/rotate`, and no delete). Activating a WASync Trigger points that one slot at n8n. So: if your own backend was already receiving webhooks, **it stops** the moment the trigger takes over. And two WASync Triggers cannot both hold the slot — the second one wins. If you need events in more than one place, receive them once and fan out yourself: let n8n hold the slot and forward from a workflow, or let your backend hold it and call an n8n Webhook node. Test and production trigger URLs are different URLs, so switching between them also moves the slot. Because deliveries are dropped after three failed attempts, keep a reconciliation path even in n8n: a scheduled workflow calling **Message → Get Many** every 30–60 seconds catches anything the trigger missed while the instance was restarting. ## When the node is not enough [#when-the-node-is-not-enough] The node covers the common path. For media sends, pairing codes, connection provisioning, `Idempotency-Key` handling or anything else in the [API reference](/docs/api-reference), use n8n's **HTTP Request** node with the same credential: base URL `https://developers.wasync.app/api/v1`, header `Authorization: Bearer `. # OAuth2 for third-party apps (/docs/guides/oauth2) An [API key](/docs/quickstart/create-account-and-key) does everything in these docs with none of the machinery. OAuth is the right tool for exactly one job: your app is installed by *other* WASync customers, and those customers have to consent to connections they own. ## Register the app [#register-the-app] Register at [https://developers.wasync.app/apps](https://developers.wasync.app/apps). You get a `client_id` and a `client_secret` (shown once), and you set one or more `redirect_uri` (matched exactly at token exchange), an optional `webhook_url`, and the scopes you need. ## The flow [#the-flow] **Authorization Code with PKCE — `S256` is required.** Send the user to `/oauth/authorize` with `response_type=code`, your `client_id`, `redirect_uri`, `scope`, a `state` and a `code_challenge`. | Endpoint | URL | | ---------------------------- | -------------------------------------------------------------------- | | Authorize | `https://cloudapi.wasync.app/oauth/authorize` | | Token (`client_secret_post`) | `https://cloudapi.wasync.app/oauth/token` | | Discovery | `https://cloudapi.wasync.app/.well-known/oauth-authorization-server` | These URLs — and the [MCP server URL](/docs/guides/mcp) — read `cloudapi.wasync.app` on purpose. They are protocol identifiers your client library and our discovery documents have already registered, so they must match byte-for-byte. Only the REST base URL and the human-facing pages use the canonical `developers.wasync.app`. ## Consent depends on who owns the connections [#consent-depends-on-who-owns-the-connections] **Bitrix24.** WASync shows a short user code, and someone with Write access to the portal's **API & Agents** area enters it under **Settings → API & Agents**, picking connections and scopes. Every Bitrix24 administrator has that access; so does anyone an administrator has granted it to in the access matrix on the Staff page. **Standalone.** The developer approves at [https://developers.wasync.app/authorize](https://developers.wasync.app/authorize) — auto-approved when they own exactly one workspace with at least one connection. ## Exchange the code [#exchange-the-code] ```bash title="Token exchange" curl -X POST https://cloudapi.wasync.app/oauth/token \ -d grant_type=authorization_code \ -d code=$AUTH_CODE \ -d redirect_uri=https://your.app/callback \ -d client_id=$CLIENT_ID \ -d client_secret=$CLIENT_SECRET \ -d code_verifier=$CODE_VERIFIER ``` `access_token` lives **15 minutes**. `refresh_token` lives **30 days and rotates on use** — persist the new one atomically and serialise refreshes across workers, or two workers racing will invalidate each other's token. The access token goes in the same header as an API key: `Authorization: Bearer …`. Both credential types reach every endpoint. ## One structural limit [#one-structural-limit] A grant is only ever issued over connections that **already exist**, so an OAuth-only integration cannot create a workspace's first connection. An API key can — which is why the [quickstart](/docs/quickstart) starts with one. ## Webhooks for OAuth apps [#webhooks-for-oauth-apps] An OAuth app sets `webhook_url` on the app itself rather than calling `PUT /webhook`, and the grant must have been approved **with** `whatsapp.events` or nothing is delivered. Everything else — the signature scheme, the retry policy, the payloads — is identical to the [Webhooks guide](/docs/guides/webhooks). Subscriptions created before **24 July 2026** receive only `message.received`; those created before **10 August 2026** do not receive the connection events. Re-authorize to pick up the newer event types, or write to support and ask for them to be added to your existing subscription. # Pairing code & QR (/docs/guides/pairing-and-qr) Pairing applies to `qr` connections. A `cloud_api` number never scans anything and answers `409 not_supported_for_provider`. ## The QR path [#the-qr-path] `POST /connections` returns an initial QR as a data-URI PNG. WhatsApp rotates the pairing code roughly every **20 seconds**. The `qr` in the create response is stale within seconds of being displayed, and this fails **silently**: the phone never pairs and nothing on screen explains why. Poll `GET /connections/{id}` every 3–5 s and re-render the `qr` from *every* response until `status` is `"connected"`. Do not cache it, and do not hide the refresh behind a button the user has to press. The same rule applies to an idempotent replay: when `POST /connections` returns `200` with `Idempotency-Replayed: true`, the `qr` in that response has been re-fetched fresh rather than replayed from storage — precisely because a stored code would no longer scan. ## The pairing-code path [#the-pairing-code-path] A QR needs two devices: a screen showing it and a phone photographing it. A large share of real onboardings happen on **one** device — the customer finishes your flow on the same phone that runs WhatsApp, and cannot photograph its own screen. For them the QR path is not awkward, it is impossible. ```bash title="POST /connections/{id}/pairing-code" curl -X POST https://developers.wasync.app/api/v1/connections/conn_8f3a21/pairing-code \ -H "Authorization: Bearer $WASYNC_API_KEY" \ -H "Content-Type: application/json" \ -d '{"phoneNumber":"40740267964"}' ``` ```json title="200 response" { "code": "7S59-1KZP" } ``` The customer opens WhatsApp → **Settings → Linked devices → Link with phone number** and types the code. `phoneNumber` is E.164 **without** the leading `+` — digits only. Anything else is rejected with `400 { "error": "invalid_phone_number" }` rather than cleaned up for you: silently rewriting the number you sent is how a customer ends up pairing an account nobody asked for. Uses `whatsapp.manage`, same as creating the connection. The engine can decline to issue one. That is an ordinary outcome, not an outage, and it answers `502 { "error": "pairing_code_unavailable" }` instead of a generic 500 precisely so you can tell the two apart and send the user back to the QR. An integration that ships only the pairing-code path will, sooner or later, show a customer a screen with no way forward. **Render both, side by side.** ## Asking for another code [#asking-for-another-code] You can request another code on the same connection: it returns a *new* code and does not rebuild the session, so a "send me another code" button is safe. It is capped at **5 per connection per 15 minutes**; past that you get `429 { "error": "rate_limited" }` with a `Retry-After` header to honour. The cap is not bureaucracy — repeatedly requesting codes for one number is exactly what WhatsApp's anti-abuse systems act on, and the number at risk is your customer's. ## Nothing extra is consumed [#nothing-extra-is-consumed] Pairing by code uses the same paid slot and starts the same **7-day free trial** as scanning a QR: the licence is claimed when the number actually pairs, whichever way it paired. Watching for success is unchanged too. There is no "code accepted" event, so poll `GET /connections/{id}` until `status` is `"connected"` and/or listen for the `connection.connected` webhook. Two refusals are worth coding for: * `409 already_connected` — the session is live, there is nothing to pair. * `409 not_supported_for_provider` — a `cloud_api` number. Pairing codes are a `qr` concept and never apply, so do not retry. ## Re-pairing later [#re-pairing-later] A `qr` session can break on its own. `connection.disconnected` tells you, and `needs_reconnect` is the field to drive your UI from. The QR is deliberately not in that payload — it is a scan-to-login credential — so fetch it from `GET /connections/{id}` and show it to the number's owner exactly as during first setup. See [Webhooks](/docs/guides/webhooks). # Smart Processes (SPA) in WASync (/docs/guides/smart-processes) Bitrix24 **Smart Processes** (SPA, "smart process automation") are custom CRM entities next to leads and deals: contracts, service requests, bookings, claims. WASync treats an SPA item like a lead or a deal wherever that makes sense: * the **WASync tab** in the item card shows the WhatsApp conversation of the item's client; * a conversation in **WASync Chat** can be linked to an item, and the item's responsible person counts for the "Assigned to" filter and the "only my records" scope; * messages are written to the item's **timeline** (comments), as on leads and deals; * WASync **robots** (send message, send template, start a Chat Flow, AI) run from the process's **automation rules**, and a Chat Flow can read and fill the item's fields. ## What the item needs [#what-the-item-needs] An SPA item has no phone number of its own. WASync reaches the person through the **client** bound to the item: the contact (or company) in the item's *Client* field. That field exists only when the process was created with **Client** enabled (*CRM → Smart Processes → the process → Settings → Client*). * Process without *Client*: the WASync tab explains that there is nobody to write to and links to the item card. Turn *Client* on in the process settings, then bind a contact to the item. * Item with a contact that has no phone: the tab offers to add the number, as on a deal. * Several contacts on one item: WASync uses the primary contact first, then the others in the item's order, then the company's phone. ## The WASync tab in the item card [#the-wasync-tab-in-the-item-card] Open any item of the process. The **WASync** tab works like the one on deals: the conversation with the client, sending text, files, voice notes and (on the official API plan) templates. The header shows the item's title, stage and responsible person. The tab is added automatically: * at installation, for every process that exists at that moment; * when a process is created or changed later (WASync listens to Bitrix24's process events), and once a day as a safety net; * immediately, if an administrator opens **WASync → Settings → Reinstall placements**. If a brand-new process does not show the tab yet, reload the page a minute later or use *Reinstall placements*. ## Linking a conversation to an item [#linking-a-conversation-to-an-item] In **WASync Chat**, open the conversation → *Link to record*. When the portal has Smart Processes, a type selector appears above the search: pick the process, type at least two letters of the item's title, choose the item. The inbox row then shows the process name as the record chip, the header shows the item's responsible person and stage, and *Change record* lets you move the conversation to another item. Bitrix24 permissions apply: the search runs as the operator, so only items that person may see are offered. ## Timeline [#timeline] With the default timeline setting, every message is written as a comment on the records that carry the client's phone — leads, deals, contacts, companies — and on the linked item. With *Timeline target → conversation record*, messages are written once, on the record the conversation is linked to, which may be an SPA item. ## Robots on automation rules [#robots-on-automation-rules] Open the process → **Automation rules**. The WASync robots are listed under the WASync group, exactly as on leads and deals: * **Send WhatsApp message** / **Send WhatsApp template (WABA)**: the recipient is the item's client (primary contact, other contacts, company, in that order). `{{Fields}}` of the item, its contact and its company are available in the text. * **Start a Chat Flow**: starts a flow whose record type is this process (see below). * **AI robot**: as on deals. After installing or updating WASync, **reload the automation page once**: Bitrix24 caches robot definitions until the page is reloaded. ## Chat Flows on a process [#chat-flows-on-a-process] In the Chat Flows editor, the *Record* selector lists every process that has automation enabled. A flow built for a process: * starts **only from an automation rule** of that process (the robot *Start a Chat Flow*); the "first message" and "keyword" triggers are not offered, because a message from a new number cannot create an item on its own; * can read and fill the item's fields (*Fill in a field*, *Insert field*), including custom fields, and the fields of the item's contact and company; * can move the item with **Set stage → Move item**: choose the pipeline (when the process has several) and the stage; * can assign the item, create an activity on it, and hand the conversation over, as on a deal. `{{record.stage}}` renders the stage's name, `{{record.title}}` the item's title. ## Ad attribution (click-to-WhatsApp) [#ad-attribution-click-to-whatsapp] When a conversation that started from a click-to-WhatsApp ad is linked to an item, WASync fills the item's native UTM fields (source, medium, campaign, content, term) if they are still empty, and leaves one timeline comment with the ad. Custom `UF_CRM_CTWA_*` fields are not created on Smart Processes: Bitrix24 does not let an application add user fields there. ## Limits in this version [#limits-in-this-version] * Automations v2 (event-driven sends) and the *Send conversion to Meta* robot stay on leads and deals. * A flow cannot create an SPA item from a new conversation; link the conversation to an item or start the flow from the process's automation. * *From CRM field* attachments in Chat Flows read lead and deal file fields only. * Calls started from the item card are not yet wired to the item. ## REST and MCP [#rest-and-mcp] Nothing changes in the Platform API: items are Bitrix24's own `crm.item.*` objects. In WASync's data, a linked item appears as record type `dynamic_` (for example `dynamic_137`) wherever leads appear as `lead` and deals as `deal`. # WhatsApp templates (WABA) (/docs/guides/waba-templates) A **template** is a message that Meta has approved in advance. It is the only kind of message a WhatsApp Business API (**WABA**) number may send to a customer who has not written to you in the last 24 hours. This page covers writing one in WASync, what happens at Meta, and every place you can send it from. ## What a template is, and when you need one [#what-a-template-is-and-when-you-need-one] WhatsApp gives a business a **24-hour customer service window**. It opens when the customer writes to you and stays open for 24 hours after their last message. * **Inside the window** you can send any free-form text, file or voice note. * **Outside the window** (the customer never wrote, or wrote more than 24 hours ago) only an approved template goes out. When the customer replies, the window opens again for 24 hours. In **WASync Chat**, a closed window shows the banner *Conversation paused — send a template to re-engage* with a **Pick a template** button, and a chip in the chat header shows how much of the window is left. Every template has one of three categories, which Meta uses for review and for billing: | Category | Use it for | | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------ | | **Utility** | An update about something the customer already started: appointment confirmation, order status, invoice, delivery, payment reminder. | | **Marketing** | Offers, promotions, news, getting back in touch with a past customer. | | **Authentication** | One-time codes, with wording fixed by Meta. WASync cannot create these yet. | Template messages are **billed by Meta per template message, by category** (marketing, utility, authentication). Utility templates sent inside an open 24-hour customer service window are free. The charge goes to the payment method on your Meta account, not through WASync. Creating or submitting a template costs nothing. ## Requirements [#requirements] * A **WABA number** connected to WASync, on the WABA plan. See [Connection types](/docs/concepts/connection-types) for how it differs from a QR-paired number. * To manage templates: an administrator, or a staff member with write access to **WhatsApp numbers & templates** (Staff access matrix). Reading the list needs read access. * To send them: access to the number in **Connections → Staff**, like any message. Templates exist only on the official WhatsApp Business API. On a QR-paired number the template button is not offered, and a robot or automation that tries to send one fails with: *This WhatsApp connection cannot send templates. Templates need a WhatsApp Business (Cloud API) number.* ## Create a template [#create-a-template] Open the WASync app in Bitrix24, go to **Connections**, open the **…** menu of the WABA number and choose **Message templates**. The list shows each template with its language, category, status and, for rejected ones, Meta's reason. Click **+ New template**. ### What is the message for? [#what-is-the-message-for] Pick **Inform a customer** (Utility), **Promote an offer** (Marketing) or **Send a code** (marked *Coming soon*). The choice sets the category for you. Be honest here: a promotional text submitted as Utility is rejected or moved to Marketing by Meta. You can also start from an example (*Appointment reminder*, *Order is ready*, *Offer with an image*, *Let's pick up the conversation*) and change everything in the next step. Choose the **Message language**. A template has a single language; for another language you create another template. ### Write the message [#write-the-message] Write the text the way the customer receives it; the preview on the right is what they will see (up to 1,024 characters). * **Personalize.** Click **+ Personalize** to add a variable: a common one (*Customer name*, *Date*, *Time*, *Order number*, *Expiry date*, *Product or service*, *Amount*), a **Bitrix24 field**, or your own label. Behind the scenes each one becomes `{{1}}`, `{{2}}`, and so on. Do not type braces by hand. * **Examples for approval.** Meta wants a realistic sample value for every variable (for example "Ana", "31 October"). Use believable values, never real customer data. They are not sent to anyone. * **Header (optional).** A title (up to 60 characters, no variables), or an **Image** (JPEG or PNG, up to 5 MB), **Video** (MP4, up to 16 MB) or **PDF** (up to 16 MB). The file you upload is the **sample** Meta reviews. WASync keeps it as the template's default file, so operators are not asked for it again. * **More options.** A footer (up to 60 characters), up to 3 quick-reply buttons, one link button (a fixed URL, no variables), one call button, and **Include a WhatsApp call-permission request**. Button labels are limited to 25 characters. The call-permission request is available only when WhatsApp calls are turned on for the number ([Turning calls on for a number](/docs/product/calls#turning-calls-on-for-a-number)): WhatsApp approves such a template anyway, then refuses every send from a number without calls. WhatsApp rejects a message that starts or ends with a variable, so add a word before the first one and after the last one. WASync checks this and the other rules before you can continue. ### Send for approval [#send-for-approval] Give the template a **Template name** that your team will recognise (only your team sees it). WASync generates the technical name Meta needs: lowercase letters, digits and `_`, unique on this number and language. The checklist shows what was verified. Click **Send to WhatsApp for approval**. Nothing is sent to customers. There is no draft: the list mirrors what Meta has, so a template exists in WASync only once it is submitted. ### After you submit [#after-you-submit] The template appears in the list as **Pending**. Meta reviews it: typically a few minutes, sometimes a few hours, and occasionally up to a day. WASync receives Meta's verdict automatically and updates the status. **Resync from Meta** pulls the live state if you want to check at once. | Status | Meaning | | ---------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | | **Pending** | Meta is reviewing it. It cannot be sent yet. | | **Approved** | Ready. This is the only status that can be sent. | | **Rejected** | Meta refused it. The reason shows on the card. Fix the text and create a new template. | | **Paused** | Meta paused it. Sends fail until it is active again. | | **Disabled**, **In appeal**, **Pending deletion**, **Deleted**, **Limit exceeded** | Meta's own states, shown as received. | **✕** on a card deletes the template, and also deletes it at Meta. ### The default file of a media template [#the-default-file-of-a-media-template] A template with an image, video or PDF header needs that file at every send. Meta keeps its copy only for review, so WASync keeps the sample you uploaded as the template's **default file**. For a template that was approved before this, or created in Meta, use **Set default image** (or *video*, *document*) on its card; **Change** and **Remove** are there too. Without a default, whoever sends picks the file each time. ## Templates created in Meta [#templates-created-in-meta] Templates you built in WhatsApp Manager are not in WASync until you click **Resync from Meta** in the template list. Resync imports them with their buttons and header, refreshes every status, and marks a template as **Deleted** when it no longer exists at Meta. It is safe to run any time. ## Send a template [#send-a-template] All three ways below send only **Approved** templates, only from a WABA number, and refuse a contact who has asked to stop receiving messages. If a customer replies with a stop request, WASync marks them as opted out; an administrator can clear the opt-out when the person asks to be contacted again. ### From the chat [#from-the-chat] In the **WASync tab** of a lead, deal or Smart Process item, and in **WASync Chat**, click the template icon next to the message box (*Send a Meta-approved template*). When the 24-hour window is closed, the *Pick a template* button in the banner opens the same list. 1. Search by name, language or text, and pick a template. 2. Fill in every variable. The first one is pre-filled with the contact's first name when it is known; edit it as needed. The preview shows the finished message. 3. If the template has a media header, choose the file: the template's default file (preselected when it has one) or upload another. **Send** stays disabled until a file is chosen. 4. Optionally tick **Also ask permission for a WhatsApp call after sending** (hidden when the template already asks for call permission). 5. Click **Send**. The message appears in the conversation and in the record's timeline, with the finished text. ### From Bitrix24 automation rules [#from-bitrix24-automation-rules] Open the lead, deal or Smart Process stage → **Automation rules → Add automation** and pick **Send WhatsApp Template (WABA)** in the WASync group. It runs for every record that reaches that stage, one record at a time. * **WABA Connection**: the number that sends. * **Template**: only approved templates of that number are listed. * **Variables**: one row per `{{n}}`. Click **⋯** to open **Insert Field** and choose CRM fields, or type text. A row can combine several fields and fixed text. Fields are read from the record the rule runs on. * **Header image / video / document**: for a media template, choose **File or link** (upload a file, or paste a link or a field that holds one) or **Template's example** (the default file kept by WASync). The recipient is the record's client phone. A deal without a contact yet is re-checked in the background before WASync gives up. When something stops a send, the reason is written to the record's timeline instead of failing silently: a variable that resolved to empty, a template that is no longer approved, a missing header file, an opted-out contact, or a license problem. Empty variables stop the send because Meta rejects empty parameters. After installing or updating WASync, reload the automation page once: Bitrix24 caches robot definitions until the page is reloaded. ### From Chat Flows [#from-chat-flows] In the flow editor, a **Message** step has a section called **WhatsApp Business template (window closed)**. Choose the number, an approved template, fill each variable (a CRM field like `{{NAME}}` or fixed text) and, for a media template, the header file. The template is used **only** when the number is a WABA number and the 24-hour window is closed, for example the first message to a customer who never wrote. If the window is open, the step sends the normal text. If the window is closed and the step has no template, it fails with *On a WhatsApp Business number the first message must use an approved template.* Files attached to the step are not sent with a template. An empty variable is replaced with a dash instead of stopping the step. If Meta answers with a temporary error, the step retries once before it fails. ## What is not included: bulk campaigns [#what-is-not-included-bulk-campaigns] WASync has no bulk or broadcast campaign module: you cannot upload a list and send a template to everyone. What it does is send **one template per CRM record when an automation rule runs**. To message a segment, put those leads or deals in a stage (or move them there) and let the **Send WhatsApp Template (WABA)** rule run on that stage. ### Stay within Meta's limits [#stay-within-metas-limits] * Each number has a **messaging limit** that depends on its quality tier (the Connections page shows the tier Meta assigned, for example 1,000 customers per 24 hours). Sends above it fail. * Message only people who expect to hear from you. Each block or report lowers the **quality rating**; a lower rating lowers the limit, and a template with poor feedback can be paused. * Say who you are in the first line and tell people how to stop. Respect a stop: WASync blocks templates to opted-out contacts. * When Meta restricts or limits the number, the Connections page and the Templates window show a banner (*Meta has blocked sending on this number* or *Meta has limited sending on this number*) with what to do and a link to Meta Account Quality. ## Troubleshooting [#troubleshooting] | What you see | What to do | | ----------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Status **Rejected**, with a reason on the card | Read Meta's reason. Common causes are a promotional text in a Utility template, a variable at the start or end of the text, or missing examples. Create a corrected template under a new name. | | Status **Paused** | Meta paused the template, usually because of poor customer feedback. Improve the text, or create a new template. Do not keep sending a paused one. | | *Meta has blocked / limited sending on this number* banner | Open Meta Account Quality with the button in the banner and follow its steps: payment method, business verification or an appeal. Sends and new templates stay blocked until Meta lifts it. | | *Access token expired or invalid* in the Templates window | On the Connections page, run **Connect with Facebook** on that number to refresh the token. | | Template not in the list when sending | Only **Approved** templates appear. Check the status, then **Resync from Meta**. | | Variable error when creating (*isn't a valid variable*, *needs a CRM field and an example value*) | Add variables with **+ Personalize**, not by typing braces, and give each one an example. Numbering must run 1, 2, 3 with no gaps. | | Robot did not send, timeline says *empty variable(s)* | A field mapped to a variable was empty on that record. Fill the field on the record, or change the variable to another field or to fixed text. | | *This template has a … header*, or the send is disabled | A media template needs its file. Choose a file at send time, in the rule or step, or set the template's default file. | | *This WhatsApp connection cannot send templates* | The number is QR-paired. Use a WABA number. | | *This template asks for call permission, but WhatsApp calling is not enabled on this number*, or a template marked **Needs calling** cannot be picked | Turn on calls for the number in **Connections** → **WhatsApp calls**, or send another template. | | *Templates to this contact are blocked: this contact asked to stop receiving messages* | The contact opted out. You can still reply to messages they send you. An administrator can clear the opt-out only if the person asked to be contacted again. | ## Related [#related] * [Connection types](/docs/concepts/connection-types): QR-paired numbers and WABA numbers. * [Bring a number from another provider](/docs/guides/bring-your-own-number): move an existing WABA number to WASync. * [Smart Processes (SPA) in WASync](/docs/guides/smart-processes): the template robot runs on Smart Process automation rules too. # Webhooks (/docs/guides/webhooks) Point WASync at your endpoint and you get a signing secret back. Uses `whatsapp.events`. No app registration and no consent step is involved. An account has exactly **one** webhook URL. `PUT /webhook` sets it — calling it again with a different URL *moves* the endpoint rather than adding a second one, and there is no delete. This matters as soon as more than one thing wants events: an [n8n trigger](/docs/guides/n8n) and your own backend cannot both own the slot. Fan out on your side. ## Set the endpoint [#set-the-endpoint] ```bash title="PUT /webhook" curl -X PUT https://developers.wasync.app/api/v1/webhook \ -H "Authorization: Bearer $WASYNC_API_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://example.com/wasync/webhook"}' ``` ```json title="200 response" { "url": "https://example.com/wasync/webhook", "events": [ "message.received", "message.status", "connection.disconnected", "connection.connected" ], "secret": "whsec_3f9a…" } ``` **Store the secret.** It is issued here because this is the moment you need it to write your verification code, and `GET /webhook` will not return it again — that endpoint reports `{ url, events, secretSet }`, deliberately without the secret, because a read path gets logged and pasted into tickets. Lost it? Call `POST /webhook/rotate` for a new one. The URL must be HTTPS on a publicly reachable host; `http`, localhost and private ranges are rejected with `400 invalid_webhook`. Rotation has **no overlap window**: the old secret dies the instant the new one is issued. Deploy the new secret promptly — the retry policy below covers a rollout measured in seconds, not hours. ## Event catalog [#event-catalog] | Event | Fires when | Direction | | ------------------------- | ------------------------------------------------------------------- | --------------------------------------------------------- | | `message.received` | A WhatsApp message arrives on a granted connection (text or media). | Inbound only — messages you send do not fire this. | | `message.status` | The delivery state of one of your outgoing messages changes. | Outbound only. | | `connection.disconnected` | A connection stopped working and needs its owner to pair again. | Once per outage, not repeatedly while it stays broken. | | `connection.connected` | A connection that had broken is working again. | Once, and only for a connection you were told had broken. | Ignore unknown `event` values rather than treating them as errors — new types are announced on the [changelog](/docs/changelog) before they ship. Events fire for **`qr` connections only**. `cloud_api` connections emit no webhooks today; poll `GET /messages` and `GET /connections/{id}` for those. ## Payload [#payload] ```json title="POST your webhook URL" { "event": "message.received", "connection_id": "conn_8f3a21", "message": { "id": "cmqj3k2ab0001xyz", "wa_id": "false_40700000000@c.us_3EB0A1B2C3", "from": "40700000000", "text": "Hello!", "media_url": null, "media_type": null, "timestamp": 1766138640000 } } ``` * `message.id` — WASync's stable id (the same value `GET /messages` returns as `id`). **Dedupe and join on it** — delivery is at-least-once. * `message.wa_id` — WhatsApp's own id, `null` when unknown. Support and debugging only, never a dedupe or join key. * `from` — international digits only, no `+`. * `text` is `null` for media-only messages; `media_url` / `media_type` are `null` for text messages or when the file is not publicly fetchable. * `timestamp` — epoch **milliseconds** as a number, not an ISO string. A `message.status` delivery updates one of your outgoing messages: ```json title="POST your webhook URL" { "event": "message.status", "connection_id": "conn_8f3a21", "message": { "id": "cmqj3k2ab0001xyz", "wa_id": "true_40700000000@c.us_3EB0A1B2C3", "status": "read", "timestamp": 1766138641000 } } ``` ## Verify the signature [#verify-the-signature] Every delivery carries `X-WASync-Timestamp` (epoch ms) and `X-WASync-Signature: sha256=`, which is `HMAC-SHA256(timestamp + "." + rawBody, secret)`. Compute it over the **raw** body — before any JSON parsing — and compare in constant time. Reject deliveries whose timestamp is more than \~5 minutes old, which is what blocks replays. ```js title="verify.js" import crypto from "node:crypto"; // rawBody MUST be the exact bytes you received (verify BEFORE JSON.parse). export function verifyWASync(headers, rawBody, secret) { const ts = headers["x-wasync-timestamp"]; const sig = headers["x-wasync-signature"]; // "sha256=" const expected = "sha256=" + crypto.createHmac("sha256", secret) .update(`${ts}.${rawBody}`) .digest("hex"); return Boolean(sig) && crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected)); } ``` ```js title="receiver (express)" import express from "express"; import { verifyWASync } from "./verify.js"; const app = express(); // Capture the RAW body — signature verification needs the exact bytes. app.post("/webhooks/wasync", express.raw({ type: "application/json" }), (req, res) => { if (!verifyWASync(req.headers, req.body.toString("utf8"), process.env.WASYNC_WEBHOOK_SECRET)) { return res.status(401).end(); } // Reject stale deliveries (replay window) — 5 minutes is a sane tolerance. if (Math.abs(Date.now() - Number(req.headers["x-wasync-timestamp"])) > 5 * 60_000) { return res.status(401).end(); } res.status(200).end(); // ACK fast — under 10s — then process async const { message } = JSON.parse(req.body.toString("utf8")); // ... your logic (dedupe on message.id — retries can deliver duplicates) }); ``` ## Delivery & retry policy [#delivery--retry-policy] | Property | Value | | ---------------------- | --------------------------------------------------------------------------- | | Success criterion | Any `2xx`. Everything else, including redirects, is a failure. | | Attempts | 3 per event — immediate, then after 500 ms, then after 1 s. | | Per-attempt timeout | 10 seconds. ACK fast and process async. | | After the last failure | The event is **dropped**. There is no long redelivery queue. | | Duplicates | Possible. Dedupe on `message.id`. | | Ordering | Not guaranteed. Order by `timestamp` if it matters. | | Signature on retries | Identical body and signature are resent — verify each attempt the same way. | ## Status ladder [#status-ladder] `message.status` values form a one-way ladder: `sent` (1) → `delivered` (2) → `read` (3), with `failed` as a terminal outcome that does not follow `read`. **Apply updates monotonically.** Only apply a new status if its rank is higher than the one you have stored. A message can arrive with `read` before `delivered` (a late delivery), and duplicate events are possible. Never move a message backwards in your UI. ## Reconciliation — poll as a safety net [#reconciliation--poll-as-a-safety-net] Deliveries are attempted three times and then dropped, which makes your webhook handler the **fast path, not the guarantee**. Run a background loop that polls `GET /messages?connectionId=…` every **30–60 seconds** and upserts anything the handler has not seen, using the cursor for incremental fetches. The same loop backfills status updates that arrived while your endpoint was down. Webhooks = real-time UI updates. Polling = correctness. Run both. ## Connection lifecycle [#connection-lifecycle] ```json title="POST your webhook URL" { "event": "connection.disconnected", "connection_id": "conn_8f2a…", "connection": { "id": "conn_8f2a…", "phone_number": "393331234567", "label": "Studio Rossi", "status": "disconnected", "needs_reconnect": true, "license_status": "active", "license_expires": "2027-08-08T09:00:00.000Z", "reason": "AUTH_LOST" }, "timestamp": 1786000000000 } ``` A `qr` connection can stop working for reasons outside anyone's control — the phone is switched off for a day, WhatsApp is opened on another device, the session ages out. The number then goes quiet in both directions, and without an event the first person to notice is your customer. **The QR code is deliberately not in the payload.** A WhatsApp QR is a scan-to-login credential: anyone who reads it can take over the session. The event tells you a re-pair is needed — fetch the QR itself over your authenticated `GET /connections/{id}` and show it to the number's owner, exactly as during first setup. Drive your UI off `needs_reconnect`; treat `reason` as an advisory log hint, since new values can appear. Detection latency: a disconnect is found by a 5-minute status probe (\~5 min). When the session looks recoverable an automatic heal is attempted first, so that path takes \~15–20 minutes. ## Not receiving events? [#not-receiving-events] * Is the delivery URL HTTPS on a public host? Localhost, private IPs and `http://` are rejected. Use a tunnel during development, and check what is actually stored with `GET /webhook`. * Does the credential carry `whatsapp.events`, and does it cover the connection the message arrived on? * Is the connection's licence still active? An expired licence means no events and `402` on sends. * Does your endpoint answer `2xx` within 10 seconds? Slow handlers look like failures and burn all three attempts. * Is it a `qr` connection? `cloud_api` connections emit no webhooks. * Only **inbound** messages fire `message.received` — your own sends never do. # Help Center (/docs/help-center) Every page here answers one question a customer asked us, in the words they used. Each answer says what happens, where the setting is, and links to the product page that documents the feature in full. The Help Center is kept in step with the product: when a feature changes, its answers change with it. Not answered here? Write to [support@wasync.app](mailto:support@wasync.app) with your portal name; we answer in writing, usually within the hour on business days. # Automations (/docs/product/automations) An **automation** is a Bitrix24 robot you add to a pipeline stage or a trigger. When it fires, WASync reads the lead, deal or contact, asks an AI model to write the message from the instructions you gave and the record's fields, and sends it on WhatsApp from the number you chose. It is the tool for "when the deal reaches this stage, write to the customer about exactly this deal" without a template for every case. Automations need at least one **Pro** connection on the portal; without it they are listed but do not run. ## Creating one [#creating-one] **Automations → New automation**: name, the entity it works on (lead, deal, contact), the WhatsApp number that sends, the instructions for the model (what to say, tone, what to use from the record), the language it responds in, and the mode: | Mode | Behaviour | | ----------------- | ---------------------------------------------------------------------- | | **Auto send** | The message goes out the moment the robot fires. | | **Confirm first** | A person reviews the generated text in Bitrix24 and sends or edits it. | Then add the robot **WASync AI message** to the automation rules of the stage in Bitrix24 and pick the automation. Reload the Bitrix24 page after adding robots; Bitrix24 reads their definitions at page load. ## Model [#model] Each automation uses the model set under **Chat Flows → AI assistant** (the same key the Chat Flows AI step uses), or a model of its own chosen in the automation, which overrides the portal default. Keys are stored on the server; the model never sees more than the fields you expose in the instructions. ## Attachments [#attachments] Up to five files per automation, sent with every message: images, videos, documents, voice notes. The generated text goes as the caption of the first image, video or document; with voice notes only, it goes as a separate message. Files can also come from a file field on the record. ## Statistics [#statistics] **Stats** on each automation: sent, pending (waiting for confirmation) and failed in the last 30 days, with the failure reasons, typically a record without a phone number, no Pro licence, or a refusal by WhatsApp. **Pause** stops an automation without deleting it. ## Related [#related] * [Chat Flows](/docs/product/chat-flows) for conversations that ask questions and branch; automations send one message per trigger. * [Guide: WhatsApp templates](/docs/guides/waba-templates) for Business API numbers outside the 24-hour window. # Calls (/docs/product/calls) WhatsApp calls are available on WhatsApp Business API numbers. They are not available on numbers paired by QR, and not on numbers that run in coexistence with the WhatsApp Business app on the phone. Two things have to be in place. The WASync app in Bitrix24 needs the telephony permission; when Bitrix24 offers an update of WASync in the Market, install it and calls start working with nothing to reconnect. And calls need a browser tab with Bitrix24 open, in Chrome, Edge or Bitrix24 Desktop: the voice runs in that tab, so a closed browser cannot answer. ## Turning calls on for a number [#turning-calls-on-for-a-number] Calls are a setting of each connection. Open the WASync app, go to **Connections**, and use the **WhatsApp calls** button on the number. The window shows **Incoming calls** as ON or OFF; choose **Turn on** or **Turn off**. The setting is read from WhatsApp every time the window opens, so it always shows what customers really see. Connections paired by QR show the button as **WhatsApp calls — WABA only** and cannot be switched on. With calls on, customers see a call button on that number in WhatsApp. Turn it on only when someone is available to answer: a call nobody picks up shows the customer a missed call. Calling a customer needs their permission, and WhatsApp asks for it with a call-permission request: * Tick **Also ask permission for a WhatsApp call after sending** in the template picker, or choose a template that carries the call-permission card. * Add the **Ask permission to call** step to a Chat Flow. A template that carries the call-permission card works only on a number with calls turned on: WhatsApp approves such a template anyway, then refuses every send from a number without calls. WASync therefore offers **Include a WhatsApp call-permission request** in the template builder only when calls are on, marks these templates **Needs calling** and greys them out in the template picker on a number without calls, and refuses the send before it reaches WhatsApp, from the chat, automation rules and Chat Flows alike, with the reason in the conversation. The customer sees a card in the chat asking whether you may call them. Their answer is recorded on the contact. In the CRM widget and in WASync Chat the phone icon turns green while the permission is active, and a chip beside the name reads **Calls allowed** or **Calls declined**. WhatsApp allows one permission request per customer per 24 hours and two per seven days. After four unanswered calls in a row it withdraws your permission to call that customer, so wait a few minutes before trying again. ## Who is rung for an incoming call [#who-is-rung-for-an-incoming-call] In **Settings**, administrators find the **Incoming calls** card. It decides who is rung first when a known customer calls. | Option | Who rings first | | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | | **The contact's responsible person** | The person responsible for the contact (or company, or lead) in the CRM. | | **The responsible person of the most recent open deal or lead** | That person. With no open deal or lead, it falls back to the contact's responsible person. | | **Both at once** | Both people ring together. |
## Which record a flow creates or binds to [#which-record-a-flow-creates-or-binds-to] Under **When it starts**, a **Customer writes first** flow is attached to a lead, a deal or a Smart Process item (a deal flow also picks the pipeline and stage). The flow finds the contact by phone number. It never creates a duplicate of a contact you already have. | Flow type | What happens at the first message | | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Lead** | Binds to the contact's open deal, else to the contact's open lead, else to an open lead that holds the number without a CRM contact, else creates a contact (if needed) and a lead. | | **Deal** | Binds to the contact's open deal in the chosen pipeline, else creates a contact (if needed) and a deal. | So a customer who is already being worked never gets a second lead from a flow. With **Each number creates its own lead** switched on, "already being worked" means on this number: a first-time contact gets the number's own lead, and an older lead that merely holds the phone (another tool's lead) is not reused. The deal is checked first. A lead that carries the customer's number but is not linked to any CRM contact, such as a lead imported from another tool, counts too: the flow binds to it instead of creating a lead next to it.
Two settings from **WASync Chat → Chat rules** apply to the records a flow creates: * **Who is responsible.** Bitrix24 puts a record without a responsible on the user who installed the app. To avoid that, a contact, lead or deal created by a flow takes its responsible from the rule **New chats from unknown numbers** (a fixed person or round-robin). With that rule **Off**, the flow leaves Bitrix24's default. * **Each number creates its own lead.** With this option on, "already being worked" means on the number the customer wrote to: the flow reuses only the record created or linked from that number. An open deal or lead the contact has from another channel, for example an import or another WhatsApp tool, is left alone and the flow creates the number's own lead. * **Re-contact window after a closed lead.** A flow that creates a lead uses the same window as the rule. A customer who writes back inside the window lands on the lost lead, not on a second one. See [Leads from WhatsApp chats](/docs/guides/leads-from-whatsapp-chats). ## The CRM source of the record [#the-crm-source-of-the-record] For lead and deal flows, the **Source** selector under **When it starts** lists your CRM sources. The source you pick is written on the contact, lead or deal the flow creates. You can, for example, leave a placeholder such as "not selected" for your team to fill in later, or stamp a campaign source of its own. The default, **Automatic — the WhatsApp line's source**, gives the record the source of the WhatsApp Open Channel it came through. A record the flow reuses instead of creating keeps its own source; the flow never rewrites it.
| Option | What operators see | | ----------------------------------- | -------------------------------------------------------------------------------------------- | | **All operators** (default) | The stage dropdown, and they can move the record. | | **Admins only** | Administrators keep the dropdown. Everyone else sees the current stage as a read-only label. | | **Hidden (read-only for everyone)** | Nobody changes the stage from WASync Chat. The stage stays visible. | The setting is enforced on the server, and Bitrix24 CRM permissions still apply on top: an operator who cannot edit a record in Bitrix24 cannot move its stage here either. ### Required fields before a stage change [#required-fields-before-a-stage-change] Bitrix24 applies "required on this stage" fields only in its own form, not when a stage is changed through the API. WASync adds its own rule. In the Chat rules, **Before moving to a stage, ask for these fields** lets an administrator pick, for leads and for every deal pipeline, the fields that must be filled for each stage. When an operator changes the stage, a panel asks for those fields, pre-filled from the record. The stage changes only once they are filled, in a single CRM update. **Cancel** leaves the stage as it was. Chat Flows are not affected, and the CRM widget has no stage picker. ### Sequential stages [#sequential-stages] To guide operators through the pipeline one stage at a time, turn on **Sequential stages** in the Chat rules. It is off by default, and only a Bitrix24 administrator can change it. With it on, the stage dropdown still lists the whole pipeline of the record, but only the next stage can be picked; the stages further on are greyed out with the hint "Go through *next stage* first". The order is the order of the pipeline in Bitrix24, for leads and for every deal pipeline. | Option | Default | What it allows | | ------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Also allow one step back** | On | The previous stage can be picked too. | | **Allow "Lost" from any stage** | On | The lost stages (and "Junk" for leads) can be picked from any stage, so a lost lead or deal is closed without filling in the stages in between. Off: only from the last stage before them. | | **Allow "Won" from any stage** | Off | The won stage can be picked from any stage. Off: only from the last stage before it, so a record goes through the whole pipeline before it is won. | A record in a won or lost stage can only be reopened to the first stage. A jump the rule does not allow is refused on the server too, with the message "Move to *next stage* first", and the required fields of the stage still have to be filled in. The rule applies only to stage changes made from WASync Chat. Bitrix24 has no such setting and does not let an app restrict its own Kanban, the record card or automation rules, so a record moved there can still skip stages. ## Create or link a lead from a conversation [#create-or-link-a-lead-from-a-conversation] **Create lead** does not create anything at first. It shows **Already in the CRM**: the leads found by phone number and by the linked contact (closed ones are tagged **Closed**), plus the contact's open deals. Each has a **Link** button. **Create new lead** sits below the list. On a conversation linked only to a contact, the button reads **Create or link lead**, and **Link to record** is available too. Operators see only the records their Bitrix24 role allows. Nothing is created or linked automatically by opening the list. To move a conversation that is already linked, use **Change record** next to the responsible person. It opens the same search as **Link to record**. Pick a lead, a deal or a contact and confirm. * Only WASync's link changes. The old record keeps its history, and nothing in Bitrix24 is edited. * New messages are logged on the new record. * With **Each number creates its own lead** on, the link of that number is replaced, and the target must be a lead or a deal. For when WASync creates leads on its own, see [Leads from WhatsApp chats](/docs/guides/leads-from-whatsapp-chats). ## Quick replies with "/" [#quick-replies-with-] Quick replies are saved answers with a short command name, either for the whole team (**Team**) or personal (**Mine**). They work in WASync Chat and in the WhatsApp tab of the CRM. Type `/` at the start of the message box or after a space. A picker opens with every reply already filled in for the open customer. Keep typing to filter (`/cuo`), choose with the arrow keys and press Enter or Tab to insert. A reply is never sent by itself, so you can edit it first. Esc closes the picker. The lightning button next to the box does the same for mouse and phone users.
Hi, how much is the premium plan? Good afternoon, Maria! /price
Variables are filled in on the server when the reply is inserted: | Variable | Filled with | | ---------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `{{greeting}}` | Good morning, Good afternoon or Good evening, in the customer's language and at the customer's local time. Both come from the country of the phone number (UTC when the country is unknown). | | `{{contact.first_name}}`, `{{contact.name}}` | The customer. | | `{{me.first_name}}`, `{{me.name}}` | The person sending. | | `{{record.title}}`, `{{record.stage}}`, `{{record.responsible}}` | The lead or deal linked to the conversation. | | `{{crm.FIELD}}` | Any CRM field of that lead or deal, for example `{{crm.OPPORTUNITY}}`. | A reply can carry versions in other languages. The picker chooses the version that matches the country of the customer's phone number. Manage replies on the **Quick replies** page (the lightning icon in the app menu), open to administrators and anyone with write access to Settings. It lists Team and Mine replies with add, edit and delete, language versions, how often and when each was used, and promote to team for a personal reply. * **Save as quick reply** (menu on any message you sent) turns it into a reply, with the customer's name, the greeting and the record title replaced by variables. * After you insert a reply, change it and send it, WASync asks whether to update the saved reply with your version. Quick replies are not the canned responses of Bitrix24 Open Channels. Those live in the Contact Center and do not fill in CRM data. ## Templates on Business API numbers [#templates-on-business-api-numbers] On a WhatsApp Business API number, a conversation outside the 24-hour window accepts only approved templates. The composer marks such a number as **templates only (outside 24 h)** and the template picker takes over. The window opens only when the customer writes to you. A contact who has never written, or whose last message is older than 24 hours, gets a locked composer with the explanation and a **Pick a template** button, in WASync Chat and in the WhatsApp tab of a CRM record. A missed or placed call does not open the window. If a free-text send is still refused by WhatsApp's rule, the message is not sent and the composer shows why: *Your message was not sent: this contact is outside the 24-hour window. Send a template first.* The lock lifts the moment the customer replies. Templates with an image, video or document header keep the file uploaded when they were created. Every send from WASync Chat uses it by default: the operator sees **Template image** preselected with a preview and can still change it before sending. For templates approved earlier, or created in Meta's own interface, **Set default image** in the template list sets the file once. The picker fills `{{1}}` with the contact's first name only when it is a real name and the template describes `{{1}}` as a name (or does not describe it at all). A contact with no name, or a `{{1}}` labelled as something else, such as a date, is left empty for the operator to type. How to create and approve templates: [WhatsApp Business API templates](/docs/guides/waba-templates). ## Long messages [#long-messages] On the WhatsApp Business API, a text over 4,096 characters is sent as several messages, in order, with the delivery ticks on each. In Bitrix24 the operator still sees the single original message. The limit is 10 messages (about 40,000 characters). Beyond that the operator is told the message is too long and nothing is sent. Templates and file captions keep their own limits and are not split. ## Opening and downloading files [#opening-and-downloading-files] Photos, videos and files in a conversation open with a link made at the moment you click, so they work even when the chat has been open for hours. This is the same in WASync Chat and in the WASync tab of a CRM record. * **Photos, PDFs and videos** open inside the app, over the conversation. Use **Open** for a new browser tab, **Download** to save the file, and **Esc** or a click outside the file to close it. A PDF is shown in the page itself; if it is larger than 25 MB, or your browser cannot show PDFs inside a page (most phones), the window offers **Open** and **Download** instead. * **Other documents** (Word, Excel, zip and so on) open in a new browser tab. * **Download** under a photo, video or file saves it with its original name. Files open inside the app because some browsers add a small extra code to any address opened in a new tab, which makes the storage service refuse the link. If nothing opens, check that your browser allows pop-ups for Bitrix24. ## Sending from the right number [#sending-from-the-right-number] When a customer has written to two or more of your numbers, WASync Chat keeps one conversation with the whole history of that person. A small **via +number** badge marks messages that came through a number other than the one selected for replying. The composer always shows the number a reply will go out from. With two or more numbers it becomes a picker (**Send from number**). It defaults to the number the customer wrote to last. A Business API number outside the 24-hour window is marked **templates only**. Every send path follows the number you chose: text, files, templates, voice notes, notes, takeover, and the stage or responsible changes written to the CRM. ## Starting a conversation with a number that has no chat yet [#starting-a-conversation-with-a-new-number] WASync Chat lists conversations, so a number that has never exchanged a message with any of your WhatsApp numbers is not in the list. To write to it first, type the full number in the search box, with the country code. When no conversation matches, the list offers **Start a conversation with +number**. Choose which of your numbers sends, and the thread opens empty with that number selected in **Send from**. * On a Business API number the first message to a new number is a template: the composer shows the template picker, as it does outside the 24-hour window. * Once the first message is sent, the conversation appears in the list like any other. * An employee limited to their own records can start a conversation only with a number that is on a lead, deal or contact assigned to them. WASync looks the number up in the CRM and links the conversation to that record. If the number is on nobody's record, create the lead or contact in Bitrix24 first and open WhatsApp from the record. This is also the way to reach the second phone of a customer whose record has several numbers; from the record itself, use the number picker in the WASync tab ([Records with several phone numbers](/docs/product/crm-records#records-with-several-phone-numbers)). ## When a contact changes their number [#when-a-contact-changes-their-number] On a Business API number, WhatsApp tells us when a contact moves to a new WhatsApp number. WASync then: * adds a note to the conversation, "This contact changed their WhatsApp number to +number", in your portal's language. The same note appears in the Bitrix24 Open Channel chat; * adds the new number to the phone field of the conversation's lead, contact or company (for a deal or a smart process item, to its contact). The old number stays on the record. A comment on the CRM timeline says which number changed to which; * shows a banner over the old conversation, **This contact now uses +number**, with **Open conversation**. The new number's conversation is linked to the same CRM record. Replies can't be sent from the old conversation any more, but you can still write internal notes there. If you prefer to update phone numbers yourself, turn off **When a contact changes their WhatsApp number** in the Chat rules. The note and the banner still appear. A chat flow that was running on the old number keeps running there and does not move to the new one. QR connections don't receive this notice from WhatsApp, so nothing changes on them. ## Contacts without a phone number (usernames) [#contacts-without-a-phone-number] WhatsApp is introducing usernames, country by country. A customer who has a username can keep their phone number hidden from businesses. When such a customer writes to one of your **WhatsApp Business API** numbers, WhatsApp sends their username but no phone number. WASync then: * shows the conversation in WASync Chat as usual, with **@username** where the phone number would be (or **No phone number** when they have no username; hover over it for a short explanation). You can search for the conversation by the username, with or without the "@"; * forwards the messages to the Bitrix24 Open Channel. The chat is named after the username, and the lead Bitrix24 creates from it has no phone number; * lets you reply as usual, from WASync Chat and from the Open Channel. The reply goes to the customer's WhatsApp account directly, without a phone number. Templates work too, except authentication (one-time code) templates, which WhatsApp only delivers to a phone number; * when **Unknown chats** creates leads, creates the lead titled with the username and without a phone number. Some things need a phone number and are not available for these conversations: QR connections can't reach them (only Business API numbers are offered in **Send from**), WhatsApp calls, scheduled messages, and starting a new conversation by typing a number. A chat flow still runs and answers, but it does not create or link a CRM record for a contact without a phone number, and **Each number creates its own lead** skips them. ### When the customer later shares their number [#when-the-customer-later-shares-their-number] If the same customer later writes from their phone number (or turns off the hidden number), WhatsApp tells us both identities belong to one person. WASync keeps the two conversations apart and adds a note to each one, for example "This contact also writes as +57 300 111 2233" in the username conversation and "This contact also writes as @username" in the phone one. The note also appears in the Open Channel chats. Nothing is merged automatically; if they are the same person for you, ask our support to merge the two conversations. ## Disappearing messages [#disappearing-messages] When a contact has turned on disappearing messages in WhatsApp, the conversation header shows a small amber label next to their name, for example **Disappearing: 24 h**, **Disappearing: 7 days** or **Disappearing: 90 days**. It appears in WASync Chat and in the WASync tab of a CRM record. Hover over it for a short explanation. * On the customer's phone, messages are deleted after that time, so a quote or an offer you send may disappear before they read it. Consider asking them to confirm they received it, or send the important part again closer to when they need it. * Nothing is deleted on your side: the full history stays in WASync and in Bitrix24. * The label is updated from the customer's own messages. It appears after their next message once they turn the setting on, and goes away after their next message once they turn it off. This works on QR connections only. WhatsApp does not share the setting with WhatsApp Business API numbers, so no label appears on them. ## Sending a message later [#sending-a-message-later] Write the message, then click the clock next to **Send** (in WASync Chat and in the WASync tab of a CRM record). Pick **In 1 hour**, **Tomorrow, 09:00**, **Monday, 09:00** or any date and time up to 30 days ahead, and click **Schedule**. The message waits above the text box until it goes out; the × cancels it until then. WASync sends it at that time even if nobody has the chat open, from the number you chose, and the CRM timeline credits you as the author. * Text messages only: a message with files cannot be scheduled. * On WhatsApp Business API numbers, WhatsApp only accepts a free-form text if the customer wrote to you in the 24 hours before. If they did not, the scheduled message is not sent; use a template instead. * Each person sees and cancels their own scheduled messages; an administrator can cancel anyone's. ## Voice-note transcription [#voice-note-transcription] WASync can write out WhatsApp voice notes, so operators read them instead of listening. An administrator turns it on in **Settings → Voice-note transcription**. From then on, every voice note a customer sends, and every voice note your team sends, gets its text under the player in WASync Chat and in the WASync tab of a CRM record; while it is being processed the bubble shows "Transcribing…". The text is also in the chat export. * It runs on **your own account** with the service you choose on the card: **OpenAI** (Whisper), **Groq** (Whisper large-v3, fast and inexpensive) or **ElevenLabs** (Scribe, very accurate on noisy audio). For OpenAI, the key from your AI settings is used when your AI provider is OpenAI; otherwise, and for Groq and ElevenLabs, enter that service's API key on the card. The audio is sent to the service under your key and your contract with them, and the service bills the transcription to your account. * Voice notes over 10 minutes or 25 MB are not transcribed. * Voice notes sent by automations, chat flows and robots are not transcribed. * Voice notes received before the setting was turned on stay as they are. ## Carousel templates [#carousel-templates] A carousel template is a message followed by 2 to 10 cards the customer swipes sideways. Create one in **Templates → New template → Carousel**: * the main text above the cards (variables allowed, as in any template); * the media of the cards: all images or all videos; * each card: its file, an optional short text (up to 160 characters; give every card a text, or none) and 1 or 2 buttons. The buttons are the same kind and in the same order on every card: quick reply, link or phone number. WhatsApp accepts carousels only as **Marketing** templates. WASync keeps each card's file with the template and sends it every time, because WhatsApp asks for the media again at each send. Send a carousel like any other template: from WASync Chat, the WASync tab of a CRM record, a chat flow or a robot. In the conversation it shows as a strip of cards with their text and buttons. A carousel created in Meta's own tool can be sent only if its card files are public links; create it in WASync to be sure each card has its file. ## Link click tracking [#link-click-tracking] An administrator can turn on **Settings → Link click tracking**. From then on, links in text messages sent from WASync (WASync Chat, the WASync tab of a CRM record, chat flows and scheduled messages) are sent as a short link on our domain that opens the original page. * Under the message you see **Opened N× · last 14:05**, or **Not opened yet**. * The first time the customer opens a link, a comment appears on the record's CRM timeline: "Customer opened the link: …". * The preview WhatsApp builds when the message is sent does not count as an open; neither do other link-preview robots. * The customer sees our short domain instead of yours. Templates, files and replies typed in the Bitrix24 Open Channel are not changed. * We store when a link was opened and the kind of device, not the IP address. # Create an account and a key (/docs/quickstart/create-account-and-key) There are two equally valid ways to get an API key, depending on how you use WASync. Open the app in Bitrix24, go to **Settings → API & Agents**, and find the **API keys** card. Name the integration and click **Create key**. Creating a key needs at least one connection with the **API add-on** active ($12 per number per month) — without one, the button is disabled with the reason, and the server answers `403 addon_required`. The key is shown once, right there, with a **Copy** button, and carries the standard scopes `whatsapp.read whatsapp.send`. IP allowlists, webhook configuration, and managing several portals from one account live in the developer console, not in this card — the card links to it. Go to [https://developers.wasync.app/keys](https://developers.wasync.app/keys), create an account with an email and a password, and create a key. Give it a name, tick the scopes you need, and optionally restrict it to a set of IP addresses. The key is shown **once** — only a hash of it is stored. Copy it into your environment straight away. ```bash title="env" export WASYNC_API_KEY=wsk_live_… ``` Send it on every request: ```http Authorization: Bearer $WASYNC_API_KEY ``` That is the whole auth setup. No redirect URI, no PKCE, no consent screen, no token refresh. ## Scopes [#scopes] Tick only what the integration needs — scopes are per key. | Scope | What it allows | | ----------------- | --------------------------------------------------------- | | `whatsapp.read` | List connections and read messages. | | `whatsapp.send` | Send messages and read receipts. | | `whatsapp.events` | Receive webhooks, and configure where they go. | | `whatsapp.manage` | Create, inspect, restart, log out and delete connections. | Scopes and the reachable connection list are resolved live on every request, so revoking a key or narrowing it takes effect on the very next call — there is nothing cached and nothing to refresh. The details, and what each scope costs you if it leaks, are under [Scopes](/docs/concepts/scopes). The optional IP allowlist is enforced on API calls only. The page where you edit it is authenticated by your account, not by the key, so it stays reachable from any address. See [IP allowlist](/docs/security/ip-allowlist). ## What a connection costs [#what-a-connection-costs] Each WhatsApp number needs an active licence to send and receive. A new number starts on a **7-day free trial**, then $19 per number per month for a `qr` (WAPP) number or $29 per number per month for a `cloud_api` (WABA) number, in USD. On a Bitrix24 portal, API access to a number is a separate **$12 per number per month** add-on. [Licences & trial](/docs/concepts/licences-and-trial) has the full picture. # Your first call (/docs/quickstart/first-call) Base URL `https://developers.wasync.app/api/v1`. ## List the connections you may use [#list-the-connections-you-may-use] ```bash title="GET /connections" curl https://developers.wasync.app/api/v1/connections \ -H "Authorization: Bearer $WASYNC_API_KEY" ``` Only connections with an active licence appear. Each carries a `provider` of `qr` or `cloud_api`, an `id` (a cuid — the stable identifier you should store against your own customer record) and a `status`. Uses `whatsapp.read`. `developers.wasync.app` is the canonical host, but `cloudapi.wasync.app` is a permanent alias for exactly the same API — same keys, same paths, same responses — and it remains valid indefinitely. No existing integration has to change anything. The OAuth endpoints, the `/.well-known/…` documents and the MCP server URL are protocol identifiers registered by clients: they stay on `cloudapi.wasync.app` on purpose. ## Check your capacity before you promise it [#check-your-capacity-before-you-promise-it] ```bash title="GET /account" curl https://developers.wasync.app/api/v1/account \ -H "Authorization: Bearer $WASYNC_API_KEY" ``` ```json title="200 response" { "slots": { "total": 30, "used": 28, "available": 2, "nextExpiry": "2027-08-08T09:00:00.000Z" }, "connections": { "total": 28, "connected": 27, "needsReconnect": 1 } } ``` `slots.available` tells you whether you can onboard another number right now, and `nextExpiry` is the date you need to invoice your own customer before — so a slot never expires underneath someone who has already paid you. `connections.needsReconnect` counts the numbers currently waiting for their owner to scan a QR; subscribe to [connection events](/docs/guides/webhooks) to be told the moment that number changes instead of polling for it. Uses `whatsapp.read`. A slot is capacity, not a phone number. Delete a connection and its slot returns to your pool carrying whatever time is left on it — the next number you connect picks it up automatically. That is what lets you move a paid slot from a departing customer to a new one without paying twice. ## Connect a number [#connect-a-number] One call creates the connection and returns a QR code to scan. It works on a brand-new workspace with no connections at all — with a key there is nothing to click in a portal first. ```bash title="POST /connections" curl -X POST https://developers.wasync.app/api/v1/connections \ -H "Authorization: Bearer $WASYNC_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{"label":"Support line"}' ``` ```json title="201 response" { "connection": { "id": "conn_8f3a21", "status": "connecting", "qr": "data:image/png;base64,iVBORw0KGgo…" } } ``` WhatsApp rotates the pairing code roughly every **20 seconds**, so the `qr` in the create response is stale within seconds of being displayed. This fails silently: the phone never pairs and nothing on screen explains why. Poll `GET /connections/{id}` every 3–5 s and re-render the `qr` from every response. Do not cache it, and do not hide the refresh behind a button the user has to press. [Pairing code & QR](/docs/guides/pairing-and-qr) covers the one-device alternative. Uses `whatsapp.manage`. Connections created this way are `qr` numbers; `cloud_api` numbers are onboarded through Meta embedded signup instead. This endpoint is standalone-workspace only — a Bitrix24 portal is answered with `403 forbidden_portal_kind`, because there connections are created by the portal admin inside WASync. Send an `Idempotency-Key` — creating a connection consumes a paid slot, and a timed-out retry without one buys you two. [Errors & idempotency](/docs/concepts/errors-and-idempotency) has the four cases you must handle. # Your first message (/docs/quickstart/first-message) ## Send a text [#send-a-text] ```bash title="POST /messages" curl -X POST https://developers.wasync.app/api/v1/messages \ -H "Authorization: Bearer $WASYNC_API_KEY" \ -H "Content-Type: application/json" \ -d '{"connectionId":"conn_8f3a21","to":"40700000000","text":"Hi from my app 👋"}' ``` ```json title="200 response" { "messageId": "cmqj3k2ab0001xyz", "waMessageId": "true_40700000000@c.us_3EB0A1B2C3", "status": "sent" } ``` `to` is international digits only, no `+` — e.g. `40700000000`. `text` is at most 4096 characters. For media, supply `media` instead of `text`: `{ filename, mimetype, data (base64, ≤ 16 MB), caption? }` — exactly one of the two. Voice notes use `mimetype: audio/ogg` and a `voice-*.ogg` filename. Uses `whatsapp.send`. A `qr` send normally takes 1–7 s, up to about 20 s for long texts, and the self-heal path can take \~2.5 minutes. A `cloud_api` send is about 1 s. **A slow send is not a failure** — a client that gives up at 30 s and retries sends the customer the message twice. Always pass an `idempotencyKey` (a UUID per logical send) and retry with the *same* one. ## Two ids — join on the right one [#two-ids--join-on-the-right-one] The response carries two identifiers and they are not interchangeable. | Id | Where it appears | Use it for | | -------------------- | ---------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | | `messageId` (a cuid) | `messageId` on POST, `id` on GET, `message.id` in both webhooks | The **only** joinable id. Store it on send, dedupe on it, match `message.status` events against it. | | `waMessageId` | `waMessageId` (REST), `wa_id` (webhooks), `wa_message_id` (media send) | Support tickets and debugging. It can be `null` — never join or dedupe on it. | One degraded case is worth coding for: `{ "messageId": null, "waMessageId": "…", "status": …, "persisted": false }` with HTTP 200 means the message **was delivered** but was not persisted. Do not retry it. ## Read the thread back [#read-the-thread-back] ```bash title="GET /messages" curl "https://developers.wasync.app/api/v1/messages?connectionId=conn_8f3a21&limit=20" \ -H "Authorization: Bearer $WASYNC_API_KEY" ``` ```json title="200 response" { "messages": [ { "id": "cmqj3k2ab0001xyz", "waMessageId": "true_40700000000@c.us_3EB0A1B2C3", "connectionId": "conn_8f3a21", "direction": "outgoing", "text": "Hi from my app 👋", "mediaUrl": null, "mediaType": null, "status": "delivered", "errorMessage": null, "createdAt": "2026-07-22T10:00:00.000Z" } ], "nextCursor": "cmqj3k2ab0001xyz", "hasMore": true } ``` Newest first, cursor-paginated: `limit` is 1–100 (default 20), and `cursor` takes the previous response's `nextCursor`. Uses `whatsapp.read`. ## Give the customer blue ticks [#give-the-customer-blue-ticks] ```bash title="POST /messages/read" curl -X POST https://developers.wasync.app/api/v1/messages/read \ -H "Authorization: Bearer $WASYNC_API_KEY" \ -H "Content-Type: application/json" \ -d '{"connectionId":"conn_8f3a21","phone":"40700000000"}' ``` Call this when an operator opens the conversation in *your* UI — otherwise nobody ever opens the chat in WhatsApp, the customer's messages stay on double grey ticks and the thread looks ignored. Body is `{ connectionId, phone?, messageId? }` with at least one of `phone` / `messageId` (the cuid of an *incoming* message; `messageId` wins when both are given). It uses `whatsapp.send`, not `whatsapp.read`, because it transmits a receipt to the customer. Idempotent, no key, no rate limit. Returns `{ "ok": true, "marked": 3 }`. ## Next [#next] * Be told about inbound messages instead of polling: [Webhooks](/docs/guides/webhooks). * Build it without code: [n8n](/docs/guides/n8n) or [MCP](/docs/guides/mcp). * Generate a client from the contract: `npx @openapitools/openapi-generator-cli generate -i https://developers.wasync.app/openapi.json -g typescript-fetch -o ./wasync-client` # Quickstart (/docs/quickstart) From nothing to a delivered WhatsApp message in under five minutes. # API keys (/docs/security/api-keys) ## Shown once [#shown-once] A key is displayed **exactly once**, at the moment you create it. Only a hash of it is stored, so nobody — including us — can read it back to you afterwards. The page will not show it again and support cannot recover it. The practical consequence: copy it into your secret store *before* leaving the page. If you lose it, you do not recover it — you revoke it and create another. That is a two-minute operation, and it is the only safe design: a key a support process can retrieve is a key a support process can leak. ## Where a key is created [#where-a-key-is-created] There are two places, and they are not the same tool: * **The API keys card in Bitrix24** (Settings → API & Agents) — an admin names the integration and creates or revokes keys. It needs at least one connection with the API add-on active. Keys made here carry the standard scopes `whatsapp.read whatsapp.send`. * **The developer console** at [developers.wasync.app/keys](https://developers.wasync.app/keys) — the same create/revoke, plus the things the Bitrix24 card does not do: an IP allowlist per key, a choice of scopes beyond the standard pair, and several portals or numbers under one account. Revoking a key takes effect immediately no matter which place you revoke it from — there is nothing cached on either side. ## Where a key must never go [#where-a-key-must-never-go] * Not in a query string. URLs end up in access logs, proxies, browser history and referrer headers. * Not in client-side code. Anything shipped to a browser or a mobile app is readable by whoever runs it. * Not in source control, not in a screenshot, not in a ticket. Put it in an environment variable or a secret manager, and send it only as `Authorization: Bearer …`. ## Scope it down [#scope-it-down] Each key carries its own [scopes](/docs/concepts/scopes). A key that only needs to send should not be able to delete connections. Scopes are resolved live on every request, so tightening an existing key takes effect on the next call — you do not have to reissue it to narrow it. ## Two keys are cheaper than one incident [#two-keys-are-cheaper-than-one-incident] There is no limit that forces you to share one key across everything. A separate key per deployment (staging vs production) and per job (a read-only reporting task vs a sender) means a leak is contained to one blast radius and can be revoked without taking the rest down. ## Prefix [#prefix] Keys are prefixed `wsk_live_`. Secret scanners can be taught the prefix, and a value in a log that starts with it should be treated as compromised and revoked immediately. # Developer console sign-in (/docs/security/developer-console) The developer console at [developers.wasync.app](https://developers.wasync.app) holds API keys that can read and send your customers' WhatsApp messages, so its sign-in is held to a higher bar than a typical dashboard: a choice of sign-in methods, a mandatory second step, and a re-confirmation before anything sensitive happens. ## Three ways to sign in [#three-ways-to-sign-in] * **Password** — your email and password. Passwords must be 12–128 characters; we do not enforce upper/lower/symbol rules, and we never force a periodic reset. Every password is checked against a breach database when you set it — if it has appeared in a known breach, we refuse it and ask for a different one. * **Email code** — enter your email and we send a 6-digit code. It is valid for 10 minutes, works once, and is invalidated after 5 wrong guesses. * **Passkey** — a single "Continue with passkey" button. Passkeys use Face ID, Touch ID, Windows Hello or a hardware key, never leave your device, and cannot be phished or reused on another site. ## Two-step sign-in [#two-step-sign-in] A password or an email code proves you know something; it does not prove the device is yours. So on top of one of the three methods above, most accounts also confirm a **second step**: * **Passkey** — recommended. Because a passkey already required your device and your face, fingerprint or PIN, signing in *with* a passkey satisfies both the first and second step at once. Signing in with a password or an email code still asks for the second step separately. * **Authenticator app** — any standard TOTP app (Google Authenticator, 1Password, Authy, etc.). Scan the QR code once to enrol; after that it asks for the 6-digit code it shows. * **Recovery codes** — ten single-use codes, shown exactly once when you set up two-step sign-in. Store them somewhere safe. Each one works instead of a passkey or authenticator code, and using one does not disable the others. ## What's mandatory, and when [#whats-mandatory-and-when] * **New accounts** must set up a second step right after creating the account. You can put it off once; after that the console will ask again before letting you continue. * **Existing accounts** get a 14-day banner asking them to set it up voluntarily; after those 14 days it becomes mandatory, the same as a new account. * **Admin accounts** have no grace period — a second step is required from the moment this changed. ## Devices and sessions [#devices-and-sessions] Signing in creates a session tied to your browser, not a token you copy around. By default a session is good for 12 hours of inactivity or 24 hours total, whichever comes first. Checking **Keep me signed in for 30 days** extends that to 30 days total, with a 7-day inactivity limit. Under **Security → Devices** you can see every signed-in session — browser, approximate location and last-seen time — and sign any of them out, including the one you are currently using. When we notice a sign-in from a device we have not seen before, we email you with the device, approximate location and time, and a link to sign it out if it was not you. ## Activity log [#activity-log] **Security → Activity** shows the last events on your account: sign-ins, sign-outs, password and two-step changes, API key creation, and similar. We keep this history for 12 months. It is there so that if something looks wrong, you can see exactly what happened and when, without having to ask us. ## Confirming it's you again [#confirming-its-you-again] A handful of actions are sensitive enough that the console asks you to confirm your second step again, even if you are already signed in — this matters if your second step was verified more than five minutes ago: * Creating or revoking an API key * Rotating a webhook secret * Deleting a WhatsApp connection or closing a workspace * Turning off a passkey or authenticator app, or regenerating your recovery codes * For account admins: extending a licence or changing a partner's status When one of these is triggered, a "Confirm it's you" dialog appears asking for your passkey, authenticator code or a recovery code. Once confirmed, the action goes through and the confirmation is good for a few more minutes. ## Repeated failed attempts [#repeated-failed-attempts] A few wrong passwords in a row bring up a Cloudflare Turnstile challenge on the sign-in form — the same kind of check you see on many sites, not a code sent anywhere. Ten wrong passwords within 15 minutes apply a 15-minute temporary lock to the account, and we email the owner when that happens. The lock only affects password sign-in — you can still sign in with a passkey or an email code while it is active, so a lock can never be used to keep you out of your own account. ## What we never do [#what-we-never-do] * We never send a sign-in code or a password reset by SMS. * We never put a one-time code or any secret in the subject line of an email — it only ever appears in the body, so it cannot leak through a notification preview or a mail client's list view. ## Recovering access [#recovering-access] If you lose your passkey or authenticator device, use one of your ten recovery codes to sign in and set up a new second-factor device from **Security**. If you have also lost your recovery codes, there is no self-service recovery for two-step sign-in by design — the whole point is that it cannot be bypassed by anyone who only has your email. Contact us in writing at [support@wasync.app](mailto:support@wasync.app) and we will verify your identity before restoring access. # Security (/docs/security) How keys are stored, how to pin them to addresses, and how fast a revocation takes effect. # IP allowlist (/docs/security/ip-allowlist) A key can optionally be pinned to a set of IPv4/IPv6 addresses or CIDR ranges. Edit the list at [https://developers.wasync.app/keys](https://developers.wasync.app/keys). A call from an address that is not on the list is refused with: ```json title="403" { "error": "ip_not_allowed" } ``` ## Why it is a different code from `invalid_key` [#why-it-is-a-different-code-from-invalid_key] `403 ip_not_allowed` and `401 invalid_key` are deliberately distinct, because the fix is opposite: | Code | What is wrong | What to do | | -------------------- | ------------------------------------------------------------ | ------------------------------------------------ | | `401 invalid_key` | The key is unknown or revoked. | Create a new key. Retrying will never help. | | `403 ip_not_allowed` | The key is **fine**; the calling address is not on its list. | Add the address. **Do not rotate the key.** | Collapsing the two would send you rotating a perfectly good key while the real problem — a new egress address after a deploy, a container that moved hosts — stays unfixed. Branch on the code, never on the status alone. ## You cannot lock yourself out [#you-cannot-lock-yourself-out] The allowlist is enforced on API calls. The page where you edit it is authenticated by your **account**, not by the key, so it stays reachable from any address. There is no state in which a key's own allowlist prevents you from fixing that allowlist. ## When it is worth it [#when-it-is-worth-it] An allowlist is most useful when your callers have stable egress: a fixed NAT gateway, a VPC egress IP, an on-premise server. It turns a leaked key into a key that only works from your infrastructure. It is worth less when your callers are elastic — serverless platforms and CI runners rotate addresses, and a list you have to keep chasing will eventually be widened to something meaningless. In that case, prefer narrow [scopes](/docs/concepts/scopes) and short-lived deployments of the key. # Revocation timing (/docs/security/revocation) Scopes and the reachable connection list are resolved **live, on every request**. Nothing about a credential is cached in the credential itself and nothing has to be refreshed. ## What that buys you [#what-that-buys-you] **Revocation is immediate.** Delete a key and the next call using it gets `401 invalid_key`. There is no propagation window, no token that stays valid until it expires, and no cache to wait out. If a key is in a log you can pasted into a ticket, revoking it now is genuinely now. **Narrowing is immediate too.** Remove a scope from an existing key and the next call that needed it gets `403 insufficient_scope`. You do not have to reissue the key to tighten it. **A new connection is visible immediately.** A connection you just created shows up on the very next `GET /connections`. There is nothing to refresh after a provisioning step. ## OAuth tokens [#oauth-tokens] An OAuth `access_token` is the one thing with a lifetime of its own: 15 minutes. Its **scopes and connection list are still resolved live**, so revoking the grant stops it reaching anything immediately — but the token string itself remains syntactically valid until it expires. `refresh_token` lives 30 days and **rotates on use**. Persist the new one atomically and serialise refreshes across workers: two workers refreshing at once will invalidate each other, and the symptom is an integration that logs out at random under load. ## Webhook secrets [#webhook-secrets] Rotation has **no overlap window**. `POST /webhook/rotate` issues a new secret and the old one stops verifying immediately. Deploy the new secret promptly — the delivery retry policy (3 attempts: immediate, 500 ms, 1 s) covers a rollout measured in seconds, not hours, and anything dropped in between has to be picked up by your [reconciliation poll](/docs/guides/webhooks). ## If you think a credential leaked [#if-you-think-a-credential-leaked] Revoke it at [https://developers.wasync.app/keys](https://developers.wasync.app/keys) . It stops working on the next call. Create a replacement with the narrowest scopes that still work. Rotate the webhook secret if the leak could have exposed it — `GET /webhook` never returns it, so a leak means it came from your side. Read back `GET /messages` over the affected window to see what was sent while the credential was out. Support is written-only: email or chat. # Slot quota and connection health (/docs/api-reference/account/getAccount) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Create a new connection (/docs/api-reference/connections/createConnection) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Delete a connection (/docs/api-reference/connections/deleteConnection) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Get connection status (/docs/api-reference/connections/getConnection) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # List authorized connections (/docs/api-reference/connections/listConnections) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Log out a connection (/docs/api-reference/connections/logoutConnection) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Request a pairing code (link with phone number) (/docs/api-reference/connections/requestPairingCode) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Restart a connection session (/docs/api-reference/connections/restartConnection) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # List recent messages (/docs/api-reference/messages/listMessages) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Mark inbound messages as read (blue ticks) (/docs/api-reference/messages/markMessagesRead) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Send a WhatsApp message (text or media) (/docs/api-reference/messages/sendMessage) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Read the webhook configuration (/docs/api-reference/webhook/getWebhook) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Rotate the webhook signing secret (/docs/api-reference/webhook/rotateWebhookSecret) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # Set the webhook endpoint (/docs/api-reference/webhook/setWebhook) {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} # How do I answer a WhatsApp call in Bitrix24 without hunting for the notification? (/docs/help-center/calls/answer-whatsapp-call-in-bitrix24) An incoming WhatsApp call rings in the Bitrix24 call card, the same card used for telephony, with **Answer**, **Ignore**, **Mute** and **End**; the voice runs in the browser, and the right panel shows the WASync tab with the customer's conversation. After the call its duration is logged on the record. Calls need a WhatsApp Business API number on the Cloud API (not a number in coexistence with the phone app), a verified business, an approved display name and calling enabled on the number, which you do from **Connections → the number's menu → Calling**. Availability by country is decided by Meta and checked by the app before it lets you enable it. Use Chrome, Edge or Bitrix24 Desktop. ## Related [#related] * [Calls](/docs/product/calls) # The call duration in the CRM is wrong; it includes the ringing time. (/docs/help-center/calls/call-duration-includes-ringing) The logged duration is the talk time only: the timer starts when the call is answered (confirmed by Meta or by the first audio packet), not when it starts ringing. A call that nobody answered is logged as missed with a duration of zero, so the reports count real conversations. ## Related [#related] * [Calls](/docs/product/calls) # If the responsible person does not answer, do colleagues ring too? (/docs/help-center/calls/colleagues-ring-if-responsible-does-not-answer) Yes. The call first rings the responsible person for about eight seconds; if they do not answer, or they are offline, it rings everyone who is online and has access to that number in **Team**. The first person to answer takes the call. If the responsible is not even logged in, the second step starts right away. ## Related [#related] * [Calls](/docs/product/calls) # WhatsApp calls (/docs/help-center/calls) Answering in the Bitrix24 call card, who is rung, what is logged. # Who is rung first for an incoming call? (/docs/help-center/calls/who-is-rung-first) You choose in **Settings → Calls**, for the whole portal: ring the **contact's responsible** first, or the responsible of the customer's **latest open deal** (if there is none, the open lead, then the contact). After that first step the usual fallback applies: everyone online with access to the number. ## Related [#related] * [Calls](/docs/product/calls) # My card is refused by Stripe. How else can I pay? (/docs/help-center/api-and-billing/card-refused-by-stripe) A refusal with a generic code comes from the issuing bank, not from WASync, so the first thing to try is another card or asking the bank to allow the payment. If that is not possible, write to [support@wasync.app](mailto:support@wasync.app) with your portal name and the plan: we send a **Revolut payment link** by email, and once the payment is in, the licence is activated by hand, usually the same day. The invoice is issued the same way as for card payments. ## Related [#related] * [Licences and trial](/docs/concepts/licences-and-trial) # API, MCP and billing (/docs/help-center/api-and-billing) Files through the MCP, payments, invoices. # Do I get an invoice? (/docs/help-center/api-and-billing/invoices) Yes. Stripe emails an invoice and a receipt for every payment, and all of them are available at any time from **Connections → the number → Manage subscription** in the app, which opens the Stripe customer portal. The company details on the invoice (name, address, VAT number) are the ones in that portal: fill them in before the payment, because an invoice is issued with the details at the moment of payment. Prices are in USD, without VAT; VAT is added according to your country and VAT status at checkout. Companies outside Romania also receive a fiscal invoice from TDACRM Solutions SRL for each payment. ## Related [#related] * [Plans, trial and invoices](/docs/administration/billing) # Can the MCP send files, or only text? (/docs/help-center/api-and-billing/mcp-send-files) Files too. The MCP server exposes **send\_whatsapp\_file** next to the text tool: the agent passes a public **https URL** (preferred, any reasonable size) or the file itself in **base64** up to 5 MB, plus a file name, the type and an optional caption, and the file goes out from an authorised number like a text message, with the same permissions, audit and limits. URLs are fetched with strict checks (https only, public hosts only). Larger media goes through the REST API. ## Related [#related] * [Guide: MCP](/docs/guides/mcp) # Can I bring my WhatsApp Business API number from Twilio, 360dialog or Wazzup? (/docs/help-center/connections/bring-number-from-another-provider) Yes. In **Connections** use **Bring a number from another provider**. The wizard runs the checks first (your business is verified with Meta, the account has room, two-step verification is off at the current provider), then Meta's own dialog where you enter the number, receive the code by SMS or call, and the number moves into a WhatsApp Business Account that you own. Your old provider keeps working until the move completes, usually a few minutes. What comes along: the number, its display name, the Official Business Account status, the quality rating and the messaging limits, plus the approved, good-quality templates, which Meta copies without re-approval. What stays behind: the chat history at the old provider and templates that were rejected or pending. If the number's page at your current provider has no **Two-step verification** tab, Meta has already retired the PIN for that number: proceed and tick the box in the wizard. ## Related [#related] * [Guide: bring a number from another provider](/docs/guides/bring-your-own-number) # Connections and numbers (/docs/help-center/connections) QR and Business API numbers: disconnections, bringing a number, coexistence, deleting a connection, reliability. # Can I keep WhatsApp Business on my phone and still have the number in Bitrix24? (/docs/help-center/connections/keep-whatsapp-business-on-phone-and-in-bitrix24) Yes. Choose **Add WABA** in Connections and, in Meta's dialog, the option for a number that is already in the **WhatsApp Business app**; you scan a QR from the app and the number stays on the phone. It is then a Business API number too: templates, Meta's limits on business-initiated conversations and the 24-hour window apply, while the app keeps working as before. Three things to know: a message typed on the phone does not open the 24-hour window for the API side; WhatsApp calls are not available on a number in coexistence; and the import of the last six months of conversations and of the contacts can be requested once, in the first 24 hours after connecting, after which Meta no longer offers it. ## Related [#related] * [Connections](/docs/product/connections) * [Connection types](/docs/concepts/connection-types) # A message sent from the phone at 8 pm did not appear in Bitrix24. Can that happen? (/docs/help-center/connections/message-from-phone-missing-in-bitrix24) On a connected number, no. Every message is stored by WASync before it is passed on, and the hand-over to Bitrix24 is retried for hours when Bitrix24 is slow or refuses it; an undeliverable message raises an alert instead of disappearing. Messages typed on the phone are mirrored the same way. What can lose a message is the connection itself being down at that moment: a QR number whose linked device was removed, or a phone that was offline for a long time. Check the connection's history in **Connections** around that time; if it shows a disconnection, the message never reached WASync and is only on the phone. ## Related [#related] * [Connections](/docs/product/connections) # Messages go to my old provider, or sending fails with error 131070. (/docs/help-center/connections/messages-go-to-old-provider-error-131070) This happens to a number brought from another provider when Meta's **Conversation routing** is on for it and the old provider is still its primary partner. The number shows as connected in WASync, but Meta hands every conversation to the old provider: customer messages do not arrive in WASync, and what you send fails with error **131070** ("another app is controlling this thread"). Reconnecting or re-registering the number does not change it; the setting is yours, at Meta. WASync checks this after the move and several times a day, and shows a red warning on the number in **Connections** when it finds it. To fix it: in **Meta Business Suite → Settings → WhatsApp accounts**, select the number, open **Conversation routing** and set **WASync** as **Primary** for **Customer service**, **Click-to-WhatsApp ads**, **Utility**, **Marketing** and **Calls**, and as the **Escalation** partner. If you no longer use the old provider, you can remove it under **Partners** or **Messaging accounts** instead. The warning clears itself at the next check. ## Related [#related] * [Guide: Conversation routing at Meta](/docs/guides/bring-your-own-number#conversation-routing-at-meta) * [Connections](/docs/product/connections#conversation-routing-at-meta) # I scanned the QR twice with the same phone and now I have duplicate notes. (/docs/help-center/connections/scanned-qr-twice-duplicate-notes) Since 30 September 2026 a second scan of a number that is already connected on your portal is refused, so this cannot happen again: the new connection is marked as a duplicate and dismantled, and the existing one keeps working. The duplicate timeline notes created before that guard stay in Bitrix24; delete them from the record if they bother you. If you need a number on two connections on purpose, that is not supported; use one connection and give more people access to it in **Team**. ## Related [#related] * [Connections](/docs/product/connections) # I want to delete a connection. What do I lose? (/docs/help-center/connections/what-do-i-lose-when-deleting-a-connection) Before deleting, the dialog shows what the number is doing: whether it is live, how many messages it carried in the last 24 hours (all traffic, as a sign it is in use), and which flows and automations are attached to it. Deleting removes the number from WASync, its conversations in WASync Chat, the Open Channel line that was created for it and the flows bound to it. Nothing in the CRM is touched: leads, deals, contacts, the timeline comments and the files remain. If you only need to re-pair the same number, use **Reconnect** instead; it keeps everything. ## Related [#related] * [Connections](/docs/product/connections) # Why did my WhatsApp disconnect? (/docs/help-center/connections/why-did-my-whatsapp-disconnect) When a QR number drops, WASync emails the administrators and shows the cause it could establish on the connection: most often WhatsApp removed the linked device, which happens when the number was logged out from the phone, when the same number was moved to the Business API, or after WhatsApp's own enforcement on messages to many new contacts in a short time. The alert also says how many new contacts were written in the hours before the drop, which is the usual sign of the last case. To reconnect: **Connections → the number → Reconnect**, scan the QR with the phone, and the conversations resume. Flows, the Open Channel line and the team's access stay attached to the connection. To keep a QR number healthy: no bulk sends to contacts who never wrote to you, warm a new number up gradually, and keep the phone online. For higher volumes or campaigns, use a Business API number. ## Related [#related] * [Connections](/docs/product/connections) # Can the customer's WhatsApp name and photo be copied to the CRM contact? (/docs/help-center/crm/copy-whatsapp-name-and-photo-to-contact) Yes. Turn on **Copy WhatsApp name and photo to the contact card** in **Settings → CRM**; it is off by default. When a conversation becomes linked to a contact, the name from WhatsApp is written only if the card has no name or just the phone number as its name, and the photo only if the card has none. Existing names and photos are never overwritten. The photo is available on QR numbers only; the Business API does not provide it. ## Related [#related] * [CRM records and timeline](/docs/product/crm-records) # CRM records and timeline (/docs/help-center/crm) Leads, deals, contacts, timeline comments, sources, ads attribution, Smart Processes. # All new chats land on me, the administrator, instead of the Open Channel queue. Why? (/docs/help-center/crm/new-chats-land-on-the-administrator) Because a record created without an explicit responsible lands on the Bitrix24 user who installed the app, and the Open Channel then routes the conversation to the responsible of the record. Set the rule in **Settings → Chat rules → New chats from unknown numbers**: **Off** (no lead is created for unknown numbers), a **fixed person**, or a **rotation** over a list of employees. Flows that create records at enrolment follow the same rule. Three switches in the same place refine it: create the lead also on numbers that feed an Open Channel; create the lead when an operator writes first to an unknown number, with that operator as the responsible; and create a lead for a known contact that has no open lead or deal. ## Related [#related] * [The responsible of records WASync creates](/docs/product/crm-records#the-responsible-of-records-wasync-creates) # The same message appears on lead 1, lead 2 and the contact. Can it be logged on one record only? (/docs/help-center/crm/one-timeline-comment-per-conversation) Yes. By default every message is written on every record that carries the customer's phone number, including closed leads. In **Settings → CRM → Where to write the timeline** choose **One comment on the conversation's record**: from then on each message is written once, on the record the conversation is linked to (the one shown in the chat header, which you can change with **Change record**). Nothing is deleted: comments already written stay on the records that have them; only new messages follow the new rule. ## Related [#related] * [CRM records and timeline](/docs/product/crm-records) # The lead was lost, the customer writes back an hour later, and a new lead is created. Can it reattach? (/docs/help-center/crm/recontact-window-after-lost-lead) Yes. In **Settings → Chat rules → New chats from unknown numbers** set the **re-contact window**, in **hours** (it is 0, off, by default). A customer who writes back while their lost lead was closed less than that many hours ago is attached to that lead again instead of getting a new one, and an option reopens the lead into a stage you choose. The window applies only to leads closed as **lost**, not to converted ones, and it is used both for new chats and when a flow would create a lead at enrolment. Outside the window the normal rule applies and a new lead is created. ## Related [#related] * [CRM records and timeline](/docs/product/crm-records) # Can I send WhatsApp from a CRM Marketing campaign or an automation rule? (/docs/help-center/crm/send-whatsapp-from-crm-marketing-or-automation-rule) Yes. WASync registers as a message provider in Bitrix24, so **WASync WhatsApp** appears wherever Bitrix24 lets you pick an SMS provider: CRM Marketing campaigns, the automation rule **Send message**, business processes and the message button on a lead, deal or contact. The text is sent as a free WhatsApp message from the number you set as default for this in the connection's settings, and the delivery status comes back to Bitrix24. On a Business API number a free text reaches only customers who wrote to you in the last 24 hours; outside that window Meta refuses it and Bitrix24 shows the message as failed. On a QR number there is no such window. For messages outside the window use templates, from WASync Chat or from a Chat Flow. ## Related [#related] * [WhatsApp from CRM Marketing and automation rules](/docs/product/crm-records#whatsapp-from-crm-marketing-and-automation-rules) # The customer writes to number X (from an ad) but already has a deal on another number. I want a separate lead per number. (/docs/help-center/crm/separate-lead-per-whatsapp-number) Turn on **Each number creates its own lead** in **Settings → Chat rules → New chats from unknown numbers**. The setting is portal-wide and applies to all your WhatsApp numbers. From then on the record of a conversation is kept per number: a customer who writes to number X gets X's lead, even if the same person has a deal from number Y, and flows that create records at enrolment follow the same rule. The reverse is also true, by design: one customer handled on two of your numbers has two leads. If you want one customer to be one record across all numbers, leave the setting off. ## Related [#related] * [CRM records and timeline](/docs/product/crm-records) * [Which record a flow creates or binds to](/docs/product/chat-flows#which-record-a-flow-creates-or-binds-to) # We work with Smart Processes. Does WASync work on them? (/docs/help-center/crm/smart-processes-support) Yes, on every Smart Process type. Items get the WASync tab with the conversation, messages are written on the item's timeline, the WhatsApp robots are available in the process's automation rules, and Chat Flows can be attached to items. Attribution from ads is written in the item's UTM fields. One condition for the automatic linking of a conversation to an item: the process must have **Client** (contact) enabled, because the phone number lives on the contact. Without it the tab is there, but you link conversations by hand. ## Related [#related] * [Guide: Smart Processes](/docs/guides/smart-processes) # All timeline comments are signed by the person who installed the app. Can they be signed by the operator? (/docs/help-center/crm/timeline-comments-signed-by-operator) Yes, and this is the current behaviour. A message sent by an operator from the Open Channel, from WASync Chat or from the WhatsApp tab on a record is written on the timeline as that operator. Incoming messages from customers are written as the app's technical user, because no employee wrote them. The exception is a message typed on the company phone or in WhatsApp Web: it reaches Bitrix24 without an operator identity, so it is also written as the technical user. ## Related [#related] * [CRM records and timeline](/docs/product/crm-records) # Which ad brought the customer? I want the campaign and ad set, not only the ad id. (/docs/help-center/crm/which-ad-brought-the-customer) Without any setup, a conversation that starts from a Click-to-WhatsApp ad already carries the ad id, on the contact and on the open leads or deals. To get the campaign and the ad set as well, add a **Meta Ads token** (a System User token with `ads_read` from your Business Manager) in **Settings**, card **Campaign and ad set on conversations from ads**. From then on the record's UTM fields hold the campaign, the ad set and the ad, in Meta's convention, and the timeline notes the attribution. The ad information arrives with the message the customer sends from the screen the ad opened, whether they kept the suggested text or not. A message written later from the normal chat list carries no ad. It works on Business API and on QR numbers. ## Related [#related] * [Guide: campaign and ad set on conversations from ads](/docs/guides/meta-ads-campaign-attribution) # An employee filters by their own name and still sees other people's chats. Why? (/docs/help-center/wasync-chat/employee-filter-shows-other-peoples-chats) Because the "Assigned to" filter and the **Only my records** level match a conversation by the responsible of the lead or deal **and** by the responsible of the CRM contact. A lead handed to a colleague stays visible to the person who still owns the contact, which is what most portals expect. If your process gives every contact to one fixed employee while the leads rotate, that rule gets in the way. On request we can switch your portal so that the contact's responsible counts only when the customer has no open lead or deal; otherwise the lead or deal owner wins. Write to support with your portal name. ## Related [#related] * [WASync Chat](/docs/product/wasync-chat) # After an agent closes the lead, I want the chat to disappear from them so another agent can take the customer. Possible? (/docs/help-center/wasync-chat/hide-chat-from-agent-after-closing-lead) Yes. In **Settings → Chat rules → Hide closed** turn the rule on and set after how many days a closed lead or deal stops giving visibility; **0** means the chat disappears the moment the record is closed. The rule applies to employees on the **Department** and **Only my records** levels; administrators and the **All** level keep seeing the conversation. A second switch, **Ignore the contact's responsible**, is usually needed too: without it, a contact assigned to the same agent keeps the chat visible even after the lead is closed. When the customer writes again and a new lead is created, the conversation appears for the new lead's responsible. ## Related [#related] * [WASync Chat](/docs/product/wasync-chat) # Operators can change the stage from the chat. Can I hide that button? (/docs/help-center/wasync-chat/hide-stage-button-in-chat) Yes. In **Settings → Chat rules → Stage picker** choose who may change the CRM stage from the WASync Chat header: **everyone**, **administrators only**, or **hidden** so the header shows the stage but nobody changes it there. The stage filter in the conversation list and the picker already respect each employee's CRM rights in Bitrix24; this setting narrows them further. ## Related [#related] * [WASync Chat](/docs/product/wasync-chat) # WASync Chat (/docs/help-center/wasync-chat) The shared inbox: who sees what, stages, quick replies, linking conversations to records, long messages. # My long message was rejected by WhatsApp (over 4,096 characters). What now? (/docs/help-center/wasync-chat/long-message-over-4096-characters) Nothing: WASync splits it for you. WhatsApp's limit for one text message on the Business API is 4,096 characters; a longer text is cut into several messages, choosing the cut in this order: a paragraph break, a line break, the end of a sentence, any space. Code blocks are never split in the middle, and each part is recorded as its own message in the thread. Up to ten parts are sent. The limit on a file description (caption) is 1,024 characters and is not split: a longer caption is refused, so keep captions short and put the long text in a separate message. ## Related [#related] * [WASync Chat](/docs/product/wasync-chat) # A chat stayed linked to someone else's deal. Can I move the conversation to another record? (/docs/help-center/wasync-chat/move-conversation-to-another-record) Yes. Open the conversation, press **Change record** in the header and pick the lead, deal or contact it should belong to. From then on the header shows that record, new timeline comments go to it, and the "Assigned to" filter and the visibility levels follow it. Nothing is moved or deleted: the chat thread belongs to the WhatsApp number and stays whole, and the comments already written on the old record's timeline remain there. ## Related [#related] * [WASync Chat](/docs/product/wasync-chat) # Do you have quick replies? I want to type "/" like in other tools. (/docs/help-center/wasync-chat/quick-replies-with-slash) Yes. Type **/** at the start of a line, or after a space, in WASync Chat or in the WhatsApp tab on a CRM record, and pick a reply from the list. Replies are **personal** or **shared with the team**, in the same list, and are managed under **Quick replies** in the app. A reply can contain variables with double braces: `{{greeting}}` for a greeting that follows the customer's local time, `{{contact.first_name}}` and other contact fields, `{{record.title}}` for the current lead or deal, and `{{crm.UF_CRM_…}}` for any CRM field. The greeting and the date formats follow the language and time zone deduced from the customer's phone country. A reply can also have versions in several languages, picked by the customer's country. ## Related [#related] * [WASync Chat](/docs/product/wasync-chat) # When I close a lead from the chat, the required field "reason" is not asked. How do I enforce it? (/docs/help-center/wasync-chat/required-fields-when-changing-stage-from-chat) Bitrix24 does not apply its "required fields per stage" when a stage is changed through the API, which is how the chat changes stages, and it does not expose that configuration to apps. WASync has its own list for this: in **Settings → Chat rules → Required fields per stage** an administrator picks, for each lead or deal stage, the fields that must be filled before a record can be moved there from the chat. When an operator picks such a stage in the chat header, a panel asks for exactly those fields and the stage changes only after they are filled. The list has to mirror the one in your CRM by hand; it is not read from Bitrix24. ## Related [#related] * [WASync Chat](/docs/product/wasync-chat) # Can I restrict employees to see only the chats of their own leads and deals? (/docs/help-center/wasync-chat/restrict-employees-to-their-own-chats) Yes. Open the WASync app in Bitrix24, go to **Team**, and on the employee's row choose the visibility: **All conversations**, **Department** (the records of people in their Bitrix24 department) or **Only my records** (the leads, deals and contacts where they are the responsible person). Employees without an explicit choice get the level set in **Settings → Chat rules → Default visibility**. Bitrix24 administrators always see everything. The same level applies to the conversation list, the search, the "Assigned to" filter and the export. ## Related [#related] * [WASync Chat](/docs/product/wasync-chat) # How do I send a voice note? (/docs/help-center/wasync-chat/send-a-voice-note) Use the microphone button at the right end of the message box, in WASync Chat and in the WhatsApp tab of a CRM record. Click it to start (the tooltip reads **Record a voice note**), speak, then choose **Send voice note**; **Cancel recording** throws the recording away. The first time, your browser asks for access to the microphone. If it is blocked, the button tells you so: allow microphone access in the browser's site settings for the page and try again. Inside the Bitrix24 window the microphone can be blocked too, so check that setting if the button still refuses. It works on both kinds of number, QR and WhatsApp Business API. On a Business API number the note goes out as an audio message, and only while the 24-hour customer-service window is open; outside it, WhatsApp accepts only approved templates. If you already have a recording, use the attach button in the same box and pick the audio file instead. Voice notes your customers send play right in the conversation, and they reach the Bitrix24 Open Channel as a file. ## Related [#related] * [WASync Chat](/docs/product/wasync-chat) * [Voice-note transcription](/docs/product/wasync-chat#voice-note-transcription) * [The 24-hour window and templates](/docs/guides/waba-templates#what-a-template-is-and-when-you-need-one) # When I send a template with an image, why does it ask for the image again? (/docs/help-center/wasync-chat/template-with-image-asks-for-image-again) Because Meta keeps the header image only for the approval of the template; at every send the file has to be supplied again. WASync stores the sample you uploaded when the template was created and pre-selects it in the send dialog, so in practice you confirm it or pick another file for this customer. Syncing templates from Meta does not remove the stored sample. This applies to Business API numbers only; QR numbers do not use templates. ## Related [#related] * [WASync Chat](/docs/product/wasync-chat#templates-on-business-api-numbers) * [Guide: WhatsApp templates](/docs/guides/waba-templates) # How do I make the bot write only to new customers, not to people we already talk to? (/docs/help-center/chat-flows/bot-only-for-new-customers) On the flow's Start card, under **Change when it starts**, turn on **Only customers who never wrote to you before**. The flow then starts only for a number that has never exchanged a message, in either direction, with any WhatsApp number of your portal. "New" is decided from the conversation history, not from the CRM: a customer who exists in Bitrix24 but never wrote on WhatsApp is new; a customer who wrote once last year is not, even without a CRM record. Skipped customers are visible in the flow's history with the reason "known contact". ## Related [#related] * [Only customers who never wrote to you before](/docs/product/chat-flows#only-customers-who-never-wrote-to-you-before) # The bot started when a customer only replied to a message we sent. How do I avoid that? (/docs/help-center/chat-flows/bot-started-on-a-reply-to-our-message) Leave the flow option **Flows do not start on a reply to your team** on; it is on by default, with a window of 72 hours that you can change. When the newest outgoing message to that customer on that number was written by a person, an incoming message inside the window is treated as a reply to your team, not as a new conversation, and the flow stays quiet. What counts as "written by a person": a message from WASync Chat, from the WhatsApp tab on a record, from the Open Channel, or typed on the company phone. What does not count: the bot's own messages, robots, automations and the inactivity reminders. So a customer who answers your bot late still gets a fresh run, while a customer who answers your colleague does not get greeted by a bot. ## Related [#related] * [Chat Flows: when a flow starts](/docs/product/chat-flows#when-a-flow-starts) # How do I make the WhatsApp bot stop when a colleague replies? (/docs/help-center/chat-flows/bot-stops-when-colleague-replies) It stops by itself. Every flow has a switch, **Stop when a colleague replies**, in **Flow settings → Handover**, and it is on by default. The moment a person from your team writes to the customer, from WASync Chat, the WhatsApp tab on a CRM record or the Open Channel, the run ends and the customer talks to the colleague. No step is needed in the flow for this. Two details worth knowing: * Messages typed on the phone or in WhatsApp Web do not stop the bot; they do not carry an operator identity. * Messages sent by the bot itself, by robots, by automations and the inactivity reminders never count as a colleague, so they never stop a run by mistake. The companion switch in the same place, **Run once per customer**, prevents the flow from enrolling a contact it has already finished with. ## Related [#related] * [Chat Flows: when a flow starts](/docs/product/chat-flows#when-a-flow-starts) # Leads created by the bot get the wrong source. Can I choose it? (/docs/help-center/chat-flows/choose-crm-source-of-flow-leads) Yes. On the Start card there is a **Source** selector with your portal's CRM sources. Every contact, lead or deal the flow creates carries that source. A record the flow reuses, such as an open deal, is left untouched. Without a selection the record gets the source configured on the Bitrix24 Open Channel that received the message: **Contact Center → the channel → CRM settings → Source**. That is also the setting to check when leads created by the Open Channel itself, not by a flow, show an unexpected source such as the name of a channel that was used for something else before. ## Related [#related] * [The CRM source of the record](/docs/product/chat-flows#the-crm-source-of-the-record) # Can I start a different flow for each Meta ad? (/docs/help-center/chat-flows/different-flow-per-meta-ad) Yes. On the Start card choose **Customer writes first → From a specific ad** and list the ad ids from Ads Manager (one flow can hold several ids, so a whole campaign can share a flow). A number can have as many inbound flows as you need. When a message matches more than one flow, the most specific wins: the flow for the customer's ad first, then a keywords flow, then **Any message**. A message from an ad you did not list, or from no ad at all, falls through to the keyword and "Any message" flows. The ad id, and with a Meta Ads token the campaign and ad set, are also written on the lead. ## Related [#related] * [Chat Flows: when a flow starts](/docs/product/chat-flows#when-a-flow-starts) * [Campaign and ad set on conversations from ads](/docs/guides/meta-ads-campaign-attribution) # My flow has 200 steps. How do I find one? (/docs/help-center/chat-flows/find-a-step-in-a-large-flow) Press **Ctrl+F** in the editor, or use **Find a step** in the toolbar, and type part of the step's title or message. The canvas jumps to the first match and flashes it; **Enter** and **Shift+Enter** move to the next and previous match. While a step is selected, its incoming and outgoing lines are coloured and the rest of the canvas fades, so you can follow one path through a large flow. A flow can hold up to 300 steps. ## Related [#related] * [The editor](/docs/product/chat-flows#the-editor) # The flow creates a new lead although the customer already has an open deal. Can it attach to the existing one? (/docs/help-center/chat-flows/flow-attaches-to-existing-open-deal) It does, by default. A lead flow first looks for the customer's contact in the CRM, then for an open deal of that contact, then for an open lead of that contact, then for any open lead that holds the number even without a contact (leads imported from another tool). It binds to the first one it finds and creates a lead only when nothing open exists. Three situations still produce what looks like a duplicate, on purpose: * **Each number creates its own lead** is on in Chat rules: the record is per WhatsApp number, so a customer handled on two numbers has two leads. * The existing lead is **closed**. A lost lead can be taken back only inside the re-contact window set in Chat rules; otherwise a new lead is right. * The phone on the old record is stored in a format that does not match (no country code, a different spelling); fix the phone on the record. ## Related [#related] * [Which record a flow creates or binds to](/docs/product/chat-flows#which-record-a-flow-creates-or-binds-to) # Can a flow look something up in an external system through an API? (/docs/help-center/chat-flows/flow-calls-external-api) Yes. Add an **HTTP request** step. It calls any REST endpoint with the method, headers and body you define; flow variables such as the customer's answers or CRM fields can be inserted anywhere in the URL, the headers or the body. Fields from the JSON response are mapped into variables that later steps use in messages, conditions or CRM fields, and the step has separate branches for success and error. Headers you mark as secret, typically the API key, are stored encrypted and are not shown again after saving; a re-save without retyping keeps the stored value. The request itself is made by an isolated worker, not by the WASync server, and only to public addresses. ## Related [#related] * [HTTP request step](/docs/product/chat-flows#http-request-step) * [Guide: HTTP request in Chat Flows](/docs/guides/chat-flows-http-request) # The general flow greeted the customer again right after another flow handed them to a person. Why, and how do I stop it? (/docs/help-center/chat-flows/general-flow-greeted-again-after-handoff) This used to happen because "Any message" really meant "any message while no flow is running": the moment the ad flow handed the customer to a person, the next message started the general flow. It no longer does. An **Any message** flow now stays quiet when any flow on that number ended with the customer in the last 72 hours, whether it completed, handed off, escalated or was cancelled. The window is the same one used for "Flows do not start on a reply to your team". A close for inactivity does not count, so a customer who went silent and comes back later is greeted again. Flows triggered by an ad or by keywords are not affected by this rule and still start. ## Related [#related] * [Chat Flows: when a flow starts](/docs/product/chat-flows#when-a-flow-starts) # Chat Flows (/docs/help-center/chat-flows) Bots on WhatsApp: when they start, when they stop, reminders, ads, sources and the records they create. # How do I insert a step between two steps that are already connected? (/docs/help-center/chat-flows/insert-step-between-connected-steps) Hover the connecting line between the two steps. A **+** appears on the line; press it, pick the step type, and the new step is inserted with the connections rewired: the first step now leads to the new one, and the new one leads to the step that followed. Nothing has to be dragged or reconnected by hand. ## Related [#related] * [The editor](/docs/product/chat-flows#the-editor) # Can the bot send a reminder if the customer does not reply, and close after that? (/docs/help-center/chat-flows/reminder-and-close-after-inactivity) Yes. Open **Flow settings → If no reply**, or the same section on a single question to override it for that step. You set four things: after how many minutes to send a reminder, the reminder text, after how many more minutes to close the run, and an optional **closing message** the customer receives at that moment. The close touches only the conversation: the run ends, the lead or deal keeps its stage, nothing is changed in the CRM. The customer is not locked out either: a message that arrives after the close starts the flow again from the beginning. The reminder and the closing message are recorded as the bot's own messages, so they never count as a colleague taking over. ## Related [#related] * [Inactivity reminders and closing](/docs/product/chat-flows#inactivity-reminders-and-closing) # Can I rotate new conversations among a group of employees? (/docs/help-center/chat-flows/rotate-conversations-among-employees) Yes. Add an **Assign to** step and switch it from "one person" to **rotate within a group**, then order up to 50 employees. Each new run takes the next person on the list and sets them as the responsible of the lead or deal; the step's counter survives re-saves of the flow, so the rotation does not restart when you edit something else. The counter belongs to the step: two steps, or two flows, with the same list rotate independently. Employees who have been deactivated in Bitrix24 are skipped automatically, and the history of the run names the person who was chosen. ## Related [#related] * [Assign to a person or rotate within a group](/docs/product/chat-flows#assign-to-a-person-or-rotate-within-a-group)