2xx response.
Delivery headers
Every delivery attempt carries these headers:
Headers describe the delivery attempt; the body describes the event. On a replay,
Sphere-Timestamp and Sphere-Signature are freshly generated — so the same verification code path handles originals and replays — while the body remains byte-for-byte identical to the original.
How the signature is computed
The signature is an HMAC-SHA256 digest, hex-encoded:secret— the endpoint’s signing secret (whsec_...), returned once when you created the endpoint.timestamp— the value of theSphere-Timestampheader.rawBody— the raw HTTP request body bytes, exactly as transmitted.
Sphere-Signature using a constant-time comparison.
Guard against replay attacks
To prevent captured deliveries from being re-sent by a third party, reject deliveries whoseSphere-Timestamp is more than 5 minutes old. Manual replays get a fresh timestamp and signature, so legitimate replays always pass this check.
Reference implementations
Each snippet takes the raw body bytes, the two headers, and your endpoint secret, and returns whether the delivery is authentic.Test your verifier
Before the first real event arrives, run your implementation against this known-good test vector. Every input is fixed, so a correct verifier produces exactly the signature shown. Any difference means the bytes you are signing are not the bytes SpherePay signed — almost always a re-serialized body or a missing. separator.
., and the raw body:
Sphere-Signature is:
Check without code
Reproduce the signature from a shell with OpenSSL:(stdin)= instead of SHA2-256(stdin)=; the hex digest is the same.
Send a signed test delivery to your endpoint
This script plays the part of SpherePay. It signs the test body with the current time and sends it to your receiver with the same headers SpherePay sends. Nothing is sent to or from SpherePay, and nothing is created in your account.- Start your receiver locally. The script posts to
http://localhost:3000/sphere-webhook. If your receiver listens somewhere else, change the URL in the last command. - Give the receiver and the script the same secret. Either configure your receiver with the test secret in the script, or replace
SECRETin the script with thewhsec_secret of the endpoint you are testing. - Run the script. Paste the whole block into a terminal on macOS, Linux or WSL, where
curlandopensslare installed. It creates a fresh timestamp on every run, so the 5-minute tolerance check passes. - Read the response. The
-iflag prints the HTTP status line. A correct receiver answers2xx. - Run it again with a change. Edit one character in
BODYor inSECRETand run it again. A correct receiver must answer with a non-2xxstatus such as401.
When verification fails
Respond with a non-2xx status code (for example 401) and do not process the payload. The delivery is recorded as failed on SpherePay’s side, giving you an audit trail in the Events API.
If you registered the same receiver URL under multiple SpherePay applications, each application’s endpoint has its own secret. Use the
applicationId in the payload to select the correct secret — see Event payloads. If you cannot parse the body before verifying, try each of your known secrets.