API Docs

Link Identity Platform · v1

API Reference

The Link Identity API exposes device registration, biometric enrollment, verification, and real-time event delivery over a single REST surface. All protected endpoints use OAuth 2.0 Client Credentials and require a Bearer token.

Base URLhttps://identity-api.imlink.network

Overview#

Four steps take you from credentials to a verified palm scan.

  1. Create OAuth client credentials in Integrations → OAuth Clients.
  2. Request a token from POST /v1/auth/token.
  3. Send Authorization: Bearer <access_token> on protected endpoints.
  4. Refresh the token before expiry using the expires_in field — request a new one ~60 seconds early.

Note

All requests and responses are JSON. Errors return { success: false, message } — see Error Format for the full shape.

Authentication#

Exchange client credentials for a short-lived Bearer token, then attach it to every protected call.

POST/v1/auth/tokenPublic

Generate an access token. This endpoint itself is public — Bearer auth is not required to call it.

Field
Type
Required
Description
grant_type
string
Required
Must be client_credentials.
client_id
UUID
Required
Client ID from the Link Identity console.
client_secret
string
Required
Secret shown once during credential creation.
Request
POST https://identity-api.imlink.network/v1/auth/token
Content-Type: application/json

{
  "grant_type": "client_credentials",
  "client_id": "06a4dc18-b06c-4e1c-ad25-204d44bf0c71",
  "client_secret": "cs_live_xxx"
}
Response 200
{
  "success": true,
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "Bearer",
  "expires_in": 3600
}
200Token issued successfully.
400Invalid body or unsupported grant type.
401Invalid client_id or client_secret.

Note

There is no refresh token in client-credentials flow — request a new token when the current one expires.

Credential Rotation#

How rotation and revocation affect tokens already in flight.

RotateCreates a new client_secret. Tokens issued from the old secret remain valid until they expire on their own.
DeleteImmediately invalidates all active tokens for that OAuth client.
ExpiryTokens expire after expires_in seconds and must be reissued.

Warning

For emergency revocation (suspected credential leak), delete the OAuth client to invalidate tokens without a grace period.

Endpoints

Register Device#

Reserve a hardware ID and one-time pairing code before connecting a scanner.

POST/v1/devicesBearer required

Registers a new scanner and returns a pairing code that the device uses to complete provisioning.

Field
Type
Required
Description
device_name
string
Required
Human-readable label. 1-255 characters.
location
string
Required
Physical location details. 1-255 characters.
Request body
{
  "device_name": "Lobby Scanner A",
  "location": "Main Entrance - Floor 1"
}
Response 201
{
  "success": true,
  "data": {
    "hardware_id": "hw_a1b2c3d4e5",
    "device_name": "Lobby Scanner A",
    "location": "Main Entrance - Floor 1",
    "pairing_code": "PAR-7X92-KZQM",
    "status": "pending_pair"
  },
  "message": "Device registered successfully. Use the pairing code to pair the device."
}
201Device record created and one-time pairing code returned.
400Validation or business-rule failure.
401Missing or invalid Bearer token.

Create Enrollment Challenge#

Initiate a biometric enrollment for a user against a specific paired scanner.

POST/v1/enrollBearer required

Creates an enrollment challenge. The device captures the biometric; the result is delivered asynchronously via webhook.

Field
Type
Required
Description
user_id
UUID
Required
Platform user ID.
hardware_id
string
Required
Paired hardware ID returned from /v1/devices.
palm_type
enum
Required
left or right.
metadata
object | null
Optional
Arbitrary key-value data echoed back in the challenge.
Request body
{
  "user_id": "d1e2f3a4-b5c6-7890-abcd-ef1234567890",
  "hardware_id": "hw_a1b2c3d4e5",
  "palm_type": "right",
  "metadata": { "employee_id": "EMP-4421", "department": "Engineering" }
}
201Challenge created; device should capture biometric.
403Token lacks the required tenant permissions.
404User or hardware_id not found.
409User already enrolled for this palm/device context.
422Schema validation failed.

Tip

A successful response means the challenge is pending. The completion result is delivered asynchronously via the user.enrolled webhook.

Create Verification Challenge#

Run a 1:1 palm match against a previously enrolled user.

POST/v1/verifyBearer required

Creates a verification challenge. The match result is emitted asynchronously over a webhook.

Field
Type
Required
Description
user_id
UUID
Required
Previously enrolled user ID.
hardware_id
string
Required
Scanner hardware ID running the verification.
palm_type
enum
Required
Must match the enrolled palm: left or right.
metadata
object | null
Optional
Custom context echoed to response and webhook payloads.
Request body
{
  "user_id": "d1e2f3a4-b5c6-7890-abcd-ef1234567890",
  "hardware_id": "hw_a1b2c3d4e5",
  "palm_type": "right",
  "metadata": { "session_id": "sess_0099", "access_point": "turnstile-7" }
}
201Challenge created (not yet verified).
401Missing or expired Bearer token.
422Schema validation failure.

Tip

The biometric result arrives via the user.verified webhook with result: match | no_match.

Webhooks

Create Webhook#

Register an HTTPS endpoint to receive event deliveries.

POST/v1/webhooksBearer required

Subscribes a callback URL to one or more event keys. Deliveries POST a JSON payload signed with the optional API key.

Field
Type
Required
Description
name
string
Required
Display name for the webhook.
events
string[]
Required
One or more event keys to subscribe to.
endpoint
URL
Required
HTTPS callback URL that receives POST payloads.
api_key
string | null
Optional
If provided, sent as the X-API-Key header on every delivery.
Request body
{
  "name": "Production Events",
  "events": ["device.paired", "user.enrolled", "user.verified"],
  "endpoint": "https://yourapp.example.com/webhooks/identity",
  "api_key": "whsec_your_secret_key_here"
}
201Webhook created and activated.
400Invalid endpoint, events, or body format.
403Insufficient permissions for webhook management.
409Duplicate webhook endpoint or name conflict.

Event Types#

The three event keys you can subscribe to today.

device.pairedDevice pairing completed.
user.enrolledBiometric enrollment completed.
user.verifiedVerification match or no-match result.

Payload Format#

Every event delivery uses the same envelope: event key, ID, fired-at timestamp, and a payload-specific data block.

Delivery
POST https://yourapp.example.com/webhooks/identity
Content-Type: application/json
X-API-Key: whsec_your_secret_key_here

{
  "event": "user.verified",
  "event_id": "evt_9f8e7d6c5b",
  "fired_at": "2026-05-20T14:32:11Z",
  "data": {
    "challenge_id": "ch_verify_1a2b3c4d",
    "user_id": "d1e2f3a4-b5c6-7890-abcd-ef1234567890",
    "hardware_id": "hw_a1b2c3d4e5",
    "palm_type": "right",
    "result": "match",
    "verified_at": "2026-05-20T14:32:10Z",
    "metadata": { "session_id": "sess_0099", "access_point": "turnstile-7" }
  }
}

Note

Respond with 2xx within 10 seconds to acknowledge delivery. Non-2xx responses are retried with exponential backoff.

Reference

Error Format#

Every non-2xx response uses the same JSON shape.

Error body
{
  "success": false,
  "message": "Human-readable description of the error"
}

HTTP Status Codes#

The status codes you should expect across the API.

400Bad Request — invalid fields or business-rule violations.
401Unauthorized — missing or invalid token or credentials.
403Forbidden — token valid but lacks the required permission.
404Not Found — referenced resource does not exist.
409Conflict — duplicate or conflicting resource state.
422Unprocessable Entity — schema validation failed.
500Internal Server Error — unexpected server error.