UniLink Python SDK (Build With UniLink Using Python)

UniLink Python SDK (Build With UniLink Using Python)
The official UniLink Python SDK gives you a clean, Pythonic interface to the UniLink API — install it in one command and build data pipelines, Django integrations, and automation scripts with minimal boilerplate.
- Install with
pip install unilink, initialize with your API key, and call methods likeclient.contacts.create()andclient.orders.list(). - Both synchronous (requests-based) and async (aiohttp-based) interfaces are included in the same package.
- Ideal for data pipelines, Django/Flask backends, scheduled scripts, and ETL workflows that need UniLink data.
Python is the dominant language for data pipelines, automation scripts, and backend integrations that move data between services. The UniLink Python SDK brings the same clean, documented interface to the Python ecosystem that the JavaScript SDK provides for Node.js — install it in a virtual environment, set your API key as an environment variable, and start calling methods with named parameters and typed return values. Whether you are writing a nightly script that syncs UniLink contacts to your data warehouse, a Django view that shows order history, or a Flask webhook handler, the SDK handles the HTTP layer so you can focus on the logic.
What the Python SDK Does
The UniLink Python SDK provides a synchronous client built on the requests library and an asynchronous client built on aiohttp. The synchronous UniLink class is the right choice for scripts, Celery tasks, management commands, and any context where you call the API sequentially without concurrency concerns. The asynchronous AsyncUniLink class is the right choice for FastAPI endpoints, async Django views, and any code that uses Python's asyncio event loop — it avoids blocking the event loop during HTTP calls. Both clients expose identical method signatures, so switching between them requires only changing the import and adding await keywords.
The SDK is organized into resource namespaces: client.pages, client.contacts, client.orders, client.products, client.analytics, and client.domains. Each namespace provides list(), get(id), create(data), update(id, data), and delete(id) methods where the API supports them. Method parameters are keyword arguments — no positional argument ambiguity. The list() methods accept filter keyword arguments like status='pending', start_date='2026-01-01', and tag='subscriber' that map directly to the API's query parameters. Return values are Python dicts parsed from the JSON response.
Errors are raised as instances of UniLinkError, a subclass of Exception with status_code and message attributes. Specific subclasses cover common HTTP error conditions: UniLinkAuthError for 401 responses, UniLinkNotFoundError for 404, UniLinkRateLimitError for 429, and UniLinkConflictError for 409. Catching these specific exceptions rather than the base UniLinkError lets you handle each condition appropriately — retry on rate limit, skip on not found, update on conflict — without parsing error messages manually.
How to Get Started
- Create or activate a Python virtual environment and install the package:
pip install unilink. The package requires Python 3.8+ and installsrequestsas its only mandatory dependency. - Generate an API key from Settings → API at app.unilink.us. Set it as an environment variable:
export UNILINK_API_KEY="your_key_here"(add to your.envfile or shell profile). - Initialize the client:
import os; from unilink import UniLink; client = UniLink(api_key=os.environ['UNILINK_API_KEY']). - Make your first call:
pages = client.pages.list(); print(pages['data']). Confirm you see your account's pages returned as a list of dicts. - Test a write call if your key has write scope:
contact = client.contacts.create(email='test@example.com', tags=['sdk-test']); print(contact['id']). Verify the contact appears in your UniLink dashboard.
How to Use the Python SDK
- Sync client (scripts and Django/Flask):
from unilink import UniLink; client = UniLink(api_key=os.environ['UNILINK_API_KEY'])— use this for all non-async contexts. - Async client (FastAPI and asyncio):
from unilink import AsyncUniLink; client = AsyncUniLink(api_key=os.environ['UNILINK_API_KEY']); orders = await client.orders.list(status='pending')— identical method names, addawait. - List with filters:
contacts = client.contacts.list(tag='subscriber', start_date='2026-04-01', per_page=100)— all filter parameters are keyword arguments matching the API's query parameter names. - Iterate all pages:
for contact in client.contacts.iterate(tag='subscriber'): process(contact)— theiterate()method is a generator that yields individual records across all pages automatically. - Error handling:
from unilink import UniLinkConflictError; try: client.contacts.create(email=email) except UniLinkConflictError as e: client.contacts.update(e.existing_id, tags=[...])— theUniLinkConflictErrorexposes the existing resource's ID for immediate update use.
Key Settings
| Setting | What It Does | Recommended |
|---|---|---|
api_key | Your UniLink Bearer token, used for all requests — set once at initialization | Load from os.environ['UNILINK_API_KEY'] — never hardcode in source; add to .env with python-dotenv |
timeout | Request timeout in seconds (default: 30) | Set to 10 for user-facing endpoints; keep 30 for batch data jobs where slow responses are acceptable |
retries | Number of retries on network errors and rate-limit responses (default: 3) | Keep 3 for production automation; set to 0 in development to see errors immediately without retry delay |
base_url | API base URL — defaults to https://unilink.us/api/v1 | Leave as default; override only when pointing to a local test proxy or mock server |
Django settings.py pattern | Store client initialization once in a module imported by views and tasks | Create a unilink_client.py module that initializes the client once and import it — avoid re-initializing on every request |
iterate() generator rather than calling list() in a loop. The generator fetches one page at a time and yields records, keeping memory consumption flat regardless of dataset size. A loop over 50,000 contacts with iterate() uses the same memory as a loop over 100 contacts.
Get the Most Out Of the Python SDK
For Django integrations, place the SDK client initialization in a dedicated services/unilink.py module at the application level. Import this module in your views, serializers, and management commands rather than initializing a new client in each file. This pattern gives you a single place to configure the client — timeout, retry settings, logging — and makes mocking straightforward in tests: patch the services.unilink.client object in your test setup and every code path that imports from that module uses the mock automatically.
The async client pairs naturally with FastAPI. Define a lifespan function that initializes AsyncUniLink at application startup and attaches it to the app state, then inject it as a dependency in your route functions. This avoids creating a new client connection on every request while still making it accessible anywhere in the application. The aiohttp session inside the async client reuses TCP connections across requests, which is a meaningful performance improvement when your API endpoints make multiple UniLink calls per request.
For ETL pipelines, use the SDK's iterate() generator as the source stage of your pipeline and process records in batches to stay memory-efficient. A pattern like collecting 500 records at a time from the generator and writing them to your data warehouse in a batch insert keeps both the UniLink API call rate and the database write overhead manageable. Tune the batch size based on your warehouse's optimal insert size — typically between 100 and 1,000 rows for most cloud data warehouses.
When running scheduled scripts with cron or Celery Beat, add structured logging around SDK calls so you have an audit trail for every automated operation. Log the method called, the filter parameters, the result count, and the execution time. This makes debugging silent failures — a script ran but pulled zero records due to a wrong date filter — straightforward compared to scripts that produce no output on success. The SDK does not emit logs by default; add them at the call site in your script wrapper.
Troubleshooting
| Problem | Cause | Fix |
|---|---|---|
UniLinkAuthError: 401 on all calls | Environment variable not set, empty, or loaded after client initialization | Print os.environ.get('UNILINK_API_KEY', 'NOT SET') before initialization — use python-dotenv's load_dotenv() at the top of your script to load .env before any other imports |
ImportError: No module named 'unilink' | Package not installed in the active virtual environment | Confirm you are in the correct virtualenv with which python and run pip install unilink inside it |
Async client raises RuntimeError: no running event loop | Calling async methods with await outside an async function or event loop | Use asyncio.run(main()) to run the top-level coroutine, or switch to the synchronous UniLink client if asyncio is not needed |
iterate() stops early, missing records | Date filter excludes records outside the range, or the API key lacks scope for some records | Call list(per_page=1) and check the total field against expected record count; remove filters to confirm all records are accessible |
- Both sync and async clients in one package cover all Python use cases without installing multiple libraries
- Typed error subclasses make error handling precise — no string parsing to determine error type
- The
iterate()generator enables memory-efficient processing of large datasets without manual pagination - Consistent resource namespace pattern mirrors the JavaScript SDK, reducing learning overhead for full-stack teams
- Return values are plain dicts, not dataclasses or Pydantic models — no static type checking on response fields without extra setup
- Async client requires aiohttp as an additional dependency — adds to the install size for projects that only need sync access
- No built-in caching — repeated calls for the same data (e.g., fetching themes on every request) must be cached at the application layer
Does the SDK support Python 2?
No — the SDK requires Python 3.8 or higher. Python 2 reached end of life in 2020 and is not supported. If you are on Python 3.7, upgrade to 3.8+ to use the SDK.
Can I use the SDK in a Jupyter notebook?
Yes — the synchronous client works directly in Jupyter cells. For the async client in Jupyter, use await client.contacts.list() directly in a cell (Jupyter's event loop supports top-level await in recent versions), or use asyncio.run() with a wrapper coroutine in older setups.
How do I add the SDK to a Django project?
Add unilink to your requirements.txt and run pip install -r requirements.txt. Create a services/unilink_client.py module that initializes UniLink(api_key=settings.UNILINK_API_KEY), where UNILINK_API_KEY is set in settings.py from an environment variable. Import the client from this module in views and management commands.
Does the SDK handle rate limiting automatically?
Yes — when the API returns a 429 Too Many Requests response, the SDK reads the Retry-After header and waits the specified number of seconds before retrying, up to the configured number of retries (default: 3). If all retries are exhausted, a UniLinkRateLimitError is raised.
Are there type hints in the SDK for IDE support?
Method signatures have type hints for parameters, but return values are typed as dict rather than strongly-typed dataclasses. IDE autocomplete works for method parameters. For typed response parsing, use Pydantic models to validate and parse the returned dicts into typed objects at the call site.
- Install with
pip install unilinkand initialize withUniLink(api_key=os.environ['UNILINK_API_KEY']). - Use the sync client (
UniLink) for scripts and Django/Flask; use the async client (AsyncUniLink) for FastAPI and asyncio applications. - The
iterate()generator handles pagination automatically and keeps memory usage flat for large datasets. - Catch specific error subclasses (
UniLinkAuthError,UniLinkRateLimitError,UniLinkConflictError) for precise error handling logic. - Initialize the client once at module level — not on every function call — for both performance and testability.
Start building with the UniLink Python SDK — run pip install unilink, grab your API key from app.unilink.us under Settings → API, and make your first call in under five minutes.
Create Your Free Link-in-Bio Page
Join thousands of creators using UniLink. 40+ blocks, analytics, e-commerce, and AI tools — all free.
Get Started Free