Before you start
You need a public HTTPS endpoint on port 443 and a Pro or Max API key or appropriately scoped OAuth token. Keep the signing secret on your server. If you cannot host a public endpoint, use the event stream. SetOXINSIDER_API_KEY for the examples below. Webhook management requires Pro or Max access; an inactive subscription returns 402 with error.reason: "subscription_inactive".
Choose event types
The access column describes the event’s data. Webhook management itself still requires Pro or Max access, including for events markedNo.
Choose the events your application needs, then put their names in event_types when you create the webhook. List webhook events returns the supported catalog and current status.
live_sports_updatedsends one pulse per game, and at most one every 20 seconds per game. A game going live or final is sent straight away. The game clock moving on its own never sends one. See Live game pulses.suspicious_trade_flaggedandinsider_radar_flag_raisedare one event under two spellings. Subscribe with either name; listing both on one endpoint stores one. Your endpoint receives every delivery under the spelling it registered, in thex-0xinsider-event-typeheader and in the payload’stype, so an endpoint created before September 23, 2026 keeps receivinginsider_radar_flag_raised.large_trades_inserted(and its older spellingwhale_trades_inserted) carries a count of new large trades, not the trades themselves. Read the trades from Large trades.large_trade_inserted_v2carries one trade per delivery. Settrade_filterswhen you create or update the endpoint to require acondition_id,wallet, minimummin_grade, or minimummin_size_usd; all supplied filters must match.gradeis captured at publication and may benull, which never passes a minimum-grade filter. The delivery id stays stable across retries.large_trades_insertedandwhale_trades_inserted, andtrader_syncedandwhale_trader_synced, are each one event under two spellings, like the suspicious-trade pair below: an endpoint receives the spelling it registered.sharp_money_flow_detectedandsmart_money_flow_detectedare also aliases. An endpoint receives the name it registered.- The 4
export_job_*events go only to endpoints owned by the account that submitted the export. - When paid access lapses, every queued delivery of a paid type moves to
dead_letterwithlast_errorset todelivery owner is no longer authorized for this event.
Create and verify your webhook
1
Create the webhook
signing_secret and verification.token immediately; later reads do not return them. Configure your receiver with the signing secret before the next step. The webhook receives events only after verification.2
Verify it within 24 hours
42 with the returned webhook ID and the token placeholder with verification.token. This call sends a signed webhook.verification challenge to your URL. Your server must verify it and return 2xx within 10 seconds for the webhook to become active.{"type":"webhook.verification","token":"<verification_token>","webhook_id":<id>}. It is signed the same way a delivery is, and it carries x-0xinsider-timestamp, x-0xinsider-signature, and x-0xinsider-event-type webhook.verification. It carries none of the event, delivery, or idempotency headers listed below.
If verification fails, use the response to choose the next action:
422witherror.paramurl: your server answered outside2xx, took longer than 10 seconds, or is not reachable from the public internet.400witherror.paramverification_token: the token is wrong or has expired. Delete the endpoint and create it again.
Receive a delivery
Each delivery is aPOST with a JSON body and User-Agent: 0xinsider-webhooks/1.0. Verify the signature, save the event durably, and return 2xx within 15 seconds. Process the saved event afterward, so a crash after acknowledgment does not lose it.
Live game pulses
live_sports_updated reports changes to a game’s scores, status, period, live, or ended fields. A clock change alone does not send an event, but each event includes the latest clock.
Ordinary updates are limited to one event per game every 20 seconds. The next provider update after that interval triggers the event. A game’s first update, start, and final state can be sent immediately.
Events depend on provider updates. If the provider stops sending updates, the webhook also stops receiving them.
Changes during the waiting interval appear in the next event’s changed array. The body contains the current values, rather than every intermediate value.
Check the signature
Verify the signature before parsing JSON. It covers the timestamp, a dot, and the exact request body bytes.- Calculate the HMAC from the raw request bytes. Parsing and re-serializing JSON can change those bytes.
- Use the whole
whsec_...string as the key, prefix included. - Reject a request whose
x-0xinsider-timestampis more than 300 seconds from your own clock. - Split
x-0xinsider-signatureon commas and accept the request when any candidate matches. A staged rotation sends two candidates for an hour. - Compare each candidate in constant time.
- Deduplicate ordinary events on
x-0xinsider-event-idbefore acting. The verification challenge has no event ID; handle it separately.
verify before parsing JSON. For an ordinary event, save and deduplicate it before acknowledging; for a verification challenge, return a timely 2xx after the signature passes.
Handle retries and disabled webhooks
0xinsider retries a delivery when your server returns a non-2xx status, the connection fails, or the 15-second deadline expires. Each delivery has at most 8 attempts. After the eighth failure, its status becomes dead_letter.
The default retry delay grows after each failure: 60, 120, 240, 480, 960, 1,920, then 3,600 seconds. Some failures use a shorter random delay or the receiver’s Retry-After, as shown below. Delivery scheduling can add up to 10 seconds.
The delivery log reports the next attempt time and retry_schedule_reason:
Retry-After is read as a number of seconds or as an HTTP-date. A missing, malformed, or already-past value is ignored, and the delivery falls back to its ordinary wait.
Webhook deliveries reports status, last_error, next_attempt_at, and retry_schedule_reason on each row, and keeps rows for 7 days. Two more reasons appear there: manual_redelivery after Redeliver a webhook delivery, and configuration_changed when an edit to the endpoint released an attempt that had not been sent. Both next_attempt_at and retry_schedule_reason are null while an attempt is in flight and once the delivery is delivered or dead_letter.
The webhook also counts consecutive failures across all its deliveries:
failure_counton the endpoint counts consecutive failed attempts across all of its deliveries. Any success resets it to 0.- At 8 consecutive failures the endpoint’s
statusbecomesdisabledand 0xinsider emails the account owner. - Several failing deliveries can reach this limit before any one delivery uses all 8 attempts.
Replay after downtime
Event replay lets you catch up onlarge_trades_inserted and its alias whale_trades_inserted. It does not replay other event types. For those, inspect delivery logs or read the current API state after an outage.
- Store
next_cursorfrom every replay response. - After the outage, call
/api/v1/events/feed/since?cursor=<the cursor you stored>. - Process each event in
data, then store the response’s newnext_cursor. - Repeat while
has_moreistrue.
Rotate the signing secret
Use staged rotation for routine secret changes. Use immediate rotation if the secret is exposed in source control, logs, screenshots, or elsewhere.Staged rotation, with a 1-hour overlap
Staged rotation lets you deploy a new secret while both signatures remain valid for 1 hour. This avoids rejecting deliveries during the change.1
Prepare the new secret
signing_secret and sets secret_rotation.status to pending. Deliveries keep using the current secret. Deploy the new one to every receiver before you move on.2
Activate it
secret_rotation.status becomes overlap, and secret_rotation.overlap_expires_at is the instant the overlap ends, 1 hour later. Until then x-0xinsider-signature carries two comma-separated v1=<hex> candidates: the new secret’s signature first, the old secret’s second.3
Retire the old secret
secret_rotation.status goes back to idle and deliveries carry one signature again. If you never call it, the overlap ends on its own at overlap_expires_at.Idempotency-Key for each operation and reuse that key if its response is lost. Repeating prepare while the same secret is pending returns that secret again. Changing the webhook’s url discards any prepared or overlapping secret.
Immediate rotation, after a leak
Rotate a webhook secret replaces the secret in a single call.signing_secret to every receiver immediately: a delivery your server rejects is retried about a minute later and counts toward the 8 consecutive failures that disable the endpoint. A 409 with error.reason webhook_delivery_in_progress means a delivery is in flight, so send the request again once it finishes.
Limits
- Deliver to a laptop or a private network. The URL has to be public HTTPS on port 443. To read events from a machine with no public address, open the Stream instead.
- The count event
large_trades_inserteddoes not contain individual trades. Chooselarge_trade_inserted_v2for one trade per delivery. - Replay any event type other than
large_trades_inserted(whale_trades_inserted). - Count events cannot filter individual trades. For
large_trade_inserted_v2, settrade_filtersto filter by market, wallet, minimum grade, or minimum size. - Return
signing_secreta second time. Webhook and Webhooks never carry it, so rotate the secret if you lose it.