Skip to main content

Overview

Webhooks allow you to receive real-time notifications when events occur in your Parallel API operations, eliminating the need for constant polling. Our webhooks follow standard webhook conventions to ensure security and interoperability.

Setup

1. Record your webhook secret

Go to Settings → Webhooks to view your account webhook secret. You’ll need this to verify webhook signatures.
Keep your webhook secret secure. Anyone with access to your secret can forge webhook requests.

2. Configure webhook in API request

When creating a task run or Find All run, include a webhook parameter in your request:
{
  "webhook": {
    "url": "https://your-domain.com/webhooks/parallel",
    "event_types": ["event.type"]
  }
}
ParameterTypeRequiredDescription
urlstringYesYour webhook endpoint URL. Can be any domain.
event_typesarray[string]YesArray of event types to subscribe to. See API-specific documentation for available event types.

3. Webhook request headers

Your webhook endpoint will receive requests with these headers:
  • webhook-id: Unique identifier for each webhook event
  • webhook-timestamp: Unix timestamp in seconds
  • webhook-signature: One or more versioned signatures (e.g., v1,<base64 signature>)
{
  "Content-Type": "application/json",
  "webhook-id": "whevent_abc123def456",
  "webhook-timestamp": "1751498975",
  "webhook-signature": "v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2pj9o9NDN/H/pI4="
}
Signatures are space-delimited per the Standard Webhooks format. Under normal circumstances there will only be one signature, but there may be multiple if you rotate your webhook secret without immediately expiring the old secrets.
webhook-signature: v1,BASE64SIG_A v1,BASE64SIG_B

Security & Verification

HMAC Signature Verification

Webhook requests are signed using HMAC-SHA256 with standard Base64 (RFC 4648) encoding with padding. The signature header is formatted as v1,<base64 signature> where <base64 signature> is computed over the payload below:
<webhook-id>.<webhook-timestamp>.<payload>
Where:
  • <webhook-id>: The value of the webhook-id header
  • <webhook-timestamp>: The value of the webhook-timestamp header
  • <payload>: The exact JSON body of the webhook request
You must parse the version and the signature before verifying. The webhook-signature header uses space-delimited signatures; check each signature until one matches.

Verification Examples

import crypto from "crypto";

function computeSignature(
  secret: string,
  webhookId: string,
  webhookTimestamp: string,
  body: string | Buffer
): string {
  const payload = `${webhookId}.${webhookTimestamp}.${body.toString()}`;
  const digest = crypto.createHmac("sha256", secret).update(payload).digest();
  return digest.toString("base64"); // standard Base64 with padding
}

function isValidSignature(
  webhookSignatureHeader: string,
  expectedSignature: string
): boolean {
  // Header may contain multiple space-delimited entries; each is "v1,<sig>"
  const signatures = webhookSignatureHeader.split(" ");

  for (const part of signatures) {
    const [, sig] = part.split(",", 2);
    if (
      crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expectedSignature))
    ) {
      return true;
    }
  }

  return false;
}

// Example usage in an Express endpoint
import express from "express";

const app = express();

app.post(
  "/webhooks/parallel",
  express.raw({ type: "application/json" }),
  (req, res) => {
    const webhookId = req.headers["webhook-id"] as string;
    const webhookTimestamp = req.headers["webhook-timestamp"] as string;
    const webhookSignature = req.headers["webhook-signature"] as string;
    const secret = process.env.PARALLEL_WEBHOOK_SECRET!;

    const expectedSignature = computeSignature(
      secret,
      webhookId,
      webhookTimestamp,
      req.body
    );

    if (!isValidSignature(webhookSignature, expectedSignature)) {
      return res.status(401).send("Invalid signature");
    }

    // Parse and process the webhook payload
    const payload = JSON.parse(req.body.toString());
    console.log("Webhook received:", payload);

    // Your business logic here

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

Retry Policy

Webhook delivery uses the following retry configuration:
  • Initial delay: 5 seconds
  • Backoff strategy: Exponential backoff (doubles per failed request)
  • Maximum retries: Multiple attempts over 48 hours
After exhausting all retry attempts, webhook delivery for that event is terminated.

Best Practices

1. Always Return 2xx Status

Your webhook endpoint should return a 2xx HTTP status code to acknowledge receipt. Any other status code will trigger retries.

2. Verify Signatures

Always verify HMAC signatures using your account webhook secret from Settings → Webhooks to ensure webhook authenticity. Ensure that you are calculating signatures using the proper process as shown above.

3. Handle Duplicates

Although not common, duplicate events may be sent to the configured webhook URL. Ensure your webhook handler can detect and safely ignore duplicate events using the webhook-id header.

4. Process Asynchronously

Process webhook events asynchronously to avoid timeouts and ensure quick response times. For example, immediately return a 200 response, then queue the event for background processing.

5. Rotate Secrets Carefully

When rotating webhook secrets in Settings → Webhooks, consider keeping the old secret active temporarily to avoid verification failures during the transition period.

6. Monitor Webhook Health

Track webhook delivery failures and response times. Set up alerts for repeated failures that might indicate issues with your endpoint.

API-Specific Documentation

For details on specific webhook events and payloads for each API: