Sources
Configure external services that send webhooks to Provenance.
An inbound source represents an external service that sends webhook events to Provenance. Each source defines how to verify incoming requests and optionally validate their payload structure.
Creating a source
POST /api/inbound-sources
{
"title": "Stripe Webhooks",
"mnemonic": "STRIPE",
"description": "Receives payment events from Stripe",
"originId": "uuid",
"verification": {
"algorithm": "hmac-sha256",
"signatureHeader": "stripe-signature",
"encoding": "hex",
"signaturePrefix": "",
"timestampField": "timestamp",
"replayTolerance": 300
},
"verifySecret": "{{secret.stripeWebhookSecret}}",
"payloadSchema": {
"type": "object",
"required": ["id", "type", "data"],
"properties": {
"id": { "type": "string" },
"type": { "type": "string" },
"data": { "type": "object" }
}
},
"isActive": true
}Fields
| Field | Required | Description |
|---|---|---|
title | Yes | Display name for the source |
mnemonic | Yes | Unique short code (e.g. STRIPE, GITHUB) |
description | No | What this source receives |
originId | Yes | Origin UUID — interactions from this source are tagged with this origin |
verification | No | Signature verification configuration (see below) |
verifySecret | No | Secret used for signature verification — supports template variables like {{secret.name}} |
payloadSchema | No | AJV JSON schema to validate incoming payloads |
isActive | Yes | Whether the source accepts incoming webhooks |
Signature verification
Provenance verifies webhook signatures to ensure requests are authentic. The verification object supports:
| Field | Description |
|---|---|
algorithm | hmac-sha256, hmac-sha1, or plain (direct string comparison) |
signatureHeader | HTTP header containing the signature (e.g. x-hub-signature-256 for GitHub) |
encoding | hex or base64 |
signaturePrefix | Prefix to strip from the header value before comparison (e.g. sha256= for GitHub) |
timestampField | Header or payload field containing the event timestamp (for replay protection) |
replayTolerance | Maximum age in seconds before rejecting the event (e.g. 300 for 5 minutes) |
Examples by provider
Stripe
{
"algorithm": "hmac-sha256",
"signatureHeader": "stripe-signature",
"encoding": "hex"
}GitHub
{
"algorithm": "hmac-sha256",
"signatureHeader": "x-hub-signature-256",
"encoding": "hex",
"signaturePrefix": "sha256="
}Plain token comparison
{
"algorithm": "plain",
"signatureHeader": "x-webhook-token"
}Payload schema
Optionally validate the structure of every incoming payload at the source level. This catches malformed requests before they reach any mapping.
The schema uses AJV JSON Schema format:
{
"type": "object",
"required": ["id", "type", "data"],
"properties": {
"id": { "type": "string", "pattern": "^evt_" },
"object": { "type": "string", "const": "event" },
"type": { "type": "string" },
"data": {
"type": "object",
"required": ["object"],
"properties": {
"object": { "type": "object" }
}
}
}
}Generating schemas from samples
In the Dashboard UI, you can paste a sample webhook payload and auto-generate a schema. The generator infers types, required fields, nested objects, arrays, and string patterns (like ^evt_ for IDs starting with evt_).
Template variables in secrets
The verifySecret field supports template variables, so you never need to hardcode secrets:
{
"verifySecret": "{{secret.stripeWebhookSecret}}"
}The secret is resolved at runtime from your configured secrets store.
Webhook URLs
Once created, each source gets two webhook URLs:
POST /api/inbound/{tenantSlug}/{sourceId}
POST /api/inbound/{tenantSlug}/by-mnemonic/{mnemonic}Configure either URL in your external service's webhook settings. The mnemonic-based URL is easier to read and doesn't change if you recreate the source.