Webhooks & API

Inbound Webhooks

Receive HTTP POSTs from external systems and start flows

Inbound webhooks let external systems push data into Wexio. Any service that can POST JSON — a payment provider, your own backend, a no-code tool — can trigger a Wexio flow by hitting a unique URL.

Inbound webhook detail page

Request Flow

External System                        Wexio
      │                                   │
      │  POST /webhooks/in/{connectionId} │
      │  Auth header (mode-specific)      │
      │  Body: { ...JSON payload... }     │
      │ ────────────────────────────────► │
      │                                   │
      │                         1. Verify authentication
      │                         2. Check payload size (≤100 KB)
      │                         3. Parse JSON
      │                         4. (Optional) Capture schema
      │                         5. Resolve the target contact
      │                         6. Find matching flow triggers
      │                         7. Start each matching flow
      │                                   │
      │  202 Accepted                     │
      │ ◄──────────────────────────────── │

Creating an Inbound Connection

From Settings → Webhooks & API, tap New connection and choose Inbound.

Create inbound connection modal

Give the connection a name that matches what's on the other side (e.g. "Stripe Payments", "n8n Lead Pipeline", "Backend Orders API"). Wexio generates:

  • A unique URL: https://api.wexio.io/webhooks/in/{connectionId}
  • A signing secret (for Shared Secret mode)

The signing secret is shown once on creation. Copy it to your partner system immediately — if you lose it, use Rotate secret to generate a new one.

Authentication Modes

Pick an auth mode that matches what the partner system uses. Wexio supports seven modes covering 30+ SaaS providers.

Authentication mode picker
ModeWhen to useSecret format
Shared Secret (default)Any system that lets you configure a custom request header — n8n, Zapier, Make, IFTTT, your own backendRandom string generated by Wexio
StripeStripe webhooks (Payments, Billing, Connect)whsec_… from Stripe dashboard
SlackSlack Events API, slash commands, interactive components"Signing Secret" from the app's Basic Information page
SvixAny Svix-powered SaaS — Clerk, Resend, Orb, Knock, Humanloop, Dub, Beamwhsec_… from the provider's dashboard
PaddlePaddle Billing v2 notificationspdl_ntfset_… from Paddle's Notifications
RevolutRevolut Business webhooksShown once on webhook creation in Revolut
Generic HMAC-SHA256GitHub, Shopify, Mailgun, Paystack, Razorpay, PagerDuty, Zendesk, HubSpot v3, Linear, Vercel, Netlify, any custom HMACProvider-specific; you configure the header name and encoding

Shared Secret (default)

Send the secret as the x-webhook-secret request header on every POST:

POST /webhooks/in/{connectionId}
x-webhook-secret: <your-secret>
Content-Type: application/json

{ ...payload... }

Wexio bcrypt-compares the header against the stored hash. There's no per-body signature — suitable when HTTPS is your only transport guarantee, or when replays are mitigated with X-Idempotency-Key.

Provider modes (Stripe, Slack, Svix, Paddle, Revolut)

Pick the mode, paste the signing secret from the provider's dashboard, and Wexio handles everything else — header parsing, HMAC computation, timestamp tolerance (±5 minutes), timing-safe comparison. The original signing key rotations from each provider are supported (multiple v1=… or h1=… values in one header).

Stripe mode signing secret

Generic HMAC-SHA256

For any provider that signs the raw body with HMAC-SHA256:

Generic HMAC configuration
FieldDescription
Signing secretThe provider's secret
Signature header nameWhere the signature lands (e.g. X-Hub-Signature-256 for GitHub, X-Shopify-Hmac-Sha256 for Shopify)
EncodingHex (most providers) or Base64 (Shopify, HubSpot v3, Zendesk)
Header prefixOptional string to strip before comparing (GitHub prefixes with sha256=)

One-click presets prefill these fields for GitHub, Shopify, Mailgun, Paystack, Razorpay, PagerDuty, Zendesk, HubSpot v3, Linear, Vercel, Netlify, and Bitbucket Cloud.

Not yet supported natively

ProviderSchemeRecommendation
PayPal v2RSA + JWKSProxy through n8n/Zapier/Make until native support lands
WiseRSA, rotating keysSame
Paddle ClassicRSASame
DiscordEd25519Same
SendGrid Signed EventsECDSAUse the unsigned webhook with Shared Secret, or proxy
Apple IAP / Google PlayJWSProxy for now
Intercom (legacy SHA-1)SHA-1Use Intercom's newer SHA-256 webhooks, or proxy

See Webhooks → Integrations for the full support matrix and per-provider setup steps.

Contact Resolution

How Wexio maps an incoming payload to a contact in your organisation.

Contact resolution settings
FieldDescription
Connection nameDisplay name — only affects the UI
Identifier typeOne of Channel user ID, Phone number, Email, Chat ID
JSON path to identifierWhere to read the identifier from the payload — JSONPath syntax, e.g. $.customer.email
Channel integrationRequired when identifier type is Channel user ID — scopes the lookup to a specific Telegram bot / WhatsApp number / Instagram page

Examples:

PayloadIdentifier typeJSON pathChannel integration
Stripe CustomerEmail$.data.object.email
Telegram user eventChannel user ID$.user.idyour Telegram bot
WhatsApp callbackPhone number$.contacts[0].wa_idyour WhatsApp number
Internal systemChat ID$.wexio_chat_id

If the path returns nothing, or the identifier doesn't match any People row, the log is tagged IDENTIFIER_NOT_FOUND and no flow runs.

Capture Schema

To make payload fields available as flow variables, Wexio learns the shape from a sample payload. This is also the step where you test that the partner is hitting the URL correctly.

Capture schema button

How it works:

  1. Tap Capture schema on the connection detail page. A 5-minute tunnel opens.
  2. Trigger a real event on the partner side (or use Inject payload to paste a sample JSON manually).
  3. Wexio infers the schema from that single payload — every scalar leaf becomes a variable — replaces the current schema (no merge), bumps the version, and closes the tunnel.
  4. The payload used for capture is not dispatched to flows — capture is a separate path so you can experiment safely.
Payload schema with learned fields

The Payload Schema panel shows every learned field, its inferred type, and whether it's required. Use these fields as {{webhook.<path>}} variables in any flow bound to this connection.

Schema is advisory — Wexio never rejects a payload because a field is missing. The schema only drives the variable picker. Missing fields render as null at runtime.

Inject a sample payload

If the partner is hard to trigger on demand, use Inject payload to paste JSON directly. Wexio treats it exactly like a live capture.

Inject payload dialog

Bind the Connection to a Flow

Open any flow, add a Webhook Received trigger, and pick this connection. The flow will run every time a matching payload is received and a contact resolves successfully.

One connection can power many flows — the connection owns the auth and mapping; each flow chooses what to do with the payload.

Request Headers Wexio Honours

HeaderPurpose
Content-Type: application/jsonRequired
x-webhook-secretRequired when auth mode is Shared Secret
Stripe-Signature / X-Slack-Signature / svix-signature / Paddle-Signature / Revolut-SignatureRead automatically by the matching provider mode
x-request-idOptional correlation ID; echoed in the history log
X-Idempotency-KeyOptional dedup key — replays within the retention cache return the cached response

Outcomes & HTTP Responses

Every request lands a row in the history log with one of these outcomes:

OutcomeStatusMeaning
ACCEPTED202Authenticated, parsed, at least one flow dispatched
SAMPLE_CAPTURED202Absorbed by an open capture tunnel; no flow ran
UNAUTHORIZED401Signature / secret mismatch
INVALID_JSON400Body was not valid JSON
PAYLOAD_TOO_LARGE413Body exceeded 100 KB
IDENTIFIER_NOT_FOUND422No contact resolved from the payload
TRIGGER_NOT_FOUND404Connection is paused, missing, or has no bound flow triggers
ERROR500Unclassified failure — file a ticket if this appears

Rotate the Signing Secret

Settings → Webhooks → your connection → Rotate secret. A new secret is generated and shown once. The old one stops working immediately — update the partner configuration before rotating, or accept a short window of 401s.

Stripe, Slack, Paddle, and several other providers support dual-signing during rotation — use that window on their side and paste the new secret to Wexio last.

Pause & Resume

From the connection detail page, tap Pause to stop accepting requests without deleting the connection. Paused connections return 404 TRIGGER_NOT_FOUND to every incoming request. Resume at any time.

Rules and Caveats

  • Payload limit: 100 KB. Larger payloads are rejected with 413.
  • Credentials are never returned to clients — the API doesn't expose the stored signing secret.
  • Signature headers are not loggedx-webhook-secret, Stripe-Signature, Authorization, and similar are scrubbed from the history log on the server side before write.
  • Retention: 30 days of history per connection, including auth failures for self-diagnosis.

On this page