Recost middleware for Python — API cost intelligence
Project description
recost
Python SDK for ReCost — automatically tracks outbound HTTP API calls from your application and reports cost, latency, and usage patterns to the ReCost dashboard or your local VS Code extension.
How it works
The SDK monkey-patches urllib3, httpx, and aiohttp to intercept outbound requests at runtime. It captures metadata only (URL, method, status, latency, byte sizes — never headers or bodies), matches each request against a built-in provider registry, aggregates events into time-windowed summaries, and ships those summaries either to the ReCost cloud API or to the ReCost VS Code extension running locally.
Your app
└─ requests.get("https://api.openai.com/v1/chat/completions", ...)
│
▼
Interceptor ← patches urllib3, httpx, aiohttp
│ RawEvent { host, path, method, status_code, latency_ms, ... }
▼
ProviderRegistry ← matches host/path → provider + endpoint_category + cost
│
▼
Aggregator ← buffers events, flushes WindowSummary every 30s
│
▼
Transport
├─ local mode → WebSocket → VS Code extension (port 9847)
└─ cloud mode → HTTPS POST → api.recost.dev
Installation
pip install recost
With optional framework and local mode extras:
pip install recost[fastapi] # FastAPI/Starlette middleware
pip install recost[flask] # Flask extension
pip install recost[local] # WebSocket for VS Code extension
pip install recost[all] # Everything
Quick start
Local mode (VS Code extension)
No API key needed. Telemetry goes to the ReCost VS Code extension over localhost.
from recost import init
init() # all defaults — local mode on port 9847
Cloud mode
import os
from recost import init, RecostConfig
init(RecostConfig(
api_key=os.environ["RECOST_API_KEY"],
project_id=os.environ["RECOST_PROJECT_ID"],
environment=os.environ.get("PYTHON_ENV", "development"),
))
FastAPI
from fastapi import FastAPI
from recost.frameworks.fastapi import RecostMiddleware
app = FastAPI()
app.add_middleware(RecostMiddleware, api_key="...", project_id="...")
Flask
from flask import Flask
from recost.frameworks.flask import ReCost
app = Flask(__name__)
eco = ReCost(app, api_key="...", project_id="...")
Configuration
All fields are optional.
| Option | Type | Default | Description |
|---|---|---|---|
api_key |
str |
— | ReCost API key (rc-...). If omitted, runs in local mode. |
project_id |
str |
— | ReCost project ID. Required in cloud mode. |
environment |
str |
"development" |
Environment tag attached to all telemetry. |
flush_interval |
float |
30.0 |
Seconds between automatic flushes. |
max_batch_size |
int |
100 |
Early-flush threshold (number of events). |
local_port |
int |
9847 |
WebSocket port for the VS Code extension. |
debug |
bool |
False |
Log telemetry activity to stderr. |
enabled |
bool |
True |
Master kill switch. Set False to disable in tests. |
custom_providers |
list[ProviderDef] |
[] |
Extra provider rules merged with higher priority than built-ins. |
exclude_patterns |
list[str] |
[] |
URL substrings that cause a request to be silently dropped. |
base_url |
str |
"https://api.recost.dev" |
Override for self-hosted deployments. |
max_retries |
int |
3 |
Retry attempts for failed cloud flushes. |
on_error |
Callable |
— | Called on internal SDK errors. |
Custom providers
from recost import init, RecostConfig, ProviderDef
init(RecostConfig(
custom_providers=[
ProviderDef(
host_pattern="api.internal.acme.com",
path_prefix="/payments",
provider="acme-payments",
endpoint_category="charge",
cost_per_request_cents=0.5,
),
],
))
Cleanup / teardown
init() returns a handle with a dispose() method that stops the interceptor, cancels the flush timer, and closes the transport connection.
handle = init(RecostConfig(api_key="..."))
# Later — e.g. in a test teardown or process shutdown handler:
handle.dispose()
Disabling in tests
import os
from recost import init, RecostConfig
init(RecostConfig(enabled=os.environ.get("PYTHON_ENV") != "test"))
Supported providers
The registry ships with built-in rules for these providers. Cost estimates are rough per-request averages for relative comparison — actual costs vary by model, token count, and region.
| Provider | Host | Tracked endpoints | Cost estimate |
|---|---|---|---|
| OpenAI | api.openai.com |
chat completions, embeddings, image generation, audio transcription, TTS | 0.01–4.0¢/req |
| Anthropic | api.anthropic.com |
messages | 1.5¢/req |
| Stripe | api.stripe.com |
charges, payment intents, customers, subscriptions | 0¢ (% billing) |
| Twilio | api.twilio.com |
SMS, voice calls | 0.79–1.3¢/req |
| SendGrid | api.sendgrid.com |
mail send | 0.1¢/req |
| Pinecone | *.pinecone.io |
vector upsert, query | 0.08¢/req |
| AWS | *.amazonaws.com |
all services (wildcard) | 0¢ (complex pricing) |
| Google Cloud | *.googleapis.com |
all services (wildcard) | 0¢ (complex pricing) |
Unrecognized hosts produce a RawEvent with provider=None — they still appear in telemetry grouped under "unknown".
What is captured (and what is not)
Captured:
- Request timestamp, method, URL (query params stripped), host, path
- Response status code
- Round-trip latency (ms)
- Request and response body size (bytes)
- Matched provider, endpoint category, and estimated cost
Never captured:
- Request or response headers (contain API keys)
- Request or response body content (may contain user data or PII)
Core types
from recost import (
RawEvent,
MetricEntry,
WindowSummary,
RecostConfig,
ProviderDef,
TransportMode,
)
Testing
pip install -e ".[dev]"
pytest
API reference
All requests go to https://api.recost.dev. Authentication uses an rc- prefixed API key passed as Authorization: Bearer {api_key}.
Send telemetry manually (what the SDK does on flush)
curl -s -X POST https://api.recost.dev/projects/{project_id}/telemetry \
-H "Content-Type: application/json" \
-H "Authorization: Bearer {api_key}" \
-d @payload.json | jq .
View recent telemetry windows
curl -s "https://api.recost.dev/projects/{project_id}/telemetry/recent?limit=10" \
-H "Authorization: Bearer {api_key}" | jq .
View analytics for a project
curl -s "https://api.recost.dev/projects/{project_id}/analytics?from=2026-01-01T00:00:00Z&to=2026-12-31T23:59:59Z" \
-H "Authorization: Bearer {api_key}" | jq .
License
Licensed under the Business Source License 1.1 © 2026 Andres Lopez, Aslan Wang, Donggyu Yoon. Converts to Apache 2.0 on 2030-04-02.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file recost-0.1.0.tar.gz.
File metadata
- Download URL: recost-0.1.0.tar.gz
- Upload date:
- Size: 25.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
66b49d6a7f2e61bfe79f87dd73d92e424551f3503a39ea85db920c836b879b15
|
|
| MD5 |
955971e47cbbb5800f72e9aee2aa15a6
|
|
| BLAKE2b-256 |
0872e983fa30303057d7feebfcbcc517da29bb392246ace4a920e74e19029c7a
|
Provenance
The following attestation bundles were made for recost-0.1.0.tar.gz:
Publisher:
pypi-publish.yml on recost-dev/middleware-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
recost-0.1.0.tar.gz -
Subject digest:
66b49d6a7f2e61bfe79f87dd73d92e424551f3503a39ea85db920c836b879b15 - Sigstore transparency entry: 1238615432
- Sigstore integration time:
-
Permalink:
recost-dev/middleware-python@28ad8a2b86af712ed9731b4474470e244bd26c80 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/recost-dev
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi-publish.yml@28ad8a2b86af712ed9731b4474470e244bd26c80 -
Trigger Event:
push
-
Statement type:
File details
Details for the file recost-0.1.0-py3-none-any.whl.
File metadata
- Download URL: recost-0.1.0-py3-none-any.whl
- Upload date:
- Size: 21.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8fab08f7f17597dd05e67d85283ba033140dfc366aa2b1571b5db1c95462e9c2
|
|
| MD5 |
a0ebfa637a099357344175ff0de78e9e
|
|
| BLAKE2b-256 |
271dcdfe9630a4533d0132e073da756399e5d7eb3b05af3c40ab4c884505f648
|
Provenance
The following attestation bundles were made for recost-0.1.0-py3-none-any.whl:
Publisher:
pypi-publish.yml on recost-dev/middleware-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
recost-0.1.0-py3-none-any.whl -
Subject digest:
8fab08f7f17597dd05e67d85283ba033140dfc366aa2b1571b5db1c95462e9c2 - Sigstore transparency entry: 1238615434
- Sigstore integration time:
-
Permalink:
recost-dev/middleware-python@28ad8a2b86af712ed9731b4474470e244bd26c80 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/recost-dev
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi-publish.yml@28ad8a2b86af712ed9731b4474470e244bd26c80 -
Trigger Event:
push
-
Statement type: