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
You configure a webhook endpoint - an HTTPS URL on your server that receives event notifications
You select which events your endpoint should receive
When a subscribed event occurs, BetaTesting sends an HTTP POST request to your endpoint with details about the event
Your server processes the event and returns a
2xxresponse to acknowledge receipt
Setting Up a Webhook
Webhooks are managed from your Company Settings > Integrations page.
Creating a Webhook
Go to Company Settings > Integrations
Scroll to the Webhooks section
Click Create Webhook
Enter your Endpoint URL - this must be an HTTPS URL (e.g.,
https://your-app.com/webhooks/betatesting)Select the events you want to receive
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
On the Integrations page, find the webhook you want to edit
Click Edit
Update the URL or change the event subscriptions
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:
Find the webhook on the Integrations page
Click Rotate Secret
A new signing secret will be generated and displayed once
Update your server to use the new secret
The old secret is invalidated immediately.
Deleting a Webhook
Find the webhook on the Integrations page
Click Delete
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 |
|
|
| HMAC-SHA256 signature for verifying the request is from BetaTesting |
| 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 |
| string | The event type (e.g., |
| integer | Unix timestamp of when the event occurred |
| object | Event-specific payload β always includes |
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 generatedv1- The HMAC-SHA256 signature
Verification Steps
Extract the timestamp and signature from the
X-BetaTesting-SignatureheaderConstruct the signed payload by concatenating the timestamp, a period (
.), and the raw JSON request body:{timestamp}.{json_body}Compute the expected signature using HMAC-SHA256 with your webhook's signing secret:
HMAC-SHA256(key=your_signing_secret, message="{timestamp}.{json_body}")Compare your computed signature with the
v1value 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:
Respond quickly - Return a
200response immediately and process the event asynchronously. Don't do heavy processing in the request handler.Be idempotent - Your processing logic should handle receiving the same event ID more than once without side effects.
Verify signatures - Always validate the
X-BetaTesting-Signatureto ensure the request is from BetaTesting.Use HTTPS - Webhook URLs must use HTTPS. BetaTesting does not deliver to plain HTTP endpoints.
Log deliveries - Store the
X-BetaTesting-Event-IDand payload for debugging and audit purposes.
