active to expired. Instead of polling
GET /orders, you register one endpoint, keep its
signing secret, and get a signed POST with a JSON body for every change.
Endpoints are managed through the API at
https://api.proxyjam.com/public/v1/webhooks.
Before you start
- Credentials. The webhook endpoints need full access: a signed-in session,
or an API key created without a scope restriction.
A key limited to specific scopes, and an OAuth token, are
refused with
403 INSUFFICIENT_SCOPEanddetails.required_scopeset tofull-access. - One active endpoint per account. You can keep several endpoints, but only
one of them can be enabled at a time. Creating or enabling a second one
answers
409 CONFLICT. - A public URL. Use
https. The URL may be up to 2048 characters, must not carry a username or password, and must resolve to a public address: hosts such aslocalhost, private ranges (10.0.0.0/8,192.168.0.0/16, …), loopback and link-local addresses are refused with422 VALIDATION_ERROR. To develop locally, expose your server through a tunnel with a public hostname.
Events
There is one event type today.
Every endpoint subscribes to it automatically; there is no event list to
configure. The body carries a
version field — currently 2026-04-01 — that
changes if the shape of the payload ever changes.
Payload
string
The event id. It stays the same on every retry of the same event, so use it
to drop duplicates. Treat it as opaque.
string
The event type,
proxy.status_changed. Also sent as X-ProxyJam-Event.string
Payload schema version,
2026-04-01.string
When the status changed, ISO 8601 in UTC.
object
object
Request headers
Every delivery is aPOST with these headers:
Verifying the signature
Each endpoint has its own signing secret,whsec_ followed by 64 hex
characters. It is returned once, as signing_secret, in the response that
creates the endpoint. After that the API shows only secret_preview — the
first 12 and last 6 characters — so you can tell secrets apart, but cannot
recover one. Store it as you would a password.
The signature is computed over a string made of three parts joined by dots:
X-ProxyJam-Signature is v1= followed by the hex HMAC-SHA256 of that string,
keyed with the whole signing secret, whsec_ prefix included. To verify a
delivery:
1
Read the raw body
Take the request body as bytes, before any JSON parsing. Re-serialising a
parsed object changes the bytes and breaks the signature.
2
Check the timestamp
Reject the request if
X-ProxyJam-Timestamp is more than five minutes away
from your clock. Every attempt, retries included, is signed with a fresh
timestamp, so a genuine delivery is never old.3
Recompute and compare
Build the signing string, compute the HMAC, and compare it with the header
in constant time.
401 or 403; it is not
retried.
Responding and retries
Answer with any2xx status as soon as you have accepted the event, and do the
work afterwards. Each attempt waits at most 10 seconds for your response.
Redirects are not followed.
A delivery gets five attempts in total. The wait before each retry starts
at 30 seconds and doubles — about 30 s, 1 min, 2 min and 4 min — and would never
exceed two hours. Retries are picked up by a job that runs once a minute, so
expect the actual gaps to be up to a minute longer. After the fifth failed
attempt the delivery is abandoned.
Deleting the endpoint cancels its pending retries, and a retry that comes due
while the endpoint is disabled is cancelled instead of sent. Changes that
happen while no endpoint is enabled are not delivered later.
Because a retry follows any attempt whose answer did not arrive in time, the
same event can reach you more than once. Deduplicate on the body’s
id. And
since events can also arrive out of order, compare occurred_at — or fetch
the order — before acting on a status.
Managing endpoints
All five endpoints live underhttps://api.proxyjam.com/public/v1.
An id that does not exist, or belongs to another account, answers
404 NOT_FOUND. Errors use the usual error envelope.
The endpoint object
string
Endpoint id, the
{endpoint_id} in the paths above.string
Always
proxy.status_changed for now.string
Where deliveries are sent.
boolean
Whether the endpoint receives deliveries.
string
The first 12 and last 6 characters of the signing secret.
string | null
When a test delivery was last sent.
string | null
When a delivery last succeeded.
List endpoints
limit is 1–100 (default 50), offset defaults to 0. The response is
{"items": [ …endpoint objects… ]}.
Create an endpoint
string
required
The URL to deliver to, 1–2048 characters. See Before you start
for what is accepted.
boolean
default:"true"
Create it enabled. Pass
false to create a second endpoint while another
one is active.201 with the endpoint object plus one more field:
string
The full signing secret,
whsec_…. Shown in this response only — store it
now.Update an endpoint
string
A new URL, validated like the one at creation. The signing secret stays the
same.
boolean
false stops deliveries: new changes are not sent, and retries that come due
are cancelled. true turns it back on, provided no other endpoint is
enabled; it does not replay what was missed.Delete an endpoint
Send a test delivery
409.
A test delivery is easy to tell apart: meta.is_test is true, id starts
with test:, proxy.status is test, proxy.previous_status is null,
change_source is manual_test, and the order id and proxy address are
placeholders. It gets a single attempt and is never retried.
The response reports what happened:
delivery.status is delivered on success and failed otherwise — or
blocked if the URL now resolves to an address that is refused, with
error_code ssrf_blocked. When the request did not get an HTTP answer,
error_code says why: timeout, network_error or dns_error. response_body_excerpt holds up to the first
1024 characters of what your server answered. The recorded request_headers
omit X-ProxyJam-Signature.
Rotating the secret
A secret belongs to its endpoint and cannot be changed. To rotate, create a new endpoint with"enabled": false, give its secret to your receiver, then
disable the old endpoint and enable the new one. Delete the old one once
nothing depends on it.