SlideCold Python SDK
The official Python client for the SlideCold API (Instagram cold-DM outreach):
SlideCold and AsyncSlideCold clients with typed methods for every API operation, generated from the
OpenAPI spec.
Looking for a command line or an MCP server? They live in their own repos:
- CLI: slidecold/slidecold-cli (
slidecold login,slidecold campaigns list, ...) - MCP server: slidecold/slidecold-mcp (
npx -y slidecold-mcp)
Install
pip install slidecold # Python 3.9+, the only dependency is httpx
Create an API key at https://slidecold.com/settings. Keys look like cs_....
Authentication
The API key is resolved in this order:
- the
api_key=argument - the
SLIDECOLD_API_KEYenvironment variable - the config file written by
slidecold loginfrom slidecold-cli:~/.config/slidecold/config.json($XDG_CONFIG_HOME/slidecold/config.jsonif set,%APPDATA%\slidecold\config.jsonon Windows)
The base URL follows the same order (base_url=, SLIDECOLD_BASE_URL, config baseUrl), then defaults to
https://slidecold.com/api/v1. The config file is {"apiKey": "cs_...", "baseUrl": "..."}. The SDK only reads
it; it never writes it.
SDK quickstart
from slidecold import SlideCold
with SlideCold() as client: # or SlideCold(api_key="cs_...")
for campaign in client.campaigns.list():
print(campaign["id"], campaign["name"], campaign["status"])
campaign = client.campaigns.create(
name="Spring outreach",
audienceIds=["aud_123"],
accountIds=["acc_456"],
templates=[{"body": "Hey, quick question about your page"}],
)
print(client.campaigns.stats(campaign["id"]))
csv_text = client.audiences.export("aud_123") # str
members = client.audiences.list_members("aud_123", min_followers=1000, limit=50)
client.conversations.send_reply("conv_789", message="Thanks, sending details now")
client.conversations.send_photo("conv_789", file="offer.jpg")
Request bodies use the API's field names. Pass them as keyword arguments, as a dict, or both:
client.campaigns.update(id, {"status": "ACTIVE"}) is the same as client.campaigns.update(id, status="ACTIVE").
Path parameters are positional and query parameters are snake_case keyword arguments. Every method's
docstring lists the scope it needs. Responses are plain dicts and lists, typed with the TypedDicts in
slidecold.types.
Async
import asyncio
from slidecold import AsyncSlideCold
async def main():
async with AsyncSlideCold() as client:
accounts, campaigns = await asyncio.gather(client.accounts.list(), client.campaigns.list())
asyncio.run(main())
Instagram login jobs
Adding an account, re-logging in and session checks run in the background and return {"jobId": ...}.
wait_for_login_job polls accounts.login_status until the job finishes:
job = client.accounts.create(username="mybrand", password="...", proxyId="prx_1")
status = client.wait_for_login_job(job["jobId"], interval=2, timeout=120)
if status["state"] == "failed":
print(status.get("error"))
It returns the final status (completed, failed or unknown) and raises TimeoutError after timeout seconds.
AsyncSlideCold.wait_for_login_job is the async version.
Options
SlideCold(api_key=None, base_url=None, timeout=30, max_retries=2). GET requests are retried on 429, 5xx and
connection errors with exponential backoff (honouring Retry-After). Other methods are never retried, so a
DM is never sent twice. client.request("operationId", path=..., query=..., body=...) calls any operation by
its OpenAPI operationId.
Scopes
Each API key has scopes of the form <resource>:<read|write> for accounts, audiences, campaigns and
conversations. A :write scope also grants :read. Proxies use the accounts scopes. The scope for each
operation is shown in its method docstring.
Errors
All errors derive from slidecold.SlideColdError and carry status, message (the API's error string)
and body (the parsed response).
| Exception | When |
|---|---|
AuthenticationError |
401: the key is missing or invalid |
PermissionDeniedError |
403: the key lacks a scope (This API key is missing the campaigns:write scope) or a plan limit was hit |
NotFoundError |
404 |
RateLimitError |
429 |
APIError |
any other error status (base class of the four above) |
APIConnectionError |
no response: DNS, connection or timeout |
from slidecold import PermissionDeniedError
try:
client.campaigns.delete("cmp_1")
except PermissionDeniedError as e:
print(e.status, e.message)
Webhooks
SlideCold signs each webhook with an X-SlideCold-Signature header: the hex HMAC-SHA256 of the raw JSON
body, keyed with the endpoint secret (whsec_...). Verify it against the raw bytes, before parsing:
from slidecold import verify_webhook_signature
@app.post("/webhooks/slidecold") # Flask
def slidecold_webhook():
if not verify_webhook_signature(
request.get_data(), request.headers.get("X-SlideCold-Signature", ""), WHSEC
):
abort(401)
event = request.get_json()
...
Development
uv sync
uv run python scripts/generate.py # regenerate from openapi.yaml
uv run ruff check . && uv run ruff format --check . && uv run mypy && uv run pytest
src/slidecold/_operations.py, _resources.py and types.py are generated from openapi.yaml and committed.
CI fails if they are stale.
License
MIT
Metadata
Release files for slidecold 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| slidecold-0.2.0.tar.gz | 40.0 kB | Without provenance | Details for slidecold-0.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| slidecold-0.2.0-py3-none-any.whl | Python 3 | none | any | Details for slidecold-0.2.0-py3-none-any.whl |
Total release size: 67.1 kB
Release files / slidecold-0.2.0.tar.gz
| Download URL | slidecold-0.2.0.tar.gz |
|---|---|
| Size | 40.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a476959cadb46bc725b0104035661f9155da408e84f89b82ac6acbf6c04e0a5b
|
|
BLAKE2b-256 checksum How to use checksums |
61109bb8f547d9627f487869867619784a99ef078c8245f38f100176b9b0563d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Release files / slidecold-0.2.0-py3-none-any.whl
| Download URL | slidecold-0.2.0-py3-none-any.whl |
|---|---|
| Size | 27.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8ac07e12d8b40863962207e1221535e9f6a3d18c6f70282ec96799444e99a14e
|
|
BLAKE2b-256 checksum How to use checksums |
e4631badf7e95c3b57cede18f1f78ab712144561fb9d4043e7371681171a51e5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Security for slidecold 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.