KEYRA

KEYRA Developer Documentation

Integrate hardware-rooted human authorization into your application. KEYRA issues cryptographic challenges, verifies attestation on-device, and returns signed proof that a human approved an action.

API v1Sandbox
Overview →

Introduction

Hardware-rooted human authorization for apps, AI agents, and high-trust workflows.

  • A KEYRA developer account (sandbox available at launch)
  • KEYRA ONE device or simulator for local testing
  • HTTPS endpoint for webhook delivery

Getting started

Install an SDK, configure secrets, and issue your first challenge.

Install SDK

Installshell
npm install @keyra/sdk
Initializejs
import { Keyra } from "@keyra/sdk";

const keyra = new Keyra({ apiKey: process.env.KEYRA_API_KEY });

Configure

Store secrets in environment variables. Never expose KEYRA_API_KEY in client-side code.

VariableDescription
KEYRA_API_KEYSecret key for server-side API calls. Never expose in client bundles.
KEYRA_WEBHOOK_SECRETUsed to verify webhook signatures (HMAC-SHA256).
KEYRA_ENVsandbox | production. Defaults to sandbox.

First challenge

Create a challenge from your backend, present it to KEYRA ONE, then verify the signed attestation when the user approves.

Create challengetypescript
const challenge = await keyra.challenges.create({
  action: "transfer.approve",
  userId: "usr_8f2a",
  payload: {
    amount: 12500,
    currency: "USD",
    memo: "Wire to Acme Corp",
  },
  expiresIn: 120, // seconds
});

// Returns: { id, status: "pending", expiresAt }

Authentication

Send your API key as a Bearer token on every server-side request.

Headershttp
Authorization: Bearer sk_live_...
Content-Type: application/json

Challenges API

Single-use, time-bound authorization requests bound to your action payload.

Create challenge

POST /v1/challengesjson
{
  "action": "transfer.approve",
  "userId": "usr_8f2a",
  "payload": { "amount": 12500, "currency": "USD" },
  "expiresIn": 120
}

Response 201 Created

json
{
  "id": "chl_9k2m",
  "status": "pending",
  "expiresAt": "2026-05-29T18:42:00Z"
}

Verify response

Forward the attestation from the client to your backend and verify with the SDK — never trust client-only validation.

Verify attestationtypescript
const result = await keyra.challenges.verify(challengeId, {
  attestation: req.body.attestation,
  deviceId: req.body.deviceId,
});

if (result.status === "approved") {
  // Proceed with protected action
}

Endpoints

MethodPathDescription
POST/v1/challengesCreate a single-use authorization challenge.
GET/v1/challenges/:idRetrieve challenge status and metadata.
POST/v1/challenges/:id/verifyVerify attestation payload from KEYRA ONE.
POST/v1/credentials/registerBegin WebAuthn / passkey registration.
POST/v1/credentials/authenticateBegin WebAuthn authentication ceremony.

Webhooks

Receive signed events when a human approves, rejects, or lets a challenge expire.

Express handlertypescript
app.post("/webhooks/keyra", (req, res) => {
  const sig = req.headers["keyra-signature"];
  if (!keyra.webhooks.verify(req.rawBody, sig)) {
    return res.status(401).send("Invalid signature");
  }

  switch (req.body.type) {
    case "challenge.approved":
      fulfillTransfer(req.body.data.challengeId);
      break;
    case "challenge.rejected":
      cancelPendingAction(req.body.data.challengeId);
      break;
  }

  res.status(200).send({ received: true });
});

Event types

EventDescription
challenge.approvedHuman authorized the challenge on KEYRA ONE.
challenge.rejectedUser explicitly rejected or timed out.
challenge.expiredChallenge TTL elapsed without a response.
device.pairedNew KEYRA ONE bound to a user account.

WebAuthn

FIDO2-aligned passkey flows — biometric templates never leave the secure element.

  1. Server requests registration or authentication options.
  2. Browser calls navigator.credentials.
  3. Server verifies attestation with KEYRA SDK helpers.
Registration flowtypescript
// Server: issue registration options
const options = await keyra.credentials.registrationOptions({
  userId: "usr_8f2a",
  displayName: "Jane Founder",
});

// Client: pass options to navigator.credentials.create()
// Server: verify attestation with keyra.credentials.verifyRegistration()

SDK reference

Typed clients with retry logic and webhook signature verification.

JavaScript / TypeScript

npm install @keyra/sdk

Python

pip install keyra-sdk

Go

go get keyra.dev/sdk/v1

Error codes

Errors include code, message, and optional details. Retry only on 429 and 5xx.

CodeHTTPDescription
invalid_api_key401Missing or invalid API key.
challenge_expired410Challenge TTL elapsed.
challenge_already_used409Challenge was already consumed.
attestation_invalid422Signature or device certificate failed verification.
device_not_found404No paired KEYRA device for this user.
rate_limit_exceeded429Too many requests; retry with backoff.
Example errorjson
{
  "code": "challenge_expired",
  "message": "Challenge chl_9k2m expired at 2026-05-29T18:42:00Z"
}