Forms. CRM. WhatsApp. A more connected way to grow. Meet your platform ↗
custom website whatsapp integration

Connect Any Website to WhatsApp Automation with Insta AI 365

2026-10-12 · 18 min read · Developer guide

2026-10-12 · 18 min read · Developer guide

Your website already knows when an order is paid, a booking is confirmed or a payment fails. This guide shows how to send that event to Insta AI 365 from your own backend and have one of your approved WhatsApp templates go out automatically — no plugin, on any stack that can make a signed HTTPS request.

1. What this does

Custom Website Integration is an HTTP endpoint plus an automation engine. Your backend posts a signed JSON event. Insta AI 365stores it, matches it against the automations you have switched on, fills your template’s placeholders from the event, and sends the message through your own connected WhatsApp Business Account.

Three things are yours: the credentials, the event you send, and the automation that decides what happens. Queueing, de-duplication, retries and the policy checks are handled for you.

Accepting an event is not sending a message. A 202 means the event is stored durably. Whether a WhatsApp message follows depends on an automation being enabled, the template still being approved, the mapped fields being present, and the consent and policy checks passing. The execution log says which of those happened — this guide will not pretend the two are the same thing.

2. Who it is for

The event vocabulary is deliberately not ecommerce-only. The same engine serves any business whose website knows something worth telling a customer:

BusinessEventMessage
Ecommerceorder.paidOrder confirmation with the order number and total
Travel agencybooking.createdItinerary confirmed, with the reference and date
Clinic or dental practiceappointment.rescheduledThe new time, and who the patient is seeing
Educationlead.createdApplication received, and the next step
Real estateappointment.bookedViewing confirmed, with the address and the agent
Professional servicespayment.succeededA receipt with the reference and amount
Any subscription businesspayment.failedA payment problem the customer can actually act on

3. Prerequisites

Four things, before the first request can succeed:

  • An Insta AI 365 account on a plan that includes integrations or the communication hub. The WhatsApp Business API plans include both, so a WhatsApp-only customer is not locked out.
  • A connected WhatsApp Business Account. An automation cannot be switched on until the website is bound to one of your connected numbers.
  • At least one approved template. Templates are approved by Meta, not by us. A draft, pending, rejected or paused template cannot be selected.
  • Server-side access to your website. The signing secret must never reach a browser, so the event has to be sent from your backend.

4. Quick start

In Insta AI 365, open Integrations → Custom Website and press Connect website. Give it a name and the domain — just the host, no https:// and no path.

You are shown an API key and a signing secret. Copy both now. The server keeps only a SHA-256 hash of the key and encrypted ciphertext of the secret, so neither can be shown a second time; rotating is the only way to get new ones.

export INSTAAI_API_KEY="iak_…"
export INSTAAI_SIGNING_SECRET="iss_…"   # server only, never in a browser bundle

Then send a test event using the snippet on the Developer setup tab — it is generated from the same contract the endpoint validates against, so a sample the server would reject cannot be published there. The event appears under Events within a second or two, with its id and processing status.

5. Authentication

Two separate credentials, because they fail differently. The API key identifies the integration; the signing secret proves the body. A key leaked from a log or a proxy cannot forge an event on its own.

CredentialShapeSent asStored as
API keyiak_ + 32 random bytes, base64urlx-instaai-keyA SHA-256 hash, nothing else
Signing secretiss_ + 32 random bytes, base64urlNever sent — it computes the signatureEncrypted at rest

The tenant is resolved from the API key alone. If your payload carries an organisation or tenant id, it is ignored — a caller that could name its own tenant would be the whole isolation story undone.

6. Request signing

HMAC-SHA256, hex, over the exact string <timestamp>.<raw request body>.

signature = hex( HMAC_SHA256( signing_secret, timestamp + "." + raw_body ) )
RuleValue
AlgorithmHMAC-SHA256
Signed payload<unix seconds> then . then the raw body bytes
EncodingHex. Case is not significant.
Signature headerx-instaai-signature
Timestamp headerx-instaai-timestamp — unix seconds
Replay window±300 seconds, in both directions
ComparisonConstant time
Serialise once, sign what you send. The commonest integration bug here is serialising the object twice — once to sign, once to send. Key order or whitespace differ by a byte and the signature does not match. Build the JSON string, sign that string, send that same string as the body.

The timestamp is inside the signed material deliberately: signing only the body would let anyone replay a captured request under a fresh timestamp. A delivery outside the window is refused whether or not its signature is valid, and the error says so — in practice it means the sending server’s clock is wrong.

7. API reference

POST /ecommerce/websites/events

One endpoint. It is the only route that takes your events, and it authenticates by API key rather than by session.

POST https://api.instaai365.com/ecommerce/websites/events
Content-Type: application/json
x-instaai-key: iak_…
x-instaai-timestamp: 1791900000
x-instaai-signature: 3f2a…
{
  "event_id": "order_10421_paid",
  "event_type": "order.paid",
  "occurred_at": "2026-10-12T10:30:00.000Z",
  "data": {
    "order": {
      "id": "10421",
      "number": "ORD-10421",
      "total": 2499,
      "currency": "INR",
      "status": "paid"
    },
    "customer": {
      "name": "Asha Menon",
      "first_name": "Asha",
      "phone": "919876543210",
      "marketing_consent": "granted"
    }
  }
}
FieldRequiredNotes
event_idYesYour own id. This is the idempotency key — make it deterministic, not a fresh UUID per attempt.
event_typeYesOne of the names in the catalogue below. Anything else is a 422.
occurred_atNoISO 8601. Defaults to the time we received it.
data.orderNoOrder fields. Up to 100 line items.
data.customerNoName, phone, email, marketing consent. The phone is the recipient.
data.bookingNoReference, start and previous start, service, provider, location.
data.paymentNoReference, amount, currency, method label, failure reason.
The top level is strict: an unrecognised key is rejected rather than ignored. A typo like eventType instead of event_type then fails loudly on your first test, rather than silently never firing in production.

Status codes

CodeMeaningWhat to do
202Accepted and stored durablyNothing. Automations run shortly after.
409This event_id was already acceptedStop retrying. The response carries the stored event id.
401The API key does not match an active integrationCheck the key; check the website has not been revoked or disconnected.
403The signature did not verify, or the timestamp is outside the windowCheck what you signed; check the server clock.
413The body is larger than 64 KBSend only the fields your templates need.
422Authentic, but the payload does not match the contractRead the message — it names the field and the rule.
429Over 600 requests in a minute for this integrationBack off, then retry with the same event_id.
503A problem on our sideRetry with the same event_id. Nothing was stored.

Every response, refusals included, carries a correlationId. Quote it in a support request; it is also the one field worth logging. A 202 looks like this:

{
  "accepted": true,
  "eventId": "4d3f…",
  "automationsMatched": 1,
  "correlationId": "9b1c…"
}

automationsMatched is worth watching during setup: zero means the event was stored and no enabled automation wanted it, so no message will follow. A 409 carries duplicate: true and the stored eventId.

Limits

LimitValue
Request body64 KB
Rate600 requests per minute, per integration
Replay window±300 seconds
Line items per order100

Those are the figures the shipped code enforces. There is no published per-day quota on this endpoint; your WhatsApp sending volume is governed separately, by your plan and by Meta’s own messaging limits for your number.

8. Event catalogue

These are the event names the endpoint accepts. Each one is a trigger you can choose in the automation builder.

EventMeans
customer.createdSomebody registered an account
lead.createdAn enquiry or contact form was submitted
contact.createdA contact was added to your own system
order.createdAn order was placed, before payment
order.paidPayment for an order cleared
order.fulfilledAn order shipped or was completed
order.cancelledAn order was cancelled
order.refundedAn order was refunded
booking.createdA booking was confirmed
booking.cancelledA booking was cancelled
appointment.bookedAn appointment was scheduled
appointment.rescheduledAn appointment moved to a new time
appointment.cancelledAn appointment was cancelled
appointment.reminderRemind someone of an upcoming appointment
payment.succeededA payment cleared
payment.failedA payment attempt failed
payment.refundedA payment was refunded
custom.eventAnything else — its meaning comes from the automation you point at it

A booking event carries no order at all. Send the shape that fits what actually happened:

{
  "event_id": "appt_9931_rescheduled_2",
  "event_type": "appointment.rescheduled",
  "data": {
    "booking": {
      "reference": "APPT-9931",
      "starts_at": "2026-10-15T09:00:00Z",
      "previous_starts_at": "2026-10-13T05:30:00Z",
      "service": "Dental check-up",
      "provider_name": "Dr Nair",
      "location": "Andheri clinic"
    },
    "customer": { "name": "Ravi Kumar", "first_name": "Ravi", "phone": "919812345678" }
  }
}

9. Idempotency and retries

event_id is the idempotency key, scoped to your integration. Make it name the thing that happened — order_10421_paid, not a fresh UUID per attempt. Then a retry after a timeout returns 409 and your customer is not messaged twice.

Two guarantees are in play and both matter. The endpoint collapses duplicate deliveries onto one stored event. Separately, the engine keeps one logical send per automation and event, so even a replayed event cannot produce a second message. A retry you ask for from the dashboard is recorded as its own attempt, attributable to whoever requested it.

ResponseRetry?
429Yes, after backing off. Same event_id.
503Yes, with backoff. Same event_id.
Network error or timeoutYes. Same event_id — a duplicate is safe.
401, 403, 413, 422No. Each needs a change on your side first.
409No. We already have it.

10. Creating an automation

Open Integrations → Custom Website and press Create Automation. The builder walks through the website, the trigger event, an approved template and the variable mapping, then shows a preview before anything can be switched on.

Every automation is created paused, and changing its template or its mapping pauses it again. That is deliberate: an enabled automation whose configuration just changed would send the new shape to the next real customer with nobody having looked at it. Switching it on is a separate, explicit act — and when it cannot be switched on, it says which check failed rather than appearing to succeed.

All of it is decided server-side. The website, the template name, its category and its approval status are read from your own records rather than taken from whatever the browser submitted, and every route is scoped to your workspace and gated on the integrations permission.

11. Choosing a template

The picker lists only templates on your connected WhatsApp Business Account that are approved and active. Each row shows the name, language, category, how many values the body expects and a preview of the body text, so two similarly named templates can be told apart before anything is mapped.

Template stateSelectableWhy
Approved and activeYesMeta will accept it
Pending reviewNoNot approved yet — the first real event would fail
RejectedNoMeta refused it. Edit and resubmit.
Paused or disabledNoMeta has suspended it, usually for quality
Deleted at Meta after you selected itNoThe automation shows it as a blocking issue and will not send

An empty list means one of two things, and the screen says which: either no WhatsApp Business Account is bound to this website yet — set that on the WhatsApptab — or you have no approved templates. You create and submit those in your WhatsApp template manager; approval is Meta’s decision and usually takes between a few minutes and a day. We cannot approve one on your behalf, and the builder offers no placeholder that pretends otherwise.

Templates are held once per workspace, keyed by name and language, not per connected number. So if you have more than one WhatsApp number, the picker shows every approved template in the workspace — make sure the one you choose is approved on the number this website actually sends from, or Meta will refuse the message.

Which component types this path can send. This automation fills body text variables only. A template whose header needs an image, video, document or location, and a template with variable URL or copy-code buttons, will not have those parameters supplied here — so choose a body-only template for an automation, and use the campaign tools when the message needs header media. The builder names the component it cannot fill rather than creating an automation that cannot send.

12. Mapping variables

WhatsApp templates use positional placeholders — {{1}}, {{2}} — so the builder shows one row per placeholder the template declares, in order. You map each to a field chosen from a closed list of what the selected trigger actually carries.

{{1}} → customer.firstName        e.g. "Ravi"
{{2}} → appointment.startsAt      e.g. "15 Oct 2026, 2:30 pm"
{{3}} → booking.service           e.g. "Dental check-up"

The field list is an allowlist, not a path into your JSON. Arbitrary paths would let a template variable carry a field nobody intended to send into a message on somebody’s phone. A sample of what is available:

FieldRenders asCarried by
store.nameHexhealth StoreEvery event
customer.firstNameAshaAny event with a customer
order.numberORD-10421Order events
order.total₹2,499.00Order events
shipping.trackingNumberIN123456789order.fulfilled
booking.referenceAPPT-9931Booking and appointment events
appointment.startsAt15 Oct 2026, 2:30 pmBooking and appointment events
payment.amount₹1,768.82Payment events
payment.failureReasonThe card was declinedpayment.failed

Dates render for a human in your business’s timezone and money groups for its currency — you send ISO 8601 and a number, and the engine formats them. Newlines and tabs inside a value are collapsed to single spaces, because WhatsApp rejects a parameter containing them: a message that fails at the provider is worse than one whose address lost a line break.

The mapping is validated before you can save, and again when the message is about to go out. A placeholder with no mapping, a field the chosen trigger cannot carry, and a template that wants more values than you have mapped are three distinct errors with three distinct messages.

When a mapped field is missing from the event

If the event does not carry a mapped field and you have set no fallback, the message is not sent, and the execution is logged as skipped with the reason. That is the deliberate choice: “Your order ORD-10421 has shipped, track it at ” cannot be taken back once a customer has read it. Set a fallback on any placeholder where a generic value is genuinely acceptable.

13. Category, consent and eligibility

Meta assigns every template a category, and the category decides what it may be used for. We enforce that when the message is sent, not only when you save the automation.

CategoryUseConsent
UTILITYTransactional messages the customer's own action triggered — order confirmations, appointment changes, receiptsNo marketing opt-in required
MARKETINGPromotions, offers, re-engagementA recorded opt-in for that number. Its absence blocks the send.
AUTHENTICATIONOne-time passcodes, through Meta's authentication template flowUse that flow — do not put codes in ordinary body variables

Report consent on the event itself, with data.customer.marketing_consent set to granted, revoked or unknown. A revoked record is never overwritten by silence, and neither an unknown nor an absent consent will satisfy a MARKETING template: absence of evidence is not consent. Honour opt-outs in your own system too — a customer who replies STOP has told your number, not just your database.

Do not relabel promotional content as Utility to avoid the opt-in requirement. Meta re-categorises templates and penalises accounts for it, and the cost lands on your own number’s quality rating. If the message sells something, it is marketing. The WhatsApp Business Messaging Policy is the authority here, not our interface.

The eligibility checks re-run at execution time: the automation must still be enabled, the template still approved and active, the WhatsApp connection still valid, the mapped values present, consent satisfied for the category, and your plan’s messaging entitlement not exhausted. Any failure is recorded against that execution with a readable reason — so a template Meta pauses an hour after you activate stops the automation, instead of producing a run of failed sends.

14. Node, PHP and Python

All three read credentials from the environment, serialise the body once and sign that exact string, set a real timeout, separate retryable failures from permanent ones, and log neither credentials nor customer data. The signature each one produces was checked against the server’s own verification before this was published, so all three interoperate byte for byte.

Node.js

const crypto = require("node:crypto");

const ENDPOINT = "https://api.instaai365.com/ecommerce/websites/events";
const API_KEY = process.env.INSTAAI_API_KEY;
const SIGNING_SECRET = process.env.INSTAAI_SIGNING_SECRET;

async function sendEvent(event) {
  // Serialise once. Signing one string and sending another is the single
  // commonest cause of a 403 here.
  const body = JSON.stringify(event);
  const timestamp = Math.floor(Date.now() / 1000).toString();
  const signature = crypto
    .createHmac("sha256", SIGNING_SECRET)
    .update(timestamp + "." + body)
    .digest("hex");

  const controller = new AbortController();
  const timer = setTimeout(() => controller.abort(), 15000);

  try {
    const res = await fetch(ENDPOINT, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "x-instaai-key": API_KEY,
        "x-instaai-timestamp": timestamp,
        "x-instaai-signature": signature,
      },
      body,
      signal: controller.signal,
    });

    const result = await res.json().catch(() => ({}));

    // 202 accepted; 409 we already have this event_id. Both are success.
    if (res.status === 202 || res.status === 409) return result;

    // 429 and 5xx are worth sending again with the same event_id. 4xx are not.
    if (res.status === 429 || res.status >= 500) {
      throw Object.assign(new Error("instaai: retry later"), { retryable: true });
    }

    // Log the status and the correlation id. Never the body or the headers.
    throw new Error("instaai: rejected " + res.status + " " + (result.correlationId || ""));
  } finally {
    clearTimeout(timer);
  }
}

module.exports = { sendEvent };

Next.js

Call it from a route handler, a server action or your payment webhook — never from a client component. Anything imported into a component ships to the browser, and a signing secret in a browser bundle is a public signing secret.

// app/api/orders/[id]/paid/route.ts — a server route, not a component.
import { NextResponse } from "next/server";
import { sendEvent } from "@/server/instaai";   // the module above

export async function POST(request: Request) {
  const order = await confirmPayment(request);

  await sendEvent({
    event_id: `order_${order.id}_paid`,
    event_type: "order.paid",
    occurred_at: new Date().toISOString(),
    data: {
      order: { id: order.id, number: order.number, total: order.total, currency: "INR" },
      customer: { name: order.customerName, phone: order.customerPhone },
    },
  });

  return NextResponse.json({ ok: true });
}

PHP / Laravel

<?php

namespace App\Services;

use Illuminate\Support\Facades\Http;
use RuntimeException;

class InstaAiEvents
{
    private const ENDPOINT = 'https://api.instaai365.com/ecommerce/websites/events';

    public function send(array $event): array
    {
        $apiKey = config('services.instaai.key');      // INSTAAI_API_KEY
        $secret = config('services.instaai.secret');   // INSTAAI_SIGNING_SECRET

        // Serialise once, sign exactly what you send.
        $body = json_encode($event, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
        $timestamp = (string) time();
        $signature = hash_hmac('sha256', $timestamp . '.' . $body, $secret);

        $response = Http::timeout(15)
            ->withHeaders([
                'Content-Type'        => 'application/json',
                'x-instaai-key'       => $apiKey,
                'x-instaai-timestamp' => $timestamp,
                'x-instaai-signature' => $signature,
            ])
            ->withBody($body, 'application/json')
            ->post(self::ENDPOINT);

        $status = $response->status();

        if ($status === 202 || $status === 409) {
            return $response->json() ?? [];
        }

        if ($status === 429 || $status >= 500) {
            throw new RuntimeException('instaai: retry later, status ' . $status);
        }

        throw new RuntimeException('instaai: rejected, status ' . $status);
    }
}

// Dispatch from a queued job, so a slow HTTP call never holds up the response
// your own customer is waiting for:
//
//   SendInstaAiEvent::dispatch($payload)->onQueue('webhooks');

Python

import hashlib
import hmac
import json
import os
import time

import requests

ENDPOINT = "https://api.instaai365.com/ecommerce/websites/events"
API_KEY = os.environ["INSTAAI_API_KEY"]
SIGNING_SECRET = os.environ["INSTAAI_SIGNING_SECRET"]


class Retryable(RuntimeError):
    """Worth sending again with the same event_id."""


def send_event(event: dict) -> dict:
    # Serialise once, sign exactly what you send, post those same bytes.
    body = json.dumps(event, separators=(",", ":"), ensure_ascii=False).encode("utf-8")
    timestamp = str(int(time.time()))
    signature = hmac.new(
        SIGNING_SECRET.encode("utf-8"),
        timestamp.encode("utf-8") + b"." + body,
        hashlib.sha256,
    ).hexdigest()

    response = requests.post(
        ENDPOINT,
        data=body,
        headers={
            "Content-Type": "application/json",
            "x-instaai-key": API_KEY,
            "x-instaai-timestamp": timestamp,
            "x-instaai-signature": signature,
        },
        timeout=15,
    )

    if response.status_code in (202, 409):
        return response.json()
    if response.status_code == 429 or response.status_code >= 500:
        raise Retryable(f"status {response.status_code}")
    raise RuntimeError(f"rejected: status {response.status_code}")


# Call this from the place that already knows the booking is confirmed — a
# Django signal, a Celery task — and give it a deterministic event_id.

Emit the event from the place in your backend that already knows the fact is true and final — after the gateway confirms the payment, after the booking row commits — and do it from a queue, so a slow HTTP call never delays the response your own customer is waiting for.

15. End to end

A clinic moves an appointment. The whole path, once:

  1. 1.The clinic’s Django backend saves the new time and calls send_event with appointment.rescheduled and the id appt_9931_rescheduled_2.
  2. 2. The endpoint checks the size, resolves the integration from the API key, applies the rate limit, verifies the signature and timestamp, validates the payload against the contract, stores the event, and answers 202 with the stored event id.
  3. 3. One execution is queued per enabled automation on that trigger.
  4. 4. The worker claims the execution, re-checks that the template is approved, that consent satisfies its category and that there is a recipient, then renders ["Ravi", "15 Oct 2026, 2:30 pm", "Dental check-up"].
  5. 5.The message goes out through the clinic’s own WhatsApp number, and the execution records the provider’s message id. Delivery and read arrive later, against that id.

16. Accepted, sent, delivered, read, failed

Five different facts. The log keeps them apart on purpose, because conflating the first with the fourth is how an integration comes to be believed to work when it does not.

StateMeans
Accepted (202)The event is stored. No message has been sent.
QueuedAn automation matched; an execution is waiting for the worker.
SkippedDeliberately not sent — paused, no consent, a missing mapped value, the template withdrawn. The reason is recorded.
SentWhatsApp accepted the message and returned a message id.
Delivered / ReadReported later by WhatsApp, against that message id.
FailedWe tried and could not — a provider rejection, an exhausted plan limit, sending disabled.

A preview in the builder renders example values and sends nothing. A test sendis a real WhatsApp message: it goes to the number you type out in full and confirm, it counts against your plan, and the result reports the provider’s message id — or the provider’s refusal. There is no third mode that pretends to send.

17. Logs and troubleshooting

The Events tab shows what arrived. The Message log shows what each automation did with it, with the provider message id, the values that were rendered and a masked recipient.

SymptomLikely causeFix
401 on every requestWrong key, or the website was revoked or disconnectedCheck the key; reconnect the website if it was revoked
403, signatureThe body was serialised twice, or the wrong secret is in useSign the exact string you send; confirm the secret after any rotation
403, timestampThe sending server's clock is more than 5 minutes outRun NTP on that host
422 naming a fieldThe payload does not match the contractRead the message — it names the field and the rule
Event accepted, no messageNo enabled automation for that triggerSwitch the automation on, and clear any blocking issue it lists
Skipped: a missing valueThe event did not carry a mapped fieldSend the field, or set a fallback on that placeholder
Skipped: no consentA MARKETING template with no opt-in recorded for that numberReport consent on the event, or use a Utility template
Skipped: template not usableMeta paused, rejected or deleted the templateFix it in your template manager, then re-enable the automation
Nothing at all under EventsThe request never reached usCheck egress from your host, and that you are posting to the path above

18. Security and data minimisation

  • Keep the signing secret server-side. Never in browser JavaScript, a mobile app, a URL or a client-readable environment variable. If it has ever been in one, rotate it.
  • Rotate from the dashboard. The previous key stops working immediately — a grace period in which a leaked key still works is a delay, not a rotation — so deploy the new values first.
  • Revoke when a site is retired.That destroys the credentials and pauses the website’s automations. Your history is kept.
  • Send the minimum.The contract has no field for a card number, a bank account, a password, an identity number, a diagnosis or a clinical note, and anything outside the declared fields does not survive validation. Do not route one-time passcodes through ordinary body variables; Meta’s authentication template flow exists for those.
  • Remember where a variable ends up.It is rendered into a message on a personal phone, often readable on a lock screen and in a notification. “Your test result is positive” is not a template variable.
  • Log the correlation id, not the payload.It is enough to trace a request without copying a customer’s name and number into your application logs.

19. Production checklist

  • Credentials in your secret manager, not in source control.
  • event_id deterministic per real-world event, so a retry de-duplicates instead of sending twice.
  • Events emitted from a queue or a background job, not inline in a request.
  • 429, 503 and network errors retried with backoff; 4xx not retried.
  • NTP running on every host that signs a request.
  • A Utility template for anything transactional.
  • Consent reported on the event if you use MARKETING templates.
  • A test send to your own number, and the preview read end to end, before you activate.
  • Someone watching the message log through the first day of real traffic.

20. FAQ

Do I need a plugin?

No. This is an HTTP endpoint, so any backend that can make a signed HTTPS request works — WordPress, Laravel, Django, Rails, .NET, a Cloudflare Worker. Packaged platform connectors are a separate thing and are not required for this.

Will a retry message my customer twice?

Not if your event_id is deterministic. The endpoint de-duplicates the event, and the engine separately keeps one logical send per automation and event.

Can I send a template with an image header?

Not through this path — it fills body text variables only, so header media is never supplied. Choose a body-only template for an automation and use the campaign tools when the message needs header media.

Can I add conditions, like only orders above a value?

Not yet. An automation fires on its trigger for every event of that type. Filter on your own side — emit the event only when your condition holds — and the behaviour is the same. We would rather say that plainly than ship a condition field that is quietly ignored.

Who approves templates?

Meta. We read their verdict and refuse anything not approved and active. The WhatsApp Cloud API documentation covers templates, categories and messaging limits in full.

What happens if I disconnect WhatsApp?

Automations for that website show a blocking issue and cannot be switched on until a connection is selected again. Nothing is deleted.

Can one website drive several automations?

Yes, and several can share a trigger — an order.paid confirmation in English and another in Hindi, for instance. Each is queued, rendered and logged separately.

Connect your website

Create the integration, copy your credentials, send a signed test event, then map your first approved template. The Developer setup tab carries the snippet for your stack.

A CLOSER LOOK

Check the whole path from website event to customer message

A custom website integration starts with an event your backend can reliably identify, such as a completed purchase or confirmed booking. Follow this guide’s request format and signing process, then map the event fields to the approved message template your automation uses.

Receiving an accepted event response is only one checkpoint. Check that the matching automation is enabled, required fields are present and the execution log shows what happened. Use the delivery state to distinguish a queued action from a message that actually reached the customer.

Questions about Website to WhatsApp API Integration Guide

Does an accepted webhook mean a WhatsApp message was sent?

No. An accepted event indicates that the event was received for processing. Sending still depends on the configured automation, template, required data and applicable messaging checks.

How should I troubleshoot website-to-WhatsApp automation?

Check the event response, matching automation, field mappings and execution log in sequence. Use the guide’s retry and idempotency guidance so a retry does not create unintended duplicate work.

YOUR NEXT CHAPTER STARTS HERE

More meaningful conversations.
More momentum.

Bring your sales process together. Let your team move forward.

CRM + WhatsAppExplore plans →Book a demo ↗