Webhooks v1

Glyde Webhook API

Subscribe to real-time events across your restaurant operations. Receive instant HTTP callbacks when data changes — from check updates and payment captures to menu edits and shift changes.

🔑 Authentication

All webhook management endpoints require a Glyde API key passed via the Authorization header. Generate keys from the Glyde Dashboard → Developer → API Keys.

Request Header
Authorization: Bearer glyde_sk_live_a1b2c3d4e5f6...

Managing Subscriptions

Create, list, update, and delete webhook subscriptions. Each subscription targets a single URL and can listen to one or more event types.

Create a Subscription

POST /v1/webhooks
{
  "url": "https://yourapp.com/glyde/webhooks",
  "events": [
    "restaurant.updated",
    "check.updated",
    "check.closed",
    "payment.completed"
  ],
  "restaurant_ids": ["rst_8f3k..."],  // optional — omit for all locations
  "description": "Production POS integration",
  "metadata": { "team": "integrations" }
}
ParameterTypeDescription
url required string HTTPS endpoint that will receive POST requests. Must return 2xx within 15 seconds.
events required string[] Array of event types to subscribe to. Use "*" for all events.
restaurant_ids string[] Scope to specific restaurant locations. Omit to receive events for all locations in your organization.
description string Human-readable label for this subscription.
metadata object Arbitrary key-value pairs stored with the subscription.
Response — 201 Created
{
  "id": "whk_9x4mT...",
  "url": "https://yourapp.com/glyde/webhooks",
  "events": ["restaurant.updated", "check.updated", ...],
  "secret": "whsec_a1b2c3d4e5f6g7h8...",
  "status": "active",
  "created_at": "2026-02-17T14:30:00Z"
}
The secret is only returned once at creation. Store it securely — you'll need it to verify webhook signatures.

List Subscriptions

GET /v1/webhooks
// Returns an array of all active webhook subscriptions

Update a Subscription

PATCH /v1/webhooks/{webhook_id}
{
  "events": ["check.*", "payment.*"],
  "status": "paused"
}

Delete a Subscription

DELETE /v1/webhooks/{webhook_id}
// Returns 204 No Content

📦 Payload Format

Every webhook delivery is an HTTP POST with a JSON body following a consistent envelope structure.

Webhook Payload Envelope
{
  "id": "evt_3kLm9...",
  "type": "check.updated",
  "api_version": "2026-02-01",
  "created_at": "2026-02-17T14:32:10.482Z",
  "restaurant_id": "rst_8f3k...",
  "data": {
    // Event-specific payload — see event reference below
  },
  "previous_attributes": {
    // For *.updated events — contains the changed fields' prior values
  }
}

Delivery Headers

Headers sent with every webhook POST
Content-Type: application/json
Glyde-Webhook-Id: evt_3kLm9...
Glyde-Webhook-Timestamp: 1708181530
Glyde-Webhook-Signature: v1=5a3c1e9b...

🔄 Retries & Reliability

Glyde expects your endpoint to return a 2xx status within 15 seconds. If your endpoint fails or times out, we'll retry with exponential backoff.

AttemptDelayMax Elapsed
1st retry30 seconds~30s
2nd retry2 minutes~2.5m
3rd retry15 minutes~17m
4th retry1 hour~1h 17m
5th retry4 hours~5h 17m
After 5 failed attempts, the event is marked as failed and the subscription's status changes to degraded. Consecutive failures over 72 hours will automatically pause the subscription.

🛡 Verifying Signatures

Every webhook includes an HMAC-SHA256 signature computed from the payload body and your subscription secret. Always verify signatures to ensure authenticity.

Node.js — Signature Verification
import crypto from 'crypto';

function verifyGlydeSignature(payload, headers, secret) {
  const timestamp = headers['glyde-webhook-timestamp'];
  const signature = headers['glyde-webhook-signature'];

  // Reject timestamps older than 5 minutes to prevent replay attacks
  const age = Math.floor(Date.now() / 1000) - parseInt(timestamp);
  if (age > 300) throw new Error('Timestamp too old');

  const signed = `${timestamp}.${payload}`;
  const expected = 'v1=' + crypto
    .createHmac('sha256', secret)
    .update(signed)
    .digest('hex');

  if (!crypto.timingSafeEqual(
    Buffer.from(signature), Buffer.from(expected)
  )) throw new Error('Invalid signature');

  return true;
}

Event Reference

All available event types organized by domain. Use wildcard patterns like check.* to subscribe to all events in a category.

🏪 Restaurant Events

Fired when restaurant-level information changes — profile details, operating hours, service areas, and configuration.

restaurant.updated
Restaurant profile information was modified — name, phone, address, tax ID, or any store-level config.
Core
restaurant.hours.updated
Regular operating hours, holiday hours, or special event hours were changed for a location.
Core
restaurant.service_area.updated
Delivery zones, pickup boundaries, or service areas were created, updated, or removed.
Core
restaurant.opened
A location has opened for business (start of business day or returned from temporary closure).
Core
restaurant.closed
A location has closed for the day, either by schedule or manual override.
Core
restaurant.tax_config.updated
Tax rates, tax groups, or tax-exempt settings were modified.
Core

Example: restaurant.updated

Payload
{
  "id": "evt_r3jk9...",
  "type": "restaurant.updated",
  "created_at": "2026-02-17T10:15:00Z",
  "restaurant_id": "rst_8f3k...",
  "data": {
    "id": "rst_8f3k...",
    "name": "TGI Fridays — DFW Terminal B",
    "phone": "+12145551234",
    "address": {
      "line_1": "2400 Aviation Dr, Terminal B",
      "city": "DFW Airport",
      "state": "TX",
      "postal_code": "75261"
    },
    "timezone": "America/Chicago"
  },
  "previous_attributes": {
    "phone": "+12145559876"
  }
}

🧾 Check Events

Real-time updates on check lifecycle — from creation through close. Includes balance changes, item-level detail, applied discounts, and split-check operations.

check.created
A new check was opened — includes table/seat info, server assignment, guest count, and order type (dine-in, takeout, delivery).
Core
check.updated
Any modification to an open check — items added or voided, discounts applied, balance due changed, guest count adjusted, or table transferred.
Core
check.closed
Check has been fully settled and closed. Includes final totals, all applied payments, tax breakdown, tip totals, and close timestamp.
Core
check.voided
An entire check was voided by a manager, including the void reason, authorizing employee, and original check total.
Important
check.reopened
A previously closed check was reopened for adjustments — includes reopen reason and authorizing employee.
Important
check.split
A check was split into multiple child checks. Contains parent check ID and array of new child check IDs with their respective items and balances.
Core
check.transferred
A check was transferred to a different table, section, or server. Includes origin and destination info.
Core

Example: check.updated

Payload
{
  "id": "evt_ck29a...",
  "type": "check.updated",
  "created_at": "2026-02-17T19:42:08Z",
  "restaurant_id": "rst_8f3k...",
  "data": {
    "id": "chk_m2x7...",
    "check_number": 1047,
    "table": "B-12",
    "server": { "id": "emp_4v...", "name": "Jamie R." },
    "guest_count": 3,
    "order_type": "dine_in",
    "items": [
      {
        "id": "itm_x1...",
        "name": "Loaded Potato Skins",
        "quantity": 1,
        "price": 12.49,
        "modifiers": ["extra bacon", "no sour cream"],
        "status": "sent",
        "sent_at": "2026-02-17T19:42:08Z"
      }
    ],
    "subtotal": 47.96,
    "tax": 3.96,
    "discounts": 0.00,
    "total": 51.92,
    "balance_due": 51.92,
    "opened_at": "2026-02-17T19:28:00Z"
  },
  "previous_attributes": {
    "subtotal": 35.47,
    "total": 38.68,
    "balance_due": 38.68
  }
}

📋 Order Events

Track the fulfillment lifecycle of orders — from kitchen firing to completion. Ideal for KDS integrations, delivery orchestration, and real-time order tracking.

order.placed
A new order was submitted — includes full item list, special instructions, estimated prep time, and order channel (POS, online, kiosk, third-party).
Core
order.fired
An order or course was sent to the kitchen — includes fire time, station routing, and any coursing details.
Core
order.ready
Order has been marked ready for pickup or runner. Includes prep duration and fulfillment type.
Core
order.fulfilled
Order was delivered to the guest or picked up. Marks completion of the fulfillment cycle.
Core
order.cancelled
An order was cancelled before or during fulfillment — includes cancellation reason, refund status, and authorizing employee.
Important
order.item.voided
A single item within an order was voided — includes item details, void reason, waste tracking flag, and authorization.
Important
order.item.modified
An item's modifiers, quantity, or special instructions were changed after the order was placed.
Core

Error Handling

HTTP status codes returned by the webhook management API.

200 OK — Request succeeded.
201 Created — Subscription created successfully.
204 No Content — Subscription deleted.
400 Bad Request — Invalid parameters or malformed JSON.
401 Unauthorized — Missing or invalid API key.
404 Not Found — Subscription or resource doesn't exist.
409 Conflict — A subscription with this URL and event combination already exists.
422 Unprocessable — URL is not reachable or doesn't support HTTPS.
429 Too Many Requests — Rate limit exceeded.
500 Internal Server Error — Retry with backoff.

Best Practices

💡
Respond quickly. Return a 2xx immediately and process the payload asynchronously. If your handler takes longer than 15 seconds, Glyde will treat it as a failure and retry.
💡
Handle duplicates. Use the id field on every event for idempotency. The same event may be delivered more than once during retries — your handler should safely ignore duplicates.
💡
Always verify signatures. Never process a webhook payload without validating the Glyde-Webhook-Signature header. This protects against spoofed deliveries.
💡
Use previous_attributes for diffing. On *.updated events, only the changed fields appear in previous_attributes. Compare against data to see exactly what changed without fetching the full resource.
💡
Subscribe to only what you need. Use specific event types or wildcard patterns (check.*) rather than "*" to reduce noise and minimize processing overhead.

Rate Limits

Webhook management API endpoints are rate-limited per API key.

EndpointLimitWindow
POST /v1/webhooks10 requestsper minute
GET /v1/webhooks60 requestsper minute
PATCH /v1/webhooks/{id}30 requestsper minute
DELETE /v1/webhooks/{id}10 requestsper minute
Webhook deliveries are not rate-limited — you will receive events as fast as they occur. Design your endpoint to handle burst traffic during peak service hours.

🏷 Versioning

The Glyde Webhook API uses date-based versioning. Every webhook payload includes an api_version field so you can handle schema evolution gracefully.

VersionStatusChanges
2026-02-01 Current Initial release — all event types documented on this page.
When we introduce breaking changes to payload schemas, we'll publish a new API version and maintain the previous version for at least 12 months. You can pin your subscription to a specific version via the api_version parameter during creation.