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 errors — AuthError (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.

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)

Source distribution for sibfly 0.2.0
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)

Table of built distributions (wheels) for sibfly 0.2.0
File Interpreter ABI Platform Actions
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.

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page