Documentation

Webhooks

Receive HTTP callbacks when key events occur in your SimuTest tests.

Overview

Webhooks let you receive real-time notifications without maintaining a persistent connection. When an event occurs, SimuTest sends an HTTP POST request to your configured endpoint with a JSON payload describing the event.

Webhooks are ideal for CI/CD pipelines — use quality_gate.failed to block deployments and test.completed to trigger downstream workflows like report distribution or Slack notifications.

Note: Your endpoint must respond with a 2xx status code within 10 seconds. Timeouts and non-2xx responses trigger the retry policy.

Supported Events

EventDescription
test.startedTest has been created and sessions are starting
test.progressPeriodic progress update (every 10% of sessions completed)
test.completedAll sessions finished; report is available
test.failedTest encountered a fatal error and could not complete
quality_gate.passedAll scores met or exceeded the configured threshold
quality_gate.failedOne or more scores fell below the configured threshold

Payload Format

All webhook payloads share a common envelope with event, test_id, timestamp, and a data object specific to the event type.

test.completed payload

{
  "event": "test.completed",
  "test_id": "test_abc123",
  "timestamp": "2025-01-15T10:25:12Z",
  "data": {
    "url": "https://example.com",
    "task": "Find and purchase the premium plan",
    "sessions_total": 200,
    "sessions_completed": 200,
    "duration_seconds": 1512,
    "aggregate_scores": {
      "task_completion": 0.84,
      "cta_findability": 0.79,
      "overall": 0.82
    },
    "quality_gate": {
      "passed": true,
      "threshold": 0.75
    },
    "report_url": "https://app.simutest.dev/reports/rpt_def456",
    "report_id": "rpt_def456"
  }
}

quality_gate.failed payload

{
  "event": "quality_gate.failed",
  "test_id": "test_abc123",
  "timestamp": "2025-01-15T10:25:12Z",
  "data": {
    "threshold": 0.80,
    "score": 0.72,
    "failed_criteria": ["task_completion", "cta_findability"],
    "report_url": "https://app.simutest.dev/reports/rpt_def456"
  }
}

Security

Every webhook delivery includes an X-SimuTest-Signature header. The value is an HMAC-SHA256 signature of the raw request body using your webhook secret, prefixed with sha256=.

Always verify the signature before processing the payload. Use a timing-safe comparison to prevent timing attacks.

import crypto from 'crypto';

function verifyWebhook(
  payload: string,
  signature: string,
  secret: string
): boolean {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(payload, 'utf8')
    .digest('hex');

  const trusted = Buffer.from(`sha256=${expected}`, 'ascii');
  const received = Buffer.from(signature, 'ascii');

  return crypto.timingSafeEqual(trusted, received);
}

// Express handler
app.post('/webhooks/simutest', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-simutest-signature'] as string;
  const isValid = verifyWebhook(req.body.toString(), signature, process.env.WEBHOOK_SECRET!);

  if (!isValid) {
    return res.status(401).send('Invalid signature');
  }

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

  res.status(200).send('OK');
});

Retry Policy

If your endpoint fails to respond with a 2xx status within 10 seconds, SimuTest will retry with exponential backoff:

AttemptDelay
1st retry5 seconds
2nd retry30 seconds
3rd retry5 minutes
After 3rd failureDelivery abandoned; webhook is disabled after 10 consecutive failures

Delivery attempts and their status are visible in the Settings → Webhooks dashboard. You can manually replay any delivery from the last 72 hours.

Configuration

Configure webhooks from the Settings → Webhooks page in the dashboard, or via the API:

curl -X POST https://api.simutest.dev/v1/webhooks \
  -H "Authorization: Bearer st_live_abc123..." \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://yourapp.com/webhooks/simutest",
    "events": ["test.completed", "quality_gate.failed"],
    "secret": "whsec_your_random_secret"
  }'

Omit the events array to subscribe to all events. Set a unique secret for each endpoint — SimuTest will use it to sign all deliveries to that URL.