Always verify webhook signatures before processing any event. Skipping this
step opens your application to spoofed requests.
How Signatures Work
HOST Pay signs every outgoing webhook using HMAC-SHA256. The signing input is:
Where:
timestamp is the Unix epoch value from the X-Webhook-Timestamp header (as a string).
compact_json_body is the raw request body serialized with no extra whitespace.
The resulting signature is hex-encoded and placed in the X-HostPay-Signature header with a v1= prefix (e.g., v1=abc123...).
Verification Steps
- Extract the raw timestamp from
X-Webhook-Timestamp.
- Read the raw request body before parsing it as JSON.
- Construct the signed string:
timestamp + "." + raw_body.
- Compute
HMAC-SHA256(secret, signed_string) and hex-encode it.
- Compare your result to the value after the
v1= prefix using a constant-time comparison.
- Optional but recommended: Reject requests where the timestamp is more than 5 minutes old to prevent replay attacks.
Verifying with the SDK (recommended)
The official SDKs implement all of the steps above — constant-time
comparison and replay protection included. Pass the raw request body and
headers straight from your framework:
Deliveries older than 5 minutes are rejected by default (pass a custom
tolerance in seconds to change this).
Verifying Manually
Implementing the check yourself in another language:
Read the raw request body before any JSON parsing — re-serializing the parsed body changes whitespace and breaks signature verification.