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.
Metadata
Release files for sibfly 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| sibfly-0.2.0.tar.gz | 11.8 kB | Without provenance | Details for sibfly-0.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| sibfly-0.2.0-py3-none-any.whl | Python 3 | none | any | Details for sibfly-0.2.0-py3-none-any.whl |
Total release size: 22.3 kB
Release files / sibfly-0.2.0.tar.gz
| Download URL | sibfly-0.2.0.tar.gz |
|---|---|
| Size | 11.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
37bb06603c6c823252d55d723dbc1b219d013f46d3a460e0293dc5c8cd19e460
|
|
BLAKE2b-256 checksum How to use checksums |
559daa98b897761f9369305f7b3fab650776ce3c4263688b5c2941e1c5e9d5d4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.10.12
|
Release files / sibfly-0.2.0-py3-none-any.whl
| Download URL | sibfly-0.2.0-py3-none-any.whl |
|---|---|
| Size | 10.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
95e895309974ab58b10648fc802ced88ec4a3fb0418ab0d670e64dd057b3a119
|
|
BLAKE2b-256 checksum How to use checksums |
99de48c97b648ef339fb9399fb3114703902c0ebb69ba526c7518156e3ed2297
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.10.12
|
Security for sibfly 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.