Skip to main content
When integrating with Rye’s Universal Checkout API, you might need your backend to perform actions in response to changes in Rye’s system. For example, notifying a customer when their order completes, or handling a failed offer retrieval. While polling Rye’s APIs is possible, it can be inefficient and increases system load. To support event-driven architectures, Rye provides webhook functionality. Webhooks enable you to receive real-time updates when checkout intent state transitions occur.

Use Cases

  • Order Fulfillment: Trigger downstream processes when a checkout intent completes.
  • Error Handling: React immediately when an offer retrieval or order placement fails.
  • Customer Notifications: Send real-time updates to buyers about their order status.

Setting Up Webhooks

1

Navigate to Account Settings

Go to the Rye Console and find the Webhooks section on the accounts tab.
2

Set Up an Endpoint

Enter your publicly accessible endpoint URL. It must be reachable over the internet and capable of handling HTTP POST requests.
3

URL Verification Handshake

After saving your endpoint, Rye sends a verification challenge. Your endpoint must respond with the ID of the webhook endpoint, found under source.id:Verification Request:
{
  "id": "evt_e56b5b2b40d4491fbab2ecb96bc911a7",
  "object": "event",
  "type": "webhook_endpoint.verification_challenge",
  "createdAt": "2026-03-18T02:30:00.000Z",
  "source": {
    "type": "webhook_endpoint",
    "id": "we_dc275d547a374a73aceca0e4e1a045d2"
  }
}
Expected Response:
{
  "challenge": "we_dc275d547a374a73aceca0e4e1a045d2"
}
4

Implement Signature Verification

Each webhook includes a cryptographic signature to verify its authenticity. See the verification section below.

Payload Format

Most webhook payloads are thin events — they contain the resource ID and the event type, not the full resource. To get the complete state, call the API after receiving the event. Example Payload:
{
  "id": "evt_ci_abc123def456_completed",
  "object": "event",
  "type": "checkout_intent.completed",
  "createdAt": "2026-03-18T02:30:00.000Z",
  "source": {
    "type": "checkout_intent",
    "id": "ci_abc123def456"
  }
}
After receiving this event, fetch the full checkout intent:
curl -X GET https://api.rye.com/api/v1/checkout-intents/ci_abc123def456 \
  -H "Authorization: Bearer YOUR_API_KEY"
Thin events keep webhook payloads small and stable. The API always returns the most current state of the resource, so fetching after notification ensures you have the latest data.
Some events (e.g. product.updated) also include a data field carrying a snapshot of the resource at the time the event was emitted. This is a convenience for consumers that don’t need strict consistency, but it does not replace fetching. The snapshot can be stale if events are delivered out of order or the underlying resource changes between emission and delivery. For authoritative state, still call the corresponding lookup endpoint using source.id — the same pattern as with thin events.

Webhook Headers

Every webhook request includes the following headers:
HeaderDescription
x-rye-signatureHMAC-SHA256 signature for verifying authenticity.
x-rye-event-idUnique event ID.
x-rye-timestampUnix timestamp (seconds) of the event delivery.
x-rye-topicThe event topic (e.g., checkout_intent.completed).
CORS Configuration: Ensure your backend allows Rye’s custom headers (x-rye-signature, x-rye-event-id, x-rye-timestamp, x-rye-topic) in your CORS policy.

Verifying Webhook Signatures

Each webhook is signed using HMAC-SHA256 with your HMAC secret key, available in the Rye Console under the Webhooks section.

Signature Format

The x-rye-signature header contains a hex-encoded HMAC-SHA256 signature of the raw request body:
v0=5bc05741c3dcbfe8187b980fe9bf1fe22c1fbd3aa56b9d78387667c04e8d27c3

Verification Steps

SDKs contain an event.unwrap(...) helper function which can be used to verify a signature and parse a webhook payload. If you are using a language we do not have an SDK for, you can manually verify webhook signatures by following the instructions below:
  1. Extract the signature value from the x-rye-signature header (strip the v0= prefix).
  2. Compute HMAC-SHA256 of the raw request body using your secret key.
  3. Hex-encode the result and compare with the extracted signature using a constant-time comparison.
  4. Reject the request if they do not match.

Code Examples

import { CheckoutIntents } from "checkout-intents";
import express from "express";

const app = express();
const client = new CheckoutIntents();

const WEBHOOK_SECRET = process.env.RYE_HMAC_SECRET_KEY!;

app.use(express.raw({ type: "application/json" }));

app.post("/webhook", (req, res) => {
  const signatureHeader = req.headers["x-rye-signature"] as string;
  if (!signatureHeader) {
    return res.status(401).send("Unauthorized");
  }

  const event = client.events.unwrap(
    req.body.toString(),
    signatureHeader,
    WEBHOOK_SECRET,
  );

  // Handle the challenge during setup
  if (event.type === "webhook_endpoint.verification_challenge") {
    return res.json({ challenge: event.source.id });
  }

  // Process the webhook event
  const topic = req.headers["x-rye-topic"];
  console.log(`Received event: ${topic}`);
  res.status(200).send("OK");
});

app.listen(3000, () => {
  console.log("Webhook server listening on port 3000");
});

Best Practices

Process Webhooks Asynchronously

Webhook requests must respond within 5 seconds. Verify the signature, acknowledge receipt, and process the event in the background.

Handle Out-of-Order Delivery

Webhooks may arrive out of order. Use the createdAt field to determine event ordering, or simply fetch the latest state from the API — since events are thin notifications, the API always returns the most current data.

Deduplicate Events

Each event has a deterministic id (e.g., evt_ci_abc123def456_completed). Store processed event IDs to skip duplicates:
  1. Extract the event id from the payload.
  2. Check if you’ve already processed this id.
  3. If yes, return 200 without reprocessing.
  4. If no, process the event and store the id.

Fetch Fresh State

Since webhook payloads are thin, always call the API to get the full checkout intent after receiving an event. This ensures you have the most up-to-date data, regardless of delivery order.