The API · v1
Read it once, wire it once.
What you need to mint a key, detect objects in a frame, classify land cover from satellite, describe a scene, and add the MCP server to your agent. Every endpoint below is live today at https://geo.qa/api. For Earth-observation facts, geo.qa builds on the open emem.dev ledger, whose answers carry verifiable receipts.
§ 1
Quickstart
Three steps. Mint a key, ask geo.qa to detect what’s in a frame, and read the result. The same key unlocks the satellite tools and the MCP server.
1 · Mint a key
Sign in at geo.qa, then generate a key from Account → API keys. Keys are public-scope: they call the public API and cannot reach admin endpoints. Usage is bounded by your plan on the pricing page. The secret is shown once.
2 · Detect objects in a frame
curl -X POST https://geo.qa/api/tool/camera-stream/detections \ -H "Authorization: Bearer $GEOQA_KEY" \ -H "Content-Type: application/json" \ -d '{ "image_url": "https://example.com/frame.jpg", "prompts": ["person", "vehicle", "truck"], "alert_triggers": ["truck"], "confidence_threshold": 0.25 }'
Detection returns boxes, labels and confidences. Any prompt in alert_triggers comes back with is_alert: true and in a top-level alerts[] list. Add ask_question for a vision-language read of the scene under scene_analysis.
What is answering. The detector on duty is closed-set — a COCO-trained box model on CPU — and it names itself in model on every response. A prompt it has no class for is refused, by name, in refused_prompts, rather than answered with an empty list: an empty list here means looked and found none. GET /api/world-model/capabilities lists what it can return. Prompts that are a measurement rather than a sighting — building, road, water — are refused too, naming the corpus that holds the real answer.
3 · Read the response
{
"detections": [
{ "label": "car", "confidence": 0.9063,
"bbox": [x1,y1,x2,y2], /* corners in pixels, not x/y/w/h */
"bbox_normalized": [0.259,0.322,0.400,0.393],
"is_alert": false },
/* … */
],
"total_objects": 21,
"model": "fasterrcnn_mobilenet_v3_large_fpn (cpu_detect@3)",
"refused_prompts": [
{ "prompt": "fire", "reason": "closed-set; no class for this" }
],
"alerts": [],
"scene_analysis": null
}
No account? POST /api/v1/object-detection runs the same detector without a key, rate-limited per IP — the fastest way to try it. See § 4.
§ 2
Concepts
geo.qa fuses two kinds of source. Your own sensors — camera streams, drones, uploaded frames — run through the vision tools. Earth observation — satellite land cover, indices, weather — is resolved against the open emem.dev grid. Both answer against one addressable memory of ground.
| noun | what it is |
|---|---|
| place | Where. A lat/lon, a bounding box, or a polygon. Satellite tools resolve a place to its ground cell on the open emem.dev grid (~9.55 m), so the same spot cites the same way across sources. |
| band | What. A named measurement: a land-cover class, a vegetation index, a weather field, a detection label. The satellite bands come from the emem.dev registry; the vision labels are open-vocabulary prompts you supply. |
| frame | An observation. A single image or video frame from a sensor you run. Pass it as an image_url or image_base64. The raw frame is analyzed and discarded; only the result is returned. |
| fact | The answer. A value at a place with its provenance — a detection with a score, a land-cover proportion, an index reading. Earth-observation facts carry the source COG/scene they were materialized from. |
| receipt | The proof. For facts cited from the open emem.dev ledger: canonical CBOR → BLAKE3 hash → ed25519 signature, verifiable offline against the signer’s public key. See § 8. |
§ 3
Authentication
The authenticated tools take a public-scope key as a bearer token. Generate one from Account → API keys in the app; it starts with on_. Public keys call the public API and are rejected (403) on admin endpoints.
Authorization: Bearer on_…
One tool is open: POST /api/v1/object-detection needs no key and is rate-limited per IP, so you can try detection before you sign up. Everything under /api/tool/… and /api/scene needs a key, and each call is bounded by your memory-storage quota — a full quota returns 402 (see § 9).
MCP clients (§ 6) pass the same key in an X-API-Key header, which the server forwards to the tool it proxies.
§ 4
Vision tools
Analyze a frame from any camera, drone, or upload. These run the detection and vision-language heads geo.qa serves for its own sensor pipeline.
/api/v1/object-detection. Open-vocabulary detection. No auth, rate-limited per IP./api/tool/camera-stream/detections. Detection with alert_triggers and an optional ask_question. Bearer key./api/scene. Vision-language scene description — a human-readable read of what’s in the frame. Bearer key.Request body
{
"image_url": "https://…", // or image_base64 (raw or data: URL)
"prompts": ["person", "vehicle"], // labels to detect, up to 20
"confidence_threshold": 0.15, // drop weaker boxes
"alert_triggers": ["fire"], // flag these as alerts
"ask_question": "anything unusual?" // optional VLM read
}
§ 5
Satellite tools
Land-use / land-cover from satellite, at a point, across a box, or inside a polygon. These resolve a place against Sentinel-2/Landsat and return class labels with fractional coverage. All take a Bearer key.
/api/tool/satellite/lulc/analyze?lat=..&lon=... Land cover at a single point./api/tool/satellite/lulc/bbox. Samples a grid across a box./api/tool/satellite/lulc/polygon. Samples points inside a polygon ring.# land cover across a bounding box curl -X POST https://geo.qa/api/tool/satellite/lulc/bbox \ -H "Authorization: Bearer $GEOQA_KEY" \ -H "Content-Type: application/json" \ -d '{ "min_lat": 12.9, "min_lon": 77.5, "max_lat": 13.0, "max_lon": 77.6, "grid_size": 5 }'
For richer Earth-observation — vegetation indices, surface water, forest loss, weather, similarity search — call the open emem.dev protocol directly, or let geo.qa cite it for you (§ 8).
§ 6
MCP server
geo.qa runs a native Model Context Protocol server over Streamable HTTP at https://geo.qa/api/mcp. It wraps the same tools above so an agent can use them natively. Five tools today — and tools/list is the authority, not this list:
Client config
Drop this into your MCP client (Claude Desktop, Cursor, Windsurf, any agent runtime). The key is a public-scope key from your account; the open detect_objects tool works even without it.
{
"mcpServers": {
"geoqa": {
"transport": "streamable-http",
"url": "https://geo.qa/api/mcp",
"headers": {
"X-API-Key": "on_…"
}
}
}
}
Discover the live schema by POSTing {"jsonrpc":"2.0","id":1,"method":"tools/list"} to /api/mcp. For the ~81-tool Earth-observation surface (NDVI, water, forest, weather, receipts), point a second MCP client at the open emem.dev protocol.
§ 7
Discovery
Everything an agent needs to find and call the API on its own:
/api/public-docs/openapi. The machine-readable OpenAPI 3.0 spec — generate a typed client from it./.well-known/agent-card.json. The A2A agent card, every tool published as a skill. Also served at /agent.json./.well-known/oauth-protected-resource. RFC 9728 metadata for this API. A refusal from /api/mcp points here in WWW-Authenticate./llms.txt. A curated index for LLM crawlers and agent frameworks./.well-known/ai-plugin.json. OpenAI-compatible tool manifest.There is no separate published SDK to install — generate one from the OpenAPI spec, or add the MCP server for native tool use. Field names are stable; breaking changes ship under a new /v2 path.
§ 8
Recall & receipts
geo.qa’s Earth-observation answers are grounded in the open emem.dev ledger: a signed, content-addressed memory of Earth built on public satellite and climate sources. When geo.qa cites an EO fact, it carries a receipt from that ledger.
A receipt is canonical CBOR → a BLAKE3 content hash → an ed25519 signature. It verifies offline against the signer’s public key, with no callback to us. Every route below takes no credential, now or ever: an answer you cannot check without an account is not worth much.
# one door, any token shape. no key, no account. curl -s https://geo.qa/api/world-model/verify \ -H 'content-type: application/json' \ -d '{"token":"emem:fact:defi.zb4e6.fIsI.hujO:oqdnpskm73q53cnuo46ieyb5dvtxr4fey6qlffxtkjqbzqe7y5gq"}' → { "matches": true, "value_verbatim": "0.23483583750695602", "signer": "777er3yih…" } # or skip us: pin the key and check it in your own process curl -s https://geo.qa/.well-known/geoqa.json
Check a file, not a receipt
Every file uploaded to geo.qa is signed the moment it arrives: an ed25519 signature over the sha256 of the bytes as stored, their length, their media type and the time. Hash a file you were handed and ask whether we hold that record — the file never has to leave your machine, only the hash is sent.
# what geo.qa holds for these exact bytes. no key, no account. curl -s https://geo.qa/api/world-model/media/receipt/$(sha256sum ./drone.mp4 | cut -d' ' -f1) → { "found": true, "receipt": {…}, "verify": "…/verify/by-cid/<cid>" } → 404 { "found": false } — no record of those bytes. That is a statement about our records, not a verdict about your file.
It proves the bytes have not changed since we received them. It does not say the content is true, and a coords block, when present, is what the FILE claimed, not a verified location. The same check is on the public verifier, which hashes in your browser.
Also unauthenticated: POST /api/world-model/verify/receipt for a whole receipt object, /verify/batch for up to 256 at once, and the transparency log at /verify/log/sth, /verify/log/proof/{cid} and /verify/log/consistency. There is a paste-a-receipt page at /verify that needs no sign-in.
A single verifier checks any emem-format receipt. Durable signing of private-tenancy facts (your own cameras and sensors) is rolling out — see the roadmap in § 11.
Preview
Private tenancy
Beyond the stateless tools above, geo.qa is building a private, per-tenant memory: register a sensor once, then recall its dated observations against a place and window, run monitoring loops, and receive signed webhooks. The pieces exist inside the app (sensor registry, saved streams, monitored areas, world-model recall); a stable public REST surface for them is in private preview, not yet generally available.
If you want early access to per-tenant recall, monitoring loops, or scoped agent keys, talk to us. We’ll turn it on for your tenancy and document the exact shapes as they ship — we won’t list an endpoint here until you can call it.
§ 9
Errors
Standard HTTP status codes with a machine-readable code and a human message in the body.
| status | meaning |
|---|---|
| 400 | request shape or parameter error; fix and resend |
| 401 | missing, malformed, or revoked key |
| 402 | memory storage limit reached; free space or upgrade your plan |
| 403 | admin-scope key used on the public API; mint a public-scope key |
| 429 | rate-limited; back off per Retry-After |
| 5xx | our side; the request is safe to retry |
§ 10
Rate limits
The anonymous detector (/api/v1/object-detection) and the MCP endpoint are rate-limited per IP with a token bucket; responses carry X-RateLimit-Remaining and X-RateLimit-Reset, and a 429 carries Retry-After. Authenticated tools are not per-call metered — they draw against your plan’s memory-storage quota, and return 402 when it is full. Your daily allowances follow your tier on the pricing page.
§ 11
Status & roadmap
geo.qa is early and we keep this honest. Here is what is live today and what is still ahead — no version history we didn’t ship.
| Live now | Object detection, camera-stream detections, scene analysis, satellite LULC (point / bbox / polygon), the native 3-tool MCP server, OpenAPI + llms.txt + ai-plugin.json discovery, and receipt verification against the open emem.dev ledger. |
|---|---|
| In progress | Durable ed25519 signing of private-tenancy facts; a stable public REST surface for per-tenant recall and monitoring loops (today in the app, in private preview for the API); scoped agent keys. |
| Ahead | Signed webhooks, world-model training on your own memory, and airgapped tenancy delivery. We’ll document each here the day it can be called, not before. |
Call one endpoint today.
Hit the open detector with a frame URL, or mint a key and classify land cover from satellite. Everything on this page is live — nothing here is a promise you can’t call.
geo.qa · a vortx ground decoder · emem.dev open protocol