Colpero Spatial API
Query 3D scenes via HTTP. Pay per request with USDC via x402 protocol. Built for robots and autonomous agents.
Overview
What is the Colpero Spatial API?
The Colpero Spatial API lets autonomous agents query 3D environments over HTTP. Scenes are stored in OpenUSD format. Each query runs real spatial computation (distances, pathfinding, area calculations) and returns structured JSON.
All paid endpoints use the x402 protocol from Coinbase for micropayments. Agents pay with USDC on Base Sepolia. No API keys, no accounts, no subscriptions. Just HTTP + payment headers.
Base URL
https://api.colpero.com // production (coming soon)
http://localhost:3000 // local development
Response Format
All responses are application/json. Errors return standard HTTP codes with a JSON body:
{
"error": "Object 'unknown_obj' not found in scene"
}
Available Scenes
| ID | Description | Dimensions |
|---|---|---|
warehouse_demo |
Warehouse with racks, forklifts, and loading dock | 30m x 20m |
office_demo |
Office with desks, meeting rooms, kitchen | 15m x 12m |
Authentication
How x402 payments work
x402 is an HTTP-native payment protocol. Instead of API keys, clients pay per request
with USDC. The server returns 402 Payment Required with payment instructions.
The client signs a USDC transfer and retries.
Step-by-step
1. Send a request without payment. The server returns 402 Payment Required:
# Request
POST /scenes/warehouse_demo/distance HTTP/1.1
Content-Type: application/json
{ "object_a": "rack_A", "object_b": "loading_dock" }
# Response: 402 Payment Required
{
"x402Version": 1,
"accepts": [{
"scheme": "exact",
"network": "base-sepolia",
"maxAmountRequired": "5000",
"payTo": "0x...",
"asset": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
"maxTimeoutSeconds": 300,
"resource": "http://localhost:3000/scenes/warehouse_demo/distance"
}]
}
2. Sign the USDC transfer using @coinbase/x402-client:
import { paymentHeaders } from "@coinbase/x402-client";
const headers = await paymentHeaders(
wallet, // viem WalletClient
paymentRequirements, // from 402 response
"http://localhost:3000/scenes/warehouse_demo/distance"
);
3. Retry with the payment header. Server verifies via facilitator and returns data:
POST /scenes/warehouse_demo/distance HTTP/1.1
Content-Type: application/json
X-PAYMENT: <base64-encoded-signed-payment>
{ "object_a": "rack_A", "object_b": "loading_dock" }
# Response: 200 OK
# X-PAYMENT-RESPONSE: <settlement-receipt>
{
"object_a": "rack_A",
"object_b": "loading_dock",
"distance_meters": 21.4234,
...
}
PAY_TO_ADDRESS set,
all endpoints are free. No payment headers needed. Use this for local development.
Network Details
| Parameter | Value |
|---|---|
| Network | base-sepolia |
| Currency | USDC (ERC-20) |
| USDC Contract | 0x036CbD53842c5426634e7929541eC2318f3dCF7e |
| Facilitator | https://x402.org/facilitator |
| Amount unit | USDC micro-units (6 decimals). $0.001 = "1000" |
Endpoints
API Reference
All endpoints accept and return JSON. Scene IDs correspond to .usda files
in the scenes directory (e.g. warehouse_demo, office_demo).
Server health check and capability declaration. Use this to verify connectivity and check if payments are enabled.
curlcurl http://localhost:3000/health
response
{
"status": "ok",
"version": "0.1.0",
"node_id": "default",
"capabilities": [],
"allowed_scenes": "all",
"payment_enabled": false,
"network": "base-sepolia"
}
| Field | Type | Description |
|---|---|---|
status | string | Always "ok" if server is running |
node_id | string | Node identifier in the network |
payment_enabled | boolean | Whether x402 payments are enforced |
network | string | "base-sepolia" or "base" |
List all available scenes with metadata and endpoint links.
curlcurl http://localhost:3000/scenes
response
[
{
"id": "warehouse_demo",
"name": "Warehouse Demo",
"description": "30m x 20m warehouse with racks and loading dock",
"file": "warehouse_demo.usda",
"endpoints": {
"objects": "/scenes/warehouse_demo/objects",
"distance": "/scenes/warehouse_demo/distance",
"nearest": "/scenes/warehouse_demo/nearest",
"area": "/scenes/warehouse_demo/area",
"path": "/scenes/warehouse_demo/path",
"query": "/scenes/warehouse_demo/query"
}
}
]
Returns active spatial computing nodes from the on-chain ERC-8004 registry. Filter by capability or minimum reputation score.
query parameters| Parameter | Type | Required | Description |
|---|---|---|---|
capability | string | No | Filter by capability (e.g. "reconstruction") |
minReputation | integer | No | Minimum reputation score |
curl "http://localhost:3000/nodes?capability=reconstruction&minReputation=80"
response
{
"count": 2,
"nodes": [
{
"agentId": "0x1234...abcd",
"owner": "0xabcd...1234",
"capabilities": ["reconstruction", "pathfinding"],
"pricing": {
"pricePerQuery": "0.01",
"pricePerCompute": "0.005",
"pricePerPath": "0.008"
},
"endpoint": "https://node1.colpero.com",
"reputation": 95,
"totalSuccess": 1250,
"totalFailure": 5,
"active": true
}
]
}
REGISTRY_CONTRACT_ADDRESS to be configured. Results are cached for 60 seconds.
List all objects in a scene with their 3D positions, scales, types, and semantic metadata.
curlcurl http://localhost:3000/scenes/warehouse_demo/objects
response
[
{
"name": "rack_A",
"path": "/World/rack_A",
"type": "rack",
"position": { "x": 5, "y": 1.5, "z": 5 },
"scale": { "x": 1.2, "y": 3, "z": 2.4 },
"metadata": {
"semantic_type": "rack",
"label": "Storage Rack A"
}
},
...
]
Compute Euclidean distance (meters) between two named objects in the scene.
request body{
"object_a": "rack_A",
"object_b": "loading_dock"
}
curl
curl -X POST http://localhost:3000/scenes/warehouse_demo/distance \
-H "Content-Type: application/json" \
-d '{"object_a": "rack_A", "object_b": "loading_dock"}'
response
{
"object_a": "rack_A",
"object_b": "loading_dock",
"distance_meters": 21.4234,
"positions": {
"a": { "x": 5, "y": 1.5, "z": 5 },
"b": { "x": 25, "y": 0.1, "z": 10 }
}
}
Find the N nearest objects to a target object, sorted by distance.
request body{
"target": "forklift_1",
"count": 3
}
curl
curl -X POST http://localhost:3000/scenes/warehouse_demo/nearest \
-H "Content-Type: application/json" \
-d '{"target": "forklift_1", "count": 3}'
response
[
{
"name": "rack_A",
"type": "rack",
"distance_meters": 14.3212,
"position": { "x": 5, "y": 1.5, "z": 5 },
"metadata": { "semantic_type": "rack" }
},
...
]
Calculate the floor footprint area (square meters) of a named region or zone.
request body{
"region": "loading_dock"
}
curl
curl -X POST http://localhost:3000/scenes/warehouse_demo/area \
-H "Content-Type: application/json" \
-d '{"region": "loading_dock"}'
response
{
"region": "loading_dock",
"area_sq_meters": 96.0,
"dimensions": {
"width_meters": 8,
"length_meters": 12,
"height_meters": 0.1
},
"center_position": { "x": 25, "y": 0.1, "z": 10 }
}
Compute the shortest navigable path between two objects using A* pathfinding. Returns waypoints in meters. Grid resolution: 0.5m. Agent padding: 0.4m.
request body{
"from": "rack_A",
"to": "loading_dock"
}
curl
curl -X POST http://localhost:3000/scenes/warehouse_demo/path \
-H "Content-Type: application/json" \
-d '{"from": "rack_A", "to": "loading_dock"}'
response
{
"from": "rack_A",
"to": "loading_dock",
"path_distance_meters": 28.5432,
"waypoints": [
{ "x": 5, "y": 0.1, "z": 5 },
{ "x": 15, "y": 0.1, "z": 8 },
{ "x": 25, "y": 0.1, "z": 10 }
]
}
Ask a natural language question about the scene. Powered by Claude with tool use. The AI agent calls spatial tools internally to build an accurate answer.
request body{
"question": "Which rack is closest to forklift_1 and how far is it?"
}
curl
curl -X POST http://localhost:3000/scenes/warehouse_demo/query \
-H "Content-Type: application/json" \
-d '{"question": "Which rack is closest to forklift_1 and how far is it?"}'
response
{
"question": "Which rack is closest to forklift_1 and how far is it?",
"answer": "Rack A is the closest rack to forklift_1, at approximately 14.32 meters."
}
Pricing Summary
| Endpoint | Method | Price (USDC) | Micro-units |
|---|---|---|---|
/health | GET | Free | 0 |
/scenes | GET | Free | 0 |
/nodes | GET | Free | 0 |
/scenes/:id/objects | GET | $0.001 | 1000 |
/scenes/:id/distance | POST | $0.005 | 5000 |
/scenes/:id/nearest | POST | $0.005 | 5000 |
/scenes/:id/area | POST | $0.003 | 3000 |
/scenes/:id/path | POST | $0.008 | 8000 |
/scenes/:id/query | POST | $0.010 | 10000 |
Quickstart
Integrate in 5 minutes
1. Install dependencies
npm install @coinbase/x402-client viem
2. Create a wallet
You need a wallet with testnet USDC on Base Sepolia. Get test USDC from the Coinbase faucet.
3. Query the API
import { createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { baseSepolia } from "viem/chains";
import { paymentHeaders } from "@coinbase/x402-client";
const API = "http://localhost:3000";
// Setup wallet
const account = privateKeyToAccount("0xYOUR_PRIVATE_KEY");
const wallet = createWalletClient({
account,
chain: baseSepolia,
transport: http(),
});
// Helper: make a paid request
async function paidRequest(path: string, body?: object) {
const url = `${API}${path}`;
const method = body ? "POST" : "GET";
// Step 1: initial request → 402
const initial = await fetch(url, {
method,
headers: { "Content-Type": "application/json" },
body: body ? JSON.stringify(body) : undefined,
});
if (initial.status !== 402) return initial.json();
// Step 2: extract payment requirements
const requirements = await initial.json();
// Step 3: sign payment
const payment = await paymentHeaders(
wallet,
requirements.accepts[0],
url
);
// Step 4: retry with payment
const paid = await fetch(url, {
method,
headers: {
"Content-Type": "application/json",
...payment,
},
body: body ? JSON.stringify(body) : undefined,
});
return paid.json();
}
// ── Usage examples ──
// List scenes (free)
const scenes = await fetch(`${API}/scenes`).then(r => r.json());
console.log(scenes);
// Get objects ($0.001)
const objects = await paidRequest("/scenes/warehouse_demo/objects");
console.log(`Found ${objects.length} objects`);
// Compute distance ($0.005)
const dist = await paidRequest("/scenes/warehouse_demo/distance", {
object_a: "rack_A",
object_b: "loading_dock",
});
console.log(`Distance: ${dist.distance_meters}m`);
// Find path ($0.008)
const path = await paidRequest("/scenes/warehouse_demo/path", {
from: "rack_A",
to: "loading_dock",
});
console.log(`Path: ${path.path_distance_meters}m, ${path.waypoints.length} waypoints`);
// Natural language query ($0.01)
const answer = await paidRequest("/scenes/warehouse_demo/query", {
question: "What is the total area of the loading dock?",
});
console.log(answer.answer);
Running locally (dev mode)
# Clone and install
git clone https://github.com/colpero/colpero-spatial-api.git
cd colpero-spatial-api
npm install
pip install -r requirements.txt
# Configure (leave PAY_TO_ADDRESS empty for free mode)
cp .env.example .env
# Start server
npm run dev
# API is live at http://localhost:3000
# All endpoints are free in dev mode
Docker
docker-compose up
# API at http://localhost:3000
# Health check: http://localhost:3000/health