Skip to content
Docs
API reference Go to dashboard
DocsWebhooks

Webhooks

Alpheris receives webhooks from connected platforms — Shopify, Stripe and Meta (Instagram & WhatsApp). Every incoming call is verified with a cryptographic signature. This page explains which endpoints exist, how signature verification works and what you need to set up for it.

What is this about?

Webhooks at Alpheris work in both directions. Outbound is the part you set up yourself: you register a URL in the dashboard and we send the events you subscribed to there as a signed POST — covered right below. Inbound works the other way round and needs nothing from you: external platforms you've connected to your store report events back to Alpheris — for example a new Instagram DM, a changed Stripe subscription or an uninstalled Shopify app. Alpheris sets up these endpoints automatically when you connect the respective integration. As a rule, you don't need to register anything manually.

i
These webhooks are an internal platform detail. They're configured automatically when you connect an integration (Shopify OAuth, Meta OAuth, Stripe Checkout). You only need to understand them if you want to trace the signature verification or debug an integration.

Outbound webhooks

With the Webhooks area in the dashboard you can register your own endpoints: Alpheris sends the events you subscribe to as a POST to your URL — signed, so you can verify the request really came from us. You'll find it in the left sidebar under Webhooks, right below API Keys. Available from Business upwards; owners and admins can manage it.

1
Create an endpoint
Dashboard → Webhooks → Create endpoint. The name is optional, the URL must be https. Then tick the events you want to receive.
2
Save the signing secret
Right after creation we show the secret in full exactly once. After that the overview only shows whsec_…xxxx. Lost it? The rotate icon generates a new one — the old one stops working immediately.
3
Test the delivery
The check icon in the row sends a ping event right away and shows you the real HTTP status your server returned. The dot in front of the name then turns green or red.

Events

TypeWhen
conversation.createdA visitor starts a new conversation
conversation.handoff_requestedA customer asks for a human agent
conversation.closedA conversation is closed
message.receivedA customer message arrives
ticket.createdA ticket is created
ticket.closedA ticket is closed
lead.createdA lead is captured
i
Current status: all events above are delivered - usually within 15 seconds, each exactly once. Counting starts when the endpoint is created. Automation tools like Zapier, Make or n8n are easiest to connect under Integrations.

Payload shape

json
{
  "id": "evt_9f2c1a4b7e8d0c3a5b6f2e11",
  "type": "ticket.created",
  "created_at": 1785062400,
  "data": { }
}

Verifying the signature

Every delivery carries two headers. What gets signed is the raw body with the timestamp prepended and separated by a dot — that is <timestamp>.<body>, using HMAC-SHA256 with your signing secret, hex-encoded:

HeaderContents
X-Alpheris-TimestampUnix time of the delivery, included in the signature
X-Alpheris-Signaturesha256=<hexdigest>
User-AgentAlpheris-Webhook/1
python
import hmac, hashlib

def signature_ok(raw_body: bytes, headers, secret: str) -> bool:
    ts  = headers["X-Alpheris-Timestamp"]
    sig = headers["X-Alpheris-Signature"]
    expected = "sha256=" + hmac.new(
        secret.encode(), ts.encode() + b"." + raw_body, hashlib.sha256
    ).hexdigest()
    # compare in constant time, never with ==
    return hmac.compare_digest(sig, expected)
Same scheme as the form webhook in lead capture — so you only need one verification routine for both. And as above: verify against the raw body, not against re-serialised JSON.

Good to know

TopicBehaviour
Protocolhttps only. URLs carrying credentials (https://user:pass@…) are rejected.
TargetsPrivate, loopback and link-local addresses are blocked, including cloud metadata IPs. Checked at send time, not when saving.
RedirectsWe do not follow redirects. Your URL must be the destination.
Timeout5 seconds per delivery. Answer quickly and process the payload asynchronously.
SuccessAny 2xx status. Anything else counts as a failure and turns the dot in the overview red.
RetriesNone for now. A failed delivery is not retried — plan your receiver accordingly.
LimitUp to 10 endpoints per workspace.

What else Alpheris calls outbound

Lead forms can additionally push their data straight to your API — setup and payload are documented under lead capture → form webhook. All other outbound calls go exclusively to the third-party services we depend on (email via Microsoft Graph, replies to Meta, billing via Stripe) and are not configurable webhooks.

Inbound webhooks at a glance

All inbound webhook routes verify the raw request body against a signature from the sender. If verification fails, the request is rejected — there is no unverified processing path.

PlatformEndpointSignature headerMethod
ShopifyPOST /shopify/webhooksX-Shopify-Hmac-Sha256HMAC-SHA256 (Base64)
StripePOST /stripe/webhookStripe-SignatureStripe signature (construct_event)
InstagramPOST /integrations/instagram/callbackX-Hub-Signature-256HMAC-SHA256 (Meta)
WhatsAppPOST /integrations/whatsapp/callbackX-Hub-Signature-256HMAC-SHA256 (Meta)
Shared principle: what's always verified is the raw, unmodified request body — not a freshly re-serialized JSON. That's why nothing in the payload may be changed between receipt and verification.

Shopify webhooks

When you connect a Shopify store via OAuth, Alpheris registers the app webhooks automatically and receives them at POST /shopify/webhooks (alias: /api/integrations/shopify/webhooks). Among others, app uninstall, shop update and product delta sync are processed so that your catalog stays up to date in the knowledge base.

Authenticity is verified via the X-Shopify-Hmac-Sha256 header: Alpheris computes an HMAC-SHA256 over the raw body using the app secret and compares it in constant time (Base64) against the header.

python
# How Alpheris verifies the Shopify signature (simplified)
import hmac, hashlib, base64

digest = base64.b64encode(
    hmac.new(app_secret.encode("utf-8"), raw_body, hashlib.sha256).digest()
).decode("utf-8")

valid = hmac.compare_digest(digest, request.headers["X-Shopify-Hmac-Sha256"])
i
The same HMAC mechanism also secures the Shopify OAuth callback when you connect the store. More on the Shopify integration is under Shopify.

Stripe webhooks

Stripe reports billing events to POST /stripe/webhook. From these, Alpheris keeps your plan and subscription status in sync — for instance when a subscription is created, updated or canceled, or an invoice is paid or fails.

Verification runs via the official Stripe library using the Stripe-Signature header and the webhook secret (construct_event). Invalid signatures are rejected with 400.

Idempotency

Stripe redelivers events on network or timeout errors. To ensure an event never takes effect twice (no double provisioning, no duplicate emails), Alpheris maintains an idempotency store: every event ID is atomically "claimed" before processing. Events already seen are skipped with ok (duplicate).

Stripe eventEffect in Alpheris
checkout.session.completedProvision plan after completed checkout
customer.subscription.created / .updatedPlan / status sync
customer.subscription.deletedSubscription ended → deactivate plan
invoice.payment_succeeded / invoice.paidPayment recorded
invoice.payment_failedProcess failed payment
i
Stripe webhooks concern only your own billing with Alpheris. Details on plans and trial are under Plans & Billing.

Meta webhooks (Instagram & WhatsApp)

Instagram and WhatsApp are connected via Meta OAuth. Incoming messages and events reach Alpheris through the callback endpoints and land in your Inbox. Both use Meta's standard method: signature verification via X-Hub-Signature-256 (HMAC-SHA256 over the raw body using the app secret).

Verify handshake (WhatsApp)

When setting up the WhatsApp webhook, Meta performs a one-time verify handshake: a GET request with hub.challenge and hub.verify_token. Alpheris checks the verify token and echoes the challenge back once it matches. After that, only signed POST events are accepted.

http
# Incoming Meta event (simplified)
POST /integrations/instagram/callback
X-Hub-Signature-256: sha256=<hex-digest>
Content-Type: application/json

# Alpheris verifies sha256(raw_body, app_secret) against the header
# before the message is taken into the inbox.
i
The OAuth scopes for Instagram are instagram_business_basic, instagram_business_manage_messages and instagram_business_manage_comments. Connecting is done entirely through the Dashboard — you don't have to enter a webhook URL by hand.

Fetch your own events (polling)

While the events above are not emitted yet — and generally whenever you want the full set rather than individual events — use the API reference. Authenticate with an API key and poll the relevant endpoints on an interval.

1
Create an API key
Create a key in the Dashboard under API Keys. Available for Business & Enterprise.
2
Check auth
Call GET /api/me and make sure the key is valid (otherwise 401/402).
3
Poll at intervals
Poll GET /api/inbox/threads or GET /api/inbox/tickets and bring new entries into your system.
bash
# Fetch new inbox threads (polling instead of an outbound webhook)
curl -sS https://console.alpheris.com/api/inbox/threads \
  -H "Authorization: Bearer <SHOP_API_KEY>"
i
More on auth, endpoints and retry strategy is under Custom API and in the API Reference.

Frequently asked questions

Do I have to enter a webhook URL somewhere?

No. The inbound webhooks are set up automatically when you connect the respective integration (Shopify, Stripe Checkout, Meta OAuth).

Why does a signature verification fail?

Almost always because a proxy or middleware modified the body, or a wrong/expired secret is involved. Since verification is done against the raw body, no reformatting may happen between receipt and verification. In that case, check the integration in the Dashboard and reconnect it if needed.

Can Alpheris notify my system on every new message?

Not via push at the moment. Instead, use polling via the API (see above).

i
For data processing and the subprocessors used (Stripe, Microsoft, Meta, etc.), see our DPA and the Security & Privacy page.