Payment Verification Failed
payment_verification_failed400
The payment signature didn't verify against our processor. The transaction was not completed and no charge was made.
What this means
A payment came back from the processor (Dodo) and we attempted to verify its signature before activating the subscription. The signature didn't match — either because the payload was tampered with, the request was crafted incorrectly, or there's a configuration mismatch between client and server expectations. We refuse to honor unverified payments, so no plan was activated and no charge will be captured.
When you'll see this
- A custom client is constructing the payment verification request manually and miscomputing the signature.
- The processor's webhook payload arrived with an unexpected shape (rare — usually a processor-side change).
- An attempt was made to replay an old payment confirmation against a new order ID.
- The processor's signing key on our side is out of sync after a rotation.
Learn more about how this works
Every payment confirmation includes a signature derived from the order details plus a shared secret known only to us and the processor. We recompute the signature on receipt and compare. If it doesn't match, we treat the entire payment as untrusted — the safest assumption when signatures don't line up is to assume tampering and refuse the transaction.
In practice: almost nobody hits this in normal operation. The official Asterwise checkout flow handles signature verification automatically. This error surfaces mostly during custom integrations or when teams try to "skip ahead" in the payment flow with their own signing logic.
Example response
{
"success": false,
"error": "payment_verification_failed",
"message": "Payment signature verification failed.",
"details": [],
"retry_after": null,
"doc_url": "https://docs.asterwise.com/reference/errors/payment_verification_failed",
"request_id": "req_01HXYZABCDEFGH",
"timestamp": "2026-05-25T12:34:56Z"
}
- Don't retry the same payment payload — the signature won't get better with repetition.
- Start a fresh checkout from asterwise.com/dashboard and complete the flow through the official UI.
- If you're building a custom integration, double-check your signature computation against the processor's documentation — most commonly, the order_id or amount used to compute the signature doesn't match what's in the verification request.
This isn't a transient error. Don't retry. Log the request_id, surface a clear "payment couldn't be verified, please try again" message to the user, and route them back to checkout.
Python:
Production handler
- Python
- TypeScript
import httpx
import logging
logger = logging.getLogger(__name__)
class PaymentVerificationError(Exception):
"""Payment signature didn't verify. No charge was made."""
def verify_payment(payload, base_url, headers):
response = httpx.post(
f"{base_url}/v1/billing/verify",
headers=headers,
json=payload,
timeout=15,
)
if response.status_code == 400:
body = response.json()
if body.get("error") == "payment_verification_failed":
logger.error(
"Payment verification failed",
extra={"request_id": body.get("request_id")},
)
raise PaymentVerificationError(
"Payment couldn't be verified. Restart checkout."
)
response.raise_for_status()
return response.json()
class PaymentVerificationError extends Error {}
async function verifyPayment(
payload: unknown,
baseUrl: string,
headers: HeadersInit,
) {
const response = await fetch(`${baseUrl}/v1/billing/verify`, {
method: "POST",
headers,
body: JSON.stringify(payload),
});
if (response.status === 400) {
const body = await response.json();
if (body.error === "payment_verification_failed") {
console.error("Payment verification failed", {
request_id: body.request_id,
});
throw new PaymentVerificationError(
"Payment couldn't be verified. Restart checkout.",
);
}
}
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.json();
}
Avoid this error by
- Use the official Asterwise checkout flow on the dashboard. It handles signature verification end-to-end without manual signing.
- If you're building a custom payment integration, test signature computation against documented test fixtures before going to production.
- Never store or replay payment verification payloads — they're single-use by design.
- After a payment completes, refresh the user's subscription state from the API rather than trusting client-side payment status.