Skip to main content

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, 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.

Project details


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.

Supported by

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