Hosted UI
Code entry, resend, passkey prompts, and your branding — on our hosted
verify page. You do not build or maintain a verification screen.
One call to start
POST /session from your backend returns sessionId, verifyUrl and a
single-use handoff token. Your client_id and secret stay on your server.One call to finish
GET /session/{sessionId} answers “what happened?” for 24 hours. Idempotent,
poll-safe, and the only place an outcome ever comes from.Nothing is pushed to you
No callback, no webhook, no signature to verify, no delivery log. Your server
asks; it is never told. There is no receiver route to build or defend.
Verify any action — not just login
A session is created for an action, and you decide what that action is. Nothing in the API is tied to a login screen, so the same calls work anywhere in your product:
Mount your start route wherever the action lives —
POST /auth/login, POST /payments/confirm, POST /profile/change-phone. The Authentica calls are identical every time; only your own surrounding logic changes.
What you integrate
Two routes. That is the whole of it.
Flow at a glance
- Your backend calls
POST /session→ receivessessionId,verifyUrland a single-usehandofftoken. Storestate+sessionIdagainst the action. - The browser auto-submits a hidden form:
POST verifyUrlwithhx=handoff. - The user completes verification on Authentica.
- The browser is redirected to your
returnUrlwith a plainGETcarrying?session_id=…&state=…. - Your landing route calls
GET /session/{sessionId}with Basic auth, checksstateanduserRefagainst its own record, and only then performs the action.
handoff token never travels in a URL, and nothing on the return URL is secret.
This is the OAuth authorization-code shape: an opaque reference on the front channel, redeemed over an authenticated back channel. Stripe Checkout’s
?session_id= and Adyen’s redirectResult work the same way. It is a pattern your security reviewer already knows.What you need before coding
- API base URL (
{BASE}) —https://authentica-merge-integration.t2.sa. Use this for/sessionand/session/{id}. Not your app URL. For the browser, use theverifyUrlfrom/sessionas-is (do not build it yourself and do not append anything to it). client_idandsecret— from the portal (the secret stays on the server).- One registered URL — your
returnUrl, the GET landing page, matched exactly as registered.

