Skip to main content

Apidepth SDK for Python — track outbound API latency, error rates, and rate limit quota.

Project description

apidepth-python

PyPI Python License: MIT

Track outbound API latency, error rates, and rate limit quota across your third-party vendors — Stripe, OpenAI, Anthropic, Twilio, GitHub, and more.

Zero config for supported vendors. No code changes to your existing HTTP calls.


How it works

Real traffic, not synthetic probes. Every outbound HTTP call your application makes to a known vendor is timed at the socket level, tagged with outcome and environment metadata, and batched to the Apidepth collector in the background. The latency number in your dashboard is the number your users feel — not a probe running from a data center somewhere else.

Fleet benchmarking. Because Apidepth aggregates anonymized timing data across all customers, your dashboard shows not just "your Stripe p95 is 420ms" but "the fleet median is 280ms — you may have a regional routing issue." That comparison is only possible with real traffic from real deployments, which is why no synthetic probe tool can offer it.

Proof of Innocence. When all endpoints to a vendor spike simultaneously, Apidepth surfaces a verdict: isolated (the spike is yours alone — likely your code or infrastructure) or tracking (the fleet sees the same thing — vendor-side). The attribution card makes it fast to tell ops "it's Stripe, not us."

Alerts and weekly digest. Apidepth fires alerts when vendor latency crosses your configured threshold and sends a weekly digest summarizing what changed. Monitoring without alerting is passive; this is working for you.

Rate limit intelligence. Apidepth tracks 429 patterns and projects quota burn-down before you hit the ceiling — with a burn-down card showing time-to-throttle at current request rate.


Installation

pip install apidepth

For requests instrumentation (most common):

pip install "apidepth[requests]"

For httpx instrumentation:

pip install "apidepth[httpx]"

Getting started

Django

Add to INSTALLED_APPS and configure in settings.py:

INSTALLED_APPS = [
    ...
    "apidepth.integrations.django",
]

APIDEPTH = {
    "api_key": env("APIDEPTH_API_KEY"),
    "environment": env("DJANGO_ENV", default="development"),
}

Flask

from flask import Flask
from apidepth.integrations.flask import Apidepth

app = Flask(__name__)
app.config["APIDEPTH_API_KEY"] = os.environ["APIDEPTH_API_KEY"]
app.config["APIDEPTH_ENVIRONMENT"] = "production"

Apidepth(app)

Standalone / scripts

import apidepth
from apidepth import registry_loader

apidepth.configure(
    api_key=os.environ["APIDEPTH_API_KEY"],
    environment="production",
)
apidepth.instrument()       # call before any outbound HTTP
registry_loader.load_and_start()  # loads remote vendor registry + starts refresh thread

import requests
resp = requests.get("https://api.stripe.com/v1/charges/ch_abc123", ...)

load_and_start() fetches the latest vendor registry from the network (with a local disk cache fallback) and starts a background refresh thread. Without it, only the six bundled vendors are recognised. Django and Flask integrations call this automatically.

For Gunicorn / uWSGI, call Collector.register_fork_safety() once before the server forks so each worker gets its own flush thread:

from apidepth.collector import Collector
Collector.register_fork_safety()

Configuration

Option Default Description
api_key None Required. Your Apidepth API key.
environment None Deployment environment tag, e.g. "production".
enabled True Set False to disable all instrumentation.
sample_rate 1.0 Float 0.0–1.0. Fraction of requests to capture.
ignored_hosts [] List of hostnames to never record.
extra_vendors {} Map {"vendor-name": "host"} for in-house APIs.
flush_interval 20 Background flush interval in seconds.
registry_cache_path /tmp/apidepth_registry.json Disk cache for the vendor registry.
registry_refresh_interval 21600 Registry refresh interval in seconds (6 h).
on_flush_error None Callable(exc, ctx) for routing errors to Sentry etc.
collector_url production endpoint Override for self-hosted collectors.

What gets captured

Every outbound HTTP request to a recognised vendor produces one event:

Field Description
vendor Vendor slug, e.g. "stripe", "openai"
endpoint Normalized path, e.g. "/v1/charges/:id"
method HTTP verb: "GET", "POST", etc.
status HTTP status code, or None on timeout
outcome "success", "client_error", "server_error", "timeout", "unknown"
duration_ms Wall-clock time in milliseconds
cold_start Always False — see Known differences
env Environment tag from environment config option
ts Unix timestamp in milliseconds
rl_remaining Remaining quota, e.g. 4999 — present when vendor rate limit headers are found
rl_limit Total quota, e.g. 5000 — present when vendor rate limit headers are found
rl_reset_at Quota reset time in epoch milliseconds — present when vendor rate limit headers are found

What is never captured

  • Request or response bodies
  • Request or response headers (including Authorization)
  • Query string parameters
  • Any credential, token, or secret your application uses to authenticate with a vendor
  • User identifiers or PII of any kind

Path normalization strips resource IDs before the event leaves your server. /v1/charges/ch_3Ox4Kz2e becomes /v1/charges/:id.


Supported vendors

Vendor Host
Stripe api.stripe.com
OpenAI api.openai.com
Anthropic api.anthropic.com
Twilio api.twilio.com
Resend api.resend.com
GitHub api.github.com

Additional vendors are loaded from the remote registry every 6 hours.

Custom vendors

apidepth.configure(
    extra_vendors={"payments-api": "api.payments.internal"},
)

Rate limit tracking

The SDK extracts quota state from response headers and includes it in every event. Supported header families (checked in priority order):

  • OpenAI / Anthropic: x-ratelimit-remaining-requests, x-ratelimit-limit-requests, x-ratelimit-reset-requests
  • GitHub: x-ratelimit-remaining, x-ratelimit-limit, x-ratelimit-reset
  • IETF draft / HubSpot: ratelimit-remaining, ratelimit-limit, ratelimit-reset
  • Stripe / generic 429: retry-after

Reset values are normalised to epoch milliseconds regardless of the source format (Unix timestamp, seconds-from-now, OpenAI duration strings like "1m30s").


Debugging

from apidepth.collector import Collector

print(Collector.instance().stats())
# {
#   'queue_size': 0,
#   'consecutive_failures': 0,
#   'total_dropped': 0,
#   'last_flush_at': 1747008000.123,
# }

Framework compatibility

Framework Version Integration
Django 3.2+ apidepth.integrations.django in INSTALLED_APPS
Flask 2.0+ Apidepth(app)
FastAPI / Starlette any Call apidepth.instrument() at startup
Scripts / workers Call apidepth.instrument() at startup

Python compatibility

Python 3.9–3.13. No required runtime dependencies (stdlib only). requests and httpx are optional instrumentation targets detected at runtime.


Known differences from the Ruby gem

cold_start is always false

The Ruby gem tags the first outbound request on each TCP connection with cold_start: true using Net::HTTP#started?. The Apidepth collector uses this flag to exclude DNS + TCP + TLS handshake overhead from latency percentile calculations (p50/p95/p99), keeping those metrics representative of steady-state vendor performance.

Neither requests (backed by urllib3) nor httpx exposes a public API for detecting whether the underlying socket is a keep-alive reuse. The Python SDK therefore always sends cold_start: false.

Practical impact depends on your traffic pattern:

Traffic pattern Impact
High-throughput web service Negligible — cold starts are a tiny fraction of total requests; percentile inflation is unmeasurable
Low-throughput service / cron job Noticeable — the first request per run pays ~50–200 ms of connection overhead that isn't excluded from percentiles; p95/p99 may read slightly higher than in Ruby
Serverless / short-lived worker Material — every invocation starts cold; all latency data includes connection overhead; comparisons against Ruby-instrumented services will show the Python side as systematically higher

The raw duration values are accurate — only the percentile statistics are affected. If cold-start exclusion matters for your environment, filter those events manually in your dashboard (e.g. a warm-up request flag in thread-local state) until the underlying libraries expose the required connection-state API.

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

apidepth-0.2.2.tar.gz (96.0 kB view details)

Uploaded Source

Built Distribution

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

apidepth-0.2.2-py3-none-any.whl (42.9 kB view details)

Uploaded Python 3

File details

Details for the file apidepth-0.2.2.tar.gz.

File metadata

  • Download URL: apidepth-0.2.2.tar.gz
  • Upload date:
  • Size: 96.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for apidepth-0.2.2.tar.gz
Algorithm Hash digest
SHA256 366d130832a440da2725855f036800f1d84f728a24d6179368d10b4892abd8e9
MD5 33e1d226f12e9d34a38ad00a6d285f91
BLAKE2b-256 bef9aa682bbd009baf2291b1576788b20638926c4bd3ac91edd0644da5d8424a

See more details on using hashes here.

Provenance

The following attestation bundles were made for apidepth-0.2.2.tar.gz:

Publisher: release-please.yml on apidepth-io/apidepth-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 apidepth-0.2.2-py3-none-any.whl.

File metadata

  • Download URL: apidepth-0.2.2-py3-none-any.whl
  • Upload date:
  • Size: 42.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for apidepth-0.2.2-py3-none-any.whl
Algorithm Hash digest
SHA256 a9de4005e0c1b9d72ac3606ed6dbd6d785fe807376a7e4d1796fd5eae7ffab5f
MD5 45aa554c57e43128301ceaeb7d991c61
BLAKE2b-256 2e004b58070a8bb9f720e3412c7a36fc364de70276228269bf548a4bc5bcf33b

See more details on using hashes here.

Provenance

The following attestation bundles were made for apidepth-0.2.2-py3-none-any.whl:

Publisher: release-please.yml on apidepth-io/apidepth-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