Docs Go to app →

Python SDK

letterapp is the official Python client for the ingestion API. It batches events on a background thread, retries on transient failures, and generates idempotency keys for you - so the common letter.track(...) call from a request handler is non-blocking and safe to retry.

If you’d rather call the HTTP API directly, see the Ingestion API.

Packageletterapp on PyPI
LicenseMIT
RuntimePython 3.8+
SizeZero runtime dependencies (standard library only)

Install

pip install letterapp

The package has no runtime dependencies - HTTP goes over the standard library urllib, threading over threading + queue. Works on any Python 3.8+: Django, Flask, FastAPI, Celery workers, scripts, Lambda.

You’ll need an API key from Dashboard - Settings - API keys before the SDK will do anything useful.

Quick start

import os
from letterapp import Letter

letter = Letter(api_key=os.environ["LETTER_API_KEY"])

letter.identify(
    user_id=user.id,
    email=user.email,
    traits={"name": user.name, "plan": "free"},
)

letter.group(
    user_id=user.id,
    account_id=workspace.id,
    name=workspace.name,
    traits={"plan": workspace.plan, "mrr": 49},
)

letter.track(
    user_id=user.id,
    event="Workspace Created",
    properties={"workspace_id": workspace.id},
)

# Required before the process exits on long-running servers.
letter.close()

Create the api_key in Dashboard - Settings - API keys. It’s shown once on creation and never again - store it somewhere safe.

You can also use the client as a context manager, which flushes on exit:

with Letter(api_key=os.environ["LETTER_API_KEY"]) as letter:
    letter.track(user_id=user.id, event="Workspace Created")

Constructor options

OptionDefaultWhat it does
api_key-Required. lt_live_... from Settings.
base_urlhttps://api.letter.appOverride for self-hosting.
flush_at50Send a batch when this many items are queued.
flush_interval0.1 (seconds)Send queued items at most this often.
max_retries3Retry attempts on 5xx and 429.
timeout10.0 (seconds)Per-request socket timeout.
on_errorprints to stderrCalled when a background flush fails.

Methods

  • identify(user_id, email=, traits=, timezone=, timestamp=, message_id=)

  • group(user_id, account_id, name=, traits=, timestamp=, message_id=)

  • track(user_id, event, properties=, timestamp=, message_id=)

    These enqueue and return immediately. Transport errors surface via on_error. Fast path for long-running servers.

  • flush() - send everything queued now; blocks until the request settles.

  • close() - flush, stop the background thread, refuse new enqueues. Runs automatically at interpreter exit, but call it explicitly before sys.exit() so no events are lost.

Retry behavior

  • 429: wait Retry-After seconds, then retry (up to max_retries).
  • 5xx or network errors: exponential backoff (0.25s x 2^attempt + jitter).
  • 4xx other than 429: raised immediately (via on_error), no retry.

The SDK auto-generates a UUID message_id per call, so retries dedupe at the server. See Idempotency for the underlying guarantee.

Serverless mode

In serverless / function environments there’s no background time between requests to drain the queue, so set flush_at=1 and call flush() at the end of each handler:

letter = Letter(api_key=os.environ["LETTER_API_KEY"], flush_at=1)

def handler(event, context):
    letter.track(user_id=user_id, event="Checkout Started")
    letter.flush()

Errors

Configuration errors and non-retryable API responses raise LetterError (carrying .status and .body), which uses the same shape as the HTTP API - see Error format. Background transport errors are passed to on_error instead, since they can’t be raised to the caller.

Versioning

The SDK follows semver. While we’re at 0.x:

  • patch (0.1.0 -> 0.1.1) - bug fixes only.
  • minor (0.1.0 -> 0.2.0) - new options, new methods, behavior changes.
  • major (0.x -> 1.0.0) - only once the HTTP API and signatures are stable. Until then, pin a minor range (letterapp~=0.1).

Every request sends a User-Agent: letterapp-python/<version> header so we can spot outdated clients in server logs.