Guide to Solidgate Webhooks: Features and Best Practices
Solidgate webhooks notify your systems about payment activity: an order updates, a chargeback is received, a subscription changes. If you're building payments on Solidgate, webhooks are how you react to these events without polling.
This guide covers how Solidgate webhooks work, the events you'll handle, its unusual signature scheme (get this exactly right), the retry behavior, and the best practices for production.
What are Solidgate webhooks?
Solidgate webhooks are HTTP POSTs delivered to endpoints you configure. Each carries two headers: merchant (your webhook public key, prefixed wh_pk_) and signature (the computed signature). The signature scheme is unusual and easy to get wrong, so the securing section below is the part to focus on.
Solidgate webhook features
| Feature | Details |
|---|---|
| Configuration | Solidgate Hub: keys under Developers; endpoints/events under Developers > Channels |
| Headers | merchant (public key, wh_pk_), signature |
| Signature scheme | base64(hex(HMAC-SHA512(secretKey, publicKey + rawBody + publicKey))) |
| Keys | wh_pk_ (public) / wh_sk_ (secret) |
| Retries | 8 attempts: 15m, 30m, 1h, 2h, 4h, 8h, 16h, 24h |
| Acknowledgement | 2xx within 30 seconds |
| SDK | @solidgate/node-sdk, solidgate-sdk (no dedicated webhook-verify helper) |
Common events
Solidgate event names are dotted and product-scoped:
| Event | Fires when |
|---|---|
card_gate.order.updated | A card order updates |
card_gate.chargeback.received | A chargeback is received |
alt_gate.order.updated | An alternative-payment order updates |
subscription.updated.v2 | A subscription updates (the .v2 suffix is real) |
Subscribe to the events you process, and consult Solidgate's webhook reference for the full list.
Setting up Solidgate webhooks
Set your webhook keys in Solidgate Hub > Developers, and configure endpoints and events under Developers > Channels. Each delivery carries the merchant (public key) and signature headers you verify with.
Securing Solidgate webhooks
The scheme has a distinctive double-encode. Construct text = publicKey + rawBody + publicKey, compute HMAC-SHA512(secretKey, text), take the hex string of that digest, then base64-encode the hex string (not the raw digest bytes). Compare the result to the signature header. Use the secret key (wh_sk_) and the exact raw body.
const crypto = require("crypto");
const SECRET_KEY = process.env.SOLIDGATE_WEBHOOK_SECRET_KEY; // wh_sk_
function verify(rawBody, publicKey, signature) {
const text = publicKey + rawBody.toString() + publicKey;
const hex = crypto.createHmac("sha512", SECRET_KEY).update(text).digest("hex");
// base64 of the HEX STRING, not the raw digest bytes
const expected = Buffer.from(hex).toString("base64");
const a = Buffer.from(expected);
const b = Buffer.from(signature || "");
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
const publicKey = req.headers["merchant"];
if (!verify(req.body, publicKey, req.headers["signature"])) {
return res.sendStatus(401);
}
res.sendStatus(200); // acknowledge within 30s
processQueue.add(JSON.parse(req.body)); // process asynchronously
});
The same in Python (matching Solidgate's official example):
import base64
import hashlib
import hmac
import os
SECRET_KEY = os.environ["SOLIDGATE_WEBHOOK_SECRET_KEY"].encode() # wh_sk_
def verify(raw_body: bytes, public_key: str, signature: str) -> bool:
text = (public_key.encode() + raw_body + public_key.encode())
hmac_hash = hmac.new(SECRET_KEY, text, hashlib.sha512).digest()
# base64 of the hex string (Solidgate's official construction)
expected = base64.b64encode(hmac_hash.hex().encode("utf-8")).decode("utf-8")
return hmac.compare_digest(expected, signature or "")
Solidgate webhook limitations and pain points
The double-encode is easy to get wrong
The Problem: The signature is base64(hex(HMAC-SHA512(...))), base64 of the hex string, not base64 of the raw digest bytes. And the signed text wraps the body in the public key (publicKey + body + publicKey). Almost every "obvious" implementation (base64 of the digest, or signing the body alone) fails.
Why It Happens: Solidgate's official construction double-encodes and brackets the body with the public key.
Workarounds:
- Follow the construction exactly:
text = pk + body + pk, HMAC-SHA512 withwh_sk_, hex, then base64 the hex string.
How Hookdeck Can Help: Hookdeck verifies the Solidgate signature at the edge, so your application receives pre-verified events without reproducing the double-encode.
Raw body sensitivity
The Problem: The body is wrapped into the signed text verbatim, so any re-serialization breaks verification.
Why It Happens: The signature is over the exact raw body between the two public-key copies.
Workarounds:
- Capture the raw body and verify before parsing.
How Hookdeck Can Help: Hookdeck verifies against the bytes as received, so your app never has to preserve the raw body.
No SDK verify helper
The Problem: The official SDKs exist but don't ship a dedicated webhook-verification helper, so you implement the scheme yourself.
Why It Happens: The SDKs target the payment APIs, not webhook ingestion.
Workarounds:
- Use the constant-time implementation above, centralized in one place.
How Hookdeck Can Help: Hookdeck verifies the signature at the edge, so your app receives pre-verified events without hand-rolled crypto.
Retries and duplicates
The Problem: Solidgate retries 8 times (15m through 24h), so the same event can arrive more than once, and double-processing a payment event is costly.
Why It Happens: At-least-once delivery favors eventual delivery.
Workarounds:
- Dedupe on an event/order id, make side effects idempotent, and confirm state via the API before releasing value.
How Hookdeck Can Help: Hookdeck deduplicates deliveries at the edge, so retries don't double-process. See our guide to webhook idempotency.
Best practices
Verify with the exact double-encode
text = pk + rawBody + pk, HMAC-SHA512 with wh_sk_, hex, then base64 the hex string; compare in constant time to signature.
Verify against the raw body
Capture the raw body so the wrapped signed text matches.
Acknowledge within 30 seconds, process asynchronously
Return 2xx quickly and defer work to a queue. See why to process webhooks asynchronously.
Dedupe and confirm before settling
Dedupe on an event/order id, and confirm payment state via the API before releasing value.
Make Solidgate webhooks production-ready
Hookdeck verifies the signature, deduplicates, and durably queues every payment event
Conclusion
Solidgate webhooks use an unusual signature: base64(hex(HMAC-SHA512(secretKey, publicKey + rawBody + publicKey))), delivered with merchant and signature headers. The double-encode and the public-key-wrapped body are the things to get exactly right; then verify against the raw body, dedupe across the 8-attempt retry schedule, and confirm state before releasing value.
Hookdeck verifies the signature, deduplicates, and durably queues every event at the edge, so your app only ever processes verified, unique payment events.
Get started with Hookdeck for free and handle Solidgate webhooks reliably in minutes.