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 request containing a challenge parameter. Your endpoint must respond with the exact challenge value.Verification Request:
{
  "id": "e56b5b2b-40d4-491f-bab2-ecb96bc911a7",
  "developerId": "your_developer_id",
  "createdAt": "2026-03-18T02:30:00.000Z",
  "type": "WEBHOOK_URL_VERIFICATION",
  "data": {
    "challenge": "8eaacf92948128c760d0a25af59231693b2f930fcf8bad61d780fa2796d923bec5bc64e6da55f17196b10a10850f0fa2"
  }
}
Expected Response:
{
  "challenge": "8eaacf92948128c760d0a25af59231693b2f930fcf8bad61d780fa2796d923bec5bc64e6da55f17196b10a10850f0fa2"
}
4

Implement Signature Verification

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

Events

Webhooks are sent when a checkout intent transitions between states. See the Checkout Intent Lifecycle for the full state machine.
EventDescriptionState Transition
checkout_intent.offer_retrievedAn offer is ready with pricing and availability details.retrieving_offerawaiting_confirmation
checkout_intent.offer_failedOffer retrieval failed (e.g., unsupported merchant, product unavailable).retrieving_offerfailed
checkout_intent.completedThe order was successfully placed and confirmed.placing_ordercompleted
checkout_intent.order_failedOrder placement failed after confirmation (e.g., out of stock, payment declined).placing_orderfailed

Payload Format

Webhook payloads are thin events — they contain the checkout intent ID and the event type, not the full resource. To get the complete checkout intent 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 checkout intent, so fetching after notification ensures you have the latest data.

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

  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 crypto from "crypto";
import express from "express";
const app = express();
const WEBHOOK_SECRET = process.env.RYE_HMAC_SECRET_KEY!;

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

function verifySignature(body: Buffer, signatureHeader: string): boolean {
  if (!signatureHeader.startsWith("v0=")) return false;
  const expectedSignature = signatureHeader.slice(3);

  const hmac = crypto.createHmac("sha256", WEBHOOK_SECRET);
  hmac.update(body);
  const computedSignature = hmac.digest("hex");

  const computedBuf = Buffer.from(computedSignature);
  const expectedBuf = Buffer.from(expectedSignature);
  if (computedBuf.length !== expectedBuf.length) return false;
  return crypto.timingSafeEqual(computedBuf, expectedBuf);
}

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

  const event = JSON.parse(req.body.toString());

  // Handle the challenge during setup
  if (event.type === "WEBHOOK_URL_VERIFICATION" && event.data?.challenge) {
    return res.json({ challenge: event.data.challenge });
  }

  // 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.