How Webhook Callbacks and Signature Verification Work in Payment Processing
What a webhook callback signature does in payment processing
A webhook callback signature is a security code that a payment processor sends along with a notification to prove the message actually came from them and hasn't been altered in transit. When you use a payment API—like the one offered by a processor handling USDT or other digital assets—the processor needs to tell your system when a payment arrives, fails, or completes. Instead of your system constantly asking "did a payment come in yet?", the processor sends an automatic notification (the webhook) to a web address you provide. That notification includes a signature: a unique string of characters generated using a secret key that only you and the processor know.
Your job is to verify that signature before trusting the message. If someone tries to forge a payment notification or intercept and change one, the signature won't match, and you reject it. This prevents fraud where an attacker could trick your system into thinking a payment arrived when it didn't, or that a smaller payment was actually larger.
Key Takeaways
- A webhook signature proves a payment notification came from your processor and wasn't changed after being sent.
- The processor creates the signature using a secret key shared only with you; you recreate it on your end to verify the message matches.
- If the signature you calculate doesn't match the one the processor sent, reject the notification and do not process the payment.
- Most processors publish the exact algorithm and the exact order of data to use when calculating the signature, and following those steps precisely is critical.
- Store your secret key securely—never commit it to public code repositories or share it with anyone outside your payment team.
How the signature verification process works step by step
The processor sends your system a webhook notification containing payment data (amount, transaction ID, timestamp, status) and a signature. Your code receives both. You then recreate the signature yourself using the same secret key and the same data the processor used. If your calculated signature matches the one in the notification, the message is authentic. If it doesn't match, you reject it.
The exact steps depend on your processor's documentation. Most use HMAC-SHA256 (a standard cryptographic algorithm), but some use HMAC-SHA1, SHA256, or another method. Your processor will tell you which one, and they will also specify the exact format of the data to sign—for example, whether to use the raw JSON body, a concatenated string of specific fields in a specific order, or something else. Skipping this step or guessing the format will cause your signature to never match, and you'll reject all legitimate payments.
Here is the typical flow: (1) Processor sends webhook to your URL with a JSON body and a signature header. (2) Your code reads the body and the signature. (3) Your code recreates the signature by hashing the body with your secret key using the processor's specified algorithm. (4) Your code compares the two signatures. (5) If they match, you process the payment. If they don't, you log the mismatch and reject the notification.
Where to find your secret key and API credentials
Your processor provides a secret key (sometimes called a webhook secret, signing secret, or API secret) when you set up your account or create an API key. This key is usually shown once in your merchant dashboard, often under a section labeled "API Keys", "Webhooks", "Security", or "Developer Settings". Write it down immediately—most processors don't show it again, and you'll need to regenerate it if you lose it.
Never paste your secret key into code that gets committed to GitHub, GitLab, or any public repository. Never email it or share it with contractors or team members who don't absolutely need it. Store it in an environment variable on your server, in a secrets management tool (like AWS Secrets Manager or HashiCorp Vault), or in a configuration file that is not version-controlled. Your payment processing code reads the key from that secure location at runtime.
If you suspect your secret key has been exposed, regenerate it immediately in your processor's dashboard. Any webhooks signed with the old key will fail verification after you do this, so coordinate the change during a maintenance window if possible.
Common mistakes that break signature verification
The most common error is using the wrong data to calculate the signature. Your processor specifies exactly what to hash—often the raw request body as a string, not a parsed JSON object. If you parse the JSON, reorder the fields, or add whitespace, the hash will be different from what the processor calculated, and verification will fail. Read your processor's documentation word for word and test with a sample webhook before going live.
Another frequent mistake is using the wrong algorithm or the wrong secret key. Double-check that you're using HMAC-SHA256 (or whatever your processor specifies), not plain SHA256 or a different algorithm. Verify that you're reading the secret key from the correct environment variable or configuration file, not a hardcoded string or a different key.
A third mistake is not handling the signature header correctly. Some processors send it in a header called X-Signature, others use Signature, X-Webhook-Signature, or something else. Check your processor's documentation for the exact header name and read it case-insensitively (HTTP headers are case-insensitive by spec, but some frameworks handle them differently).
Testing your webhook signature verification before going live
Most payment processors provide a way to send test webhooks from your merchant dashboard. Use this feature to send a test notification to your webhook URL and verify that your code correctly validates the signature. Your processor will usually show you the exact payload and signature they sent, so you can also manually test your verification code in isolation.
Write a small test script that takes the sample payload and signature from your processor, runs your verification code against it, and confirms it returns "valid". Then modify the payload slightly (change one character) and confirm your code rejects it. This confirms your algorithm is correct before you deploy to production.
If your processor offers a webhook simulator or sandbox environment, use it. Send test payments through the sandbox, watch the webhooks arrive at your system, and confirm your code processes them correctly. Only after this works should you enable webhooks in your live environment.
What to do if a webhook signature fails verification
When a signature doesn't match, log the event with full details: the timestamp, the notification body, the signature received, the signature you calculated, and the webhook URL. Do not process the payment. Do not update your database. Do not send a confirmation to the customer. Simply reject it and alert your team.
A failed signature can mean several things: your code has a bug, your secret key is wrong, the processor's system is sending malformed data, or someone is trying to forge a notification. Check your logs and your code first. If you recently rotated your secret key, confirm that your live environment is using the new one. If everything looks correct on your end, contact your processor's support team with the full webhook details and ask them to investigate.
Some processors allow you to retry failed webhooks from the dashboard. After you fix the issue, you can ask them to resend the notification so your system can process it. Others require you to manually query the processor's API to check the payment status if a webhook is lost or rejected.
Securing your webhook endpoint and secret key in production
Your webhook URL should only accept POST requests from your processor's IP addresses or domains. Check your processor's documentation for their IP range or domain and configure your firewall or load balancer to reject requests from anywhere else. This prevents random people on the internet from sending fake webhooks to your endpoint.
Use HTTPS (not HTTP) for your webhook URL. Your processor should support this, and it encrypts the notification in transit so no one can read or modify it on the network. Verify that your SSL certificate is valid and up to date.
Never log the full secret key, even in debug mode. If you need to log webhook activity for troubleshooting, log the signature and the payload, but mask or omit the secret key. Rotate your secret key periodically (every 90 days is common) and keep an audit trail of when keys were created and rotated.
Frequently Asked Questions
What if my processor doesn't send a signature with the webhook?
Some processors do not sign webhooks, which is a security weakness. If yours doesn't, ask them to add signature support. In the meantime, you can verify the webhook came from them by checking the source IP address against their published IP range, but this is less secure than cryptographic verification. Do not process unsigned webhooks without additional verification.
Can I use the same secret key for multiple webhook endpoints?
Yes, but it's safer to use a separate key for each endpoint. If one endpoint is compromised, an attacker can only forge webhooks for that endpoint, not all of them. Most processors let you create multiple API keys or webhook secrets, so use that feature.
What does HMAC-SHA256 mean?
HMAC stands for Hash-Based Message Authentication Code. SHA256 is the hashing algorithm. Together, HMAC-SHA256 takes your secret key and the message data, runs them through a mathematical function, and produces a unique fixed-length string. The same key and data always produce the same output, but changing even one character of the data or key produces a completely different output. This is what makes it useful for verification.
How long should my secret key be?
Your processor generates the key, so you don't choose its length. Most processors generate keys that are 32 to 64 characters long. Treat whatever length they give you as the correct one and don't try to shorten or modify it.
What if I need to change my webhook URL?
Update the URL in your processor's dashboard under your webhook settings. The processor will start sending notifications to the new URL immediately. Make sure the new endpoint is live and can verify signatures before you make the change, or you'll start rejecting all webhooks. Test with a sample webhook first.