API: Webhooks
Overview
Endpoints:
POST /v1/webhooks/:providerPOST /v1/t/:tenantSlug/webhooks/:provider
They normalize provider payloads, validate signatures, dedupe events, and forward to your callback URL with automatic retries.
Request path
:provider—stripe,generic,shopify,github;paypalis controlled-rollout;braintreeis reserved until its official verifier is enabled.- Optional
:tenantSlugfor 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
- Authenticate – via API key (
Authorization: Bearer ck_...) or tenant slug route. - Validate – provider adapter verifies the signature header using the secret configured in your dashboard. Invalid signatures return
400. - Deduplicate – events are deduped by tenant + provider + eventId. Duplicates return
200withcached: true. - Log – event metadata is stored so you can inspect each event in the dashboard.
- 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.
Data handling
Syllecta stores operational metadata for observability and may store raw payload/debug data within the configured retention window for replay and troubleshooting. Routine dashboard views use redacted payloads.
Avoid sending card data, passwords, access tokens, session cookies, long-lived secrets, or unnecessary personal data in webhook payloads. See Security and data protection before connecting real customer traffic.
Forwarded payload
Syllecta forwards a normalized JSON payload to your callback URL:
{ "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
{ "ok": true }
200 OK (dedup hit)
{ "ok": true, "cached": true }
202 Accepted (queued)
{ "ok": true, "queued": true }
400 Bad Request (invalid signature)
{ "error": "invalid signature" }
400 Bad Request (missing event id)
{ "error": "missing event id" }
403 Forbidden
{ "message": "tenant not allowed" }
Providers
| Provider | Verification status | Signature header | Notes |
|---|---|---|---|
| stripe | Supported | Stripe-Signature | Raw-body HMAC, constant-time compare, timestamp max-age guard |
| generic | Supported | X-Syllecta-Signature | Format t=timestamp,v1=hex; raw-body HMAC with max-age guard |
| shopify | Supported | X-Shopify-Hmac-Sha256 | Raw-body base64 HMAC-SHA256; dedupe uses Shopify webhook id when present |
| github | Supported | X-Hub-Signature-256 | sha256=... raw-body HMAC; dedupe uses GitHub delivery id when present |
| paypal | Controlled rollout | PayPal transmission headers | Requires transmission id/time/signature plus auth algo and cert URL; enable per tenant after verification review |
| braintree | Reserved | bt_signature + bt_payload | Not production-enabled yet; not treated as PayPal traffic |