---
title: "QuickNode settlement webhook (Routed + GPVRecorded)"
method: POST
path: "/webhooks/quicknode/{tenant_id}/routed"
tags: ["webhooks"]
---

# QuickNode settlement webhook (Routed + GPVRecorded)

`POST /webhooks/quicknode/{tenant_id}/routed`

## Request

- Base URL: `https://api.instruxi.dev/api/v1/enforcer`
- URL: `https://api.instruxi.dev/api/v1/enforcer/webhooks/quicknode/{tenant_id}/routed`
- Auth: none declared. Required headers: `x-qn-signature`, `x-qn-nonce`, `x-qn-content-hash`, `x-qn-timestamp`

Terminates QuickNode (Streams/QuickAlerts) webhook deliveries carrying raw EVM logs, ABI-decodes Base RouterV2 `Routed` and GpvTracker `GPVRecorded` occurrences, and republishes each canonical body onto its settlement topic. Authenticated by the x-qn-* header set: x-qn-signature = hex HMAC-SHA256(token, nonce + contentHash + timestamp), with sha256(body) additionally required to equal x-qn-content-hash and the timestamp bound to a 5m/30s replay window — NOT enforcer bearer/API-key auth. Returns 200 for anything QuickNode should not retry (including payloads with no Routed logs), 401 on any signature/content-hash/timestamp failure, and 503 only for a transient publish failure that warrants redelivery. Success and 401/503 bodies are plain status text; only the 400 is JSON.

## Path parameters

- `tenant_id` string, required

## Headers

- `x-qn-signature` string, required
- `x-qn-nonce` string, required
- `x-qn-content-hash` string, required
- `x-qn-timestamp` string, required

## Response `200`

accepted (or dropped as non-retryable)

## Other responses

- `400`: malformed tenant_id
- `401`: missing/invalid signature, content-hash mismatch, or stale timestamp
- `413`: payload exceeds the server body limit
- `503`: transient publish failure — QuickNode should redeliver

---

[API](https://skmtc.dev/instruxi/apis/enforcer-api.md) · [All operations](https://skmtc.dev/instruxi/apis/enforcer-api/llms.txt) · [OpenAPI document](https://skmtc.dev/instruxi/apis/enforcer-api/revisions/fa82bc1becc0?raw)
