Skip to main content
This page covers inbound webhooks — evidence pushed to ReconLayer by providers and chain indexers. For the opposite direction (ReconLayer notifying your systems of state changes), see Outbound Webhooks.
Provider webhooks are one of the three ways evidence enters ReconLayer, alongside file imports and integration polling.

Provider webhooks: Bridge

Today, ReconLayer ships a native inbound webhook integration for Bridge. Each Bridge integration you configure gets its own dedicated webhook URL:
{integrationKey} is the integrationKey you chose when creating the Bridge integration (POST /v1/bridge-integrations), and it’s how ReconLayer resolves which organization and which signing key the incoming payload belongs to — there is no Authorization or x-organization-id header on this route.
POST /webhooks/bridge (without an {integrationKey}) is intentionally rejected with 400 invalid_request and the message “Use /webhooks/bridge/:integrationKey so the webhook can resolve organization context.” Configure Bridge to send webhooks to the per-integration URL only.

Signature verification

Bridge signs every webhook with the header:
ReconLayer verifies this signature against the integration’s stored webhookPublicKey:
  1. Parses t= (timestamp, milliseconds) and v0= (base64-encoded signature) from the header. Missing or malformed headers fail verification immediately.
  2. Rejects the webhook if |now - t| exceeds a 10-minute (600,000 ms) replay tolerance window.
  3. Verifies an RSA-SHA256 signature over the string ${timestamp}.${rawBody} using the integration’s public key.
Even when the signature is invalid, ReconLayer still persists the payload as a RawRecord (with validationStatus: 'failed', signatureValid: false) for audit purposes — the matching engine is skipped, but nothing is silently dropped. The 400 response includes details.rawRecordId and details.sourceRef so you can locate the record.

Responses

object
Returned when the signature is valid. Same shape used across all evidence endpoints:
object
The integrationKey in the path does not resolve to a known, active Bridge integration.
object
Signature missing, malformed, expired (outside the 10-minute window), or failed RSA-SHA256 verification.
See Receive a Bridge Webhook and Reject Ambiguous Bridge Webhook Entrypoint. For how the payload is normalized into FlowLegs, see Bridge Integration.

Listing configured inbound endpoints

GET /v1/webhook-endpoints lists the inbound webhook URLs ReconLayer has generated for your active integrations (currently Bridge):
See List Inbound Integration Webhook Endpoints.

No native webhook for your provider? Submit evidence directly

If you’re integrating a provider, bank, or system that doesn’t have a native ReconLayer webhook adapter, push evidence directly through the canonical evidence endpoints. These are the same entry points used internally by Bridge polling and on-chain ingestion — they go through the identical ingestEvidence pipeline and produce the same EvidenceAcceptanceResponse. Both endpoints require Authorization, x-organization-id, and an Idempotency-Key header.

POST /v1/evidence/provider

Use this for any provider/PSP-side settlement, payout, or transfer event.
string
required
Provider identifier, e.g. "acme-psp".
string
required
A stable identifier unique per (organizationId, source) — used for duplicate detection.
string
Link directly to a known PaymentIntent if you already know it.
string
The provider’s own transfer/transaction ID.
string
Your reference, used for matching against PaymentIntent.externalReference.
string
e.g. intermediary_in, transfer, intermediary_out, destination (defaults to intermediary_in for provider evidence).
string
default:"confirmed"
A FlowLeg status, e.g. pending, confirmed, failed, reversed.
object
required
{ "amount": string, "currency": string }.
string
ISO 8601 timestamp of when the event occurred.
array
Additional FlowLegReference key/value entries.
object
required
The raw payload as received from the provider — stored verbatim on the RawRecord.
See Submit Provider Evidence.

POST /v1/evidence/onchain

Use this for an on-chain transfer observed by your own indexer or RPC node, for chains/providers not covered by a native on-chain integration.
string
default:"evm"
Currently only evm is supported — other values raise an error during normalization.
string
required
The on-chain transaction hash. Lowercased during normalization.
number
required
EVM chain ID (e.g. 1 for Ethereum, 137 for Polygon).
string
Sender address.
string
Recipient address.
string
ERC-20 token contract address, if applicable.
string
Your reference, used for matching against PaymentIntent.externalReference.
string
default:"confirmed"
A FlowLeg status.
object
required
{ "amount": string, "currency": string }.
string
Optional override for the dedup key; if omitted, derived from txHash.
object
required
The raw payload — stored verbatim on the RawRecord.
See Submit On-chain Evidence and On-chain Integrations for the EVM normalization details (hex address lowercasing, tx_hash/external_reference references, chainFamily/networkId metadata).

Idempotency on evidence endpoints

Both endpoints require Idempotency-Key. ReconLayer hashes the request body and stores it against the key:
  • Same key + same body → replays the original response with Idempotency-Replayed: true.
  • Same key + different body → 409 idempotency_key_conflict.
  • Same key while the original request is still processing → 409 idempotency_request_in_progress.
Both endpoints return 201 for newly accepted evidence and 200 if ingestEvidence determined the record was a (organizationId, source, sourceRef) duplicate (duplicate: true in the response body) — this is independent of, and in addition to, the Idempotency-Key mechanism.

Next steps