Webhooks & API

Webhook History

Browse and live-tail inbound requests and outbound delivery attempts

Every connection has a History tab on its detail page. Two subtabs — Inbound and Outbound — show the last 30 days of traffic, updated live as new events land.

Webhook history panel

Browsing Inbound Requests

The Inbound subtab lists every POST that landed at /webhooks/in/{connectionId} — success, failure, and everything in between.

Inbound history rows

Each row shows:

ColumnMeaning
TimestampWhen the request was received
OutcomeTerminal state — coloured pill
Request IDShort ID (usually from the x-request-id header) for correlation
Body size → attemptsSize of the body that arrived, and how many flow executions were planned
DurationEnd-to-end processing time

Outcome pills

PillMeaning
ACCEPTEDAuthenticated, parsed, at least one flow started
SAMPLE_CAPTUREDAbsorbed by an open capture tunnel — no flow ran
UNAUTHORIZEDSignature / secret mismatch — expand the row for the message detail
INVALID_JSONBody was not valid JSON
PAYLOAD_TOO_LARGEBody exceeded 100 KB
IDENTIFIER_NOT_FOUNDNo contact resolved from the payload
TRIGGER_NOT_FOUNDConnection paused / missing / no trigger bound
ERRORUnclassified failure

Expand any row to see:

  • message — human-readable reason (e.g. "Invalid secret", "Stripe signature timestamp outside ±5 min tolerance", "No published trigger could resolve a contact for this payload")
  • headers — the whitelisted subset of request headers that are safe to log (see Redaction)
  • bodyPreview — first 4 KB of the body (truncation marker if longer)
  • resolvedPeopleId — contact resolved from the payload, when applicable

Filter by outcome with the dropdown (e.g. "show me only UNAUTHORIZED") to diagnose auth issues quickly. The subscription channel does not filter — if a filter is active, scroll produces filtered-only rows but live-incoming rows still append to the top until you refresh.

Live tail

The stream indicator (• streaming) in the top-left of the panel shows the live subscription status. New rows appear at the top of the list as they're received; already-shown rows are deduped by ID.

Browsing Outbound Deliveries

The Outbound subtab lists every delivery attempt Wexio sent to an external URL.

Outbound history rows
ColumnMeaning
TimestampWhen the attempt was made
Event namee.g. chat.created, message.outbound.created, flow.order_confirmed
StatusPENDING, SUCCESS, RETRYING, FAILED, DEAD_LETTER
AttemptRetry number (1-indexed)
HTTP statusResponse from the subscriber
DurationRound-trip time

Expand a row to see:

  • destinationUrl — where Wexio POSTed
  • payload — full signed envelope sent
  • errorMessage — axios error code + HTTP status + first bytes of the response body when delivery failed

A single event (unique eventId) produces one row per attempt — they're linked in the UI so you can follow a retry chain end-to-end.

Redaction

Wexio stores history rows in the tenant database and scrubs sensitive headers before persisting. You will never see these in the history panel:

  • x-webhook-secret
  • authorization
  • cookie
  • Signature headers — Stripe-Signature, X-Hub-Signature-256, Paddle-Signature, etc.

The allowlist of headers that are persisted:

  • content-type, content-length
  • user-agent
  • x-request-id, x-idempotency-key
  • x-forwarded-for, x-real-ip

Body content is stored verbatim up to the first 4 KB for preview. For audit purposes only — Wexio does not index or search bodies.

Retention

Both inbound and outbound logs have a 30-day TTL in MongoDB. Mongo purges expired rows automatically — once a row ages out, there's no way to recover it.

Deleting a connection does not proactively clear its history; rows expire naturally at 30 days. If you need immediate cleanup, open a support ticket.

Operational Notes

  • Logging latency never slows webhooks. Writes are fire-and-forget — the HTTP response returns first, the log is persisted on the next tick, then the live-tail event is published.
  • A logging failure is non-fatal. If the history write fails, the request is unaffected; a warning lands in server logs.
  • Cross-process delivery. Both subscriptions (inbound-received, outbound-dispatched) use Redis pub/sub, so the live tail works whether Wexio is running on one node or dozens.
  • Invalid connection IDs don't log. A POST to a nonexistent connection returns 404 and is not persisted (there's no tenancy to attribute it to). Those requests show up in server logs only.

Using the History to Self-Diagnose

SymptomLikely causeFix
Stream of UNAUTHORIZED rowsWrong signing secret, or the partner rotated theirsRe-copy the signing secret into Wexio
UNAUTHORIZED with "timestamp outside tolerance"Clock skew on the partner, or an old Stripe replayCheck NTP on the sender
IDENTIFIER_NOT_FOUNDContact doesn't exist yet, or the JSON path is wrongVerify the path in the connection config; capture a fresh schema if the payload changed
INVALID_JSONPartner is sending form-encoded bodiesChange the partner to send application/json
Outbound FAILED clustersReceiver is down / slowCheck their side; Wexio will retry with exponential backoff

On this page