Skip to main content

Webhooks

Webhooks allow you to receive real-time updates from our servers. They enable you to build custom logic on your server based on events that happen during the app release process.

Getting Started

To get started, you need to create a webhook. You can do this by going to the settings page and clicking on the "Create Webhook" button.

You will be asked to provide

  • Webhook URL - The URL that will receive the webhook events
  • Webhook Secret - A secret that will be used to verify the webhook events
  • Webhook Description - A description for your webhook

How to generate a secret key

The secret key is a unique string that is used to verify the webhook events. You can generate a secret key using the following command:

# Generate a random string
openssl rand -base64 16
caution

We only store the encrypted secret key on our servers. This means that you will not be able to retrieve the secret key once you have created the webhook. So make sure to save it in your vault.

Webhook Form

Once you create the webhook, you have the ability to enable or disable the webhook.

Active Webhook

Webhook Events

Webhook events are sent to your webhook URL as a POST request with payload which contains the event information and headers which contain information to verify and prevent replay attacks.

Supported Events

EventDescription
ios.appstore.review.startedTriggered when a new iOS app submission review is started.
ios.appstore.review.completedTriggered when a new iOS app submission review is completed.

If you need us to support additional events, please contact us.

Payload

The request body for the ios.appstore.review.started event will contain the following information:

FieldDescription
eventThe event type that was triggered
buildIdThe build ID of the app submission
cfBundleIdentifierThe bundle identifier
cfBundleVersionThe bundle version
cfBundleShortVersionStringThe bundle short version string
submittedAtThe date and time that the build was submitted
{
"event": "ios.appstore.review.started",
"buildId": "17127a98-0989-46a8-a69a-b3a6378f653d",
"cfBundleIdentifier": "app.wolfia",
"cfBundleVersion": "1",
"cfBundleShortVersionString": "1.0.0",
"submittedAt": "2023-02-22T17:19:25.503847Z"
}

The request body for the ios.appstore.review.completed event will contain the following information:

FieldDescription
eventThe event type that was triggered
buildIdThe build ID of the app submission
cfBundleIdentifierThe bundle identifier
cfBundleVersionThe bundle version
cfBundleShortVersionStringThe bundle short version string
completedAtThe date and time that the build was completed
{
"event": "ios.appstore.review.started",
"buildId": "17127a98-0989-46a8-a69a-b3a6378f653d",
"cfBundleIdentifier": "app.wolfia",
"cfBundleVersion": "1",
"cfBundleShortVersionString": "1.0.0",
"completedAt": "2023-02-23T17:19:25.503847Z"
}

Headers

The header of the request will contain the following information:

HeaderDescription
X-Wolfia-SignatureThe signature of the request body signed with the webhook secret using the HMAC-SHA256 algorithm. This can be used to verify the request. (Recommended)
X-Wolfia-UntilThe date and time until the webhook request should be accepted. This helps prevent replay attacks.
X-Wolfia-Idempotency-KeyThe idempotency key of the request. This can be used ensure that you only receive the request once. (Optional)

Consuming Webhook Events

This section walks you through the steps to process a webhook event on your server. You can use the following code snippets as a starting point.

Verify and prevent replay attacks

To verify that the webhook event was sent by Wolfia, you can use the X-Wolfia-Signature header. This header contains the signature of the request body. You can use this signature to verify that the request body was not modified.

To verify the signature, you need to use the webhook secret that you provided when you created the webhook. You can use your webhook secret to generate a signature using the HMAC-SHA256 algorithm.

var crypto = require('crypto');

// Prevents man-in-the-middle attacks by verifying the signature
function isWebhookVerified(req) {
const body = req.body;
const validUntil = req.header("X-Wolfia-Until");
const signature = req.header("X-Wolfia-Signature");
return verifySignature(body, validUntil, signature);
}

// Prevents replay attacks by verifying the expiration date
function isWebhookExpired(req) {
const validUntil = req.header("X-Wolfia-Until");
const validDateTime = new Date(validUntil * 1000);
const currentTime = new Date();
return validDateTime < currentTime;
}

function verifySignature(body, validUntil, signature) {
const secret = "secret you entered when creating the webhook goes here"
const data = JSON.stringify(body) + "." + validUntil;
const hash = crypto.createHmac('sha256', secret).update(data).digest('hex');
return hash === signature
}

Handle the webhook event

Once you have verified the webhook event, you can process the event. You can use the event field to determine what type of event was triggered.

var express = require('express');
var router = express.Router();

router.post('/', function (req, res, next) {
const isExpired = isWebhookExpired(req);
const isVerified = isWebhookVerified(req);
if (isVerified && !isExpired) {
processWebhook(req.body);
res.status(200).send('OK');
} else if (isVerified && isExpired) {
res.status(400).send("Webhook expired");
} else if (!isVerified) {
res.status(400).send("Invalid signature");
} else {
res.status(400).send("Unknown error");
}
});

function processWebhook(body) {
switch (body.event) {
case "ios.appstore.review.started":
console.log(`Started review for version: ${body.cfBundleShortVersionString}.${body.cfBundleVersion}`)
// handle review start
break;
case "ios.appstore.review.completed":
console.log(`Completed review for version: ${body.cfBundleShortVersionString}.${body.cfBundleVersion}`)
// handle review complete
break;
default:
console.log("Unknown event: " + body.event)
}
}

Acknowledging Webhook Events

Once you have processed the webhook event, you should acknowledge the event by sending a 200 response. This will prevent the event from being sent again.

If you do not acknowledge the event, the event will be sent again for up to 10 times. After 10 times, the event will be discarded.

Testing Webhook Events

Once you have created a webhook, you can test it by sending a test event. If you head on over to the settings page, you can see the Debug button. Clicking on this button will open the dialog below.

Debug Dialog

You can use the dialog to send a test event to your webhook. You can select the event type and once you are ready, click on the Send test webhook button.

And that's it! ✅ You are now ready to start receiving webhook events from Wolfia. If you have any questions, please feel free to reach out to us.