Python SDK
The official Python SDK for HempData API. Supports Python 3.8+ with both synchronous and asynchronous clients.
Package: hempdataapi
Installation
pip install hempdataapi
poetry add hempdataapi
Quick Start
from hempdataapi import HempDataClient
client = HempDataClient(api_key="YOUR_API_KEY")
# Check if Delta-9 edibles are legal in Colorado
regulations = client.regulations.list(
state="CO",
substance="delta-9-thc",
product_type="edibles",
)
print(regulations.data[0].legal_status)
# "legal_with_restrictions"
Async Client
from hempdataapi import AsyncHempDataClient
import asyncio
async def main():
client = AsyncHempDataClient(api_key="YOUR_API_KEY")
regulations = await client.regulations.list(state="CO")
print(regulations.data[0].summary)
await client.close()
asyncio.run(main())
Async Context Manager
async with AsyncHempDataClient(api_key="YOUR_API_KEY") as client:
regulations = await client.regulations.list(state="CO")
Configuration
client = HempDataClient(
api_key="YOUR_API_KEY", # Required
base_url="https://api.hempdataapi.com", # Optional
timeout=30.0, # Seconds (default: 30)
max_retries=3, # Default: 3
retry_delay=1.0, # Seconds (default: 1.0)
)
Environment Variable
If no api_key is passed, the SDK reads from the HEMPDATA_API_KEY environment variable:
import os
os.environ["HEMPDATA_API_KEY"] = "YOUR_API_KEY"
client = HempDataClient() # Reads from env
Regulations
List Regulations
result = client.regulations.list(
state="CO", # optional
substance="delta-9-thc", # optional
product_type="edibles", # optional
legal_status="legal_with_restrictions", # optional
min_confidence=0.8, # optional
verified_after="2026-01-01", # optional
include_changelog=True, # optional
include_sources=True, # optional
include_bills=True, # optional
page=1, # optional
per_page=25, # optional
)
for reg in result.data:
print(f"{reg.state} — {reg.legal_status}: {reg.summary}")
Get Single Regulation
regulation = client.regulations.get("reg_a1b2c3d4-5678-9012-abcd-ef3456789012")
print(regulation.data.summary)
print(regulation.data.confidence)
Get Changelog
changes = client.regulations.changelog(
state="TX",
since="2026-01-01T00:00:00Z",
per_page=50,
)
for change in changes.data:
print(f"[{change.event_type}] {change.state}: {change.plain_english_summary}")
Compare States
comparison = client.regulations.compare(
states=["CO", "CA", "TX", "FL", "NY"],
substance="delta-9-thc",
product_type="edibles",
)
print(comparison.data.summary)
for state in comparison.data.comparison:
print(f" {state.state_name}: {state.legal_status}")
States
List All States
states = client.states.list(sort="avg_confidence", order="desc")
for state in states.data:
print(f"{state.name}: {state.total_regulations} regulations "
f"(avg confidence {state.avg_confidence:.2f})")
Get State Profile
colorado = client.states.get("CO", include_sources=True, include_bills=True)
print(colorado.data.regulatory_authority)
print(colorado.data.hr5371_impact_assessment)
for highlight in colorado.data.key_highlights:
print(f" - {highlight}")
Substances and Product Types
# List tracked substances
substances = client.substances.list()
for sub in substances.data:
print(f"{sub.name}: {sub.federal_status} "
f"({sub.states_prohibited} states prohibit)")
# List product types
product_types = client.product_types.list()
for pt in product_types.data:
print(f"{pt.name}: {pt.states_with_regulations} states")
Webhooks
Create Webhook
webhook = client.webhooks.create(
endpoint_url="https://yourapp.com/webhooks/hempdata",
filters={
"states": ["CO", "CA", "TX"],
"substances": ["delta-9-thc"],
"event_types": ["legal_status_changed"],
},
description="Monitor THC regulation changes",
)
# IMPORTANT: Save the signing secret — only returned once
print(f"Signing secret: {webhook.data.signing_secret}")
print(f"Webhook ID: {webhook.data.id}")
List Webhooks
webhooks = client.webhooks.list()
for wh in webhooks.data:
print(f"{wh.id}: {wh.status} — {wh.total_deliveries} deliveries")
Delete Webhook
client.webhooks.delete("whk_a1b2c3d4e5f6")
Verify Webhook Signature
from hempdataapi import verify_webhook_signature
# In your Flask/FastAPI handler
def handle_webhook(request):
raw_body = request.data # bytes
signature = request.headers.get("X-HempData-Signature", "")
secret = os.environ["HEMPDATA_WEBHOOK_SECRET"]
if not verify_webhook_signature(raw_body, signature, secret):
return "Invalid signature", 401
event = request.get_json()
# Process event...
return "OK", 200
FastAPI Webhook Handler
from fastapi import FastAPI, Request, HTTPException
from hempdataapi import verify_webhook_signature
import os
app = FastAPI()
@app.post("/webhooks/hempdata")
async def hempdata_webhook(request: Request):
raw_body = await request.body()
signature = request.headers.get("x-hempdata-signature", "")
if not verify_webhook_signature(raw_body, signature, os.environ["HEMPDATA_WEBHOOK_SECRET"]):
raise HTTPException(status_code=401, detail="Invalid signature")
event = await request.json()
if event["event_type"] == "legal_status_changed":
state = event["jurisdiction"]["state"]
new_status = event["after"]["legal_status"]
print(f"ALERT: {state} changed to {new_status}")
return {"status": "ok"}
Widget Check
result = client.widget.check(
substance="delta-9-thc",
product_type="edibles",
state="CO",
)
print(result.data.badge_color) # "yellow"
print(result.data.headline) # "Legal with Restrictions"
for restriction in result.data.restrictions:
print(f" - {restriction}")
CSV Export
# Get CSV as a string
csv_data = client.regulations.list(
state="CO",
format="csv",
include_sources=True,
)
# Write to file
with open("colorado-regulations.csv", "w") as f:
f.write(csv_data)
Billing
# Create checkout session
checkout = client.billing.create_checkout(
tier="professional",
billing_period="annual",
email="user@company.com",
success_url="https://yourapp.com/success?session_id={CHECKOUT_SESSION_ID}",
cancel_url="https://yourapp.com/cancel",
)
print(f"Redirect to: {checkout.data.checkout_url}")
# Create portal session
portal = client.billing.create_portal(
return_url="https://yourapp.com/dashboard",
)
print(f"Redirect to: {portal.data.portal_url}")
Error Handling
from hempdataapi import (
HempDataError,
RateLimitError,
AuthenticationError,
NotFoundError,
ValidationError,
)
try:
result = client.regulations.list(state="XX")
except AuthenticationError:
print("Invalid API key")
except RateLimitError as e:
print(f"Rate limited. Retry after {e.retry_after} seconds")
except ValidationError as e:
print(f"Bad request: {e.message} (field: {e.field})")
except NotFoundError:
print("Resource not found")
except HempDataError as e:
print(f"API error [{e.code}]: {e.message}")
Pagination
Manual Pagination
page = 1
while True:
result = client.regulations.list(
substance="delta-9-thc",
page=page,
per_page=50,
)
for reg in result.data:
print(f"{reg.state}: {reg.legal_status}")
if page >= result.meta.total_pages:
break
page += 1
Auto-Pagination Iterator
# Iterate through all pages automatically
for regulation in client.regulations.paginate(substance="delta-9-thc"):
print(f"{regulation.state}: {regulation.legal_status}")
Async Auto-Pagination
async for regulation in client.regulations.paginate(substance="delta-9-thc"):
print(f"{regulation.state}: {regulation.legal_status}")
Django Integration Example
# settings.py
HEMPDATA_API_KEY = os.environ["HEMPDATA_API_KEY"]
# views.py
from django.http import JsonResponse
from hempdataapi import HempDataClient
from django.conf import settings
client = HempDataClient(api_key=settings.HEMPDATA_API_KEY)
def check_compliance(request):
state = request.GET.get("state", "CO")
substance = request.GET.get("substance", "cbd")
product_type = request.GET.get("product_type", "edibles")
result = client.regulations.list(
state=state,
substance=substance,
product_type=product_type,
)
if not result.data:
return JsonResponse({"can_sell": False, "reason": "No data available"})
reg = result.data[0]
can_sell = reg.legal_status in ("legal", "legal_with_restrictions")
return JsonResponse({
"can_sell": can_sell,
"legal_status": reg.legal_status,
"summary": reg.summary,
"confidence": reg.confidence,
})
Type Hints
All SDK methods and response objects are fully typed. Use with mypy or Pyright for full type checking:
from hempdataapi.types import (
Regulation,
State,
Substance,
ProductType,
Webhook,
WidgetCheckResult,
ChangelogEntry,
ComparisonResult,
BillInfo,
PaginatedResponse,
)