✏️ Creating Webhooks
Webhook Management
Section titled “Webhook Management”Webhooks are managed via the following endpoint, using your partner credentials:
https://public.api.barestho.com/api/v1/partnership/webhooks/Refer to the API reference for the full list of available operations (create, retrieve, delete).
Security
Section titled “Security”Each request sent to your webhook is signed by Barestho using an
HMAC-SHA256 computed from your auth_token,
the request payload, and the current time as a timestamp.
The auth_token is defined by the partner when creating the webhook.
The following headers are included with each request:
| Header | Content |
|---|---|
X-Webhook-Signature | HMAC-SHA256 signature |
X-Webhook-Timestamp | Request timestamp (Unix) |
Signature Verification
Section titled “Signature Verification”To validate that a request originates from Barestho, reconstruct the signature as follows:
- Retrieve the timestamp from
X-Webhook-Timestamp - Serialize the request body to JSON without spaces, with keys sorted alphabetically
- Build the message to sign:
{timestamp}.{serialized_json} - Compute an HMAC-SHA256 of this message using your
auth_tokenas the key - Prefix the result with
sha256=and compare it toX-Webhook-Signature
import hmacimport hashlibimport jsonimport time
SIGNATURE_PREFIX = "sha256="TIMESTAMP_TOLERANCE_SECONDS = 300
def sign_payload(secret: str, payload: dict, timestamp: int): """ Sign a webhook payload using HMAC-SHA256.
:param secret: The shared secret key :param payload: The payload as a dict :param timestamp: The Unix timestamp of the request :return: The hex signature prefixed with 'sha256=' """
dumped_payload = json.dumps( payload, separators=(',', ':'), sort_keys=True, )
message = f"{timestamp}.{dumped_payload}" signature = hmac.new( secret.encode(), message.encode(), hashlib.sha256 ).hexdigest()
return f"{SIGNATURE_PREFIX}{signature}"
def verify_signature(secret: str, payload: dict, signature_header, timestamp_header): """ Verify a webhook signature and reject stale requests.
:param secret: The shared secret key :param payload: The raw payload as a dict :param signature_header: The value of X-Webhook-Signature :param timestamp_header: The value of X-Webhook-Timestamp :raises ValueError: If the timestamp is stale or the signature is invalid """ request_time = int(timestamp_header) if abs(time.time() - request_time) > TIMESTAMP_TOLERANCE_SECONDS: raise ValueError("Request timestamp is too old")
expected = sign_payload(secret, payload, timestamp_header)
if not hmac.compare_digest(expected, signature_header): raise ValueError("Invalid signature")