The integration contract
before you request access
Two things decide whether your integration works: what your payload has to hash to, and which of the two authorization paths an action takes. Both are on this page. The reference documentation, endpoints and SDK packages are delivered with SDK access.
How do you integrate the Yuthent SDK?
Your app calls the SDK with an actionType, actionContextId, and riskLevel. The device verifies the human and returns a signed proof. Biometric data never leaves the device. Your backend verifies the ACK with Yuthent and executes only on success. One SDK call client-side, verify the ACK server-side. A thin layer.
What You Build with Yuthent
Yuthent goes beyond login. It is action-level human verification with signed proof your backend can trust.
Protect Any Action
Login, account recovery, privileged admin actions, approvals, transfers. Not just authentication. Action authority.
Proof Bound to Context
Every approval is tied to a specific action context (actionContextId). Proof cannot be replayed for a different action.
Your Backend Enforces
Your server verifies the proof and decides whether to execute. The app is never the source of truth.
How Integration Works
Four steps from action request to backend enforcement. Your app collects approval. Your server enforces it.
Request Approval
Your app calls the SDK with an actionType, actionContextId, and riskLevel. No PII required.
On-Device Verification
The SDK verifies the human on-device and produces a signed proof bundle. Biometric data never leaves the device.
Backend Verification
Your backend sends the proof reference to Yuthent Cloud and receives a verified decision (ACK or REJECT).
Execute or Block
Your backend executes the action only after verification succeeds. Your server stays the enforcement point.
No biometric data leaves the device at any step.
ACTION_BINDING_INVALID is the contract
You send the action payload with the proof. If what you send does not hash to what the device signed, verification returns ACTION_BINDING_INVALID and you do not execute. That is the whole integration rule, and it is the one error worth writing a test for before you ship.
Two ways to trip it
You mutated the payload between signing and verifying, even by a whitespace-insignificant re-serialize that changes a value. Or you did not send the payload at all. Both return the same code, because from the verifier’s side they are the same failure: it cannot confirm what the human saw.
You cannot turn it off
At Authoritative tier the check is unconditional. Two earlier modes, one advisory and one that skipped the payload, were removed, and there is no tenant setting that restores either. If you are migrating from an integration that relied on one of them, this is the error you will meet first.
It is the same hash on every platform
Android, iOS and the server produce byte-identical canonical bytes from the same payload, held by one golden vector file that ships into all three test suites. You do not need a per-platform branch, and a mismatch is a bug in your payload rather than a difference between the SDKs.
Policy-Driven Escalation
Your backend policy engine sets the riskLevel per action, and that selects the P/S/E/A tier the SDK enforces. The tier determines how the proof is validated, and whether the action waits on the network.
Offline-Capable
Approvals are produced on-device and queued. Your backend syncs the proof later and audits it. Connectivity is not required at action time. HIGH lands on the Explicit tier: the signed proof and the monotonic counter carry the guarantee, so the action completes locally and the proof syncs within the grace window.
Example: clock-in, field approvals, card-not-present, moderate-value transfers
Real-Time Required
CRITICAL is the only level that blocks on the network. It lands on the Authoritative tier, where the synchronous server co-signature is the security boundary, so your backend must verify with Yuthent Cloud before executing. Offline, a CRITICAL action is refused rather than queued.
Example: login, high-value transfers, new beneficiary, account recovery
Not every authorized action produces a press
If you build assuming a human is challenged every time, you will build the wrong contract and it will fail the first time a customer issues a standing mandate. There are two paths to a valid authorization and your client has to handle both.
Per action
Your policy sets a riskLevel, that selects the tier, and at Explicit or Authoritative the human is challenged for that action. You get a signed proof back and you verify it before executing. This is the path the rest of this page describes.
Under a standing mandate
The human signed the bounds once, in a sealed ceremony: which action types, up to what ceiling, until when. Inside those bounds the action is authorized without interrupting anyone. Nobody is challenged, and that is the design rather than a gap in it.
On the mandate path you ask before you act, and you handle three answers.
Within bounds. The response carries an ES256 authorizationJws over the tenant, subject, mandate, action type and amount, plus the mandate id and a nonce. No press happened and none is coming. Verify the JWS and proceed.
A bound was exceeded, or an oversight actor demanded review. No JWS is issued on this branch. You escalate into the normal sealed ceremony, triggerAction with a mandate context, and the per-action path above takes over from there.
Terminal, with a reason of MANDATE_REQUIRED when no mandate covers the action, or MANDATE_REVOKED when the one it named has been revoked. This does not escalate and it does not retry. The action fails.
The failure worth designing against is the third one. A revoked mandate fails the next call rather than the next token refresh, so an action that worked a moment ago can stop working with no change on your side. Treat MANDATE_REJECTED as a real state in your flow, not an error to retry.
We Don't Need Your Business Data
Biometrics Stay On-Device
Biometric data is never transmitted. Your backend sees decisions and proof references, not biometrics.
Context IDs, Not PII
Payloads use actionType, actionContextId, and riskLevel. No user names, emails, or transaction amounts.
Minimal Payload
The SDK sends only what is needed for verification. Your business logic and user data stay in your system.
For Existing Customers
Already a customer? Use the customer portal for API keys, environments, and monitoring.
Ready to Integrate?
We work directly with engineering teams building security-critical applications. Request SDK access and start a first deployment.