curl -sS \
-X POST \
-H "Authorization: Bearer $OXINSIDER_API_KEY" \
-H 'Content-Type: application/json' \
-d '{}' \
'https://api.0xinsider.com/api/v1/webhooks/{id}/rotate-secret'import requests
url = "https://api.0xinsider.com/api/v1/webhooks/{id}/rotate-secret"
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, headers=headers)
print(response.text)const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.0xinsider.com/api/v1/webhooks/{id}/rotate-secret', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.0xinsider.com/api/v1/webhooks/{id}/rotate-secret",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.0xinsider.com/api/v1/webhooks/{id}/rotate-secret"
req, _ := http.NewRequest("POST", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.0xinsider.com/api/v1/webhooks/{id}/rotate-secret")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.0xinsider.com/api/v1/webhooks/{id}/rotate-secret")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"data": {
"created_at": "2026-09-22T03:14:42.182366Z",
"event_types": [
"whale_trades_inserted"
],
"trade_filters": {},
"failure_count": 0,
"id": 1,
"name": "Production webhook (paused)",
"object": "webhook",
"retry_policy": {
"disable_after_consecutive_failures": 8,
"max_attempts": 8,
"retry_horizon_seconds": 7380,
"terminal_status": "dead_letter"
},
"secret_rotation": {
"status": "idle",
"overlap_expires_at": null
},
"signing_secret": "whsec_4fcoxLTiUpNuOpeWeJJNUS6epNeLDwa_AGHHPptlrq0",
"status": "disabled",
"updated_at": "2026-09-22T03:14:48.156303Z",
"url": "https://example.com/0xinsider/webhook",
"verification_token_expires_at": "2026-09-23T03:14:44.903437Z",
"verified_at": null
},
"meta": {
"cached": false,
"cost": 1,
"request_id": "req_example"
},
"object": "webhook"
}Rotate a webhook secret
Rotate one webhook endpoint’s signing secret immediately and read the new secret once. The old secret stops working when the call returns.
curl -sS \
-X POST \
-H "Authorization: Bearer $OXINSIDER_API_KEY" \
-H 'Content-Type: application/json' \
-d '{}' \
'https://api.0xinsider.com/api/v1/webhooks/{id}/rotate-secret'import requests
url = "https://api.0xinsider.com/api/v1/webhooks/{id}/rotate-secret"
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, headers=headers)
print(response.text)const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.0xinsider.com/api/v1/webhooks/{id}/rotate-secret', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.0xinsider.com/api/v1/webhooks/{id}/rotate-secret",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.0xinsider.com/api/v1/webhooks/{id}/rotate-secret"
req, _ := http.NewRequest("POST", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.0xinsider.com/api/v1/webhooks/{id}/rotate-secret")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.0xinsider.com/api/v1/webhooks/{id}/rotate-secret")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"data": {
"created_at": "2026-09-22T03:14:42.182366Z",
"event_types": [
"whale_trades_inserted"
],
"trade_filters": {},
"failure_count": 0,
"id": 1,
"name": "Production webhook (paused)",
"object": "webhook",
"retry_policy": {
"disable_after_consecutive_failures": 8,
"max_attempts": 8,
"retry_horizon_seconds": 7380,
"terminal_status": "dead_letter"
},
"secret_rotation": {
"status": "idle",
"overlap_expires_at": null
},
"signing_secret": "whsec_4fcoxLTiUpNuOpeWeJJNUS6epNeLDwa_AGHHPptlrq0",
"status": "disabled",
"updated_at": "2026-09-22T03:14:48.156303Z",
"url": "https://example.com/0xinsider/webhook",
"verification_token_expires_at": "2026-09-23T03:14:44.903437Z",
"verified_at": null
},
"meta": {
"cached": false,
"cost": 1,
"request_id": "req_example"
},
"object": "webhook"
}Parameters
| Parameter | Description |
|---|---|
id | The endpoint whose secret you are replacing. |
Idempotency-Key header | Optional, and up to 255 characters. Reuse it only when you are retrying this exact request, on this same id. |
What rotation changes
| Effect | Detail |
|---|---|
signing_secret | A new value, shown in this response and nowhere else. Store it before you do anything else. |
| The old secret | It stops working the moment the call returns. There is no overlap. |
| A staged rotation | Any prepared secret is dropped and any overlap ends, so secret_rotation.status returns to idle. |
failure_count | Set back to 0. |
status | Unchanged. The endpoint does not need verifying again. |
401 or 403 is retried 60 seconds later, and it counts toward the 8 consecutive failures that disable the endpoint.
Example
curl -X POST \
-H "Authorization: Bearer $OXINSIDER_API_KEY" \
-H "Idempotency-Key: webhook-rotate-2026-09-22" \
"https://api.0xinsider.com/api/v1/webhooks/42/rotate-secret"
Handle a 409 or a 422
| Answer | What it means | What to do |
|---|---|---|
409, error.reason webhook_delivery_in_progress | A delivery is in flight on the current secret, so the secret cannot change yet. | Send the same request again once that delivery finishes. |
409, error.reason idempotency_in_progress | Your first request with this Idempotency-Key is still running. | Wait a few seconds, then send the same key again. |
422, error.param Idempotency-Key | The key was already used for a different request, such as a different endpoint id. | Pick a new key. One key belongs to one request. |
Idempotency-Key returns the first response, which means the same secret again. Keep that response out of your logs.
What it does not do
- Return the secret later. Webhook and Webhooks never carry it, so if you lose it your only option is to rotate again.
- Sign anything with the old secret. Every attempt after this call carries one signature, from the new secret.
- Give your receiver a handover window. That is what Activate a staged webhook secret is for.
- Resend anything. Watch Webhook deliveries for the first attempts signed with the new secret.
Authorizations
Legacy default or named integration API key, or OAuth 2.1 access token, in the Authorization header as Bearer oxi_sk_live_... or Bearer oxi_at_.... Default keys retain full access; integration keys are limited to their approved read, webhooks, export and usage scopes and expire within 90 days. All credentials share the owner's account limits. Data calls require an active Pro subscription and return live data. A 401 carries WWW-Authenticate: Bearer resource_metadata="https://api.0xinsider.com/.well-known/oauth-protected-resource" (RFC 6750 section 3, RFC 9728).
Headers
Opt into strict query-name validation. The default is compatible: unknown names are ignored and reported in X-Query-Ignored. With strict, an unknown name returns 400 bad_request with error.reason unknown_query_parameter before the handler runs, including when its percent escape is incomplete.
strict Optional safe-retry key. Reuse the same value only when retrying the exact same mutation request body; a different body returns 422 and an in-flight matching request returns 409.
1 - 255Path Parameters
Webhook endpoint id owned by the authenticated API key user.
Was this page helpful?