Passer au contenu

How to Fix a Failed Crypto Payment Webhook Signature

Learn how to fix a failed crypto payment webhook signature by checking the secret, raw body, timestamp, headers, and server clock.

Payora10 min readEN · RU · UK · ES · DE
How to Fix a Failed Crypto Payment Webhook Signature

How a Webhook Signature Check Works

A webhook signature is a short proof that the event came from the payment provider and not from some random POST request. The provider signs the payload with a shared secret or private key, then your app verifies that signature before trusting the event. If the signature fails, the safest response is a 401 or 400 and no order update.

That sounds simple. It rarely is.

In practice, the signature check protects you from spoofed invoices, fake refunds, and tampered payloads that look legitimate at first glance. A webhook that says “payment completed” is not useful if anyone can forge it. For teams using a crypto payment gateway for ecommerce guide, this check sits right between payment acceptance and order fulfillment, which is why one bad assumption can stop the whole flow.

Most providers sign either the full raw body, a timestamp, or both. Some use HMAC-SHA256, others use a versioned header with several signature values. One mismatch is enough. The provider may be right and your app may still reject the event if you altered even one byte.

First, Confirm the Failure Is Actually Signature-Related

Logs should answer this in under 5 minutes. If they do not, they are not detailed enough.

Start with the exact response code and error text. A 400 with “invalid signature” points one way; a 500 or timeout points another. Delivery failures, bad routes, TLS errors, and proxy timeouts can all look like webhook problems from the dashboard, but they are not the same problem. If the provider shows “delivered” and your endpoint returns 200, signature verification is probably not the source of the break.

Check three things together: the provider’s delivery log, your application log, and the reverse proxy log if you have one. A request that never reaches your code cannot fail a signature check. A request that reaches your code but returns 401 usually can. One detail matters here: if you see the event in logs but no signature error, your code may be rejecting the payload later, after the verification step.

Short answer: confirm the symptom before changing code.

Check the Shared Secret or Signing Key

This is the most common mistake, and it is boring enough to be dangerous. The webhook secret in your application must match the current secret in the payment dashboard exactly, including any hidden spaces copied from a text field. If the provider rotated the secret last Tuesday, the old key will still be sitting in your environment unless someone updated it.

Compare the secret in the dashboard with the one in your deployment environment, not just your laptop. Production, staging, and local development should each have their own value. A team that copies a test secret into production can spend 2 hours chasing a signature failure that was caused by one pasted string. That kind of issue is common during launch work and during migrations from one processor to another. For teams using the crypto payment gateway for ecommerce guide, secret mismatches often show up right after a new checkout release.

Keep old keys only if the provider supports key rotation with overlap. If both the old and new key are valid for a short window, your verifier should try the active key first and then the previous key. If the provider does not support overlap, remove the old one from every environment. No guessing.

Rebuild the Raw Request Body Exactly as Received

This is where many good implementations fail. Signature checks usually depend on the exact raw bytes the provider sent, not the JSON object your framework produced after parsing. If your code converts numbers, reorders fields, strips whitespace, or normalizes line endings, the computed signature can change even though the payload “looks” identical.

Some frameworks read the body once and then discard the original stream. Others auto-parse JSON before your middleware runs. That means the verifier receives a reconstructed object, not the raw body. The fix is usually to capture the untouched payload first, then pass that exact buffer to the signature verification function. One framework setting can decide whether the body is preserved or rewritten.

For example, a payload with 14 fields may arrive in a particular byte order that your code never sees if the parser sorts keys. A trailing newline can matter. A single UTF-8 conversion can matter. Yes, one invisible character can break the whole check.

If your stack supports it, log the body length and a hash of the raw request body before parsing. Do not log secrets. Do log the exact code path that reads the stream. That makes it much easier to trace why how to test a crypto payment sometimes passes in Postman but fails under a real provider webhook.

Validate Timestamp, Clock Sync, and Replay Protection

Many webhook schemes include a timestamp so old events cannot be replayed later. Your verifier may reject a request if the timestamp falls outside a tolerance window, often 5 minutes or another provider-defined limit. That protects against replay attacks, but it also means your server clock must be correct.

Check the system clock on every server handling webhooks. If the clock drifts by 3 minutes, the signature may fail even when the payload is correct. If the server runs in a container, verify the host time too. NTP or another time-sync service should be active on the machine that makes the verification decision. A server that is 10 minutes off can turn a valid webhook into a false failure.

Replay protection matters here as well. If your code caches seen signatures or event IDs, make sure the cache TTL matches the provider’s expected replay window. A stale cache entry can cause a valid repeated delivery to be rejected. One provider retry is not the same as a malicious replay, so the code should understand both cases. This is a small detail with large consequences.

Make Sure the Signature Header Is Parsed Correctly

Signature headers are not all shaped the same. Some providers send one header with a single hash, while others send a comma-separated list of key-value pairs, a version label, and a timestamp. Your parser needs to match that exact format. If it expects v1= and the provider sends t= plus multiple versions, the check will fail before the cryptography even starts.

Watch for trimming mistakes. Leading or trailing spaces matter. So do encoding errors when a framework decodes headers as Latin-1 instead of UTF-8. A stray newline copied into an environment variable can cause the comparison to fail. Do not normalize the header unless the provider says you may. Do not lowercase a value that is meant to be binary-safe. Those two lines cause more pain than they should.

Multiple schemes also need careful handling. Some providers publish a current signature and a previous one for transition periods. Your verifier should know which version it is using and reject unknown versions cleanly. If the header includes both a timestamp and a signature, verify both. If the provider documents a signing prefix, use it exactly as written. For more on secure webhook handling, see crypto payment security best practices.

Test With a Known Good Webhook Event

A known good event saves time. Resend one from the provider dashboard or use a documented sample payload and compare the expected signature to the one your code computes. If the sample verifies but live traffic does not, the issue is probably config, environment, or secret rotation. If neither verifies, the code path is wrong.

Use one event ID and one timestamp. Then compare four things: raw body, header value, secret, and clock. That is enough to isolate most failures. A test payload that was copied into a local file may include formatting your real endpoint never sees, so always prefer the provider’s resend tool when it exists. One resend is better than 20 guesses.

If the provider offers a signature calculator, run the same payload through it. If your output differs by even one character, you have a parsing or body-preservation issue. If the output matches but the provider still rejects the request, the secret or header parsing is wrong. That split tells you where to look next.

This is also the point where staging and production should be separated cleanly. A staging event sent to a production secret will fail every time, and the failure will look identical to a broken signature until you check the environment label.

Harden and Monitor the Webhook Endpoint

Once the signature check works, keep it working. Log the event ID, the verification result, the provider name, and the environment name. Do not log the full secret. Do not log the full raw body if it contains sensitive customer data. Use a short, readable error message for operators and a plain rejection for the provider.

Rotate the webhook secret on a schedule and document the handoff. A 2-step rotation process is safer: add the new key, confirm both keys work if overlap is supported, then remove the old one. Separate test and production endpoints so a staging mistake does not touch live orders. That sounds obvious; teams still mix them up.

Alert on a burst of signature failures, not on a single failed attempt. One failure may be a bad retry. Five failures in 1 minute deserves attention. Include the route, provider, and response code in the alert so the on-call person can tell whether the issue is a secret mismatch, a parser bug, or a clock problem. If you are still setting up the endpoint, the how to set up crypto payments article can help you keep the webhook path simple from the start.

Last point: keep a small runbook with the exact steps for how to fix a failed crypto payment webhook signature, including where the secret lives, how to resend one event, and which log line confirms verification. A 10-line runbook saves an hour at 2 a.m.

Comments

Ready to get started?

Create an account and have your first invoice running in under an hour.

Ce que cette page répond