Skip to main content

Troubleshooting: BINDING_REQUIRED / BINDING_MISMATCH on Verify

A “binding” is the association between a verification factor run and the device or token that must prove possession of it. Verify factors — passkey, flashcall, SNA, and the PSD2 SCA dynamic-linking binding on OTP sends — mint their challenge against a specific token, and the check will only pass when that same token is replayed on the verify call. A binding gate refuses the call at the 422 layer; it does not consume an attempt and it is not a transient failure — you fix the pairing, not retry. This page covers the two codes that surface the gate. The OTP-delivery and factor-enforcement gates that sit around them are on the Verify OTP and Verify factor suite pages.

What a binding is

A binding is the device/token association a factor run must carry across its full life — enroll → send → check. Each factor has its own canonical binding, and the gate rejects any run that loses it:
  • Passkey — the enrolled public key for the relying party. The verify challenge is issued against the enrollment; any other key, origin, or rpId mismatches the binding.
  • Flashcall / SNA — a device-bound network token. The SIM possession proof is anchored at send time, and /check must come back through the same device token.
  • PSD2 SCA dynamic-linking — the sca_binding object (amount, payee, optional transaction_id) you pass on POST /api/v1/verify/send. The send stores its hash; POST /api/v1/verify/check must replay the exact same object or it refuses.

BINDING_REQUIRED — a binding the route needs was not supplied

BINDING_REQUIRED fires when a binding-bearing route is called without its binding. The two shapes: A legacy row — one minted before the binding gate existed, or one you sent without a binding — carries no stored hash and passes /check unchanged. The gate only arms when the send itself carried the binding. Sample envelope:

BINDING_MISMATCH — the replayed token does not match the stored one

BINDING_MISMATCH fires when a binding is supplied but does not match the one the verification was minted with. The common cause is a token that drifted between the send and the check: a regenerated device token, a different rpId or origin on the passkey ceremony, or a replayed sca_binding whose amount, payee, or transaction_id differs from what the send stored — even when the numeric value looks the same, a reformatted amount (10.5 vs 10.50) or a re-cased payee still hashes differently. The fix is the same in both cases: pass the stable token. For PSD2 SCA, store the exact sca_binding your server sent and replay it verbatim — never recompute it from a parsed copy, because the parse can normalize whitespace or key order and change the hash. For device tokens, reuse the same device identifier between factor runs; rotating the device id at the check stage trips the mismatch. For a passkey, keep the relying party (rpId, origin) identical between enrollment and verification. Sample envelope:
Both codes are deterministic: the gate rejects the same inputs identically every time, and it does not time out. Do not retry the same body — re-mint the verification with the stable token first, or drop the binding from the send if you do not actually need to link it.

Deterministic — do not retry without fixing the pairing

The binding gates are taxonomy-side honour codes. Fix the pairing once and the check passes; retry the same body and the gate keeps refusing. If you are deliberately not on the PSD2 SCA flow, omit sca_binding from /verify/send and the gate does not arm — but once a send carries one, every check against that row must carry it too.

See also