Skip to content
pluginloom

Card testing

How card-testing limits work

Where ChargeWarden checks payments (classic checkout, Store API, pay for order), what it counts, the default limits, and how it works with WooCommerce's own Store API rate limiter.

Last updated by the PluginLoom team

ChargeWarden checks every place a card can be tried, counts attempts and failed payments per shopper, and blocks a shopper for a while when they reach a limit. Blocked shoppers see a neutral message and no payment is attempted.

Where does ChargeWarden check?#

Entry pointHow it is reachedHook ChargeWarden uses
Classic checkout?wc-ajax=checkout from the [woocommerce_checkout] pagewoocommerce_after_checkout_validation
Checkout block and direct API callsPOST /wp-json/wc/store/v1/checkoutrest_request_before_callbacks
Pay for order page/checkout/order-pay/{id}/woocommerce_before_pay_action
Store API pay for orderPOST /wp-json/wc/store/v1/checkout/{id}rest_request_before_callbacks
Add payment method (My account)Saved-card formwoocommerce_add_payment_method_form_is_valid

The Store API matters even if your store uses the classic checkout. WooCommerce's developer blog said on 18 December 2024 that it had seen "card attacks specifically targeting the Store API alone, even without the use of the Checkout block" (source (opens in a new tab)).

What counts as a failed payment?#

  • Classic checkout and pay for order: the order was created and the gateway did not return a successful payment result by the end of the request.
  • Store API: the response was a payment error (woocommerce_rest_checkout_process_payment_error or woocommerce_rest_payment_error) or the payment status was failure or error.
  • Later failures: an order a gateway marks Failed afterwards, for example from a webhook, using the identifiers saved on the order at checkout.

Form mistakes such as a missing address are not counted, because no payment was attempted.

What is counted, and how?#

IdentifierHow it is formedStored as
IP addressFrom the IP source you choose (direct connection by default)Keyed hash, plus a masked display value such as 203.0.113.x
NetworkThe /24 for IPv4 or the /64 for IPv6Keyed hash
EmailLower case, +tag removed, Gmail dots removedKeyed hash
BrowserA SHA-256 digest of coarse browser properties, made by the checkout scriptKeyed hash
CardBIN (first 6 digits) and last 4, only when the gateway exposes themKeyed hash
SessionThe WooCommerce session or Store API cart tokenKeyed hash

The keyed hash is HMAC-SHA256 with a secret unique to your site, so ChargeWarden can count repeats without storing who the shopper is.

What are the default limits?#

RuleCountsMaximumWindowThen
ip_failureFailed payments per IP510 minutesBlock 1 hour
subnet_failureFailed payments per network1210 minutesBlock 1 hour
email_failureFailed payments per email41 hourBlock 24 hours
device_failureFailed payments per browser51 hourBlock 6 hours
card_failureFailed payments per card31 hourBlock 24 hours
session_failureFailed payments per session310 minutesBlock 1 hour
ip_attemptAttempts per IP1510 minutesChallenge, or block 15 minutes
subnet_attemptAttempts per network4010 minutesChallenge, or block 15 minutes

Change any of them in Settings > Card testing > Limits. The Strict profile lowers each maximum and doubles block times; Relaxed doubles each maximum.

When is risk "elevated"?#

A shopper is elevated when any failure count is at least halfway to its limit, or an attempt count is past 60% of its limit, or attack mode is on. Elevated shoppers are asked for a challenge when you have a provider set up. Without a provider they continue until they reach a limit.

How does it work with WooCommerce's own rate limiting?#

WooCommerce core has a Store API rate limiter, documented at Store API rate limiting (opens in a new tab) (checked 24 October 2026):

  • It is off by default. When on, the default is 25 requests per 10 seconds, set with the woocommerce_store_api_rate_limit_options filter.
  • Since WooCommerce 9.6, Settings > Advanced > Features > Rate limit Checkout limits POST /wc/store/v1/checkout to 3 requests per 60 seconds.
  • It tracks the user ID when logged in, otherwise the IP address, and since 9.8 accepts your own identifier through woocommerce_store_api_rate_limit_id.
  • It answers HTTP 429 and fires woocommerce_store_api_rate_limit_exceeded.

ChargeWarden does not replace it. The wizard offers to turn on "Rate limit Checkout", and ChargeWarden records every woocommerce_store_api_rate_limit_exceeded hit as "Rate limited (WooCommerce)" on the dashboard. Core has no rate limit on the classic checkout, which ChargeWarden covers.

Which gateways are counted?#

All of them, unless you list a gateway ID in Settings > Card testing > Gateways whose failures are not counted. Blocks still apply to excluded gateways. For example, list bankbridge_ach if you do not want failed bank payments to count toward card-testing limits.

Was this page helpful?