Authentica Verify replaces the OTP you would otherwise build. Delete the code generator, the code store, throttling and retry limits, resend logic, the SMS provider contract, and the verification screen — all of it becomes two API calls. It answers one question: did this person just prove it is them? How they prove it is our problem, not yours. Today that is an SMS one-time code, or a passkey when the user has one enrolled — and your backend can force the code for high-risk actions. Because the method is ours to choose, stronger ones can be added without you changing a line. You keep your own users and your own business logic. You call us when an action needs verifying, we host the verification UI, and your server reads the outcome back over an authenticated channel whenever it wants. Your backend never talks to an SMS provider and never stores a code.

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.
Your backend sets operationSensitivity per action to say how risky it is — see Create session.

What you integrate

Two routes. That is the whole of it.

Flow at a glance

  1. Your backend calls POST /session → receives sessionId, verifyUrl and a single-use handoff token. Store state + sessionId against the action.
  2. The browser auto-submits a hidden form: POST verifyUrl with hx=handoff.
  3. The user completes verification on Authentica.
  4. The browser is redirected to your returnUrl with a plain GET carrying ?session_id=…&state=….
  5. Your landing route calls GET /session/{sessionId} with Basic auth, checks state and userRef against its own record, and only then performs the action.
The 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.
Sequence diagram and edge cases: How it works. Frontend handoff: Frontend overview.

What you need before coding

  1. API base URL ({BASE})https://authentica-merge-integration.t2.sa. Use this for /session and /session/{id}. Not your app URL. For the browser, use the verifyUrl from /session as-is (do not build it yourself and do not append anything to it).
  2. client_id and secret — from the portal (the secret stays on the server).
  3. One registered URL — your returnUrl, the GET landing page, matched exactly as registered.
Full checklist: Get your credentials.
Have your credentials? Go to the Quickstart and wire the end-to-end flow.