API Documentation

Access the RCAN Robot Registry programmatically using our JSON API.

OpenAPI 3.1 Machine-readable OpenAPI 3.1 spec available at /schemas/registry-api.openapi.yaml — compatible with Swagger UI, Redoc, Stoplight, and any OpenAPI toolchain. โฌ‡ Download spec

Base URL

https://rcan.dev/api

Authentication

Read operations (GET) are publicly accessible and require no authentication.

Write operations (POST, PATCH, DELETE) require an API key via the Authorization header:

Authorization: Bearer <RCAN_API_KEY>

Contact registry@rcan.dev to request an API key for write access.

Rate Limits

The API enforces rate limiting to ensure fair access. Limits are per IP address:

OperationLimit
Read (GET)1,000 requests / minute
Write (POST, PATCH, DELETE)100 requests / minute

Rate limit status is returned in every response via headers:

HeaderDescription
X-RateLimit-LimitMaximum requests allowed in the window
X-RateLimit-RemainingRequests remaining in the current window
X-RateLimit-ResetUnix timestamp when the window resets

When rate limited, the API returns 429 Too Many Requests.

Error Codes

RCAN-specific error codes are returned in the error_code field of error responses. See the full error codes reference for Registry API errors, federation errors, and SDK error classes.

CodeNameHTTPDescription
6001InvalidRRN400RRN format is invalid (must match RRN-{8โ€“16 digits} or RRN-{PREFIX}-{8โ€“16 digits})
6002NotFound404RRN not found in any reachable node
6003NodeUnreachable503The authoritative node for this namespace is unreachable
6004ResolutionTimeout504Resolution timed out across all nodes
6005TrustChainFailure403Node delegation certificate or record signature is invalid
6006SyncConflict409Sync record conflicts with an existing record (different node, same RRN)

Versioned API (v1) โ€” Recommended

The /api/v1/ endpoints are the canonical, versioned API. They include an api_version field in every response and add new capabilities like full-text search and RURI resolution.

GET /api/v1/index.json

API discovery endpoint. Returns the current API version, base URL, total robot count, and a list of all available endpoints with descriptions.

Example Request

curl "https://rcan.dev/api/v1/index.json"

Example Response

{
  "api_version": "1.0",
  "base_url": "https://rcan.dev/api/v1",
  "total_robots": 10,
  "endpoints": [
    { "path": "/api/v1/robots.json", "method": "GET", "description": "List all robots..." },
    ...
  ]
}
GET /api/v1/robots.json

Versioned robot list. Mirrors /api/robots.json but adds api_version and the ?q= full-text search parameter.

Query Parameters

ParameterTypeDescription
qstringFull-text search across name, manufacturer, description, and tags (case-insensitive substring)
statusstringFilter by status: active, retired, prototype, concept
manufacturerstringFilter by manufacturer name (case-insensitive, partial match)
tagstringFilter by tag (exact match, case-insensitive)
limitintegerMaximum number of results to return
offsetintegerNumber of results to skip (for pagination)

Example Requests

# Full-text search
curl "https://rcan.dev/api/v1/robots.json?q=lidar"

# Filter + paginate
curl "https://rcan.dev/api/v1/robots.json?status=active&limit=5"

Example Response

{
  "api_version": "1.0",
  "success": true,
  "data": [ ... ],
  "meta": {
    "total": 3,
    "count": 3,
    "limit": null,
    "offset": 0,
    "filters": { "status": null, "manufacturer": null, "tag": null, "q": "lidar" }
  }
}
GET /api/v1/robots/[rrn].json

Versioned single-robot lookup by RRN. Same as /api/robots/[rrn].json but includes api_version.

Example Request

curl "https://rcan.dev/api/v1/robots/RRN-000000000001.json"

Example Response

{
  "api_version": "1.0",
  "success": true,
  "data": {
    "rrn": "RRN-000000000001",
    "name": "TurtleBot 3 Burger",
    ...
  }
}
GET /api/v1/ruri/[encoded-ruri].json

Resolve a RURI to a robot registry entry. Pass the URL-encoded RURI as the path segment. Robots must have a ruri field set in their registry entry to be resolvable.

How to build the URL

const ruri = 'rcan://rcan.dev/opencastor/rover/abcdef12';
const url = `https://rcan.dev/api/v1/ruri/${encodeURIComponent(ruri)}.json`;
// โ†’ /api/v1/ruri/rcan%3A%2F%2Frcan.dev%2Fopencastor%2Frover%2Fabcdef12.json

Example Response (200)

{
  "api_version": "1.0",
  "success": true,
  "ruri": "rcan://rcan.dev/opencastor/rover/abcdef12",
  "data": { "rrn": "RRN-000000000042", "name": "OpenCastor Rover", ... }
}

Error Response (404)

{
  "api_version": "1.0",
  "success": false,
  "error": "No robot found for this RURI",
  "ruri": "rcan://rcan.dev/unknown/model/00000000"
}

Distributed Registry (ยง17)

These endpoints interact with the RCAN federated registry network. An RRN may be registered at the root node (rcan.dev) or at a delegated authoritative node. The resolve endpoint handles both transparently.

GET /api/v1/resolve/:rrn

Resolve an RRN to its full robot record. Handles both root RRNs (RRN-XXXXXXXXXXXX) and delegated RRNs (RRN-BD-00000001) by following the delegation chain.

Path Parameters

ParameterDescription
rrnThe Robot Registration Number to resolve (e.g., RRN-000000000042 or RRN-BD-00000001)

Query Parameters

ParameterTypeDescription
followbooleanFollow delegation to authoritative node (default: true). Set false to only check root.
verifybooleanVerify node signature on the record (default: true). Adds latency.

Response Headers

HeaderDescription
X-RCAN-Resolved-ByURL of the node that served this record
X-RCAN-Trust-LevelTrust level of the resolved record: root, delegated-verified, delegated-unverified

Example Requests

# Resolve a root RRN
curl "https://rcan.dev/api/v1/resolve/RRN-000000000042"

# Resolve a delegated RRN (Boston Dynamics namespace)
curl "https://rcan.dev/api/v1/resolve/RRN-BD-00000001"

Example Response

{
  "api_version": "1.0",
  "success": true,
  "rrn": "RRN-BD-00000001",
  "resolved_by": "https://registry.boston-dynamics.com",
  "trust_level": "delegated-verified",
  "data": {
    "rrn": "RRN-BD-00000001",
    "robot_name": "Atlas Unit 001",
    "manufacturer": "Boston Dynamics",
    "registered_at": "2026-01-15T09:00:00Z",
    "attestation": "active",
    "verification_tier": "certified"
  }
}

Error Responses

CodeError CodeDescription
4006001Invalid RRN format
4046002RRN not found in any reachable node
5036003Authoritative node unreachable
5046004Resolution timed out
4036005Trust chain verification failed
GET /api/v1/nodes

List all known delegated authoritative nodes in the RCAN federation. Always includes the root node (rcan.dev).

Query Parameters

ParameterTypeDescription
prefixstringFilter to a specific namespace prefix (e.g., BD). Always includes root.

Example Requests

# List all nodes
curl "https://rcan.dev/api/v1/nodes"

# Get the BD namespace delegation
curl "https://rcan.dev/api/v1/nodes?prefix=BD"

Example Response

{
  "api_version": "1.0",
  "success": true,
  "nodes": [
    {
      "prefix": "root",
      "operator": "ContinuonAI",
      "node_url": "https://rcan.dev",
      "node_type": "root",
      "manifest_url": "https://rcan.dev/.well-known/rcan-node.json"
    },
    {
      "prefix": "BD",
      "operator": "Boston Dynamics, Inc.",
      "node_url": "https://registry.boston-dynamics.com",
      "node_type": "delegated",
      "manifest_url": "https://registry.boston-dynamics.com/.well-known/rcan-node.json",
      "delegated_at": "2026-01-01T00:00:00Z",
      "expires_at": "2027-01-01T00:00:00Z"
    }
  ]
}
PATCH /api/v1/robots/:rrn/verify

Update the verification tier of a registered robot. Requires Authorization: Bearer <RCAN_API_KEY>.

Verification Tiers

BadgeTier ValueDescription
โฌœcommunityDefault; self-registered, no identity check
๐ŸŸกverifiedManufacturer email/domain confirmed
๐Ÿ”ตpartnerSigned partnership agreement on file
โœ…certifiedPassed third-party conformance test suite

Request Body

{
  "verification_tier": "verified",
  "verified_by": "registry-admin",
  "notes": "Domain ownership confirmed via DNS TXT record"
}

Example Request

curl -X PATCH "https://rcan.dev/api/v1/robots/RRN-000000000042/verify" \
  -H "Authorization: Bearer $RCAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"verification_tier":"verified","verified_by":"registry-admin"}'

Legacy Endpoints

These endpoints remain available for backwards compatibility. New integrations should prefer the /api/v1/ equivalents above.

GET /api/robots.json

List all registered robots with optional filtering and pagination.

Query Parameters

Parameter Type Description
status string Filter by status: active, retired, prototype, concept
manufacturer string Filter by manufacturer name (case-insensitive, partial match)
tag string Filter by tag (exact match, case-insensitive)
limit integer Maximum number of results to return
offset integer Number of results to skip (for pagination)

Example Request

curl "https://rcan.dev/api/robots.json?status=active&limit=5"

Example Response

{
  "success": true,
  "data": [
    {
      "rrn": "RRN-000000000001",
      "name": "TurtleBot 3 Burger",
      "manufacturer": "ROBOTIS",
      "model": "turtlebot3_burger",
      "description": "A compact, affordable mobile robot...",
      "status": "active",
      "tags": ["education", "mobile", "ros2"]
    }
  ],
  "meta": {
    "total": 10,
    "count": 5,
    "limit": 5,
    "offset": 0
  }
}
GET /api/robots/[rrn].json

Get detailed information about a specific robot by its RRN.

Path Parameters

Parameter Type Description
rrn string Robot Registration Number (e.g., RRN-000000000001)

Example Request

curl "https://rcan.dev/api/robots/RRN-000000000001.json"

Example Response

{
  "success": true,
  "data": {
    "rrn": "RRN-000000000001",
    "name": "TurtleBot 3 Burger",
    "manufacturer": "ROBOTIS",
    "model": "turtlebot3_burger",
    "description": "A compact, affordable mobile robot...",
    "image": "/robots/turtlebot3-burger.svg",
    "production_year": 2017,
    "status": "active",
    "urdf_url": "https://github.com/ROBOTIS-GIT/turtlebot3/...",
    "github_url": "https://github.com/ROBOTIS-GIT/turtlebot3",
    "website": "https://www.robotis.us/turtlebot-3/",
    "specs": {
      "weight_kg": 1.0,
      "dimensions": "138 x 178 x 192 mm",
      "max_speed_mps": 0.22,
      "dof": 2,
      "ros_version": ["ROS 1", "ROS 2"],
      "sensors": ["LDS-01 LiDAR", "IMU", "Wheel Encoders"],
      "compute": "Raspberry Pi 4",
      "battery_life_hours": 2.5
    },
    "owner": {
      "name": "Open Source Community",
      "type": "community",
      "website": "https://emanual.robotis.com/..."
    },
    "ruri": null,
    "submitted_by": "github:continuonai",
    "submitted_date": "2026-01-04",
    "tags": ["education", "mobile", "ros2", "lidar"]
  }
}

Error Response (404)

{
  "success": false,
  "error": "Robot not found",
  "rrn": "RRN-000099999999"
}
GET /api/badge/[rrn].svg

Generate an SVG badge for a robot to embed in GitHub READMEs.

Query Parameters

Parameter Type Description
style string Badge style: flat (default), flat-square, plastic
label string Custom left-side label (default: "RCAN")

Example Usage

<!-- Markdown -->
![RCAN](https://rcan.dev/api/badge/RRN-000000000001.svg)

<!-- HTML -->
<img src="https://rcan.dev/api/badge/RRN-000000000001.svg" alt="RCAN Registry">
GET /api/qr/[rrn].svg

Generate a QR code linking to the robot's registry page.

Query Parameters

Parameter Type Description
size integer QR code size in pixels (default: 200, max: 1000)

Example Usage

curl "https://rcan.dev/api/qr/RRN-000000000001.svg?size=300"

Response Format

All JSON responses follow a consistent format:

{
  "success": boolean,      // true if request succeeded
  "data": object | array,  // response payload
  "meta": {                // pagination info (list endpoints only)
    "total": number,
    "count": number,
    "limit": number | null,
    "offset": number
  },
  "error": string          // error message (only on failure)
}

CORS

Cross-Origin Resource Sharing (CORS) is enabled for all origins. You can make API requests directly from browser-based applications.

Caching

Responses include Cache-Control: public, max-age=3600 headers. Data is regenerated on each site build, so caching for up to 1 hour is recommended.

Code Examples

JavaScript / TypeScript

// Fetch all active robots
const response = await fetch('https://rcan.dev/api/robots.json?status=active');
const { data: robots } = await response.json();

// Fetch a specific robot
const robot = await fetch('https://rcan.dev/api/robots/RRN-000000000001.json')
  .then(r => r.json())
  .then(r => r.data);

console.log(robot.name); // "TurtleBot 3 Burger"

Python

import requests

# Fetch all robots
response = requests.get('https://rcan.dev/api/robots.json')
robots = response.json()['data']

# Fetch by manufacturer
response = requests.get('https://rcan.dev/api/robots.json',
                       params={'manufacturer': 'ROBOTIS'})
robotis_robots = response.json()['data']

cURL

# List all robots
curl https://rcan.dev/api/robots.json

# Filter by status and limit results
curl "https://rcan.dev/api/robots.json?status=active&limit=5"

# Get specific robot
curl https://rcan.dev/api/robots/RRN-000000000001.json