Skip to main content

Webhooks

Webhooks allow you to receive real-time HTTP notifications when events occur in QA Sphere. When an event triggers, QA Sphere sends an HTTP POST request to your configured endpoint with details about the event.

Creating a Webhook

Navigate to Settings > Integrations > Webhooks and click Create Webhook.

Connection Settings

FieldDescription
NameA descriptive name for your webhook
EndpointThe HTTPS URL where webhook payloads will be sent
SecretOptional shared secret for signature verification (recommended)
Event TypesSelect which events should trigger this webhook
EnabledToggle to enable or disable the webhook

Request Customization

You can customize the HTTP request sent to your endpoint:

  • Headers: Add custom headers (one per line, format: Header-Name: value)
  • Payload: Define a custom JSON payload template with variable substitution

Project Permissions

Control which projects trigger the webhook:

  • All Projects: Webhook fires for events in any project
  • Specific Projects: Select individual projects to monitor

Event Types

EventDescription
plan_createdA test plan was created
plan_updatedA test plan was updated, closed, reopened, or deleted
run_createdA test run was created
run_updatedA test run was updated, closed, reopened, or deleted
tcase_createdA single test case was created
tcases_createdMultiple test cases were created in a batch operation
tcase_editedA single test case was edited
tcases_editedMultiple test cases were edited in a batch operation
result_createdA single test result was recorded
results_createdMultiple test results were recorded in a batch operation

Template Variables

Use template variables in your custom payload and headers using the ${variable} syntax.

Universal Variables

Available for all event types:

VariableTypeDescription
${event_type}stringThe event type (e.g., plan_created, run_updated)
${timestamp}stringRFC3339 timestamp when the event occurred
${project_id}stringThe project's unique identifier
${project_code}stringThe project's short code (e.g., PRJ)
${id}stringThe entity's unique identifier
${name}stringThe entity's title or name
${url}stringDirect URL to view the entity in QA Sphere
${event_creator}stringName of the user who performed the action
${event_created}stringRFC3339 timestamp when the action occurred
${entity_creator}stringName of the user who originally created the entity
${entity_created}stringRFC3339 timestamp when the entity was created
${is_deleted}booleanWhether the entity is deleted (true or false)

Plan-Specific Variables

VariableTypeDescription
${event_description}stringDescription of the action (e.g., "Plan created")
${configuration}stringComma-separated list of configuration names
${completed_on}stringRFC3339 timestamp when the plan was closed (empty if open)

Run-Specific Variables

VariableTypeDescription
${event_description}stringDescription of the action (e.g., "Run created")
${assigned_to}stringName of the assigned user (empty if unassigned)
${configuration}stringConfiguration name (empty if none)
${completed_on}stringRFC3339 timestamp when the run was closed (empty if open)

Test Case-Specific Variables

VariableTypeDescription
${tcase_seq}stringTest case sequence number
${tcase_priority}stringPriority level (low, medium, high)

Result-Specific Variables

VariableTypeDescription
${event_description}stringDescription including test case and run titles
${result_status}stringResult status (e.g., passed, failed, skipped, blocked)
${result_comment}stringComment added to the result (empty string if no comment was added)
${result_links}stringComma-separated list of link URLs (empty if no links)

Bulk Event Variables

For results_created events:

VariableTypeDescription
${ids}arrayArray of result IDs (when used as exact value)
${items}arrayArray of item objects with individual details

Each item in ${items} contains:

  • id - Result ID
  • url - URL to view the result
  • result_status - Result status (e.g., passed, failed)
  • result_comment - Comment added to the result
  • result_links - Comma-separated list of link URLs

Payload Examples

Default Payload

When no custom payload is specified, QA Sphere sends:

{
"event_type": "run_created",
"timestamp": "2026-01-21T11:07:57Z",
"data": {
"id": "22",
"name": "UI Testing Test Run",
"url": "https://example.qasphere.com/project/DB/run/22",
"project_id": "1CJjW1Amf_a8hximyr325zz",
"project_code": "DB",
"event_description": "Run created",
"event_creator": "Nick Lapis-Trout",
"event_created": "2026-01-21T11:07:57Z",
"entity_creator": "Nick Lapis-Trout",
"entity_created": "2026-01-21T11:07:57Z",
"is_deleted": false,
"assigned_to": "Nick Lapis-Trout",
"configuration": "Android",
"completed_on": ""
}
}

Custom Payload with Variables

{
"event": "${event_type}",
"project": "${project_code}",
"entity": {
"id": "${id}",
"name": "${name}",
"url": "${url}"
},
"actor": "${event_creator}",
"deleted": "${is_deleted}"
}

Typed Variable Substitution

When a variable is the exact and only value of a JSON field, it preserves its type:

{
"deleted": "${is_deleted}",
"result_ids": "${ids}"
}

Results in:

{
"deleted": true,
"result_ids": ["123", "456", "789"]
}

When a variable is embedded in a string, it becomes a string:

{
"message": "Entity ${id} was ${event_type}"
}

Results in:

{
"message": "Entity 42 was run_created"
}

Integration Examples

Slack

To send webhook notifications to Slack, create a Slack Incoming Webhook and use it as your endpoint. Configure a custom payload using Slack's Block Kit format:

Event Types: Select tcase_created to notify when new test cases are added.

Custom Payload:

{
"text": "${event_creator} created a new test case in ${project_code}",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*${event_creator}* created a new test case:"
}
},
{
"type": "divider"
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*<${url}|${name}>*\nProject: ${project_code}\nPriority: ${tcase_priority}"
}
}
]
}

This produces a Slack message like:

John Doe created a new test case:


Verify login with valid credentials Project: PRJ Priority: high

tip

The text field serves as a fallback for notifications and accessibility. Always include it alongside blocks.

Request Headers

QA Sphere automatically includes these headers with every webhook request:

HeaderDescription
Content-TypeAlways application/json
X-Webhook-IDUnique identifier for this delivery (for idempotency)
X-Webhook-TimestampUnix timestamp when the request was sent
X-Webhook-SignatureHMAC-SHA256 signature (only if secret is configured)

Custom Headers

Add custom headers in the webhook configuration:

Authorization: Bearer your-token
X-Custom-Header: custom-value
X-Project: ${project_code}
Reserved Headers

The following headers cannot be overridden: X-Webhook-Timestamp, X-Webhook-Signature, X-Webhook-ID, Host, and proxy-related headers.

Signature Verification

When a secret is configured, QA Sphere signs the payload using HMAC-SHA256. We strongly recommend verifying signatures to ensure requests originate from QA Sphere.

Signature Format

The signature is provided in the X-Webhook-Signature header:

sha256=<hex-encoded-signature>

Verification Steps

  1. Get the timestamp from X-Webhook-Timestamp
  2. Get the raw request body
  3. Concatenate: {timestamp}.{body}
  4. Compute HMAC-SHA256 using your secret
  5. Compare with the signature (use constant-time comparison)

Example (Node.js)

const crypto = require('crypto')

function verifySignature(payload, timestamp, signature, secret) {
const message = `${timestamp}.${payload}`
const expectedSignature =
'sha256=' + crypto.createHmac('sha256', secret).update(message).digest('hex')

return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expectedSignature))
}

Example (Python)

import hmac
import hashlib

def verify_signature(payload, timestamp, signature, secret):
message = f"{timestamp}.{payload}"
expected = "sha256=" + hmac.new(
secret.encode(),
message.encode(),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected)

Example (Go)

import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
)

func verifySignature(payload string, timestamp int64, signature, secret string) bool {
message := fmt.Sprintf("%d.%s", timestamp, payload)
h := hmac.New(sha256.New, []byte(secret))
h.Write([]byte(message))
expected := "sha256=" + hex.EncodeToString(h.Sum(nil))
return hmac.Equal([]byte(signature), []byte(expected))
}

Delivery Behavior

Retry Policy

QA Sphere retries failed deliveries with exponential backoff:

AttemptDelay
1Immediate
230 seconds
32 minutes

After three failed attempts, the delivery is abandoned and will not be retried.

Retry Conditions

Retries occur for:

  • Network errors
  • 5XX server errors
  • 429 (Rate Limit) responses

Retries do not occur for:

  • 4XX client errors (except 429)

Timeouts

  • Connection timeout: 10 seconds
  • Total request timeout: 30 seconds

Bulk Events

When many items are created in a single operation (more than 5 items), QA Sphere sends a summary event instead of individual item details:

  • The ${name} variable contains a summary (e.g., "10 results created")
  • The ${items} array is omitted
  • The ${ids} array (for results) contains all IDs

Security Considerations

HTTPS Required

Webhook endpoints must use HTTPS. HTTP endpoints are not allowed.

Testing Webhooks

Use the Test Webhook button in the webhook configuration to send a test request. Test requests include:

{
"event_type": "test",
"timestamp": "2026-01-21T11:07:57Z",
"test": true,
"data": {
"text": "This is a test message"
}
}
Best Practices
  1. Always configure and verify webhook signatures
  2. Respond to webhooks quickly (within 10 seconds)
  3. Process webhook payloads asynchronously if needed
  4. Use the X-Webhook-ID header for idempotency
  5. Return 2XX status codes to acknowledge receipt
Need Help?

Contact support for assistance with webhook configuration.