Zero-dependency client for the SibFly ground-motion API (satellite-measured land subsidence/uplift, mm/yr, for any US address)
Project description
sibfly
Zero-dependency Python client for SibFly — satellite-measured ground motion (sinking/uplift, mm/yr and in/yr) for any US address, from NASA OPERA Sentinel-1 InSAR. Flat $0.40 per covered report; misses are free.
Pure stdlib (urllib), Python >= 3.8, fully typed (py.typed), no dependencies.
pip install sibfly
Quickstart
from sibfly import SibFly, InsufficientCredits
client = SibFly.register("agent@example.com") # self-onboard: key + free credits
try:
r = client.motion(address="425 Fremont St, Las Vegas, NV")
print(r["velocity_vertical_mm_yr"], r["assessment"])
except InsufficientCredits as e:
print("top up at:", e.top_up_url) # self-refill URL from the 402
Already have a key? SibFly(api_key="sf_...") or set SIBFLY_API_KEY in the env.
Out of credits? The full recovery loop
When a billed call raises InsufficientCredits, you can self-refill entirely
by API — no browser, no human:
import time
from sibfly import SibFly, SpendCapReached, InsufficientCredits
client = SibFly() # SIBFLY_API_KEY in env
def motion_with_refill(**q):
try:
return client.motion(**q)
except SpendCapReached:
raise # your own daily cap — topping up won't help; see below
except InsufficientCredits as e:
order = client.buy(10) # POST /api/v1/buy -> Stripe session
print("pay here:", order["checkout_url"]) # open/relay this URL
while client.balance()["credits_usd"] < 0.40:
time.sleep(15) # credits land via webhook
return client.motion(**q) # now it goes through
report = motion_with_refill(address="425 Fremont St, Las Vegas, NV")
e.buy_api on the exception carries the machine-readable refill recipe from the
402 body (suggested amount, endpoints). client.buy(amount, method="crypto")
returns {invoice_url, txn_id} for BTC instead of a Stripe checkout_url.
Spend caps
client.spend_cap(5) sets a per-key daily cap of $5; once tripped, billed calls
raise SpendCapReached (a subclass of InsufficientCredits, so old handlers
still catch it — but don't top up: you still have credits, the cap is yours).
Clear it with client.spend_cap(None).
Billed retries and Idempotency-Key — read this
motion(), batch(), and timeseries() are billed. Retrying a billed call
without an Idempotency-Key charges you again. The SDK protects you: it
auto-sets a fresh UUID Idempotency-Key header on every billed call, so its own
internal retries (network blips, 5xx) can never double-charge.
But the auto key is per call — if your code re-invokes motion(...) after
a crash, that is a new key and a new charge. To make your own retries free, pass
an explicit key and reuse it:
r = client.motion(address="...", idempotency_key="job-1234-row-7")
# same call again with the same key -> served from cache, cost_usd == 0
Replays are cached for 7 days.
Surface
| Method | Endpoint | Billed |
|---|---|---|
SibFly.register(email) |
POST /api/v1/autonomous/register — returns a ready client |
free |
client.motion(address=... / lat=..., lon=..., **gates) |
GET /api/v1/motion |
$0.40 (misses free) |
client.batch(items, async_=True) |
POST /api/v1/motion/batch (max 1000; only covered rows billed) |
per covered row |
client.batch_job(job_id) / client.wait_batch(job_id) |
GET /api/v1/motion/batch/{job_id} |
free to poll |
client.timeseries(...) |
GET /api/v1/timeseries |
yes |
client.buy(amount_usd, method="stripe") |
POST /api/v1/buy -> payment URL |
free (payment link) |
client.spend_cap(daily_usd) |
POST /api/v1/account/spend_cap (None clears) |
free |
client.coverage(...) / client.coverage_batch(items) |
GET /api/v1/coverage / POST /api/v1/coverage/batch |
free |
client.frames() / client.frame_last_updated(id) |
GET /api/v1/frames / /frames/{id}/last_updated |
free |
client.geocode(address) |
GET /api/v1/geocode |
free |
client.balance() / client.me() / client.usage() |
GET /api/v1/balance / /me / /usage |
free |
client.create_key(daily_cap_usd=..) / list_keys() / revoke_key(k) |
POST/GET /api/v1/keys, DELETE /api/v1/keys/{key} |
free |
Gates (free-miss guards) pass straight through: motion(address=..., dry_run=1),
max_age_days=90, min_confidence=0.8, include="timeseries", brief=1, ...
Built in
- Auto-retry — configurable via
SibFly(api_key, timeout=30, max_retries=3, max_backoff=30): exponential backoff with jitter on 429/5xx/network errors, honorsRetry-After. - Idempotency — a UUID
Idempotency-Keyheader is auto-attached to billed calls (motion,batch,timeseries), so a retried request is never double-charged. Passidempotency_key="..."to control it. - Typed errors —
AuthError(401),InsufficientCredits(402, carries.top_up_url/.buy_api/.suggested_top_up_usd),SpendCapReached(402spend_cap_reached, subclass ofInsufficientCredits),RateLimitError(429 after retries, carries.retry_after),NetworkError(timeouts/connection failures,retryable=True),SibFlyErrorbase (.status,.code,.request_id,.body). - Typing — full annotations +
py.typed;MotionReport,Balance,BuyResultTypedDicts.
Full API contract: https://sibfly.com/llms.txt · MIT license.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sibfly-0.2.0.tar.gz.
File metadata
- Download URL: sibfly-0.2.0.tar.gz
- Upload date:
- Size: 11.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
37bb06603c6c823252d55d723dbc1b219d013f46d3a460e0293dc5c8cd19e460
|
|
| MD5 |
4d00f063cc3ac971f29302c8d881de4b
|
|
| BLAKE2b-256 |
559daa98b897761f9369305f7b3fab650776ce3c4263688b5c2941e1c5e9d5d4
|
File details
Details for the file sibfly-0.2.0-py3-none-any.whl.
File metadata
- Download URL: sibfly-0.2.0-py3-none-any.whl
- Upload date:
- Size: 10.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
95e895309974ab58b10648fc802ced88ec4a3fb0418ab0d670e64dd057b3a119
|
|
| MD5 |
4b09ee6cfca04bf1ce2eb1afe99c9f8a
|
|
| BLAKE2b-256 |
99de48c97b648ef339fb9399fb3114703902c0ebb69ba526c7518156e3ed2297
|