Skip to content

Webhooks

Fangate exposes two webhook surfaces:

  1. Inbound webhooks — server-to-server callbacks from payment and verification providers (Fangate receives events).
  2. Outbound webhooks — creator-registered HTTPS endpoints where Fangate pushes payment events to third-party integrators.

Inbound webhooks (providers)

These are not creator-authenticated API endpoints. They are meant for payment providers and verification providers.

Payment provider webhooks

Confirmed live web routes:

EndpointMethodPurpose
/pwh/paypalPOSTPayPal payment callbacks
/pwh/stripePOSTStripe payment callbacks
/pwh/epochPOSTEpoch payment callbacks
/dataplus/epochPOSTEpoch DataPlus callbacks

Payment provider notes

  • these endpoints are part of the web route surface, not /api
  • they are server-to-server integration points
  • frontend and partner clients should not call them directly

Verification webhooks

Confirmed live routes:

EndpointMethodPurpose
/api/yoti/webhookPOSTBuyer age-verification status callback
/veriff/eventsPOSTVeriff event callback
/veriff/decisionPOSTVeriff decision callback
/veriff/autoPOSTVeriff automated callback

Verification notes

  • /api/yoti/webhook is part of the API route group
  • Veriff webhook routes are part of the web route surface
  • public API consumers should treat these as provider-owned callbacks, not interactive client endpoints

Inbound security expectations

Integrators operating inbound webhook infrastructure should assume:

  • HTTPS only
  • provider-side signature or authenticity checks where available
  • idempotent processing on duplicate callbacks
  • quick acknowledgement with backend processing deferred where needed

Outbound webhooks (integrators)

Creators and integrators register HTTPS endpoints to receive real-time payment notifications instead of polling transaction APIs.

  • Auth: Creator Sanctum bearer token or API key with api-key:webhooks.manage (see API Keys).
  • Delivery: Async queue (webhooks queue); does not block payment processing.
  • Retries: Up to 3 delivery attempts with backoff 1 min → 5 min → 30 min between failures.
  • HTTPS only at registration time.

Supported events (v1)

EventTrigger
payment.successfulPurchase completed and confirmed by PSP (payment_status = success)
payment.failedPayment rejected, declined, or cancelled (failed / cancelled)
payment.pendingPayment initiated but not yet confirmed (e.g. Epoch, PayPal)

content.approved is planned for a later release and is not emitted in v1.

Registration API

MethodPathDescription
POST/api/webhooksRegister endpoint URL, event subscriptions, optional include_set_price
GET/api/webhooksList registered webhooks for the authenticated creator
PATCH/api/webhooks/{id}Update URL, events, include_set_price, or is_active
DELETE/api/webhooks/{id}Remove a webhook

POST /api/webhooks

Request body:

json
{
  "url": "https://partner.example.com/hooks/fangate",
  "events": ["payment.successful", "payment.failed", "payment.pending"],
  "include_set_price": true
}
FieldRequiredNotes
urlYesMust be https://
eventsYesNon-empty array of supported event names
include_set_priceNoDefault false. When true, set_price is included in payment payloads (sensitive pricing data).

Response 201 includes the webhook resource plus secret (shown once). Store it immediately; it cannot be retrieved later via API.

GET /api/webhooks

Returns an array of webhook objects without the signing secret.

PATCH /api/webhooks/{id}

Partial update. Supported fields: url, events, include_set_price, is_active.

DELETE /api/webhooks/{id}

Removes the webhook and its delivery history.

Delivery payload

Each POST to your URL uses Content-Type: application/json.

json
{
  "event": "payment.successful",
  "timestamp": "2026-05-19T10:42:00Z",
  "data": {
    "transaction_id": "txn_123",
    "buyer_email": "buyer@example.com",
    "seller_earning": 8.50,
    "currency": "EUR",
    "product_id": 42,
    "media_ids": ["m_101", "m_102"],
    "set_price": 10.00
  }
}
FieldAlways includedNotes
eventYesEvent type string
timestampYesISO 8601 UTC
data.transaction_idYesFangate transaction id (txn_{id})
data.buyer_emailYesBuyer email on the transaction
data.seller_earningYesNet amount credited to the creator (major units, e.g. 8.50)
data.currencyYesISO 4217 currency code (uppercase)
data.product_idYesPurchased product id
data.media_idsYesAlways an array of media ids (m_{id}), even for a single file
data.set_priceNoOnly when include_set_price: true on the webhook

media_ids is always an array, matching the live n:m product_media pivot between products and library media (see Products and Media Library).

Delivery headers

HeaderDescription
X-Fangate-SignatureHMAC-SHA256 of the raw JSON body using your webhook secret, format sha256={hex}
X-Fangate-Delivery-IdUUID for this delivery attempt (idempotency key)
Content-Typeapplication/json

Verifying signatures (example)

php
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_FANGATE_SIGNATURE'] ?? '';
$secret = getenv('FANGATE_WEBHOOK_SECRET');

$expected = 'sha256=' . hash_hmac('sha256', $payload, $secret);

if (!hash_equals($expected, $signature)) {
    http_response_code(401);
    exit('Invalid signature');
}

Respond with 2xx to acknowledge successful processing. Non-2xx responses trigger retries per the backoff schedule.

Idempotency

Use X-Fangate-Delivery-Id to deduplicate deliveries. The same id is used across retry attempts for one logical delivery record.

Out of scope (v1)

  • Creator dashboard UI for webhook management (API only)
  • Delivery log API for integrators
  • More than 3 delivery attempts
  • Filtering events by product_id or media_id
  • content.approved events

Fangate backend developer documentation