Passkey approvals
Above a threshold, settling needs a WebAuthn signature from a person.
Set passkey_threshold and any settlement at or above it stops mid-request and asks for a WebAuthn assertion before it completes.
{
"passkey_required": true,
"challenge": "…",
"scope": "resolve"
}How it interrupts
The first request to resolve an escalation above the threshold does not
settle. It returns the object above. Resubmit the same call with an assertion:
{
"resolution": "release",
"assertion": {
"challenge": "…",
"credential_id": "…",
"signature": "…"
}
}Only then does money move.
On a phone this is the fingerprint sensor, which is the point of approving from one — the escalation arrives as a notification, and the thing that authorises it is bound to the device in the reader's hand.
Three properties that make it worth having
The challenge is consumed on use. It is deleted in the same statement that
checks it, so a captured assertion cannot be replayed. A second attempt with the
same challenge gets 403 challenge_invalid.
Challenges expire. An expired one gets the same challenge_invalid, so a
stale approval sitting in a tab is not a standing authorisation.
The signature counter must advance. A passkey whose counter goes backwards
or fails to move is refused with 403 credential_replay. A counter that does
not advance is the signature of a cloned authenticator.
An API key can never satisfy this
Settlement endpoints refuse an API key outright with 403
user_session_required, before any threshold is consulted.
That ordering matters. If a key could settle, the threshold would only apply to people, and the way round it would be to use a key — which is not a threshold, it is a speed bump.
When it is not configured
If no assertion verifier is wired on the deployment, an above-threshold
settlement is refused with 403 passkey_unavailable. It is not waved
through.
Failing closed is the only defensible direction here: the alternative is a deployment where the threshold silently does nothing, and nobody finds out until the money is gone.
Enrolment
Settings → Security in the console. A person can hold several passkeys — one per device — and each is listed with when it was added and last used.
Register one before you need it. With no passkey enrolled, an above-threshold approval is blocked rather than waved through, which is correct and also unhelpful at the moment you are trying to pay somebody.
Amounts and the threshold
passkey_threshold is an integer of the asset's smallest unit, compared as an
integer.
"8400000" 8.40 USDC
8400000 rejected — a JSON number
"8.40" rejected — not the smallest unitA threshold you can drift past through floating-point rounding is not a threshold, which is why nothing in this comparison is ever a float.