Skip to main content

marginfuse

PyPI ci license

Server-side SDK for MarginFuse: profitability guardrails for AI SaaS. Connect revenue to per-request AI cost, see gross margin per customer, and stop loss-making requests before they run.

  • Metadata only, by construction. The event shape has no field for prompts or responses, so they cannot be sent. Not a policy, an absence.
  • Never breaks your app. It does not raise into your code, and it does not block your request on MarginFuse being up. If MarginFuse is unreachable, your requests proceed unchanged.
  • Zero dependencies. Standard library only, Python 3.9+.

Server side only. This SDK carries a secret API key. Never ship it in a desktop app, a mobile app, or anything else a user can read.

Install

pip install marginfuse

Track an AI call

Monitoring. One call after each AI request, metadata only.

import os
from marginfuse import MarginFuse, Usage

mf = MarginFuse(api_key=os.environ["MARGINFUSE_KEY"])

r = client.chat.completions.create(model="gpt-4.1", messages=messages)

mf.track(
    customer_id="cus_8x2m91",  # your Stripe customer id, or your own
    feature="ai_chat",
    provider="openai",
    model="gpt-4.1",
    usage=Usage(
        input_tokens=r.usage.prompt_tokens,
        output_tokens=r.usage.completion_tokens,
    ),
)

track() returns immediately and sends on a background thread with retries. In a script, a Celery task or a Lambda handler, call mf.flush() before the process exits, or the last events go with it.

with MarginFuse(api_key=os.environ["MARGINFUSE_KEY"]) as mf:
    ...  # closing flushes

Guard a call

Protection. Ask before the call runs, and act on the answer.

from marginfuse import MarginFuse, ProviderCall, Usage


def run(decision):
    # decision.model is the one to call: a downgrade verdict changes it.
    r = client.chat.completions.create(model=decision.model, messages=messages)
    return ProviderCall(
        result=r,
        usage=Usage(
            input_tokens=r.usage.prompt_tokens,
            output_tokens=r.usage.completion_tokens,
        ),
    )


out = mf.guard(run, customer_id="cus_8x2m91", feature="ai_chat", provider="openai", model="gpt-4.1")

if out.kind == "completed":
    use(out.result)
elif out.kind == "topup_required":
    show_topup(out.decision.topup_context)
else:
    show_limit_reached()

One call does the whole loop: ask, run with the resolved model, report the real cost, acknowledge what your application did.

Why a callback and not a context manager

A with block always runs its body. Enforcement would then depend on you remembering to check a flag, and forgetting once means a blocked request reaches the provider anyway. With a callback that is structurally impossible: when the verdict is block, your function is never called.

Tell MarginFuse what a customer pays

Margin needs a revenue side. With Stripe connected it comes from there. Without one, you declare your plans in MarginFuse and say which plan each customer is on:

result = mf.identify(
    customer_id="user_8x2m91",
    plan="pro",                    # the key of a plan you declared in Settings
    name="Acme Studio",
    metadata={"tier": "legacy"},   # labels segment policies can match on
)

if not result.ok:
    log.warning("MarginFuse identify: %s", result.error)

Safe to call on every sign-in: sending the plan the customer is already on changes nothing. Sending a different one ends the current cycle and prorates what accrued. period_start backdates the cycle for a customer who has been paying since an earlier date; clear_plan=True takes them off plans.

This is the one call that does not fail open. track() retries later and decide() allows, because both have a safe default; "I could not record what this customer pays" has none, and a wrong plan is a wrong margin. So it reports the failure to you instead of swallowing it. It still never raises.

track(), guard() and decide() also accept a plan, so it can ride along with usage rather than needing its own call. There it is a hint: a key that does not resolve is ignored rather than failing your event.

OpenRouter and other gateways

Gateways report the real cost of every call. Forward it and your figures are exact instead of estimated.

from marginfuse import from_openrouter

r = client.chat.completions.create(model="anthropic/claude-sonnet-4.5", messages=messages)

mf.track(
    customer_id="cus_8x2m91",
    feature="ai_chat",
    provider="openrouter",
    model="anthropic/claude-sonnet-4.5",
    **from_openrouter(r.usage),
)

Use the helper rather than mapping the fields yourself. OpenRouter's prompt_tokens already includes cached reads and cache writes, which MarginFuse prices separately, so passing it through directly charges every cached token twice at the full input rate. The helper also formats the cost as a decimal string, because str(1.2e-07) produces exponent notation and the API rejects that.

Configuration

mf = MarginFuse(
    api_key=os.environ["MARGINFUSE_KEY"],
    base_url="https://api.marginfuse.com",  # your own deployment in dev
    timeout=1.5,  # decide() budget before failing open
    on_error=lambda err, ctx: log.warning("marginfuse %s: %s", ctx, err),
)

on_error is the only place transport failures surface. The SDK swallows them so they cannot become your outage; without the hook they are silent.

Async applications

This client is synchronous and does no I/O on the calling thread except during decide() and guard(). In an async application, keep the event loop free by running those in a worker thread:

decision = await asyncio.to_thread(mf.decide, customer_id=cid, provider="openai", model="gpt-4.1")

track() and acknowledge() already return immediately, so they are safe to call directly from async code.

What it sends

Everything, and nothing else:

event_id  customer_id  feature  provider  model  requested_model
usage(input_tokens, output_tokens, cached_input_tokens,
      cache_creation_tokens, images, audio_seconds)
cost_usd  occurred_at  outcome  decision_id  retry_of_event_id  corrects_event_id

There is no field for message content anywhere in the wire types. The conformance suite checks this against the bytes that actually leave the process, on every scenario.

Conformance

This SDK is verified against marginfuse/sdk-contract, the same contract every MarginFuse SDK in every language is held to. It is a submodule here, so the pinned commit records exactly which contract a release passed.

git clone --recurse-submodules https://github.com/marginfuse/marginfuse-python
cd marginfuse-python
uv sync
uv run pytest          # unit tests, plus the shared gateway vectors
uv run --directory contract/harness npm install
npm --prefix contract/harness run conformance python

Links

MIT, Pemira Labs.

Metadata

Release files for marginfuse 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for marginfuse 0.2.0
File Size Uploaded
marginfuse-0.2.0.tar.gz 81.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for marginfuse 0.2.0
File Interpreter ABI Platform
marginfuse-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 97.0 kB

Release files / marginfuse-0.2.0.tar.gz

Download URL marginfuse-0.2.0.tar.gz
Size 81.7 kB
Tags Source
SHA-256 checksum
How to use checksums
3fe20cf10b51735885d8b5c3a1cf73d32efe0dcc15f3cb9530ce37f572ba1b2b
BLAKE2b-256 checksum
How to use checksums
e38f92dac2506de354dc9e90abc8ea7c3988e89432d5c800692a99d4753d08d4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 3, 2026.

Transparency log

Release files / marginfuse-0.2.0-py3-none-any.whl

Download URL marginfuse-0.2.0-py3-none-any.whl
Size 15.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6950ba2bb13a40b7d6b9195e84fd83efc482ff69220d3dfa405f5a7529f08c2d
BLAKE2b-256 checksum
How to use checksums
6ee447d0666acb649114f48efe012cfc44fc9b806b3774b75c6aaa77f3c19f14
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 3, 2026.

Transparency log

Release history Release notifications | RSS feed

0.3.1

2 release files

0.3.0

2 release files

This release

0.2.0 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page