Webhooks

Receive real-time notifications when your data connections run, so downstream systems can react immediately.

Webhooks let Precog push event notifications to your own HTTP endpoints whenever a connection starts, succeeds, or fails. Instead of polling for status, your systems are told the moment something happens — enabling instant dashboard refreshes, alerting, and workflow automation.

For a conceptual overview of why webhooks matter, see the Webhooks explanation.

Setting Up a Webhook

Webhooks are configured per workspace. To create one:

  1. Open your workspace and navigate to Settings → Webhooks.
  2. Click Add Webhook.
  3. Fill in the details:
    • Name — A descriptive label (e.g. "BI Refresh Trigger" or "Slack Alerts").
    • URL — The HTTPS endpoint that will receive POST requests. Only HTTPS URLs are accepted.
    • Events — Select which events this webhook should fire for (see Event Types below).
    • Custom Headers (optional) — Add any extra HTTP headers your endpoint requires, such as authorization tokens. The header name X-Precog-Signature is reserved and cannot be used as a custom header.
  4. Click Save.

On creation, Precog generates a signing secret (prefixed with whsec_). This secret is shown only once — copy it immediately and store it securely. You will need it to verify that incoming requests genuinely come from Precog.

If you lose the secret, you can regenerate it from the webhook settings, but this will invalidate the previous secret and reset the webhook's verification status.

Event Types

Each webhook can subscribe to one or more of these events:

EventFires when
run.startedA connection begins executing
run.succeededA connection completes successfully
run.failedA connection fails

You choose which events matter for your use case. For example, a BI refresh trigger might only need run.succeeded, while an alerting system would subscribe to run.failed.

Payload Format

Every webhook delivery is an HTTPS POST request with a JSON body following this structure:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "event": "run.succeeded",
  "timestamp": "2026-03-20T14:30:00.000Z",
  "connection_id": "c1a2b3d4-e5f6-7890-abcd-ef1234567890",
  "data": {
    "connection_name": "Daily Sales Sync"
  }
}
FieldDescription
idA unique UUID for this delivery, useful for idempotency checks
eventThe event type that triggered the delivery
timestampISO 8601 UTC timestamp of when the event occurred
connection_idThe UUID of the connection that produced the event
dataEvent-specific details, including the human-readable connection name

The Content-Type header is always application/json.

Verifying the HMAC Signature

Every delivery includes an X-Precog-Signature header containing a hex-encoded HMAC-SHA256 signature of the raw request body, computed using your webhook secret. Always verify this signature before processing a delivery to confirm it was sent by Precog and has not been tampered with.

The verification process:

  1. Read the raw request body as a UTF-8 string (do not parse it first).
  2. Compute an HMAC-SHA256 digest of that string using your webhook secret.
  3. Hex-encode the result.
  4. Compare it to the value in the X-Precog-Signature header using a constant-time comparison to prevent timing attacks.

Node.js

const crypto = require("crypto");

function verifySignature(rawBody, secret, signatureHeader) {
  const expected = crypto
    .createHmac("sha256", secret)
    .update(rawBody, "utf8")
    .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(expected, "hex"),
    Buffer.from(signatureHeader, "hex")
  );
}

// In your request handler (Express with raw body parser):
const signature = req.headers["x-precog-signature"];
if (!verifySignature(req.rawBody, "whsec_your_secret_here", signature)) {
  return res.status(401).send("Invalid signature");
}

Python

import hmac
import hashlib

def verify_signature(raw_body: bytes, secret: str, signature_header: str) -> bool:
    expected = hmac.new(
        secret.encode("utf-8"),
        raw_body,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature_header)

# In your request handler:
raw_body = request.get_data()  # Flask example — use the raw bytes
signature = request.headers.get("X-Precog-Signature", "")
if not verify_signature(raw_body, "whsec_your_secret_here", signature):
    abort(401)

Go

package main

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"io"
	"net/http"
)

func verifySignature(body []byte, secret, signatureHeader string) bool {
	mac := hmac.New(sha256.New, []byte(secret))
	mac.Write(body)
	expected := hex.EncodeToString(mac.Sum(nil))
	return hmac.Equal([]byte(expected), []byte(signatureHeader))
}

func webhookHandler(w http.ResponseWriter, r *http.Request) {
	body, _ := io.ReadAll(r.Body)
	signature := r.Header.Get("X-Precog-Signature")
	if !verifySignature(body, "whsec_your_secret_here", signature) {
		http.Error(w, "Invalid signature", http.StatusUnauthorized)
		return
	}
	// Process the webhook payload...
}

Ruby

require "openssl"

def verify_signature(raw_body, secret, signature_header)
  expected = OpenSSL::HMAC.hexdigest("SHA256", secret, raw_body)
  Rack::Utils.secure_compare(expected, signature_header)
end

# In your controller:
raw_body = request.raw_post
signature = request.headers["X-Precog-Signature"]
unless verify_signature(raw_body, "whsec_your_secret_here", signature)
  head :unauthorized and return
end

Connecting Webhooks to Connections

After creating a webhook, you choose which connections send events to it. Open any connection and look for the Integrations card, where each workspace webhook appears with a toggle switch.

  • Toggle on to opt a connection into sending events to that webhook.
  • Toggle off to stop a connection from notifying that webhook.

A single webhook can receive events from multiple connections, and a single connection can notify multiple webhooks.

Testing Webhooks

Before relying on a webhook in production, verify that your endpoint is reachable and processes payloads correctly.

  1. Open the webhook in Settings → Webhooks.
  2. Click Send Test.
  3. Precog sends a test delivery to your endpoint with a sample payload.

If the test succeeds (your endpoint returns an HTTP 2xx status), the webhook is marked as Verified. If it fails, you will see the error in the delivery log — check that your URL is correct, your endpoint is reachable, and it returns a 2xx response.

Test deliveries do not retry on failure, so you get immediate feedback.

Delivery Tracking

Every webhook has a delivery log that shows the outcome of each delivery attempt in real time:

StatusMeaning
SuccessYour endpoint returned an HTTP 2xx response
FailedDelivery was unsuccessful after all retry attempts
RetryingDelivery failed but will be retried automatically
PendingDelivery is queued and has not yet been attempted

Each log entry includes the event type, HTTP status code, error message (if any), and timestamp.

Failed production deliveries are retried automatically up to 5 times. If all retries are exhausted, the delivery is marked as failed.

Managing Webhooks

Editing a Webhook

You can update a webhook's name, URL, subscribed events, and custom headers at any time from Settings → Webhooks. Changing the URL or custom headers resets the webhook's verification status — send a new test to re-verify.

Regenerating the Secret

If your secret is compromised or lost, click Regenerate Secret in the webhook settings. This generates a new secret and invalidates the previous one. Your endpoint must be updated to use the new secret for signature verification. Regenerating also resets the verification status.

Deleting a Webhook

Deleting a webhook removes it and all associated delivery history. Connected connections will no longer send events to the deleted endpoint.