Webhooks

Receive signed order.completed events on your server. This is the only supported way to fulfill orders programmatically.

Setup

  1. Open Developer in your dashboard.
  2. Add your HTTPS endpoint URL.
  3. Save the signing secret when shown — it is only displayed once.
  4. Use "Send test" to confirm your server receives events.
  5. Implement signature verification before fulfilling orders.

Event: order.completed

Sent when a buyer's payment succeeds. Flint retries up to 3 times if your endpoint does not return a 2xx response.

Headers

  • Flint-Signature — HMAC signature (verify before trusting)
  • Flint-Event order.completed
  • Flint-Delivery-Id — unique event id
  • Flint-Webhook-Test true on test deliveries from the dashboard

Payload

order.completed

{
  "id": "evt_...",
  "type": "order.completed",
  "created_at": "2026-06-30T12:00:00.000Z",
  "data": {
    "order": {
      "id": "order-uuid",
      "product_id": "product-uuid",
      "amount": 1000,
      "currency": "usd",
      "status": "completed",
      "customer_email": "[email protected]",
      "payment_method": "crypto",
      "product_name": "My product",
      "platform_fee_cents": 50,
      "seller_net_cents": 950,
      "payment_reference_id": "...",
      "completed_at": "2026-06-30T12:00:00.000Z"
    }
  }
}

Verify signatures

Signature format: t=timestamp,v1=hex_hmac. Compute HMAC-SHA256 of {timestamp}.{raw_body} using your signing secret.

Node.js

import crypto from "crypto";

function verifyFlintWebhook(rawBody, signatureHeader, secret) {
  const parts = Object.fromEntries(
    signatureHeader.split(",").map((p) => p.split("="))
  );
  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${parts.t}.${rawBody}`)
    .digest("hex");
  return expected === parts.v1;
}

Do not use success_url for fulfillment

The buyer redirect is for UX only. Always deliver products from verified webhook events.