Skip to main content

HMAC Integration Guide

This guide adds HMAC request authentication to your API so it accepts signed requests from ShadowFeed and skips x402 payment for those calls.
If you’re using Hosted Mirror mode (we host your data, no API server on your side), skip this entire guide. HMAC is only needed for Partner Bridge mode.
Already selling this data via x402 on Solana, Base, or another EVM chain? That’s the most common case. You do not stand up a new endpoint — you point ShadowFeed at the same API you already gate with x402. ShadowFeed adds a second payment rail (STX on Stacks) in front of it: the agent pays ShadowFeed in STX, and ShadowFeed proves itself to your server with an HMAC signature so your existing x402 paywall lets the call through for free. Your direct Solana/EVM buyers are unaffected. Read Coexisting with your existing x402 paywall before wiring anything.
Use the SDK if you can. @shadowfeed/provider-sdk ships this verifier as a drop-in Express/Hono adapter plus a shadowfeed verify command that handshake-tests your endpoint before you go live — and it gets the canonical path right automatically (the #1 thing hand-rolled integrations get wrong). Hand-rolling is fully supported and documented below, but whichever path you choose, run the connection test before activating — see Verify your wiring before going live.

TL;DR — 3 things to do

1

Grab your HMAC secret

From the provider dashboard or the success screen after onboarding.
2

Set it on your server

SHADOWFEED_PARTNER_SECRET=... as env var on your API server — not on ShadowFeed.
3

Paste the middleware

Copy the snippet for your stack below. Mount BEFORE your x402 middleware.

How HMAC fits into the request flow

The signature is computed from a canonical string:
Both sides must derive the same canonical string for the signature to verify. The body hash is empty string "" for GET requests.

Coexisting with your existing x402 paywall

If your endpoint is already gated by x402 (Solana, Base, other EVM), nothing about that setup changes. ShadowFeed becomes an additional, HMAC-authenticated caller in front of the same route:
Two rules make this work:
1

Run the HMAC check BEFORE your x402 middleware

A ShadowFeed call carries no x402 payment — it carries an X-Sf-* signature instead. If your x402 middleware runs first, it returns 402 Payment Required to ShadowFeed before the HMAC verifier ever sees the request.
2

On a valid signature, bypass the paywall and serve data

Set a flag (e.g. skipX402) your payment middleware honors. On a missing or invalid signature, fall through to your normal x402 flow so your direct Solana/EVM buyers keep paying as usual.
A broken HMAC bypass is silent revenue loss, not a loud error. If the signature fails to verify (wrong secret, or — far more often — a path mismatch), the request falls through to your x402 paywall, which answers 402. ShadowFeed treats any non-2xx upstream response as a failed delivery: the agent’s STX is not credited to you, and they receive an error even though they paid. You won’t see a 401 in your own logs — you’ll see a 402 you served to ShadowFeed and wonder why revenue is zero. This is why the path rules and the pre-launch test below are not optional.

Setup checklist

  • HMAC secret saved (from onboarding success screen or Rotate secret button)
  • Decided which server hosts your partner_endpoint
  • Set SHADOWFEED_PARTNER_SECRET=your-secret as env var on that server
  • Confirmed your API can read the env var (process.env, c.env, os.environ, etc.)

Verifier middleware

Pick the language tab matching your stack. All three implementations use the same canonical string format and are mutually compatible.
Get the PATH right or every single request fails — this is the most common integration killer.ShadowFeed signs the canonical string using the exact source_path you registered for the feed, then calls partner_endpoint + source_path. Your verifier must rebuild the canonical string with that same path — not necessarily what new URL(req.url).pathname returns after a mount point, reverse proxy, or x402 router has rewritten it.Two registration rules keep both sides aligned:
  1. partner_endpoint is an origin onlyhttps://api.you.com, no path, no trailing slash. Register https://api.you.com/v1 with feed path /whales and ShadowFeed signs /whales but calls …/v1/whales; your server sees /v1/whales/whales401 on every call.
  2. source_path is the literal route your server already serves — if your real route is /whale-alerts, register exactly that. A typo or a stale /v1 prefix makes ShadowFeed hit a path that doesn’t exist → 404 on every call. (A real early integration did exactly this: it 404’d on every request and served zero data for weeks before anyone noticed — because the operator was watching their own logs for 401s that never came.)
The simple examples below assume an origin-only partner_endpoint and a router mounted at the root. If your API sits behind a path prefix, see Mounted behind a prefix or an x402 router.
Where to set the secret (Cloudflare Workers):
This stores it as a Worker secret — accessible at runtime via c.env.SHADOWFEED_PARTNER_SECRET, never visible in your code or logs.

Mounted behind a prefix or an x402 router

x402 frameworks often mount everything under a prefix (e.g. /api or /x402). When that happens, new URL(req.url).pathname includes the prefix — but ShadowFeed signed the path without it. Strip the known prefix before building the canonical string:
The @shadowfeed/provider-sdk adapters do this for you — they reconstruct the signed path from the route parameter, so the canonical path is identical no matter where the router is mounted. If you can adopt the SDK, you skip this class of bug entirely.

Verify your wiring before going live

Do not make a real STX purchase your first test — it costs money and gives a vague pass/fail. Use a handshake test that signs and probes your endpoint exactly the way a buyer would, for free.
In your provider dashboard, click Test connection (calls POST /providers/id/:id/hmac/test). ShadowFeed signs a request with your stored secret against your first active feed’s source_path, fires it at partner_endpoint + source_path, and reports back:The response echoes probed_path so you can confirm ShadowFeed is hitting the exact route you expect.
Once the handshake passes, confirm the full payment path end-to-end with a single real purchase via the ShadowFeed Agent SDK:
When it works end-to-end: the agent pays STX → ShadowFeed signs + forwards → your middleware verifies and bypasses x402 → your route returns data → 97% of the price is credited to your pending_revenue counter. Confirm via the dashboard or GET /providers/id/your-id/analytics.

Common pitfalls

Building with Claude Code

If you use Claude Code to maintain your codebase, paste this prompt to bootstrap the integration:
I want to integrate my API as a ShadowFeed external data provider. My stack is [Cloudflare Workers / FastAPI / Go / etc.]. I have the HMAC secret saved as SHADOWFEED_PARTNER_SECRET. The full integration guide is at docs.shadowfeed.app/providers/hmac-integration. Walk me through:
  1. Adding the HMAC verifier middleware to my existing routes (preserve current x402 / auth)
  2. Setting the env var on my deployment platform
  3. Testing the integration end-to-end
My API base URL is https://api.mycompany.com and the feed I want to expose is at /v1/whales.
Claude can read this doc, your codebase, and walk you through the wiring step-by-step.

Reference

Canonical string

Replace each placeholder with the actual values per request.

Headers sent by ShadowFeed

Signature algorithm

Use constant-time comparison when verifying — never use plain string equality. Python: hmac.compare_digest. Go: hmac.Equal. TypeScript: compare byte-by-byte after equal-length check.

Next steps

Withdrawals & Revenue

How to cash out accumulated STX.

Troubleshooting

Debug HMAC failures, request issues.