Official Python SDK for the CannaSage Developer API.
Project description
cannasage
Official Python SDK for the CannaSage Developer API. Async-first (httpx) with a sync compatibility wrapper.
Beta. This SDK is pre-1.0 and may change. Pin a specific version in production.
Install
pip install cannasage
Quick start (async)
import asyncio
from cannasage import AsyncCannaSageClient
async def main():
async with AsyncCannaSageClient(api_key="csk_live_...") as cs:
result = await cs.sops.list(category="ipm")
print(result.data)
asyncio.run(main())
Quick start (sync)
from cannasage import CannaSageClient
cs = CannaSageClient(api_key="csk_live_...")
print(cs.sops.list(category="ipm").data)
The sync wrapper spawns a fresh asyncio event loop per call. If you're making many sequential calls, use AsyncCannaSageClient inside a single asyncio.run() block for better throughput.
Authentication
| Mode | Usage |
|---|---|
| API key | AsyncCannaSageClient(api_key="csk_live_...") |
| Bearer JWT | AsyncCannaSageClient(bearer_token="<jwt>") |
| OAuth client credentials | AsyncCannaSageClient(client_id="...", client_secret="...", scopes=["read"]) |
The OAuth client exchanges credentials lazily on the first request and caches the access token until ~1 minute before expiry.
Resources
| Resource | Methods |
|---|---|
sops |
list, get |
projects |
list, get |
connectors |
list, get, create, update, delete, sync, devices, data, push_data |
environmental |
list_data |
insights |
list |
grow_tracking |
costs, harvests |
webhooks |
list_events, list, create, update, delete, list_deliveries, test, redeliver |
oauth |
list, create, delete |
keys |
list, create, revoke, rotate, force_revoke, set_rate_limit, usage |
Every method returns an ApiResponse with .data and .meta attributes.
Webhook signature verification
from fastapi import FastAPI, Request, HTTPException
from cannasage import verify_webhook_signature
app = FastAPI()
SECRET = "whsec_..."
@app.post("/webhooks/cannasage")
async def handle_webhook(request: Request):
raw_body = await request.body()
signature = request.headers.get("X-CannaSage-Signature", "")
if not verify_webhook_signature(raw_body, signature, SECRET):
raise HTTPException(status_code=401, detail="invalid signature")
event = await request.json()
# ... handle event
return {"ok": True}
verify_webhook_signature uses hmac.compare_digest (constant-time) and never raises on mismatch — it returns bool.
Error handling
All HTTP errors raise CannaSageAPIError:
from cannasage import CannaSageAPIError
try:
await cs.sops.get("missing")
except CannaSageAPIError as err:
print(err.code, err.status, err.request_id)
if err.code == "NOT_FOUND":
...
Retries, timeouts, idempotency
- Retries: up to 3 on
429(rate limited) and503(overloaded).Retry-Afteris honoured with a 30s cap. - Timeout: default 30s per request. Override via
AsyncCannaSageClient(timeout_seconds=60). - Idempotency:
POSTrequests automatically receive a randomIdempotency-Keyheader (forward-compatible — server support coming in a future release).
License
MIT — see LICENSE.
Links
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cannasage-0.1.0b1.tar.gz.
File metadata
- Download URL: cannasage-0.1.0b1.tar.gz
- Upload date:
- Size: 11.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8cbb73747871afdb7d311820215152866fc5f11d0e8c449e526c7de18e1a1e5b
|
|
| MD5 |
45bf4f4db95bab006744e204931f34b8
|
|
| BLAKE2b-256 |
3c6288c9fc838499b9044afe5e57163e3aa915d6c11b0c9c98bb8bb5e10085c8
|
Provenance
The following attestation bundles were made for cannasage-0.1.0b1.tar.gz:
Publisher:
publish-sdks.yml on AppSprout-dev/CannaSage
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cannasage-0.1.0b1.tar.gz -
Subject digest:
8cbb73747871afdb7d311820215152866fc5f11d0e8c449e526c7de18e1a1e5b - Sigstore transparency entry: 1396362648
- Sigstore integration time:
-
Permalink:
AppSprout-dev/CannaSage@b7d372b82f567ed7fb842ee7b0364931a8b05ee7 -
Branch / Tag:
refs/tags/sdk-py-v0.1.0b1 - Owner: https://github.com/AppSprout-dev
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-sdks.yml@b7d372b82f567ed7fb842ee7b0364931a8b05ee7 -
Trigger Event:
push
-
Statement type:
File details
Details for the file cannasage-0.1.0b1-py3-none-any.whl.
File metadata
- Download URL: cannasage-0.1.0b1-py3-none-any.whl
- Upload date:
- Size: 18.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
41c6c1959dc4d1ca355319b0d840a2def8c3526d8e357ecb19225042d10ee556
|
|
| MD5 |
10a3fa7177bdff964df9f9b68db54956
|
|
| BLAKE2b-256 |
1d6cfeb6053055979fdce81f40ef00bd8bcd55e9c1934e2388f63abf35871c3e
|
Provenance
The following attestation bundles were made for cannasage-0.1.0b1-py3-none-any.whl:
Publisher:
publish-sdks.yml on AppSprout-dev/CannaSage
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cannasage-0.1.0b1-py3-none-any.whl -
Subject digest:
41c6c1959dc4d1ca355319b0d840a2def8c3526d8e357ecb19225042d10ee556 - Sigstore transparency entry: 1396362668
- Sigstore integration time:
-
Permalink:
AppSprout-dev/CannaSage@b7d372b82f567ed7fb842ee7b0364931a8b05ee7 -
Branch / Tag:
refs/tags/sdk-py-v0.1.0b1 - Owner: https://github.com/AppSprout-dev
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-sdks.yml@b7d372b82f567ed7fb842ee7b0364931a8b05ee7 -
Trigger Event:
push
-
Statement type: