SibFly API — developer & agent docs

Measured ground motion (subsidence / uplift) for any US address, in mm/year and in/year, from NASA OPERA Sentinel-1 InSAR. Measured, not modeled. Flat $0.40 per covered report; misses are free; free preflight; agents can self-register. You can be making real calls in 60 seconds.

Jump to: QuickstartAuthPricingEndpoints Params & gatesResponseErrorsIdempotency & caching MCPMachine discoveryCode snippets

Quickstart (60 seconds)

1. Get an API key — one call, no human, no captcha

curl -X POST https://sibfly.com/api/v1/autonomous/register \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]"}'
# -> { "api_key":"sf_live_...", "credits_usd":1.0, ... }  (first credits free)

2. Make your first report

curl "https://sibfly.com/api/v1/motion?address=425+Fremont+St+Las+Vegas+NV" \
  -H "Authorization: Bearer sf_live_..."

3. You get JSON back (both units, uncertainty, provenance, cost)

{ "status":"ok", "velocity_vertical_mm_yr":-6, "velocity_vertical_in_yr":-0.2362,
  "velocity_uncertainty_mm_yr":1.5, "assessment_code":"notable_subsidence",
  "confidence":0.86, "data_age_days":73, "pixel_id":"F12642_1989_5771",
  "cost_usd":0.4, "credits_remaining_usd":0.6, "request_id":"req_..." }

Tip: check coverage & price for FREE first with ?dry_run=1 (nothing is charged). Out-of-coverage, too-stale, and low-confidence results are always free.

Authentication

Every paid call takes a header Authorization: Bearer <api_key>. Keys never expire. Bearer keys are not rate-limited (un-keyed calls are). Get one via the register call above, or at /signup.

Pricing & credits

Endpoints

EndpointWhatCost
GET /api/v1/motionOne report by address= or lat=&lon=$0.40
POST /api/v1/motion/batchMany addresses, one call (≤1000). Async + since + budget cap.ok rows only
GET /api/v1/timeseriesFull history; reference_date+reference_date2 = movement between 2 dates$0.40
GET /api/v1/coverageIs a point covered? (no args = live frame list)free
POST /api/v1/coverage/batchSize a whole job before spendingfree
GET /api/v1/frames · /frames/{id}/last_updatedWhen data was last refreshed (poll to re-pull)free
GET /api/v1/balance · /usageCredits + price; per-call line-item ledgerfree
POST /api/v1/autonomous/registerAgent self-signup → api_key + free creditsfree
POST/GET/DELETE /api/v1/keysScoped, spend-capped, referer-locked child keys (safe to embed)free
POST /api/v1/account/spend_capSet/clear a daily spend cap ({"daily_usd":20})free
GET /api/v1/geocodeAddress → lat,lon,matched_address,match_type,scorefree
GET /api/v1/pixelThe exact 30 m cell polygon (GeoJSON) covering a pointfree
GET /api/v1/me · /my-reports · /my-chatsYour account, purchased reports, inspector chatsfree
POST /api/v1/chatAI-inspector Q&A about a report you already boughtnarration
POST/GET /api/v1/supportOpen + read support ticketsfree
GET /report.pdfRendered PDF report (?address=, &brief=1)$0.40
GET /api/v1/mapVelocity-heatmap PNG around a point (un-keyed = free teaser)$0.40
POST /mcpMCP server (5 tools) for AI agentsper tool

Params & free gates (on /api/v1/motion)

ParamEffect
dry_run=1Free preview: coverage + confidence + would_cost_usd, no rate, no charge.
max_age_days=NOlder than N days → free miss instead of billing stale data.
min_confidence=0..1Below threshold → free miss.
min_geocode_score=0..1Fuzzy address match (centroid) → free miss; pass lat/lon for a confident hit.
since=YYYY-MM-DDNo new observation since that date → free (great for re-checks).
include=timeseries,accelerationEmbed full history and/or acceleration in the same paid call.
brief=1Add plain-English "SibFly Inspector" narration.
units=mm|in · compact=1 · fields=a,b,cControl payload size (tokens).
mock=ok|no_coverage|stale_data|...Free deterministic sandbox response — test every branch without spending.

Response fields

Every value carries its unit in the key name (_mm_yr + _in_yr). Key fields: velocity_vertical_mm_yr/_in_yr, velocity_uncertainty_mm_yr, assessment_code (stable enum), confidence, near_threshold, neighbor_consistent, data_age_days, data_freshness, pixel_id, pixel_polygon/pixel_geojson, provenance, cost_usd, credits_remaining_usd, request_id. Full machine-readable enums + thresholds: /api/v1/schema.

Errors & statuses

Errors are JSON: {"error":"code","message":"...","retryable":true,"doc_url":"...","request_id":"..."}. Misses are HTTP 200 with a status field (no_coverage, no_data, stale_data, low_confidence, low_geocode_precision, no_new_data) and cost_usd:0 — never 404, never billed. 402 = out of credits (carries top_up_url). 429 = rate-limited un-keyed traffic (carries Retry-After).

Idempotency, caching, safety

MCP (for AI agents)

Point any MCP client at https://sibfly.com/mcp (Streamable HTTP, JSON-RPC), auth with your Bearer key. Tools: check_ground_motion, check_portfolio, get_coverage, get_motion_history, get_account. The initialize response includes a decision-tree; tools expose the same free gates (dry_run, max_age_days, min_confidence, since).

MCP arg names differ from the REST params (also in /api/v1/schema → mcp_arg_map): check_ground_motion uses explain (not brief); get_motion_history uses from_date/to_date (→ reference_date/reference_date2); get_account maps to GET /api/v1/balance; check_portfolio takes addresses[] only. units/fields/include/mock aren't exposed over MCP — use REST for those.

Machine-readable discovery

Code snippets

Python

import requests
KEY = "sf_live_..."
r = requests.get("https://sibfly.com/api/v1/motion",
    params={"address": "425 Fremont St, Las Vegas NV"},
    headers={"Authorization": f"Bearer {KEY}"})
d = r.json()
print(d["velocity_vertical_mm_yr"], d["assessment_code"], d["cost_usd"])

JavaScript

const r = await fetch(
  "https://sibfly.com/api/v1/motion?address=425+Fremont+St+Las+Vegas+NV",
  { headers: { Authorization: "Bearer sf_live_..." } });
const d = await r.json();
console.log(d.velocity_vertical_mm_yr, d.assessment_code, d.cost_usd);

Batch (portfolio)

curl -X POST https://sibfly.com/api/v1/motion/batch \
  -H "Authorization: Bearer sf_live_..." -H "Content-Type: application/json" \
  -d '{"items":[{"id":"a","address":"..."},{"id":"b","lat":30.3,"lon":-97.8}]}'
# -> { "summary":{...}, "results":[ per-item ... ], "failed":[...] }

Screening estimate from satellite radar — not an engineering or survey-grade determination. © SIB Scientific. Terms