Skip to main content

Webhooks Overview & Setup

Tap into BetaTesting Events with Webhooks

Updated this week

BetaTesting webhooks deliver real-time notifications to your systems when events occur on your tests. Instead of polling the API for changes, webhooks push data to your application the moment something happens, like a new issue being submitted, a tester completing a test, or a shipment status change.

How Webhooks Work

  1. You configure a webhook endpoint - an HTTPS URL on your server that receives event notifications

  2. You select which events your endpoint should receive

  3. When a subscribed event occurs, BetaTesting sends an HTTP POST request to your endpoint with details about the event

  4. Your server processes the event and returns a 2xx response to acknowledge receipt

Setting Up a Webhook

Webhooks are managed from your Company Settings > Integrations page.

Creating a Webhook

  1. Go to Company Settings > Integrations

  2. Scroll to the Webhooks section

  3. Click Create Webhook

  4. Enter your Endpoint URL - this must be an HTTPS URL (e.g., https://your-app.com/webhooks/betatesting)

  5. Select the events you want to receive

  6. Click Create

Your webhook's signing secret will be displayed once. Copy it immediately and store it securely - you'll need it to verify webhook signatures. The signing secret uses the format whsec_ followed by a 64-character string.

By default, you can create up to 3 webhooks per company. Each webhook can subscribe to a different set of events and deliver to a different URL. This limit can be configured by your BetaTesting account management team.

Editing a Webhook

  1. On the Integrations page, find the webhook you want to edit

  2. Click Edit

  3. Update the URL or change the event subscriptions

  4. Click Save

Enabling / Disabling a Webhook

You can toggle a webhook on or off without deleting it. Disabled webhooks do not receive any event deliveries.

Rotating the Signing Secret

If you suspect your signing secret has been compromised:

  1. Find the webhook on the Integrations page

  2. Click Rotate Secret

  3. A new signing secret will be generated and displayed once

  4. Update your server to use the new secret

The old secret is invalidated immediately.

Deleting a Webhook

  1. Find the webhook on the Integrations page

  2. Click Delete

  3. Confirm the deletion

Pending deliveries for deleted webhooks are discarded.


Webhook Delivery Format

When an event occurs, BetaTesting sends an HTTP POST request to your endpoint.

Request Headers

Header

Description

Content-Type

application/json

X-BetaTesting-Signature

HMAC-SHA256 signature for verifying the request is from BetaTesting

X-BetaTesting-Event-ID

A unique UUID for this event delivery, useful for deduplication

Request Body

All webhook payloads follow this structure:

{   
"event": "issue.submitted",
"timestamp": 1707123456,
"data": {
"testId": 12345,
"testName": "Mobile App Beta v2",
...event-specific fields
}
}

Field

Type

Description

event

string

The event type (e.g., test.status.changed, issue.submitted)

timestamp

integer

Unix timestamp of when the event occurred

data

object

Event-specific payload β€” always includes testId and testName when applicable

For a complete list of events and their payloads, see the Webhook Events Reference article.


Verifying Webhook Signatures

Every webhook delivery includes an X-BetaTesting-Signature header that you should use to verify the request is genuinely from BetaTesting and hasn't been tampered with.

Signature Format

X-BetaTesting-Signature: t=1707123456,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd

The header contains:

  • t - The Unix timestamp when the signature was generated

  • v1 - The HMAC-SHA256 signature

Verification Steps

  1. Extract the timestamp and signature from the X-BetaTesting-Signature header

  2. Construct the signed payload by concatenating the timestamp, a period (.), and the raw JSON request body:

    {timestamp}.{json_body}
  3. Compute the expected signature using HMAC-SHA256 with your webhook's signing secret:

    HMAC-SHA256(key=your_signing_secret, message="{timestamp}.{json_body}")
  4. Compare your computed signature with the v1 value from the header

Example (Python)

import hmac
import hashlib

def verify_signature(payload_body, signature_header, secret):
parts = dict(item.split("=", 1) for item in signature_header.split(","))
timestamp = parts["t"]
expected_sig = parts["v1"]

signed_payload = f"{timestamp}.{payload_body}"
computed_sig = hmac.new(
secret.encode("utf-8"),
signed_payload.encode("utf-8"),
hashlib.sha256
).hexdigest()

return hmac.compare_digest(computed_sig, expected_sig)

Example (Node.js)

const crypto = require('crypto');

function verifySignature(payloadBody, signatureHeader, secret) {
const parts = Object.fromEntries(
signatureHeader.split(',').map(item => item.split('='))
);
const timestamp = parts.t;
const expectedSig = parts.v1;

const signedPayload = `${timestamp}.${payloadBody}`;
const computedSig = crypto
.createHmac('sha256', secret)
.update(signedPayload)
.digest('hex');

return crypto.timingSafeEqual(
Buffer.from(computedSig),
Buffer.from(expectedSig)
);
}

Example (PHP)

function verifySignature(string $payloadBody, string $signatureHeader, string $secret): bool
{
$parts = [];
foreach (explode(',', $signatureHeader) as $item) {
[$key, $value] = explode('=', $item, 2);
$parts[$key] = $value;
}

$signedPayload = $parts['t'] . '.' . $payloadBody;
$computedSig = hash_hmac('sha256', $signedPayload, $secret);

return hash_equals($computedSig, $parts['v1']);
}

Security tip: Always use constant-time comparison functions (hmac.compare_digest, crypto.timingSafeEqual, hash_equals) to prevent timing attacks.


Delivery & Retry Behavior

BetaTesting uses an at-least-once delivery model. This means your endpoint may occasionally receive the same event more than once. Use the X-BetaTesting-Event-ID header to deduplicate events on your end.

Success

If your endpoint returns a 2xx HTTP status code, the delivery is considered successful and no further retries occur.

Retry Schedule

If your endpoint is unreachable or returns a non-2xx response, BetaTesting retries delivery with the following schedule:

Attempt

Delay After Previous

1st retry

1 minute

2nd retry

5 minutes

3rd retry

30 minutes

4th retry

2 hours

After 5 total attempts (1 initial + 4 retries), the delivery is marked as failed and no further retries are attempted.

Timeout

Your endpoint must respond within 10 seconds. If the response takes longer, the request is treated as a failure and will be retried.

Building Your Webhook Endpoint

When building your server to receive webhooks, keep these guidelines in mind:

  1. Respond quickly - Return a 200 response immediately and process the event asynchronously. Don't do heavy processing in the request handler.

  2. Be idempotent - Your processing logic should handle receiving the same event ID more than once without side effects.

  3. Verify signatures - Always validate the X-BetaTesting-Signature to ensure the request is from BetaTesting.

  4. Use HTTPS - Webhook URLs must use HTTPS. BetaTesting does not deliver to plain HTTP endpoints.

  5. Log deliveries - Store the X-BetaTesting-Event-ID and payload for debugging and audit purposes.

Did this answer your question?