Skip to main content

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, honors Retry-After.
  • Idempotency — a UUID Idempotency-Key header is auto-attached to billed calls (motion, batch, timeseries), so a retried request is never double-charged. Pass idempotency_key="..." to control it.
  • Typed errorsAuthError (401), InsufficientCredits (402, carries .top_up_url / .buy_api / .suggested_top_up_usd), SpendCapReached (402 spend_cap_reached, subclass of InsufficientCredits), RateLimitError (429 after retries, carries .retry_after), NetworkError (timeouts/connection failures, retryable=True), SibFlyError base (.status, .code, .request_id, .body).
  • Typing — full annotations + py.typed; MotionReport, Balance, BuyResult TypedDicts.

Full API contract: https://sibfly.com/llms.txt · MIT license.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sibfly-0.2.0.tar.gz (11.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sibfly-0.2.0-py3-none-any.whl (10.4 kB view details)

Uploaded Python 3

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

Hashes for sibfly-0.2.0.tar.gz
Algorithm Hash digest
SHA256 37bb06603c6c823252d55d723dbc1b219d013f46d3a460e0293dc5c8cd19e460
MD5 4d00f063cc3ac971f29302c8d881de4b
BLAKE2b-256 559daa98b897761f9369305f7b3fab650776ce3c4263688b5c2941e1c5e9d5d4

See more details on using hashes here.

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

Hashes for sibfly-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 95e895309974ab58b10648fc802ced88ec4a3fb0418ab0d670e64dd057b3a119
MD5 4b09ee6cfca04bf1ce2eb1afe99c9f8a
BLAKE2b-256 99de48c97b648ef339fb9399fb3114703902c0ebb69ba526c7518156e3ed2297

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 files

0.1.0

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page