On 1 September 2026 a customer of an Estonian online retailer finished a checkout. Inside that request the shop's server called Heatrail, and the answer came back in about a third of a second. The customer saw nothing of it, which is the whole point. Had the answer taken twice as long, or never arrived, the same confirmation page would have loaded at the same moment and the shop would simply have had no signal for that order. This article is about why that is a fact about the shape of the system rather than a promise about its uptime.
The property
Heatrail cannot stop, delay or cancel a purchase, because the capability does not exist. The response is data. If it does not arrive inside 800 ms, the shop's own client abandons the call and the order proceeds.
Why it holds
A removed capability, not a promise
Heatrail is called once per order, from the shop's server, at the moment the order is about to be handed to the payment provider. It answers with a score and a list of reasons. What it can do with that answer is nothing: there is no callback, no webhook that gates a payment, no configuration flag that turns advisory into enforcing, and no support request that produces one, because there is nothing to switch on.
The reasoning is short. A service that can stop a checkout eventually will, at the worst possible moment, for the wrong reason. Every such service is run by people who intend otherwise, and the intention is not what fails. What fails is a bad deploy on a Friday, a dependency that goes quiet, a rule that was right last quarter, or an operator under pressure from someone with leverage. A promise survives all of those only as long as everyone remembers it. An absent capability survives them without anyone remembering anything.
This is the reason the boundary is stated first in this library rather than last. Everything else Heatrail does is a claim about accuracy, and a claim about accuracy is worth having only from something that cannot act on being wrong.
The budget is on the shop's side of the wire
The 800 ms budget is enforced inside the shop's own process, by the plugin and the SDK, and not by anything we run. Past the budget the client abandons the request, puts the payload on a local retry queue and returns control to the checkout, which then does what it would have done anyway.
The consequence is worth being explicit about, because it inverts the usual vendor relationship. Heatrail being slow is not a problem Heatrail has to solve before the shop is safe. By the time we could notice, the client has already stopped waiting. Our availability is a question about how much signal a shop gets, never a question about whether it can sell.
One detail follows from that. The SDK refuses a zero timeout at construction, because the underlying HTTP client reads zero as no timeout at all, and a shop that configured zero while meaning unlimited patience would have removed the budget without noticing. It is rejected at construction rather than accepted and worked around later. Labelling behaves the opposite way on purpose: a check must never throw, and a label must never be silently lost, so a failed label raises an error the shop's queue can retry.
Figure 1
Degraded is a shape, not an error
When the budget runs out, when the host does not resolve, when the response is not a 2xx or the JSON is malformed, the client returns one fixed thing: ['degraded' => true, 'score' => 0, 'reasons' => []]. The zero is there because there is nothing to report, not because the order was assessed and cleared. Read degraded as no signal for this order. It never means low risk, and it is never an exception the checkout has to catch.
The numbers from the first day in production, 1 September 2026: a median round trip of 386 ms, a 95th percentile of 610 ms, and a slowest check of 799 ms against the 800 ms budget. Even the slowest check of the day came back inside the budget, and a check that had not would have cost that order its signal, not its sale.
The same day we ran the drill in staging: DNS resolution for the Heatrail host was broken deliberately, the purchase completed, and the check returned degraded in 16 ms, then drained from the queue when service returned. Sixteen milliseconds is not a measure of how fast we are. It is the cost of a client deciding, on its own, that it is not going to wait.
The three latency figures are production measurements. The 16 ms figure comes from a staging drill. Availability here decides how much signal a shop receives, never whether its checkout works.
Figure 2
Verify it
Read the client rather than this page. The timeout is a constant in the public SDK and the degraded response is a fixed array, so both claims are two greps away from being settled in your own checkout.
grep -n "DEFAULT_TIMEOUT_MS" src/HeatrailClient.php
grep -n "'degraded' => true" src/HeatrailClient.phpThen run the drill we ran. Point the SDK at a hostname that does not resolve and complete a test purchase. The order completes, the check returns degraded, and the payload waits in the local queue. If any part of that does not happen in your integration, it is a bug and we want to hear about it.
Legal footing
Because no decision is taken by Heatrail, and no legal or similarly significant effect on the buyer follows from the response alone, the response is not a decision within Article 22 GDPR. The shop's own handling of the score, by a person or by the shop's own rules, is where any decision is made, and the shop remains the controller for it. See the data processing agreement and the security model.
Related
- Reasons you can read, on what the response carries instead of a verdict, and who is meant to read it.
- Why the network cannot be enumerated, on the other half of the boundary: a call that can only be made about an order the shop actually has.
- The PHP SDK, where the budget, the queue and the degraded shape are code you can read.