Lemon Squeezy
raw JSON → REST API v1 (no official Python SDK) verified Tue May 12 auth: yes python install: stale quickstart: stale deprecated
Merchant of record platform for digital products. Acquired by Stripe in October 2024. Being absorbed into 'Stripe Managed Payments' (announced May 2025, private preview). No official Python SDK exists — only community-maintained libraries. REST API uses JSON:API spec with Bearer auth.
pip install requests Common errors
error {"detail": "Unauthenticated.", "status": "401", "title": "Unauthorized"} ↓
cause The API request was made without a valid Bearer authentication token in the Authorization header, or the API key is expired or incorrect.
fix
Ensure you have created an API key in your Lemon Squeezy dashboard (Settings » API), and include it in your request headers as
Authorization: Bearer YOUR_API_KEY. error json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0) ↓
cause Your Python code attempted to parse an API response as JSON using `response.json()`, but the response content was not valid JSON (e.g., it was an HTML error page, plain text, or empty). This often occurs if required JSON:API headers (`Accept`, `Content-Type`) are missing or incorrect, or if an invalid endpoint was hit.
fix
Always check the HTTP status code (
response.status_code) and raw response text (response.text) before attempting response.json(). Ensure your requests include Accept: application/vnd.api+json and Content-Type: application/vnd.api+json headers. error 422 Unprocessable Entity / A required field was invalid or missing. ↓
cause The API request failed validation because a required field was either missing from the payload or the provided value was invalid (e.g., wrong data type or format).
fix
Consult the Lemon Squeezy API documentation for the specific endpoint to identify all required parameters and their expected data types and formats, then adjust your request payload accordingly.
error 429 Too Many Requests ↓
cause Your application has exceeded the allowed rate limit for API calls (e.g., 300 requests per minute for the main API).
fix
Implement exponential backoff or other rate-limiting strategies in your application. Monitor the
X-Ratelimit-Limit and X-Ratelimit-Remaining headers in successful responses to manage your call frequency. Warnings
breaking Lemon Squeezy was acquired by Stripe in October 2024. As of May 2025, Stripe announced 'Stripe Managed Payments' as the successor merchant of record product. Lemon Squeezy's API may be deprecated or migrated to Stripe infrastructure in the future. New integrations should evaluate Stripe Managed Payments (waitlist) instead. ↓
fix For new projects, join the Stripe Managed Payments waitlist. For existing Lemon Squeezy integrations, no immediate action needed — Lemon Squeezy API continues operating.
breaking No official Python SDK exists. All PyPI packages named 'lemonsqueezy*' are unofficial, may be abandoned, and have no support from Lemon Squeezy / Stripe. ↓
fix Use requests or httpx against the REST API directly. The API is stable and documented at docs.lemonsqueezy.com/api.
gotcha The Lemon Squeezy API follows JSON:API spec. Response payload is wrapped: response['data'] contains the resource(s), not the top-level response. Code accessing response['products'] or response['id'] directly fails. ↓
fix Access data at response.json()['data'] for single resources or list responses. Meta and links are at the top level.
gotcha Both Accept and Content-Type headers must be 'application/vnd.api+json', not 'application/json'. Sending standard JSON headers returns 406 Not Acceptable. ↓
fix Set headers: {'Accept': 'application/vnd.api+json', 'Content-Type': 'application/vnd.api+json'}
gotcha Lemon Squeezy has Test mode (separate from live). Test mode API keys start with a different prefix. Using a live key in Test mode or vice versa will access production data unexpectedly. ↓
fix Create separate API keys for test and live modes from Settings > API.
gotcha The `pip` package manager issued warnings during installation/operation, specifically regarding running as the 'root' user and an available update. These are not directly related to the Lemon Squeezy API integration itself but rather the Python environment setup. ↓
fix Address pip warnings by using a virtual environment (e.g., `python -m venv .venv && source .venv/bin/activate`) and consider updating pip (`pip install --upgrade pip`). If running in a container, ensure appropriate user permissions are used instead of root for package installations.
Install compatibility stale last tested: 2026-05-12
python os / libc status wheel install import disk
3.10 alpine (musl) - - - -
3.10 slim (glibc) - - - -
3.11 alpine (musl) - - - -
3.11 slim (glibc) - - - -
3.12 alpine (musl) - - - -
3.12 slim (glibc) - - - -
3.13 alpine (musl) - - - -
3.13 slim (glibc) - - - -
3.9 alpine (musl) - - - -
3.9 slim (glibc) - - - -
Imports
- API client wrong
from lemonsqueezy import Clientcorrectimport requests headers = { 'Authorization': 'Bearer YOUR_API_KEY', 'Accept': 'application/vnd.api+json', 'Content-Type': 'application/vnd.api+json' } response = requests.get('https://api.lemonsqueezy.com/v1/products', headers=headers)
Quickstart stale last tested: 2026-05-12
import requests
import os
API_KEY = os.getenv('LEMON_SQUEEZY_API_KEY')
BASE_URL = 'https://api.lemonsqueezy.com/v1'
headers = {
'Authorization': f'Bearer {API_KEY}',
'Accept': 'application/vnd.api+json',
'Content-Type': 'application/vnd.api+json'
}
# List products
resp = requests.get(f'{BASE_URL}/products', headers=headers)
products = resp.json()['data']
for product in products:
print(product['id'], product['attributes']['name'])
# Verify webhook signature (HMAC-SHA256)
import hmac
import hashlib
def verify_webhook(payload: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode(),
payload,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature)