DEVELOPER DOCUMENTATION

A human check.
A backend guarantee.

Start a verification transaction on your server, open the hosted flow, then redeem and consume the result before performing a protected action.

This release supports isolated sandbox enrollment and an iProov adapter. Live human enrollment requires an approved provider configuration and licensed browser SDK. A successful sandbox test does not verify a real human.

Protect account registration

  1. Create an application in the developer console. Register the exact callback URL.
  2. Create an application API key with verification:create and verification:exchange. Keep it on your backend.
  3. Generate a transaction and store its state, nonce, PKCE verifier, action reference and expiry in your backend, bound to the current browser.
  4. Open the returned verificationUrl with the React widget or a redirect.
  5. Validate callback state and issuer, exchange the one-time code and validate the signed assertion.
  6. Atomically consume verificationId together with the protected action. A unique database constraint must prevent reuse.
import { ImReal, createTransaction } from '@imreal/server';

const imreal = new ImReal({
  origin: process.env.IMREAL_ORIGIN,
  apiKey: process.env.IMREAL_API_KEY,
  applicationId: process.env.IMREAL_APPLICATION_ID,
  environment: 'sandbox', // production is the SDK default
});

const tx = createTransaction();
// Save tx.codeVerifier privately, with the browser session.
const session = await imreal.createSession({
  assurance: 'enrolled_human',
  action: 'account.register',
  actionReference: pendingRegistration.id,
  redirectUri: 'https://your-app.com/verification/callback',
  state: tx.state,
  nonce: tx.nonce,
  codeChallenge: tx.codeChallenge,
  codeChallengeMethod: 'S256',
});

The packages are included in this repository as workspaces. They are not published to npm yet. Build and install the workspace packages locally until a reviewed release is published.

Add the React component

<ImRealWidget
  startEndpoint="/api/verification/start"
  completionEndpoint="/api/verification/status"
  verificationOrigin={IMREAL_ORIGIN}
  csrfToken={csrfToken}
  onComplete={() => refreshBackendVerificationStatus()}
/>

The start endpoint returns verificationUrl and the transaction state. After backend redemption, the callback page can post an imreal:complete message containing state and an opaque artifact to the customer origin. The widget validates both message origin and popup source. If the browser blocks the popup, it uses a redirect.

Validate before the protected operation

const proof = await imreal.exchange({
  code, codeVerifier: transaction.codeVerifier,
  redirectUri: transaction.redirectUri,
  action: 'account.register',
  actionReference: transaction.actionReference,
  nonce: transaction.nonce,
  assurance: 'enrolled_human',
});

await db.transaction(async tx => {
  // Unique constraint on verificationId rejects replay.
  await tx.insert(consumedProofs).values({
    verificationId: proof.verificationId,
  });
  await tx.insert(accounts).values(validatedRegistration);
});

Only perform the action inside the successful database transaction. Never use a hidden input, widget state or browser callback as authorization. The working demo includes this enforcement.

Choose the evidence you need

enrolled_human requires active prior enrollment and a WebAuthn credential with local user verification. It proves control of that enrolled credential. fresh_presence requires a new provider-validated live-person check for this transaction within the configured freshness window.

Identity proofing and unique-person claims are not supported in this release. The API rejects unsupported policies. Device verification may use a PIN, password or biometric; the response does not claim which modality was used.

Connect a coding agent

The MCP endpoint is /api/mcp on the deployment origin. It uses the official MCP TypeScript v2 SDK, current Streamable HTTP transport and an external OAuth issuer. Protected-resource discovery is available at /.well-known/oauth-protected-resource.

“Integrate I’m Real into this application and protect
account registration. Use a sandbox, validate the backend
action, and report any unresolved production setup.”

Agents can inspect applications, obtain guidance, provision authorized sandbox configuration and inspect pending test transactions. Read access is the default. Production configuration and secret creation stay in the dashboard; MCP cannot create successful human evidence.

The repository includes skills/imreal-integration/SKILL.md and a CLI. OAuth setup is required before remote MCP access; API keys cannot substitute for MCP OAuth.

Provision customers through your platform

A partner credential can provision customer organizations and their applications without a separate developer account for each customer. The credential is restricted to its partner hierarchy. Human credentials remain centrally managed; applications receive different pseudonymous subjects.

const org = await partner.createOrganization('Customer Ltd');
const app = await partner.createApplication({
  organizationId: org.id,
  name: 'Customer portal',
  redirectUris: ['https://customer.com/verify/callback'],
  policy: 'enrolled_human',
});

Provider attempts, initial enrollments, returning verification and fresh checks are separate usage events. Wholesale aggregation is available through the usage API. Payment collection and partner retail billing are external integrations.

API reference

The running API generates its OpenAPI document from request schemas. Management routes require a scoped API credential or authenticated console session. Hosted-flow routes use an expiring browser transaction and CSRF protection.

OperationEndpoint
Create sessionPOST /v1/verification-sessions
Inspect sessionGET /v1/verification-sessions/{id}
Redeem codePOST /v1/verification-sessions/exchange
ApplicationsGET / POST /v1/applications
Configure applicationPATCH /v1/applications/{id}
Manage credentials/v1/applications/{id}/keys
Register domains/v1/applications/{id}/domains
Webhooks/v1/applications/{id}/webhooks
Partner customersGET / POST /v1/organizations
UsageGET /v1/usage

Errors

Errors use { error: { code, message, requestId } }. Handle expired, already_used, invalid_evidence, policy_unsatisfied, provider_unavailable and quota_exceeded with an explicit retry or failure path. Never downgrade assurance on failure.

Run locally

pnpm install --frozen-lockfile
pnpm exec tsx scripts/keys.ts
docker compose -f infra/docker/compose.yaml up -d
pnpm db:migrate
pnpm db:seed
pnpm dev
# Open http://localhost:3000/demo

Use Node 24 or later. The generated environment file is private and ignored by Git. PostgreSQL and Redis remain local. The README describes tests, live provider configuration, signing-key rotation and Kubernetes deployment.