Skip to main content

Python SDK for the Hotmart API

Project description

hotmart-python — Python SDK for the Hotmart API

Python 3.11+ PyPI version License Apache 2.0

hotmart-python is a typed Python SDK for the Hotmart API. Hotmart is a Brazilian digital products platform for selling courses, ebooks, subscriptions, and memberships — supporting payments via PIX, boleto, credit/debit card, and PayPal.

This SDK handles OAuth, token refresh, retries, rate limits, and pagination automatically. You write business logic; the SDK handles the API.

Documentação em Português disponível em README-ptBR.md.


v1.0 — complete rewrite. After two years without updates, the library was redesigned from scratch: resource-based API, httpx, Pydantic v2, automatic retries, strict typing, and much more. This is a strong breaking change from v0.x — see the migration guide to update your code. If you're starting fresh, you can ignore this notice.


Features

  • Fully typed responses — every API response is a Pydantic v2 model. Your IDE completes field names; no raw dicts, no guessing.
  • Autopaginate iterators — every paginated endpoint ships a *_autopaginate variant that transparently walks all pages. One for loop, all records.
  • Automatic token management — OAuth token is acquired, cached, and proactively refreshed 5 minutes before expiry. Thread-safe with double-checked locking.
  • Retry with exponential backoff — transient errors (5xx, 429) are retried automatically with jitter and RateLimit-Reset awareness. Configurable via max_retries.
  • Proactive rate limit tracking — monitors remaining requests per window and backs off before hitting the limit.
  • Clean exception hierarchy — catch only what you care about: AuthenticationError, RateLimitError, NotFoundError, BadRequestError, and more.
  • httpx under the hood — persistent connection pool, configurable timeouts, context manager support.
  • Forward-compatible kwargs — extra **kwargs are passed directly as query params, so you can use undocumented or newly added Hotmart parameters without waiting for an SDK update.

Design Principles

  • One object, all resources. Instantiate Hotmart once and access every resource group as an attribute: client.sales, client.subscriptions, client.products, etc.
  • Fail loudly. Errors are typed exceptions, never silently swallowed or buried in return values.
  • No boilerplate. Authentication, pagination, retries, and connection management are invisible by default. Opt in to configuration only when you need it.
  • Strict typing. mypy --strict passes. All public APIs are fully annotated. Models use extra="allow" so new API fields don't break your code.

Table of Contents


Installation

pip install hotmart-python

Or with uv:

uv add hotmart-python

Requirements: Python 3.11+


Quick Start

from hotmart import Hotmart

client = Hotmart(
    client_id="your_client_id",
    client_secret="your_client_secret",
    basic="Basic your_base64_credentials",
)

# Single page
page = client.sales.history(buyer_name="Paula")
for sale in page.items:
    print(sale.purchase.transaction, sale.buyer.email)

# All pages — one iterator, no manual pagination
for sale in client.sales.history_autopaginate(transaction_status="APPROVED"):
    print(sale.purchase.transaction)

Authentication

Hotmart uses OAuth 2.0 Client Credentials. The SDK handles token acquisition and refresh automatically — you only need to supply three values at startup.

Where to find your credentials

  1. Log in to Hotmart.
  2. Go to Tools → Developer Tools → Credentials.
  3. Generate a new credential set. You will receive:
    • client_id — your application client ID
    • client_secret — your application client secret
    • basic — the Base64-encoded client_id:client_secret string prefixed with Basic (Hotmart shows this value directly in the dashboard)
from hotmart import Hotmart

client = Hotmart(
    client_id="abcdef12-1234-5678-abcd-abcdef123456",
    client_secret="your_secret_here",
    basic="Basic YWJjZGVmMTItMTIzNC01Njc4LWFiY2QtYWJjZGVmMTIzNDU2OnlvdXJfc2VjcmV0X2hlcmU=",
)

Tokens are valid for 24 hours. The SDK caches the token and proactively refreshes it 5 minutes before expiry using double-checked locking, so concurrent requests never race on token renewal.


Resources

Sales

# Single page
page = client.sales.history(buyer_name="Paula", transaction_status="APPROVED")
page = client.sales.summary(start_date=1700000000000, end_date=1710000000000)
page = client.sales.participants(buyer_email="paula@example.com")
page = client.sales.commissions(commission_as="PRODUCER")
page = client.sales.price_details(product_id=1234567)

# Refund a transaction
client.sales.refund("HP17715690036014")

# Autopaginate — iterates all pages automatically
for sale in client.sales.history_autopaginate(buyer_name="Paula"):
    print(sale.purchase.transaction)
Method Description
history(**kwargs) List all sales with detailed information
history_autopaginate(**kwargs) Iterator over all pages
summary(**kwargs) Total commission values per currency
summary_autopaginate(**kwargs) Iterator over all pages
participants(**kwargs) Sales user/participant data
participants_autopaginate(**kwargs) Iterator over all pages
commissions(**kwargs) Commission breakdown per sale
commissions_autopaginate(**kwargs) Iterator over all pages
price_details(**kwargs) Price and fee details per sale
price_details_autopaginate(**kwargs) Iterator over all pages
refund(transaction_code) Request a refund for a transaction

Subscriptions

# List subscribers
page = client.subscriptions.list(status="ACTIVE", product_id=1234567)

# Summary
page = client.subscriptions.summary()

# Purchases and transactions for a single subscriber
purchases = client.subscriptions.purchases("SUB-ABC123")
transactions = client.subscriptions.transactions("SUB-ABC123")

# Cancel one or more subscriptions
result = client.subscriptions.cancel(["SUB-ABC123", "SUB-DEF456"], send_mail=True)

# Reactivate subscriptions (bulk)
result = client.subscriptions.reactivate(["SUB-ABC123"], charge=False)

# Reactivate a single subscription
result = client.subscriptions.reactivate_single("SUB-ABC123", charge=True)

# Change billing due day
client.subscriptions.change_due_day("SUB-ABC123", due_day=15)

# Autopaginate
for sub in client.subscriptions.list_autopaginate(status="ACTIVE"):
    print(sub.subscriber_code)
Method Description
list(**kwargs) List subscriptions with filters
list_autopaginate(**kwargs) Iterator over all pages
summary(**kwargs) Subscription summary
summary_autopaginate(**kwargs) Iterator over all pages
purchases(subscriber_code) Purchase history for a subscriber
transactions(subscriber_code) Transactions for a subscriber
cancel(subscriber_code, send_mail) Cancel one or more subscriptions
reactivate(subscriber_code, charge) Reactivate subscriptions (bulk)
reactivate_single(subscriber_code, charge) Reactivate a single subscription
change_due_day(subscriber_code, due_day) Change the billing due day

Products

# List products
page = client.products.list(status="ACTIVE")

# Offers for a product
page = client.products.offers("product-ucode-here")

# Plans for a product
page = client.products.plans("product-ucode-here")

# Autopaginate
for product in client.products.list_autopaginate():
    print(product.name)
Method Description
list(**kwargs) List all products
list_autopaginate(**kwargs) Iterator over all pages
offers(ucode, **kwargs) Offers for a product
offers_autopaginate(ucode, **kwargs) Iterator over all pages
plans(ucode, **kwargs) Plans for a product
plans_autopaginate(ucode, **kwargs) Iterator over all pages

Coupons

# Create a coupon (10% off) for product 1234567
client.coupons.create("1234567", "SUMMER10", discount=10.0)

# List coupons for a product
page = client.coupons.list("1234567")

# Delete a coupon by ID
client.coupons.delete("coupon-id-here")

# Autopaginate
for coupon in client.coupons.list_autopaginate("1234567"):
    print(coupon.code)
Method Description
create(product_id, coupon_code, discount) Create a discount coupon
list(product_id, **kwargs) List coupons for a product
list_autopaginate(product_id, **kwargs) Iterator over all pages
delete(coupon_id) Delete a coupon

Club (Members Area)

The Club resource requires a subdomain argument — the subdomain of your Members Area.

# Modules in the members area
modules = client.club.modules("my-course-subdomain")

# Pages within a module
pages = client.club.pages("my-course-subdomain", module_id="module-uuid")

# Students enrolled
students = client.club.students("my-course-subdomain")

# Student progress
progress = client.club.student_progress(
    "my-course-subdomain",
    student_email="student@example.com",
)
Method Description
modules(subdomain, **kwargs) List modules in the members area
pages(subdomain, module_id, **kwargs) List pages in a module
students(subdomain, **kwargs) List enrolled students
student_progress(subdomain, **kwargs) Student progress data

Events

# Get event details
event = client.events.get("event-id-here")

# List tickets for a product
page = client.events.tickets(product_id=1234567)

# Autopaginate
for ticket in client.events.tickets_autopaginate(product_id=1234567):
    print(ticket.name)
Method Description
get(event_id) Get event details
tickets(product_id, **kwargs) List tickets for a product
tickets_autopaginate(product_id, **kwargs) Iterator over all pages

Negotiation

# Create an installment negotiation for a subscriber
result = client.negotiation.create("SUB-ABC123")
Method Description
create(subscriber_code) Create an installment negotiation

Pagination

The Hotmart API uses cursor-based pagination. Each paginated response contains a page_info object with next_page_token.

Single-page call

Returns a PaginatedResponse[T] with .items and .page_info:

page = client.sales.history(max_results=50)
print(f"Got {len(page.items)} items")
print(f"Next token: {page.page_info.next_page_token}")

# Manually fetch next page
next_page = client.sales.history(page_token=page.page_info.next_page_token)

Autopaginate (recommended)

Every paginated method has a matching *_autopaginate variant that handles all page-fetching transparently:

for sale in client.sales.history_autopaginate(buyer_name="Paula"):
    print(sale.purchase.transaction)

The iterator stops when there are no more pages — no token management, no loop conditions.


Sandbox Mode

Use sandbox=True to point all requests at Hotmart's sandbox environment. Sandbox and production credentials are not interchangeable — generate sandbox credentials in the Hotmart dashboard under the same Developer Credentials section, selecting "Sandbox" as the environment.

from hotmart import Hotmart

client = Hotmart(
    client_id="your_sandbox_client_id",
    client_secret="your_sandbox_client_secret",
    basic="Basic your_sandbox_base64_credentials",
    sandbox=True,
)

Note: Some endpoints behave differently or are not fully supported in the sandbox. See SANDBOX-GUIDE.md and HOTMART-API-BUGS.md for known issues.


Error Handling

All SDK errors inherit from HotmartError. Import and catch only the exceptions you need:

from hotmart import (
    Hotmart,
    HotmartError,
    AuthenticationError,
    RateLimitError,
    NotFoundError,
    BadRequestError,
    InternalServerError,
)

try:
    page = client.sales.history()
except AuthenticationError:
    print("Check your credentials.")
except RateLimitError as e:
    print(f"Rate limited. Retry after {e.retry_after} seconds.")
except NotFoundError:
    print("Resource not found.")
except HotmartError as e:
    print(f"API error: {e}")

Exception hierarchy:

Exception HTTP status Meaning
AuthenticationError 401, 403 Invalid or missing credentials
BadRequestError 400 Invalid parameters
NotFoundError 404 Resource not found
RateLimitError 429 Rate limit exceeded (500 req/min)
InternalServerError 500, 502, 503 Hotmart server error
APIStatusError other Unexpected HTTP status
HotmartError Base class for all SDK errors

The SDK retries automatically on transient errors (5xx, 429) with exponential backoff (0.5 × 2^attempt + jitter, cap 30s). Configure via max_retries:

client = Hotmart(..., max_retries=5)

Logging

Logging is disabled by default. Enable it by passing log_level at construction time:

import logging
from hotmart import Hotmart

client = Hotmart(
    client_id="...",
    client_secret="...",
    basic="Basic ...",
    log_level=logging.INFO,
)
Level What is logged
logging.DEBUG Request URLs, parameters — contains sensitive data, avoid in production
logging.INFO High-level operation summaries
logging.WARNING Warnings and unexpected conditions
logging.ERROR Errors during API interactions
logging.CRITICAL Critical failures

Tokens and credentials are masked in all log output.


Context Manager

Hotmart supports the context manager protocol for automatic cleanup of the underlying HTTP connection pool:

from hotmart import Hotmart

with Hotmart(
    client_id="...",
    client_secret="...",
    basic="Basic ...",
) as client:
    for sale in client.sales.history_autopaginate():
        print(sale.purchase.transaction)

Extra Parameters (kwargs)

All resource methods accept **kwargs and forward them directly to the API as query parameters. This lets you use undocumented or recently added Hotmart parameters without waiting for an SDK update:

# Pass any query parameter Hotmart supports, even if not in the method signature
page = client.sales.history(some_new_param="value")

Documentation

Document Description
README-ptBR.md Esta documentação em Português
MIGRATION.md Upgrading from v0.x to v1.0 — breaking changes and method mapping
CHANGELOG.md Full version history
CONTRIBUTING.md Development setup, code style, how to add endpoints
SANDBOX-GUIDE.md Sandbox environment usage and known limitations
HOTMART-API-BUGS.md Known Hotmart API bugs found during integration testing
HOTMART-API-REFERENCE.md Complete API reference (agent/LLM-friendly — official docs are a JS SPA)

Contributing

Contributions are welcome. See CONTRIBUTING.md for setup, coding style, how to add a new endpoint, and the PR checklist.


License

Apache License 2.0 — see LICENSE.txt for details.

This package is not affiliated with or officially supported by Hotmart.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

hotmart_python-1.0.3.tar.gz (100.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

hotmart_python-1.0.3-py3-none-any.whl (26.4 kB view details)

Uploaded Python 3

File details

Details for the file hotmart_python-1.0.3.tar.gz.

File metadata

  • Download URL: hotmart_python-1.0.3.tar.gz
  • Upload date:
  • Size: 100.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for hotmart_python-1.0.3.tar.gz
Algorithm Hash digest
SHA256 85220470ef152c3dd7ea218f71a02f79ea82cbd03c5876d5db872ee3d7327bb6
MD5 16261e6dcc8e9eb1d1b1b0909a168cb8
BLAKE2b-256 9efffe9dada5b9fa19646d48a8875adcf7bb6020249ffaf2a18996bc65e8f88e

See more details on using hashes here.

Provenance

The following attestation bundles were made for hotmart_python-1.0.3.tar.gz:

Publisher: publish.yml on im-voracity/hotmart-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file hotmart_python-1.0.3-py3-none-any.whl.

File metadata

  • Download URL: hotmart_python-1.0.3-py3-none-any.whl
  • Upload date:
  • Size: 26.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for hotmart_python-1.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 0550662299171d2c8d1eef912d98d42245dbc9ac9e32b1932c45f98672a36b21
MD5 89f60942029a9de02c95e171830ac994
BLAKE2b-256 2ecfaa1546ab2972575abdcef9eec1c657e53c3cf8b613d62a18d75d9436e9cc

See more details on using hashes here.

Provenance

The following attestation bundles were made for hotmart_python-1.0.3-py3-none-any.whl:

Publisher: publish.yml on im-voracity/hotmart-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page