zinn-sdk is our official Python client for the Zinn Digital® API, published on PyPI and imported as zinn_sdk. It is generated from the same OpenAPI specification the API is built from, every operation has synchronous and asyncio variants, and a new version is published automatically whenever the specification changes. This guide installs it, authenticates it and makes your first calls.
Install
pip install zinn-sdk
It needs Python 3.11 or later and is MIT-licensed.
Create an API key
Open the API keys page of your dashboard (app.zinndigital.com/api-keys) and press Create a key. Give the key a name and only the permissions your code needs — for example sites.view to list sites. The key is shown once; store it in an environment variable or your secret store, never in source code. You can revoke a key at any time on the same page.
Public catalogue endpoints, such as hosting regions and plans, need no key at all.
Your first calls
import os
from zinn_sdk import AuthenticatedClient, Client
from zinn_sdk.api.catalog import list_public_hosting_regions
from zinn_sdk.api.hosting import list_sites
# Public catalogue endpoints need no key.
public = Client(base_url="https://api.zinndigital.com")
regions = list_public_hosting_regions.sync(client=public)
print([region.slug for region in regions.data])
# Everything else uses a per-organisation API key.
api = AuthenticatedClient(base_url="https://api.zinndigital.com", token=os.environ["ZINN_API_KEY"])
page = list_sites.sync(client=api, limit=5)
for site in page.data:
print(site.name, site.status)
Finding an operation
Operations are grouped by API area under zinn_sdk.api and named after their operation id in snake case. Listing sites is zinn_sdk.api.hosting.list_sites; domains and DNS are under zinn_sdk.api.domains; billing under zinn_sdk.api.billing. The API reference shows each operation's id.
Sync, async and the full response
Every operation module has four functions:
sync(...) returns the parsed model, or None on an unexpected status.
sync_detailed(...) returns a Response with status_code, headers and parsed.
asyncio(...) and asyncio_detailed(...) are the same, awaitable.
import asyncio
from zinn_sdk.api.hosting import list_sites
async def main() -> None:
response = await list_sites.asyncio_detailed(client=api, limit=5)
print(response.status_code, len(response.parsed.data))
asyncio.run(main())
Use the _detailed variants when you need to tell a 403 (the key lacks a permission) from a 404.
Where to go next
- The guide on our website: zinndigital.com/developers/sdk-python
- Every endpoint, its parameters and its permission: zinndigital.com/developers/api
- The package on PyPI: pypi.org/project/zinn-sdk