Skip to main content

impreza-sdk — Official Python SDK for Impreza Host

Type-safe, sync + async client for the Impreza Host public REST API (api.imprezahost.com). Covers domains, hosting (cPanel), managed email (Titan / Workspace), VPS (Proxmox + Cloud) with smart dispatch, orders, invoices, webhooks, and crypto top-up — all behind one client object.

pip install impreza-sdk

Requires Python 3.10+. See CHANGELOG.md for the release history.

Quickstart

from impreza import Client

# Reads IMPREZA_API_KEY and IMPREZA_API_SECRET from the environment.
# Passing them explicitly works too: Client(api_key="...", api_secret="...").
with Client.from_env() as c:
    me = c.account.get()
    print(me.balance, me.currency)

    # List active services across all backends
    for svc in c.account.services.list(status="Active"):
        print(svc.id, svc.product, svc.status, svc.vps_backend)

Authentication

Two headers, no signing:

  • IMPREZA_API_KEY — imp_ + 40 hex chars (public identifier)
  • IMPREZA_API_SECRET — 64 hex chars (shown once at creation)

Generate keys in your Impreza Account. Add the source IP of every machine that calls the API to the key's IP whitelist.

export IMPREZA_API_KEY="imp_..."
export IMPREZA_API_SECRET="..."

Crypto top-up

Top up account balance with BTC / XMR / TRX / USDT-TRC20 via the existing btcpayinline gateway:

invoice = c.account.topup(amount=50, method="xmr")
print(invoice.payment_url)        # btcpayinline URL
print(invoice.expires_at)         # ISO timestamp, 2h from creation

# Poll until paid (or fail on cancellation / refund / expiry)
invoice.wait_until_paid(timeout=7200, poll_interval=30)
print(invoice.balance_after)

For push delivery instead of polling, subscribe a webhook to the topup.paid event (see below).

Domains

# Availability
print(c.domains.check(["example.com", "example.net"]))

# Lookup
domain = c.domains.get("example.com")
print(domain.status, domain.expiry_date)

# DNS CRUD (nested under domains)
records = c.domains.dns.list("example.com")
c.domains.dns.add("example.com", type="A", name="@", value="203.0.113.24", ttl=3600)
c.domains.dns.update("example.com", type="A", name="@",
                     old_value="203.0.113.24", new_value="203.0.113.25")

VPS (smart dispatch)

One c.vps.get(service_id) call returns a backend-aware bound model. The SDK looks up which backend (Proxmox or Cloud) the service is on and routes operations transparently:

vps = c.vps.get(17988)             # service id from c.account.services.list()
print(vps.backend)                 # "proxmox" or "cloud"

# Common surface — same on both backends
status = vps.status()
print(status.power_state)          # "running" (Proxmox) / "online" (Cloud)
vps.reboot()

# Backend-specific sub-resources (Proxmox)
vps.snapshots.list()
op = vps.snapshots.rollback("pre-update")  # returns Operation future
op.wait(timeout=600)               # blocks until queue completes

Basic Cloud VPS policy (candidate, awaiting rollout): use status(), refresh() (allocated resources), start(), shutdown() and reboot(). Advanced Cloud infrastructure methods remain in the SDK for compatibility, but return API FEATURE_NOT_AVAILABLE (403) after the policy is applied. Do not use stop(), images, restore, rescue, console, reinstall, resize, hostname/password, rDNS, SSH-key assignment, IPv6, ISO or boot-order operations on these services. Contact Impreza support for other infrastructure changes. Orders and cancellations use the normal client account workflow; agent-based app management is separate.

Wrong-backend access raises BackendNotSupported client-side — no network call:

vps = c.vps.get(17987)             # Cloud VPS
vps.snapshots.list()
# raises BackendNotSupported("snapshots is not supported on the 'cloud'
# VPS backend. ...")

Webhooks

The wire contract for webhook events is documented in ../openapi/asyncapi.yaml (AsyncAPI 3.0) — 16 event types across 7 domains (webhook, topup, invoice, order, service, domain, vps) plus wildcards *, vps.*, domain.*.

Subscribe to events server-side:

sub = c.webhooks.create(
    url="https://example.com/hooks/impreza",
    events=["topup.paid", "vps.power_state_changed", "domain.*"],
)
print(sub.secret)                  # 64 hex chars; shown ONCE — store it

Verify deliveries on your receiver (timing-safe HMAC-SHA256):

from impreza.webhooks import verify_signature, WebhookSignatureMismatch

# Inside your Flask / FastAPI / Django handler
try:
    event = verify_signature(
        body=request.body,                  # raw bytes, NOT a re-serialized JSON
        signature_header=request.headers["X-Impreza-Signature"],
        secret=os.environ["IMPREZA_WEBHOOK_SECRET"],
    )
except WebhookSignatureMismatch:
    return ("invalid signature", 401)

if event.type == "topup.paid":
    credit_user(event.data.client_id, event.data.amount)

Async

Every resource has an async counterpart via AsyncClient. Reach for it when you need high-fanout calls — provisioning many VPSs, polling a bulk of invoices in parallel, etc. For one-shot scripts and interactive use the sync Client is simpler and has the same surface.

import asyncio
from impreza import AsyncClient

async def main():
    async with AsyncClient.from_env() as c:
        # Read calls fan out trivially:
        me = await c.account.get()

        # Concurrent reboot across every VPS — gather() returns when
        # all complete (or any one raises). 10 calls take ~one
        # round-trip's worth of wall-clock, not 10x.
        vpss = await c.vps.list()
        await asyncio.gather(*[v.reboot() for v in vpss])

        # Async futures work the same way as their sync counterparts:
        op = await c.vps.get(17988).snapshots.rollback("pre-update")
        await op.wait(timeout=600)         # AsyncOperation.wait()

        invoice = await c.account.topup(amount=50, method="xmr")
        await invoice.wait_until_paid(timeout=7200)  # AsyncTopupInvoice

asyncio.run(main())

The impreza CLI is sync by design — CLI invocations are one-shot processes where the async-fanout speedup doesn't apply. The async path exists for library users; everything the CLI does has a Client.* equivalent. If you're integrating into a long-running async app (FastAPI, an event consumer, a batch worker), import the SDK directly and skip the CLI.

Tor routing

# Explicit
c = Client(api_key="...", api_secret="...",
           proxy="socks5://127.0.0.1:9050")

# Opt-in via flag or env var
c = Client.from_env(use_tor=True)        # equivalent to IMPREZA_USE_TOR=1

# Probe Tor; fall back to clearnet if not running
c = Client.from_env(auto_tor=True)

Backed by httpx[socks]. Sync and async parity. The probe used by For a clearnet API URL, auto_tor=True may fall back to a direct connection. A v3 .onion API URL requires a SOCKS5 proxy or use_tor=True; an unavailable auto-detected proxy raises an error before DNS or HTTP. Explicit proxy routing does not inherit HTTP_PROXY, HTTPS_PROXY or ALL_PROXY from the environment.

Error handling

All errors subclass ImprezaError, so a single except catches everything the SDK can throw:

from impreza import (
    Client, ImprezaError,
    InsufficientCredit, RateLimitExceeded, IpNotWhitelisted,
    OperationFailed, TopupFailed,
)

try:
    c.orders.create(product_id=12, billing_cycle="monthly", domain="example.com")
except InsufficientCredit as e:
    needed = e.details.get("amount_needed")
    print(f"Need ${needed} more — opening a top-up invoice")
    inv = c.account.topup(amount=needed, method="btc")
    print(inv.payment_url)
except RateLimitExceeded as e:
    print(f"Rate limited — retry after {e.retry_after}s")
except IpNotWhitelisted:
    print("Your current IP isn't on the API key's whitelist")

Action polling

Long-running Proxmox operations return Operation futures:

op = c.vps.get(17988).backups.create()
print(op.uuid, op.status)          # 'queued' initially
op.wait(timeout=1800, poll_interval=10)
print(op.is_success(), op.finished_at)

wait() raises OperationTimeout if it doesn't finish, or OperationFailed on a terminal failure state.

Reviewed application configuration

Version 0.6.0 adds configuration export, review and apply. Documents are limited to 64 KiB of UTF-8 and carry secret references instead of values. Applications retain their current configuration until a reviewed plan is explicitly applied.

See the configuration guide for SDK and CLI examples, permissions, review expiry and replay behavior.

Development

git clone https://github.com/imprezahost/impreza-devkit.git
cd impreza-devkit/sdk-python
python -m venv .venv
# Linux/macOS: source .venv/bin/activate
# Windows PowerShell: .venv\Scripts\Activate.ps1
pip install -e ".[test,dev]"

pytest                              # 266 unit tests + mocks
ruff check
mypy --strict impreza

To run the live integration smokes:

export IMPREZA_API_KEY="imp_..."
export IMPREZA_API_SECRET="..."
# Optional — only needed for the full topup decode smoke
export IMPREZA_TOPUP_INVOICE_ID="<id of an existing AddFunds invoice>"

pytest -v -s tests/

The destructive tests (real top-up creation, real Proxmox backup creation) are gated behind IMPREZA_DESTRUCTIVE_TESTS=1 and skipped by default.

License

MIT. See ../LICENSE at the repository root.

Metadata

Release files for impreza-sdk 0.7.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 impreza-sdk 0.7.0
File Size Uploaded
impreza_sdk-0.7.0.tar.gz 104.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for impreza-sdk 0.7.0
File Interpreter ABI Platform
impreza_sdk-0.7.0-py3-none-any.whl Python 3 none any Details

Total release size: 186.1 kB

Release files / impreza_sdk-0.7.0.tar.gz

Download URL impreza_sdk-0.7.0.tar.gz
Size 104.4 kB
Tags Source
SHA-256 checksum
How to use checksums
164f16729522b74adf4e285485fd8eb12f9ed1d35921b870b5349583b52d78bd
BLAKE2b-256 checksum
How to use checksums
ea641201ae846b1dd8288a9eba6338aca8929008363057da0f118ecdd91ecc3f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 22, 2026.

Transparency log

Release files / impreza_sdk-0.7.0-py3-none-any.whl

Download URL impreza_sdk-0.7.0-py3-none-any.whl
Size 81.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
389ad75274b098269db737c0033b5b6c97b0e8edf5da977d98e2231ea78f01a0
BLAKE2b-256 checksum
How to use checksums
cf0119f91a0add7747abaf3e9cf573da58fd56db634cac7b1c3abc1d419cd1f0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 22, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.7.0 This release

2 release files

0.6.0

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

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