SDKs
Seven languages, one behaviour. Each SDK is open source under MIT, carries no package dependencies of its own, and is driven through the same conformance suite before it can be published.
Install
Pick your language. The examples on every other page in these docs switch to it and stay there.
TypeScript and Node
Node 18+, zero dependencies
npm install marginfusePython
Python 3.9+, zero dependencies
pip install marginfuseGo
Go 1.21+, zero dependencies
go get github.com/marginfuse/marginfuse-goJava
Java 11+, zero dependencies
implementation("com.marginfuse:marginfuse-java:0.1.0")C# and .NET
.NET 8+, zero dependencies
dotnet add package MarginFuseRuby
Ruby 3.2+, zero dependencies
gem install marginfusePHP
PHP 8.2+, zero dependencies
composer require marginfuse/marginfuseThe same call, in each of them
This is the whole measurement integration. It sends metadata only: token counts, the model, your customer id. There is no field for the prompt, so nothing else can travel by accident.
import { MarginFuse } from "marginfuse";
const mf = new MarginFuse({ apiKey: process.env.MARGINFUSE_KEY! });
// After the AI call returns. Metadata only: there is no field for the prompt.
mf.track({
customerId: "cus_8x2m91", // your Stripe customer id, or your own
feature: "ai_chat",
provider: "openai",
model: "gpt-4.1",
usage: { inputTokens: 1204, outputTokens: 388 },
});Why they behave the same
Nothing about seven independent implementations guarantees they agree. What makes these interchangeable is that none of them owns its own definition of correct. A single shared contract holds the behaviour, and every SDK is driven through it before release.
- Sixteen behaviour scenarios, run against the packaged artifact rather than the source tree. A block verdict never calls the provider. A timeout fails open to allow. A malformed response degrades instead of crashing.
- Thirteen gateway vectors, so the cost arithmetic matches across languages down to the string that goes on the wire.
- Each SDK exports the contract version it was verified against. Two SDKs reporting the same one have passed the same scenarios and the same vectors.
Package version numbers differ per language, because each tracks its own breaking changes: a rename in Python must not tell Node users something broke. The contract version is what makes them comparable, not the package version.
What every one of them promises
tracknever throws into your code and never blocks your response. It returns immediately and retries in the background.decidealways returns a verdict. On any timeout or error it fails open toallowwithdegradedset, because MarginFuse being unreachable must never become your outage.- Failures the SDK swallowed reach you through
onErrorand nowhere else. Without it they are silent by design.