Skip to main content

Authentication

Markdown

This guide walks you through authenticating with the Human Dashboard and generating the x-unico-accesskey you will use in all Human Token API requests.

The flow has two phases:

  1. Authenticate — complete a login and obtain an access token. Two authentication methods are available:
    • Biometric login — face capture via the Unico SDK (available for both signup and signin)
    • Email OTP login — one-time code sent to the registered email address (signin only)
  2. Set up your organization — create your company profile and generate an access key (first-time signup only)

Two ways to set up your credentials​

Everything in this guide can also be done through the Human Dashboard at dashboard.unico.app — no API calls required.

OptionWhen to use
DashboardFirst-time setup, manual key rotation, occasional management
APIAutomated provisioning, CI/CD pipelines, programmatic key management

Using the dashboard​

  1. Go to dashboard.unico.app
  2. Sign up or sign in — use biometric login (face capture) or email OTP
  3. Create your organization — fill in your company name, country, and allowed domains
  4. Generate an access key — go to Access Keys and click Create key; copy it immediately, it is shown only once
  5. Manage branches — create and configure branches under Branches; each branch generates its own access key

The access key you get from the dashboard is the same x-unico-accesskey used in all API requests — the two approaches are fully interchangeable.

Base URLs​

Every endpoint on this page is served by the Human Dashboard API. The Human Token API requests, such as Create Process and Get Process, go to the API host listed in Environments.

EnvironmentAPIBase URL
ProductionHuman Dashboard API (login, organization, access keys and branches)https://api.humantoken.unico.app

Authentication methods​

Two methods are available to authenticate and obtain an authToken:

MethodEndpointWhen to use
BiometricPOST /api/console/v1/auth/biometric/sessionsSignup (new account) or Signin (returning user)
Email OTPPOST /api/console/v1/auth/email/sessionsSignin only — account must already exist

Biometric login intent​

Every call to POST /api/console/v1/auth/biometric/sessions must declare an intent:

intentWhen to useemail fieldname field
LOGIN_INTENT_SIGNUPFirst-time registration — creating a new accountRequiredRequired
LOGIN_INTENT_SIGNINReturning user — account already existsNot usedNot used
(omitted)Treated as LOGIN_INTENT_SIGNINNot usedNot used

The intent controls the validation done when you poll the session (Step 2):

  • SIGNUP — rejects the login if that biometric identity is already registered (prevents duplicate accounts).
  • SIGNIN — rejects the login if that biometric identity is not registered (account must exist to log in).

Phase 1 — Authenticate​

Step 1: Start a biometric login session​

SIGNUP (first-time registration)

curl -X POST https://api.humantoken.unico.app/api/console/v1/auth/biometric/sessions \
-H "Content-Type: application/json" \
-d '{
"intent": "LOGIN_INTENT_SIGNUP",
"email": "[email protected]",
"name": "Jane Doe"
}'
Email uniqueness

If an account is already registered with that email, the request returns 400 Bad Request.

Response:

{
"session": {
"sessionId": "b3f1a2c4-0000-0000-0000-abcdef012345",
"link": "",
"token": ""
}
}

For SIGNUP, the link and token fields are empty in the response — the biometric capture link is sent to the provided email address.

SIGNIN (returning user)

curl -X POST https://api.humantoken.unico.app/api/console/v1/auth/biometric/sessions \
-H "Content-Type: application/json" \
-d '{
"intent": "LOGIN_INTENT_SIGNIN"
}'

Response:

{
"session": {
"sessionId": "b3f1a2c4-0000-0000-0000-abcdef012345",
"link": "https://humantoken.unico.io/...",
"token": "eyJhbGciOiJSUzI1NiJ9..."
}
}

Save the sessionId.

  • SIGNUP: the biometric capture link is sent to the email provided in Step 1. Ask the user to check their inbox and complete the capture.
  • SIGNIN: open link in your browser and complete the biometric capture.

Step 2: Poll until the session is resolved​

curl https://api.humantoken.unico.app/api/console/v1/auth/biometric/sessions/b3f1a2c4-0000-0000-0000-abcdef012345

Poll every 2–3 seconds until status reaches a terminal state.

statusoutcomeMeaning
pendingpendingUser has not completed the capture yet — keep polling
processingpendingCapture done, results being computed — keep polling
completedmatchedLogin successful — authToken is present
completedno_matchBiometric did not match any record
completedinconclusiveCapture succeeded but could not be resolved
expired—Link expired — restart from Step 1
canceled—Session was canceled — restart from Step 1

Additional intent-specific errors when polling the session:

HTTPCondition
400SIGNUP — biometric identity is already registered (duplicate account)
400SIGNIN — biometric identity is not registered (account does not exist)

Successful response:

{
"result": {
"sessionId": "b3f1a2c4-0000-0000-0000-abcdef012345",
"status": "completed",
"outcome": "matched",
"authToken": "eyJhbGciOiJSUzI1NiJ9..."
}
}

Save authToken — use it as the x-console-authorization header in all subsequent Human Dashboard API requests.

Phase 1 (alternative) — Email OTP signin​

Use this flow instead of biometric if the user already has an account and prefers to authenticate via a one-time code sent to their registered email. Signup is not supported via email OTP — use the biometric flow for first-time registration.

Step 1: Send the OTP​

curl -X POST https://api.humantoken.unico.app/api/console/v1/auth/email/sessions \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]"
}'
note

The email must belong to an existing account. If no account is found, Step 2 (validate the OTP) returns 404 Not Found.

Response:

{
"session": {
"sessionId": "b3f1a2c4-0000-0000-0000-abcdef012345"
}
}

Save the sessionId. A 6-digit code is sent to the provided email address.

Step 2: Validate the OTP​

curl https://api.humantoken.unico.app/api/console/v1/auth/email/sessions/{sessionId}/{code}
HTTPCondition
200Code is valid — authToken is present
400Code is wrong (invalid otp code)
400OTP already used, max attempts reached, or expired
404Email not registered

Successful response:

{
"result": {
"sessionId": "b3f1a2c4-0000-0000-0000-abcdef012345",
"status": "completed",
"outcome": "matched",
"authToken": "eyJhbGciOiJSUzI1NiJ9..."
}
}

Save authToken — use it as the x-console-authorization header in all subsequent Human Dashboard API requests.

Phase 2 — Set up your organization​

Step 3: Create your organization​

note

This call can only be made once. It provisions your tenant and generates your branchId.

Any country is accepted. Use the ISO 3166-1 alpha-3 three-letter code (e.g. BRA, USA, MEX, DEU, IND). taxId is optional for all countries.

curl -X POST https://api.humantoken.unico.app/api/console/v1/organization \
-H "x-console-authorization: <authToken>" \
-H "Content-Type: application/json" \
-d '{
"name": "Acme Corp",
"responsibleEmail": "[email protected]",
"websiteUrl": "https://acme.com",
"countryCode": "BRA",
"logo": "https://acme.com/logo.png",
"allowedDomains": ["https://app.acme.com"]
}'

Response:

{
"organization": {
"id": "e5d3f1a2-0000-0000-0000-abcdef012345",
"name": "Acme Corp",
"responsibleEmail": "[email protected]",
"websiteUrl": "https://acme.com",
"countryCode": "BRA",
"tenantId": "tenant-acme-prod",
"branchId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"taxId": "12345678000195"
}
}

Save branchId — it identifies your default branch and is used when managing branches and access keys.

Step 4: Create an access key​

curl -X POST https://api.humantoken.unico.app/api/console/v1/access-keys \
-H "x-console-authorization: <authToken>" \
-H "Content-Type: application/json" \
-d '{
"label": "production-key"
}'

Response:

{
"accessKey": "uip_ak.prod.a1b2c3d4.e5f6g7h8.i9j0k1l2"
}
warning

The accessKey is returned only once and cannot be retrieved again. Store it in your secrets manager immediately as HUMAN_TOKEN_ACCESS_KEY.

This value is the x-unico-accesskey header used in all Human Token API requests.

What you now have​

ValueWhere to use it
branchIdIdentifying your default branch; creating branch-specific access keys
accessKeyx-unico-accesskey header in all Human Token requests

Managing your organization​

Get organization​

curl https://api.humantoken.unico.app/api/console/v1/organization/<organizationId> \
-H "x-console-authorization: <authToken>"

Response:

{
"organization": {
"id": "e5d3f1a2-0000-0000-0000-abcdef012345",
"name": "Acme Corp",
"responsibleEmail": "[email protected]",
"websiteUrl": "https://acme.com",
"countryCode": "BRA",
"tenantId": "tenant-acme-prod",
"branchId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"taxId": "12345678000195"
}
}

Update organization​

curl -X PUT https://api.humantoken.unico.app/api/console/v1/organization \
-H "x-console-authorization: <authToken>" \
-H "Content-Type: application/json" \
-d '{
"id": "e5d3f1a2-0000-0000-0000-abcdef012345",
"name": "Acme Corp",
"responsibleEmail": "[email protected]",
"websiteUrl": "https://acme.com",
"countryCode": "BRA",
"taxId": "12345678000195",
"logo": "https://acme.com/logo-updated.png",
"allowedDomains": ["https://app.acme.com", "https://checkout.acme.com"]
}'

Managing access keys​

List keys (metadata only — secret is never returned):

curl https://api.humantoken.unico.app/api/console/v1/access-keys \
-H "x-console-authorization: <authToken>"

Rotate a key (old key is immediately invalidated):

curl -X POST https://api.humantoken.unico.app/api/console/v1/access-keys/rotate \
-H "x-console-authorization: <authToken>" \
-H "Content-Type: application/json" \
-d '{"accessKey": "uip_ak.prod.a1b2c3d4.e5f6g7h8.i9j0k1l2"}'

Revoke a key (irreversible):

curl -X DELETE https://api.humantoken.unico.app/api/console/v1/access-keys \
-H "x-console-authorization: <authToken>" \
-H "Content-Type: application/json" \
-d '{"accessKey": "uip_ak.prod.a1b2c3d4.e5f6g7h8.i9j0k1l2"}'

Managing branches​

Branches let you segment your organization's configuration (name, logo, allowed domains) per product or environment. Each branch has its own access keys, so the branch context is resolved automatically from the key used in the request — no need to pass branchId in CreateProcess.

Create a branch​

curl -X POST https://api.humantoken.unico.app/api/console/v1/organization/branches \
-H "x-console-authorization: <authToken>" \
-H "Content-Type: application/json" \
-d '{
"name": "Mobile App",
"logo": "https://acme.com/mobile-logo.png",
"allowedDomains": ["https://mobile.acme.com"]
}'

Response:

{
"branchId": "7ab1c2d3-0000-0000-0000-abcdef012345"
}

Save branchId — use it when creating a branch-specific access key.

Update a branch​

curl -X PUT https://api.humantoken.unico.app/api/console/v1/organization/branches \
-H "x-console-authorization: <authToken>" \
-H "Content-Type: application/json" \
-d '{
"branchId": "7ab1c2d3-0000-0000-0000-abcdef012345",
"name": "Mobile App v2",
"logo": "https://acme.com/mobile-logo-v2.png",
"allowedDomains": ["https://mobile.acme.com", "https://app.acme.com"]
}'

Create a branch-specific access key​

To generate an access key scoped to a specific branch, include branchId in the request body:

curl -X POST https://api.humantoken.unico.app/api/console/v1/access-keys \
-H "x-console-authorization: <authToken>" \
-H "Content-Type: application/json" \
-d '{
"label": "mobile-app-key",
"branchId": "7ab1c2d3-0000-0000-0000-abcdef012345"
}'

Response:

{
"accessKey": "uip_ak.prod.z9y8x7w6.v5u4t3s2.r1q0p9o8"
}
warning

The accessKey is returned only once. Store it immediately. Any CreateProcess request authenticated with this key will automatically use the branch configuration associated with it.