API: Webhooks

Overview

Endpoints:

  • POST /v1/webhooks/:provider
  • POST /v1/t/:tenantSlug/webhooks/:provider

They normalize provider payloads, validate signatures, dedupe events, and forward to your callback URL with automatic retries.

Request path

  • :providerstripe, generic, shopify, paypal, braintree, github.
  • Optional :tenantSlug for slug-based delivery (no API key required). Slug is resolved via your tenant configuration.

Headers vary per provider.

Sample: Stripe

POST /v1/webhooks/stripe
Stripe-Signature: t=...,v1=hex
Content-Type: application/json

Sample: Generic HMAC

POST /v1/t/acme-payments/webhooks/generic
X-Syllecta-Signature: t=1692059,v1=cafebabe123...
Content-Type: application/json

Signature computed as HMAC_SHA256(secret, "${timestamp}.${rawBody}").

Flow

  1. Authenticate – via API key (Authorization: Bearer ck_...) or tenant slug route.
  2. Validate – provider adapter verifies the signature header using the secret configured in your dashboard. Invalid signatures return 400.
  3. Deduplicate – events are deduped by tenant + provider + eventId. Duplicates return 200 with cached: true.
  4. Log – event metadata is stored so you can inspect each event in the dashboard.
  5. Forward – Syllecta POSTs the normalized payload to your callback URL. Final status (processed/delivery_failed) is shown in the dashboard.

In rare cases the API may respond with 202 and queued: true when processing is delayed.

Forwarded payload

Syllecta forwards a normalized JSON payload to your callback URL:

json
{
  "id": "evt_...",
  "provider": "stripe",
  "providerRawType": "charge.dispute.updated",
  "type": "chargeback.under_review",
  "tenantId": "...",
  "occurredAt": "2026-02-23T02:59:56.000Z",
  "receivedAt": "2026-02-23T02:59:56.000Z",
  "payload": { ... },
  "headers": { ... }
}

Forwarded requests are sent as JSON with Content-Type: application/json.

Response structure

200 OK

json
{
  "ok": true
}

200 OK (dedup hit)

json
{
  "ok": true,
  "cached": true
}

202 Accepted (queued)

json
{
  "ok": true,
  "queued": true
}

400 Bad Request (invalid signature)

json
{
  "error": "invalid signature"
}

400 Bad Request (missing event id)

json
{
  "error": "missing event id"
}

403 Forbidden

json
{
  "message": "tenant not allowed"
}

Providers

ProviderSignature headerNotes
stripeStripe-SignatureHMAC via Stripe secret per tenant provider
genericX-Syllecta-SignatureFormat t=timestamp,v1=hex
shopifyX-Shopify-Hmac-Sha256base64 HMAC-SHA256
paypalTransmission headersVerified via PayPal webhook ID
githubX-Hub-Signature-256sha256=... format

Related guides