Overview

robot-id.eth is the neutral ENS protocol layer for robots. Reads go straight to chain via viem + Alchemy; writes return unsigned transactions you sign with your own wallet or multisig. There is no free self-serve tier — a key is issued only after an active on-chain USDC subscription.

5-minute Quickstart

npm i @robot-id/sdk

import { RobotIdClient } from '@robot-id/sdk'
const client = new RobotIdClient({ apiKey: 'rid_...', network: 'mainnet' })

const robot = await client.robots.get(1n)
const caps  = await client.capability.get(1n)

Authentication

Subscription-gated, SIWE via Reown AppKit. Connect a wallet on /subscribe, optionally reserve your namespace, approve USDC, and call Subscription.subscribe(tier). The on-chain Subscribed event triggers API-key minting + provisioning of the namespace you reserved (or an address-derived default). Retrieve your key via a SIWE-authenticated GET /auth/keys/info. Every request re-checks isActive; expired subscriptions get 402 Payment Required.

Robot Identity

ERC-721 + ERC-5192 (per-token soulbound) + ERC-2981 royalties. Each unit’s serialHash is keccak256(normalize(serialNumber)) — privacy-preserving but verifiable, and normalized so it matches the ENS label the gateway resolves. The ENS name <serial>.<mfr>.robot-id.eth always resolves to the current NFT holder via the CCIP-Read gateway. No registration fee — minting costs gas only.

Namespaces

An OEM picks its own namespace at checkout — e.g. boston-dynamics.robot-id.eth — and every one of its units resolves beneath it: spot-0001.boston-dynamics.robot-id.eth. Names are first-come, first-served; there is no brand-reservation list. Slugs are normalized (lowercase, dash-separated, 3–63 chars) and a small set of protocol words is reserved.

Only the OEM namespace is written on-chain (one setSubnodeRecord, owned by the OEM wallet). The unit names below it are virtual — resolved by the CCIP-Read gateway with zero ENS writes — so a single subscription scales to 100,000+ identities with one namespace write and one Merkle root.

GET  /auth/namespace/boston-dynamics        // availability (public)
→ { slug, valid, available, name }

POST /auth/namespace/reserve                // SIWE, free, at checkout
{ address, message, signature, slug:"boston-dynamics" }
→ { reserved:true, name:"boston-dynamics.robot-id.eth" }
// consumed by the Subscribed watcher → provisioned on payment

Merkle Batches (OEM)

Pre-authorize up to 100,000 serials off-chain: the API builds a Merkle tree, you commit the root via MerkleBatchOracle.submitRoot, and each unit later claims its NFT with a proof via claimWithProof(batchId, proof, …).

POST /api/v1/robots/batch/preauthorize
{ "manufacturer":"Unitree", "model":"Go2",
  "serials":[{"serialNumber":"GO2-0001","owner":"0x…"}] }
→ { batchId, root, unsignedTx }   // sign submitRoot, then distribute proofs

Capability Registry

OEM-signed, append-only attestations of what a robot is authorized to do (max_payload_kg, operating_zone, human_interaction_certified). Off-chain cert detail is pinned to IPFS and anchored by a Merkle root; verify(robotId, capabilityKey, leaf, proof) checks a proof against the latest root.

Intent Routing

IntentRouter.submitIntent is on-chain authorization + an immutable audit log. An intent is authorized only if it passes the robot’s AgentWallet limits; otherwise it’s rejected with a reason. Per-robot rate gating prevents intent floods.

OTA Verification

OTAVerifier.verify(firmwareHash, version, signature, oemAddress) gates each update. It cross-references RobotIdentity.firmwareVersion to reject downgrades. A blob signed by the registered OEM key verifies true; any other signer or a downgrade verifies false.

Subscriptions

Three tiers in USDC (6 decimals): Small Manufacturer $5,000, OEM $7,500, Enterprise $12,500. subscribe pulls via transferFrom (approve first) and sets a 30-day expiry; renewal extends from max(now, currentExpiry).

TypeScript SDK

const batch = await client.robots.preauthorize({
  manufacturer, model, capabilityClass, serials
})
const active = await client.subscription.isActive('0x…')

Intent SDK (ROS2 + voice)

import { RobotIntentPlugin } from '@robot-id/intent-sdk'
const plugin = new RobotIntentPlugin({
  robotId: 1n, apiKey: process.env.ROBOT_ID_KEY!,
  adapter: 'ros2-bridge', // alexa | google-assistant | custom-llm
})
const ack = await plugin.handleUtterance(
  "Authorize payment for charging dock B and log the task")
// → classify → check AgentWallet limits → IntentRouter.submitIntent → ack

Tools

Quickstart smoke script (oem-quickstart.sh), a REST .http collection, a WebSocket event server at /ws (robots · intent · capability channels), and GraphQL at /graphql. Swagger UI: https://robot-idapi-production.up.railway.app/docs.

Testing · Unit Tests

One .t.sol per contract under contracts/test/, covering every state-changing path: soulbound lock/transfer revert, batch Merkle verification, AgentWallet limit enforcement, IntentRouter accept/reject, CapabilityRegistry immutability, OTA accept/reject + downgrade reject, and Subscription subscribe/renew/expire/price-update.

forge test

Testing · Integration Tests (forked mainnet)

Because we launch on mainnet with no testnet-only phase, integration coverage is mandatory. The suite runs against a forked mainnet so real contracts (USDC) are exercised, not mocks:

  • Subscription lifecycle — fund a fork account with real USDC, approve, subscribe(OEM), warp 30 days, renew.
  • Batch path — preauthorize → commit root → claimWithProof for a sampled unit → assert ownership.
  • AgentWallet — userOps that pass and that exceed limits; assert enforcement.
  • OTA — verify a correctly-signed blob; reject a wrong signer / downgrade.
  • ENS end-to-end — resolve SN-X.mfr.robot-id.eth through the CCIP gateway.
RPC_URL=https://eth-mainnet.g.alchemy.com/v2/KEY \
  FOUNDRY_PROFILE=integration forge test

Error Codes

  • 401 — missing/invalid API key
  • 402 — subscription inactive or expired
  • 429 — rate limit exceeded for tier
  • 404 — robot / batch not found

Rate Limits

  • Small Manufacturer — 1,000,000 req/mo · 300/min
  • OEM — 5,000,000 req/mo · 1,000/min
  • Enterprise — unlimited · 5,000/min

Mainnet Contracts

RobotIdentity · AgentWallet · IntentRouter · CapabilityRegistry · OTAVerifier · MerkleBatchOracle · Subscription — all source-verified. See the live table on the landing page.