Skip to content

Webhooks

Track payments server-side as they progress

Glide can publish webhooks to your server as a session progresses — from creation to final settlement. Events fire for every session regardless of how it was created: through the embedded widgets or the headless SDK.

Webhooks are the recommended way to track money movement in production: unlike client-side polling, they keep working if the user closes the tab, and they let your backend be the source of truth for order fulfillment and balance updates.

Setup

Head over to the Webhooks page in the Glide Dashboard and add a webhook pointing to an HTTPS endpoint on your server.

The event

Glide sends a SESSION_UPDATE event every time a session changes. The payload is the full session object — the same shape returned by getSessionById:

{
  "webhookId": "d5fa3629-9187-4ca6-9f2b-d70f7816ce4b",
  "entityId": "a44ac1a5-5b73-4cbe-83a1-7e937189d470",
  "type": "SESSION_UPDATE",
  "payload": {
    "sessionId": "a44ac1a5-5b73-4cbe-83a1-7e937189d470",
    "paymentStatus": "paid",
    "sponsoredTransactionStatus": "success",
    "sponsoredTransactionHash": "0x36145cfe...",
    "metadata": "{\"orderId\":\"order-12345\"}"
    // ... the full session object
  }
}
  • webhookId — unique ID for this delivery. Use it to deduplicate.
  • entityId — the ID of the entity the event is about (the session ID for SESSION_UPDATE).
  • payload — the full session object. See Sessions for the field reference and status lifecycles.

Verify the signature

Every delivery includes an X-Glide-Signature header: the hex-encoded HMAC-SHA256 of the raw request body, keyed with the Webhook Signing Secret from the Glide Dashboard. Always verify it before processing the payload.

server.ts
import crypto from "node:crypto";
import express from "express";
 
const app = express();
 
app.post(
  "/glide-webhook",
  // Verify against the *raw* body — parsing and re-serializing
  // JSON can change the bytes and break the signature
  express.raw({ type: "application/json" }),
  (req, res) => {
    const signature = req.header("X-Glide-Signature");
 
    const expected = crypto
      .createHmac("sha256", process.env.GLIDE_WEBHOOK_SECRET!)
      .update(req.body)
      .digest("hex");
 
    if (
      !signature ||
      signature.length !== expected.length ||
      !crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))
    ) {
      return res.status(401).send("Invalid signature");
    }
 
    const event = JSON.parse(req.body.toString());
 
    if (event.type === "SESSION_UPDATE") {
      const session = event.payload;
      // Handle the update, e.g. fulfill the order when settled
    }
 
    res.status(200).send("ok");
  },
);

Handling events reliably

  • Treat delivery as at-least-once. The same update can arrive more than once — deduplicate by webhookId, and make your handlers idempotent (fulfilling the same order twice should be a no-op).
  • Don't rely on ordering. Process events based on the session state in the payload, not the order deliveries arrive in.
  • Act on the settled signal. paymentStatus: "paid" together with sponsoredTransactionStatus: "success" means the money has fully arrived — that's the signal to fulfill an order or credit a balance.
  • Correlate with your own records. Set the metadata field when creating the session (e.g., your order ID) and read it back from the payload, or key off sessionId.
  • Respond quickly. Return a 200 as soon as the event is persisted, and do heavy work asynchronously.

Webhooks vs. polling

Client-side, waitForSession is often all you need — it polls until settlement and works great for showing live status in your UI. Use webhooks whenever the outcome matters to your backend: order fulfillment, balance crediting, or any flow where the user may leave before settlement completes. The two complement each other — poll for UI feedback, webhook for the source of truth.