Skip to main content

Official Python SDK for instanode.dev — zero-friction developer infrastructure for AI agents

Project description

instanode

Official Python SDK for instanode.dev — zero-friction developer infrastructure. Provision real databases, caches, queues, and heartbeat monitors with a single function call. No account required. No Docker. No setup.

pip install instanode

Quickstart

Heartbeat monitor (cron job health check)

import instanode

client = instanode.Client()

# Provision a monitor — no account needed
mon = client.provision_monitor(name="nightly-backup")
print(mon.url)  # https://instanode.dev/ping/<token>

# Wrap any callable — sends /start, then success or /fail automatically
def run_backup():
    ...  # your job logic here

client.heartbeat_wrap(mon.token, run_backup)

Postgres database

import instanode

client = instanode.Client()
db = client.provision_database(name="my-app-db")

# Use the connection string with psycopg2, SQLAlchemy, Django, asyncpg, etc.
print(db.connection_url)
# postgres://user:pass@host:5432/dbname

# Anonymous resources expire in 24 h. Check the note field:
if db.note:
    print(db.note)  # "Claim your resources at https://instanode.dev/start?t=..."

Full provision (DB + cache + MongoDB + monitor)

import instanode

client = instanode.Client()

db    = client.provision_database(name="app-db")
cache = client.provision_cache(name="app-cache")
mongo = client.provision_mongodb(name="app-nosql")
mon   = client.provision_monitor(name="app-health")

print(db.connection_url)     # postgres://...
print(cache.connection_url)  # redis://...
print(mongo.connection_url)  # mongodb://...
print(mon.url)               # https://instanode.dev/ping/<token>

Authentication

Without an API key, the SDK operates in anonymous mode: resources are real but expire after 24 hours and have lower rate limits (100 pings/day, 10 MB Postgres, etc.).

To make resources permanent, call client.claim() or visit the upgrade URL that appears in result.note.

# Set via environment variable (recommended)
export INSTANODE_API_KEY=sk_...

# Or pass to the constructor
client = instanode.Client(api_key="sk_...")

Method Reference

Method Endpoint Auth required
provision_monitor(name) POST /ping/new No
heartbeat(token) POST /ping/{token} No
heartbeat_start(token) POST /ping/{token}/start No
heartbeat_fail(token) POST /ping/{token}/fail No
heartbeat_wrap(token, fn) start + success/fail No
provision_database(name) POST /db/new No
provision_cache(name) POST /cache/new No
provision_mongodb(name) POST /nosql/new No
provision_queue(name) POST /queue/new No
claim(jwt, email, team_name) POST /claim No
list_resources() GET /api/v1/resources Yes
get_resource(token) GET /api/v1/resources/{token} Yes
delete_resource(token) DELETE /api/v1/resources/{token} Yes
rotate_credentials(token) POST /api/v1/resources/{token}/rotate-credentials Yes

Tier Limits

Tier Postgres Redis MongoDB Pings/day
anonymous 10 MB / 2 conn / 24 h 5 MB / 24 h 5 MB / 2 conn / 24 h 100
hobby (claimed) 500 MB / 5 conn 25 MB 100 MB / 5 conn 1 000
pro ($12/mo) 5 120 MB / 20 conn 256 MB 2 048 MB / 20 conn 50 000
team ($49/mo) unlimited unlimited unlimited unlimited

Error handling

import instanode

client = instanode.Client()

try:
    db = client.provision_database()
except instanode.InstanodeError as exc:
    print(exc.status_code)  # 503
    print(exc.code)         # "provisioning_failed"
    print(exc.message)      # "provisioner unavailable"

    if exc.is_rate_limited():      # 429
        print("slow down")
    elif exc.is_service_unavailable():  # 503
        print("try again later")
    elif exc.is_not_found():       # 404
        print("wrong token")
    elif exc.is_conflict():        # 409  — JWT already claimed
        print("already claimed")

Context manager (auto-cleanup)

The client supports use as a context manager. No persistent connections are held, so this is mainly for idiomatic resource scoping:

import instanode

with instanode.Client() as client:
    db = client.provision_database()
    # use db.connection_url ...
# client goes out of scope here

Async support

import asyncio
import instanode.aio

async def main():
    async with instanode.aio.AsyncClient() as client:
        # Provision concurrently
        db, cache = await asyncio.gather(
            client.provision_database(name="app-db"),
            client.provision_cache(name="app-cache"),
        )
        print(db.connection_url)
        print(cache.connection_url)

        # heartbeat_wrap works with async functions too
        async def run_job():
            await asyncio.sleep(0.1)

        mon = await client.provision_monitor(name="async-job")
        await client.heartbeat_wrap(mon.token, run_job)

asyncio.run(main())

Claiming anonymous resources

When instanode.dev surfaces the upgrade URL in result.note, extract the JWT from the ?t= query parameter and call claim():

import instanode
from urllib.parse import urlparse, parse_qs

client = instanode.Client()
db = client.provision_database()

if db.note and "instanode.dev/start" in (db.note or ""):
    # parse the JWT from the URL in the note
    # e.g. note = "Claim at https://instanode.dev/start?t=eyJ..."
    upgrade_url = db.note.split()[-1]
    jwt = parse_qs(urlparse(upgrade_url).query)["t"][0]

    result = client.claim(
        jwt=jwt,
        email="dev@example.com",
        team_name="My Team",   # optional
    )
    print(f"Claimed {result.claimed} resources → team {result.team_id}")

Zero dependencies

The SDK uses only the Python standard library (urllib.request). No requests, no httpx, no aiohttp. Works in any environment including AWS Lambda, Google Cloud Functions, and minimal Docker images.


Links

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

instanode-0.2.0.tar.gz (21.4 kB view details)

Uploaded Source

Built Distribution

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

instanode-0.2.0-py3-none-any.whl (14.5 kB view details)

Uploaded Python 3

File details

Details for the file instanode-0.2.0.tar.gz.

File metadata

  • Download URL: instanode-0.2.0.tar.gz
  • Upload date:
  • Size: 21.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for instanode-0.2.0.tar.gz
Algorithm Hash digest
SHA256 67d22ba4bd8650c0192a15db521c11474b5bd2f61a0788cc96ea72926709e766
MD5 1688193c3624f2f2d5bdf882de912cde
BLAKE2b-256 686a175f297fb585a5cf680ab2b8dddf17b927c4daf6c4e1b26d040cddb1aca5

See more details on using hashes here.

File details

Details for the file instanode-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: instanode-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 14.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for instanode-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 382f69cd4a091d0569b5d4352ab69128086a1d8e880b8404cb84dd9e9ab8580e
MD5 90d2507e2c9a2323a48a07a8a8b41ad1
BLAKE2b-256 2ae65e37e6b990b626e797628a9b816370252dbee56b053f55b8e4d234abc6cd

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