Two routes: a start route your frontend calls, and the GET landing route (your registered returnUrl) that reads the outcome back. There is nothing to receive — Authentica never calls you.
1. Configuration
2. Start verify — POST /verify/start
3. Landing route — GET /verify/done
The registered returnUrl. A plain GET — normal SameSite=Lax cookies arrive, no CSRF exemption needed, nothing secret on the URL. This is where the verification is finished.
session_id and state are inputs to a lookup, not evidence. Nothing is trusted until GET /session/{id} — authenticated with your client credentials — says so.
The status response also carries assertionExchanged. It is a legacy wire field — do not read it and do not branch on it.
4. The user who never came back
No redirect fires if the tab is closed. Sweep your own pending records inside the 24 h retention window and feed verified results through the same onVerified:
5. Connect the frontend
After your start route returns { verifyUrl, handoff }:
That is the whole frontend. The browser lands on /verify/done, and your server finds out what happened.
More: Session status · Frontend overview.