Zapier

Verify a RefRef webhook in a Zap, grant the Reward, and confirm it with the RefRef API.

This Zap receives reward.earned, verifies the RefRef signature in a Code step, and confirms the Reward with a POST step. Read the overview first for the subscription and signature rules.

The Zap: Catch Raw Hook, Run Javascript, POST

Plan limits

On a free account, the editor marked this Zap as using two Pro features: Webhooks by Zapier and the third step. The free account could build and test the Zap; check Zapier's plans before you turn it on. The free plan also stopped the Code step after about one second when it called the API, so the confirmation is a separate POST step.

1. Catch the raw request

  1. Create a Zap with the trigger Webhooks by Zapier → Catch Raw Hook. Use Catch Raw Hook, not Catch Hook: it keeps the raw body and the request headers, which the signature check needs.
  2. Copy the webhook URL.
  3. Subscribe the URL with fulfillmentMode: "explicit" and keep the returned secret (see Subscribe the URL).
  4. Send one event, then select the request in the trigger's Test tab. Earn a real Reward for a complete test. Send test event… in the endpoint menu of Developers → Webhooks sends a signed sample that is enough to test the verify step, but its Reward does not exist, so the confirm step answers 404 for it.

2. Verify the signature

Add Code by Zapier → Run Javascript and map these input fields:

InputValue
rawBody1. Raw Body
webhookId1. Headers Http Webhook Id
webhookTimestamp1. Headers Http Webhook Timestamp
webhookSignature1. Headers Http Webhook Signature
secretThe endpoint secret, starting whsec_

Code by Zapier input fields

Paste this code:

const crypto = require("crypto");

// Verify the Standard Webhooks signature over id.timestamp.body.
const key = Buffer.from(inputData.secret.replace(/^whsec_/, ""), "base64");
const expected = crypto
  .createHmac("sha256", key)
  .update(
    `${inputData.webhookId}.${inputData.webhookTimestamp}.${inputData.rawBody}`,
  )
  .digest("base64");
if (!inputData.webhookSignature.split(" ").includes(`v1,${expected}`)) {
  throw new Error("Invalid RefRef signature");
}
if (Math.abs(Date.now() / 1000 - Number(inputData.webhookTimestamp)) > 300) {
  throw new Error("Old webhook timestamp");
}

const event = JSON.parse(inputData.rawBody);
return {
  eventId: event.id,
  projectId: event.projectId,
  rewardId: event.data.reward.id,
  externalId: event.data.reward.beneficiary.externalId,
};

A thrown error stops the Zap, so the later steps run only for a signed, recent request. The timestamp check refuses a sample older than five minutes: send a fresh event before you test this step.

3. Grant the Reward

Add the steps that grant the Reward in your product. Use 2. Reward Id as the idempotency key and 2. External Id to find the user.

4. Confirm the fulfillment

Add Webhooks by Zapier → POST:

FieldValue
URLhttps://<your RefRef API>/v1/rewards/ + 2. Reward Id + /fulfillment
Payload TypeJson
DataprojectId = 2. Project Id; externalReference = zapier: + 2. Event Id
Headersx-api-key = your Workspace API key

POST step: URL, payload type, and data

POST step: the x-api-key header

Write the header name in lowercase: x-api-key. In our check, the request reached RefRef without the key when the header was named X-Api-Key, and RefRef answered API key required.

Test the step. The Reward's status becomes fulfilled, and GET /v1/rewards/{rewardId} shows the externalReference that the Zap sent.

On this page