Evidence

A record you can hand to someone who was not there.

When a webhook integration breaks, the question is never just "did it fail." It is what arrived, whether the provider signature verified, which routing rule fired and at which version, what each delivery attempt returned, and what fixed it. Switchyard preserves that record as a sanitized, exportable artifact — so it holds up in an incident review, a ticket, or an agent's context.

The problem

Raw logs are not a complete incident record

A log line shows an outcome. It cannot show the rest of the story.

No provider bytes

A log line that says POST /hooks/stripe → 200 does not preserve what the provider actually sent: the method, path, content type, body size, and body SHA-256 that let you prove which payload you are talking about.

No active routing state

Logs record that an event went somewhere. They do not record which rule matched, which version of the rule set was active at that moment, or which destinations were evaluated and skipped.

No attempt history

A single failure line collapses four retries, their HTTP statuses, their error classes, and their timing into one entry — or scatters them across lines you have to stitch back together by hand.

No safe shared artifact

Raw logs carry headers, cookies, signatures, and payload bodies. Pasting them into a ticket or an agent's context ships secrets. A log line cannot produce a sanitized artifact you can hand to someone else.

The artifact

Anatomy of a Switchyard receipt

A receipt is the sanitized record of a single event: what arrived, how it was verified, where it was routed, what happened on each delivery, and how it ended.

Open the sample diagnostic receipt
Event ID
evt_20260720_143208_01
Endpoint
billing-production (end_9c2f7a1e)
Provider
stripe
Event type
payment_intent.payment_failed
Verification
Stripe signature valid
Redaction state
Sanitized (signature redacted, sensitive paths masked)
Routing rule
payments-v3 · 7
Selected destination
Billing API
Skipped destinations
Audit log, Salesforce sync
Error class
http_server_error
Recovery action
operator_replay_after_receiver_repair
Final result
Replay returned HTTP 200

Deliveries

Billing API exhausted · 4 attempts
Billing API succeeded · 1 attempt
Sample data. Not from a customer or production incident.
What arrived
Method, path, content type, body size, and body SHA-256 — enough to identify the exact payload without storing its raw bytes in the export.
Provider verification
Detection status and a verification status from a fixed vocabulary, evaluated against the configured credential.
Redaction state
Which headers and fields were masked or removed, under which redaction policy versions.
Routing rule and version
The matched rule and the immutable rule set version active at decision time — not the configuration as it looks today.
Selected and skipped destinations
Which destinations the decision selected, and which it evaluated and skipped.
Attempt timeline
Each delivery, its attempt count, and its terminal state — exhausted or succeeded.
Error class
Failures carry the product error vocabulary, such as http_server_error, not free-text guesses.
Recovery action
What an operator did to recover — in the sample, a replay after the receiver was repaired.
Final result
How the event ended: in the sample, the replayed delivery returned HTTP 200.
Sanitization statement
Every receipt declares "sanitized": true and its format version, so a reader knows what kind of document they hold.

Sanitization

What is structurally excluded

Receipts are not redacted after the fact. The sensitive material is never in the export to begin with.

  • Raw request bodies
  • Header, cookie, and signature values
  • Tokens and credentials
  • Secret material of any kind

Masked fields carry "masked": true with null values — the reader can see that a field existed and was masked, without any path to its contents. This is enforced by the server and regression-tested with seeded canaries, so evidence can go into a ticket, a pull request, or an agent's context without a redaction pass.

Privileged access to an original payload stays in the audited browser flow, outside exports and outside agent reach.

Scope

Receipt versus incident bundle

A receipt records one event. An incident bundle freezes a multi-event story.

Receipt — single event record

One event, from arrival through verification, routing, delivery attempts, and recovery. Export it when the question is about one webhook.

Incident bundle — immutable multi-event snapshot

A snapshot of selected events created in one transaction: per-event receipt summaries, routing decisions, delivery timelines with attempt outcomes and error classes, provider verification summaries, an operator note, and an explicit sanitization statement. It never changes after creation; changing the note or the selection means creating a new bundle.

Events per bundle
Up to 20
Title
Up to 200 characters
Operator note
Up to 10,000 characters
Serialized snapshot
Up to 1 MiB
Snapshot format
Format version 1

Collaboration

Safe sharing model

Evidence shares hand a sanitized artifact to someone outside your workspace without handing them anything else.

A share link grants read-only access to one sanitized receipt or incident bundle.

A share token grants nothing else: no workspace access, no raw payloads, no other events, no actions.

Discipline

Facts versus inference

The evidence states what was observed. Conclusions — human or machine — are labeled separately and verified against the facts.

Facts preserved

  • Provider verification status: valid (one of a fixed vocabulary: valid, invalid, missing, stale, malformed, not_configured, not_supported, unavailable).
  • Routing matched rule payments-v3 at rule set version 7; Billing API was selected; Analytics mirror and Sandbox were skipped.
  • Four delivery attempts returned HTTP 500 with error class http_server_error; the delivery reached the terminal state exhausted.
  • After receiver repair, a replay of the same preserved event returned HTTP 200 and the delivery reached the terminal state succeeded.

Inferences to verify

  • The receiver is failing after request deserialization — check its application logs around the attempt timestamps.
  • The failure is in the receiver, not in routing — the matched rule and selected destination stayed constant across attempts.
  • A code change between the exhausted delivery and the replay is the likely fix — confirm against the deploy record.

Switchyard's evidence carries facts: provider verification status, matched routing rules, attempt outcomes, HTTP statuses, error classes. It deliberately avoids speculation. Humans and agents attach their inferences on top, labeled as inferences.

We do not use AI to invent an explanation for missing evidence. We preserve the evidence so humans and machines can reason from the same facts.

Delivery is at least once; duplicates remain possible. Repeats are recorded as duplicate hints in the evidence, not silently merged — and neither you nor an agent should assume otherwise.

For agents

Agent-safe JSON evidence

Four CLI commands produce bounded, sanitized JSON an agent can reason over — with credentials structurally absent.

evidence commands
# What arrived — the event record
switchyard event show EVENT --endpoint ENDPOINT --json

# What happened downstream — the delivery record
switchyard delivery show DELIVERY --endpoint ENDPOINT --json

# The whole story in one sanitized machine document
switchyard receipt export EVENT --endpoint ENDPOINT --format json --stdout

# Configured intent, secret-free, to compare against observed behavior
switchyard config export ENDPOINT

Run the agent under a scoped workspace token — for example events:read deliveries:read deliveries:operate receipts:read — so the API enforces the boundary regardless of what the agent tries. Do not hand it a personal token or arbitrary command execution.

When diagnosis points to an action, the follow-up vocabulary is closed and safe — idempotent, audited with principal attribution, and communicated through exit codes:

safe follow-up operations
# Re-send a preserved event to one destination
switchyard event replay EVENT --destination DEST

# Extend an exhausted delivery budget
switchyard delivery retry DELIVERY --endpoint ENDPOINT

# Wait for an outcome instead of polling prose
switchyard delivery wait DELIVERY --endpoint ENDPOINT --until delivered --timeout 60
switchyard events wait ENDPOINT --match 'json.field=value' --timeout 30

Samples

Download a sample receipt

Inspect the exact artifact this page describes, in the two formats published here.

Sample data. Not from a customer or production incident.

Receipts and incident bundles export as JSON, Markdown, and HTML — each at format version 1. The HTML export is self-contained and script-free.

Durability

Immutability and retention

Evidence is a snapshot, not a live view.

Receipts and incident bundles are versioned snapshots of the record at export or creation time. An incident bundle never changes: event retention may delete the original events without altering the bundle, and deletion by an authorized operator is the only mutation.

Retention cleanup runs delete events according to the retention policy you configure. What a snapshot captured stays captured; what retention removed is gone from the live record — and the evidence says honestly which is which.

Boundaries

Audit and authorization boundaries

Every action on evidence is recorded. Every token means exactly one thing.

The audit history records evidence actions — share created, share revoked, incident bundle created, incident bundle deleted — with bounded metadata: identifiers, truncated titles, counts. Never tokens, and never share URLs.

Possession of a share token grants read-only access to the sanitized artifact it points at, and nothing else. It is not a workspace credential, it does not widen over time, and it stops working the moment it expires or is revoked.

See the record hold up

Walk a failed delivery from arrival to recovery, then read exactly what Switchyard does and does not claim.

The demo uses the same sample receipt published on this page — labeled as sample data throughout.