Webhooks

Fluense sends signed webhooks for checkout and charge events. Configure one URL per organization.

Configure

# Set or replace the URL (owner/admin). The signing secret is generated once and reused.
curl -s -X PUT https://api.fluense.social/orgs/$ORG/webhook \
  -H "authorization: Bearer $SESSION" \
  -H 'content-type: application/json' \
  -d '{"url":"https://example.com/fluense/webhook"}'

# Inspect
curl -s https://api.fluense.social/orgs/$ORG/webhook -H "authorization: Bearer $SESSION"

# Clear
curl -s -X DELETE https://api.fluense.social/orgs/$ORG/webhook -H "authorization: Bearer $SESSION"

PUT returns the secret (whsec_…); GET returns {url, has_secret} without exposing it.

Events

Event Fires when Payload
checkout.authorized A shopper authorizes a checkout checkout_id, auth_id, total_minor, currency, consumer_id
charge.captured You capture a charge checkout_id, auth_id, mdr_fee, buyer_amount, deferred_buyer_amount, recommender_amount
charge.voided An authorization is voided auth_id
charge.returned A refund is processed auth_id, return_id, refund, buyer_cut, rec_cut, award_adjusted

Delivery

Every delivery carries:

Header Value
x-fluense-event Event name, e.g. charge.captured
x-fluense-delivery Unique delivery id — dedupe on this across retries
x-fluense-signature sha256=<hex HMAC-SHA256 of the raw body with your secret>

Any 2xx marks the delivery delivered. Failures retry with backoff: 60 s, 5 min, 15 min, 1 h, 6 h, then the delivery is marked FAILED (5 attempts).

Verify a signature

// Node.js
import crypto from 'node:crypto'

const expected = 'sha256=' + crypto
  .createHmac('sha256', process.env.FLUENSE_WEBHOOK_SECRET)
  .update(rawBody) // the exact bytes received, before JSON parsing
  .digest('hex')

if (crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature))) {
  // trusted
}
# Python
import hashlib, hmac

expected = 'sha256=' + hmac.new(
    secret.encode(), raw_body, hashlib.sha256
).hexdigest()

if hmac.compare_digest(expected, signature):
    pass  # trusted

Always verify against the raw request body; re-serializing JSON changes the bytes.