# MarginFront — Complete Reference > Usage-based billing for AI agent companies. Track what your agents do, what they cost to run, and bill your customers accordingly. - Website: https://marginfront.com - Dashboard: https://app.marginfront.com - npm: https://www.npmjs.com/package/@marginfront/sdk - Docs: https://docs.marginfront.com - MCP Reference: https://marginfront.com/llms-mcp.txt ## What MarginFront Does MarginFront sits between your AI agent and your customers. When your agent does work — generates a report, drafts an email, answers a support ticket — you send MarginFront an event. MarginFront tracks the volume, calculates your cost to deliver (using a built-in pricing table for 300+ LLM models), and handles billing. Three integration paths, all hitting the same backend: - SDK (Node.js / TypeScript) — send usage events from your agent's code. Handles batching, retries, fire-and-forget. This is where most developers start. - REST API — send usage events (raw HTTP, any language) AND manage everything else: CRUD for agents, customers, signals, pricing plans, subscriptions. - MCP — same as API, but your AI coding assistant (Claude, Cursor, etc.) does it. See llms-mcp.txt for the full MCP tool catalog. ## Core Concepts - AGENT: Your AI product. The thing that does work for customers. Has an agent code (e.g. "cs-bot") used in events. - CUSTOMER: The end-user or company being billed. Has an externalId that matches the user ID in your system. - SIGNAL: Something the agent does or an outcome it achieves. This is what customers see on invoices. Good signals: "messages", "reports-generated", "pages-processed". Bad signals: "gpt-4o-call" — that's an internal cost detail, not a deliverable. - EVENT: A record that agent X did Y quantity of signal Z for customer W. Events carry model/provider info so MarginFront can calculate cost, plus optional quantity and metadata. - SERVICE COSTS: Calculated automatically from the model + provider + tokens you send in each event. Your customers never see this. You see it on your margin dashboard. - PRICING PLAN: Turns your costs into prices. Sets the rate you charge per unit of each signal. - SUBSCRIPTION: Ties a customer to an agent via a pricing plan. Defines billing cycle. - INVOICE: Auto-generated from subscriptions. Shows what you charge the customer. - API KEY: Starts with mf_sk_ (secret, server-side only). Identifies your organization — no org ID needed in requests. ## Setup Sequence (Golden Path) Do these in order. Each step depends on the one before it: 1. Create an Agent (your product) 2. Create a Signal (what you track — "messages", "reports", etc.) 3. Create a Pricing Plan (how much you charge per unit) 4. Link the Plan to the Agent 5. Create a Customer (who you're billing) 6. Create a Subscription (ties the customer to the agent via the plan) 7. Send your first event 8. See it on the dashboard Steps 3-4 and 6 are optional if you only need cost tracking (no revenue/invoicing). ## SDK Integration (Node.js / TypeScript) ### Install ```bash npm install @marginfront/sdk ``` ### Initialize ```typescript import { MarginFrontClient } from '@marginfront/sdk'; const mf = new MarginFrontClient(process.env.MF_API_SECRET_KEY); ``` ### Example 1: LLM Event (the 90% case) Your agent calls an LLM and you want to track the cost. Send the model name, provider, and token counts. ```typescript // After your OpenAI call completes... const response = await openai.chat.completions.create({ ... }); await mf.usage.record({ customerExternalId: 'acme-001', // required — your customer's ID agentCode: 'cs-bot', // required — your agent's code signalName: 'messages', // required — the metric being tracked model: 'gpt-4o', // required — which model was used modelProvider: 'openai', // required — who runs the model inputTokens: response.usage.prompt_tokens, // recommended — for LLM cost calc outputTokens: response.usage.completion_tokens, // recommended — for LLM cost calc }); ``` ### Example 2: Non-LLM Discrete Event (one task = one event) Your agent sends an SMS, makes an API call, or does one unit of work that isn't an LLM call. ```typescript await mf.usage.record({ customerExternalId: 'acme-001', agentCode: 'cs-bot', signalName: 'sms-sent', model: 'sms-send', // descriptive name for non-LLM services modelProvider: 'twilio', quantity: 1, // defaults to 1 if omitted, but explicit is clearer }); ``` ### Example 3: Variable-Quantity Event (output varies in size) Your agent generates a report, but reports vary in size. A 3-page report costs you less than a 15-page report, and you might bill per page. ```typescript await mf.usage.record({ customerExternalId: 'acme-001', agentCode: 'research-bot', signalName: 'report-pages', model: 'gpt-4o', modelProvider: 'openai', inputTokens: 12500, outputTokens: 8200, quantity: 15, // 15 pages — this drives per-unit billing }); ``` ### Example 4: Metadata (extra context, not used for billing) Attach debugging info, A/B test variants, or any context you want searchable later. MarginFront stores metadata but does NOT use it for cost calculation or billing. ```typescript await mf.usage.record({ customerExternalId: 'acme-001', agentCode: 'cs-bot', signalName: 'messages', model: 'gpt-4o', modelProvider: 'openai', inputTokens: 523, outputTokens: 117, metadata: { promptTemplate: 'v3-concise', abVariant: 'treatment-b', conversationId: 'conv_abc123', customerTier: 'pro', }, }); ``` ### Batch Events (1-100 per call) ```typescript await mf.usage.recordBatch({ records: [ { customerExternalId: 'acme-001', agentCode: 'cs-bot', signalName: 'messages', model: 'gpt-4o', modelProvider: 'openai', inputTokens: 500, outputTokens: 100 }, { customerExternalId: 'acme-001', agentCode: 'cs-bot', signalName: 'sms-sent', model: 'sms-send', modelProvider: 'twilio', quantity: 1 }, ], }); ``` ### Fire-and-Forget Mode (default: ON) The SDK defaults to fire-and-forget. Events send in the background — your agent never waits for MarginFront. If MarginFront is unreachable, events queue in a local retry buffer (up to 1,000 events, 5 retries each with exponential backoff). Your agent keeps running no matter what. Turn it off if you want to handle errors yourself: ```typescript const mf = new MarginFrontClient(process.env.MF_API_SECRET_KEY, { fireAndForget: false, // now usage.record() throws on errors }); ``` ### CLI (Testing) ```bash npm install -g @marginfront/sdk mf verify --api-key mf_sk_your_key mf track-event --customer-id acme-001 --agent-code cs-bot --signal messages --model gpt-4o --provider openai --input-tokens 500 --output-tokens 100 ``` ## REST API Base URL: https://api.marginfront.com/v1 Auth: x-api-key header with your secret key (NOT Authorization: Bearer) ### Track Usage Event ```bash curl -X POST https://api.marginfront.com/v1/usage/record \ -H "x-api-key: mf_sk_your_key" \ -H "Content-Type: application/json" \ -d '{ "records": [{ "customerExternalId": "acme-001", "agentCode": "cs-bot", "signalName": "messages", "model": "gpt-4o", "modelProvider": "openai", "inputTokens": 523, "outputTokens": 117 }] }' ``` ### Full Endpoint List Usage Events: POST /v1/usage/record — track one or more usage events (batch: wrap in records[] array) Customers: POST /v1/customers — create customer GET /v1/customers — list customers (paginated, searchable) GET /v1/customers/:id — get customer by ID PATCH /v1/customers/:id — update customer DELETE /v1/customers/:id — delete customer Agents: POST /v1/agents — create agent GET /v1/agents — list agents GET /v1/agents/:id — get agent by ID PATCH /v1/agents/:id — update agent DELETE /v1/agents/:id — delete agent Signals: POST /v1/signals — create signal POST /v1/signals/bulk — create multiple signals at once GET /v1/signals — list signals GET /v1/signals/:id — get signal by ID PATCH /v1/signals/:id — update signal DELETE /v1/signals/:id — delete signal Pricing Plans: POST /v1/pricing-plans — create pricing plan GET /v1/pricing-plans — list pricing plans GET /v1/pricing-plans/:id — get pricing plan by ID PATCH /v1/pricing-plans/:id — update pricing plan DELETE /v1/pricing-plans/:id — delete pricing plan POST /v1/pricing-plans/:id/copy — duplicate a pricing plan Subscriptions: POST /v1/subscriptions — create subscription GET /v1/subscriptions — list subscriptions GET /v1/subscriptions/:id — get subscription by ID PATCH /v1/subscriptions/:id — update subscription DELETE /v1/subscriptions/:id — delete subscription Invoices: GET /v1/invoices — list invoices (filterable by customer, status) GET /v1/invoices/:id — get invoice with line items Analytics: GET /v1/analytics/usage — usage analytics (requires startDate, endDate; optional groupBy, customerId, agentId, signalId) Portal Sessions: POST /v1/portal-sessions — create a portal session for a customer GET /v1/portal-sessions — list portal sessions GET /v1/portal-sessions/:id — get portal session by ID DELETE /v1/portal-sessions/:id — delete portal session Model Mapping: POST /v1/model-mappings — map an unknown model to a known one and backfill costs Verification: GET /v1/verify — verify API key and see organization info ## MCP Integration MarginFront has an MCP server for AI coding assistants (Claude Code, Cursor, VS Code, etc.). Once connected, your AI can manage customers, track events, query analytics — all in plain English. Setup (Claude Code): ```json { "mcpServers": { "marginfront": { "command": "npx", "args": ["-y", "@marginfront/mcp"], "env": { "MF_API_SECRET_KEY": "mf_sk_your_key_here" } } } } ``` See https://marginfront.com/llms-mcp.txt for the complete MCP tool catalog (13 tools). ## Field Reference ### Required for every event: - customerExternalId (string) — your customer's ID in your system - agentCode (string) — the code you gave this agent in the dashboard - signalName (string) — the metric being tracked (e.g. "messages", "reports") - model (string) — model identifier (e.g. "gpt-4o", "claude-sonnet-4", "twilio-sms") - modelProvider (string) — provider name, lowercase (e.g. "openai", "anthropic", "twilio") ### Add for LLM events (recommended for cost tracking): - inputTokens (number) — prompt / input tokens - outputTokens (number) — completion / output tokens ### Add for variable-quantity events: - quantity (number) — numeric count. Defaults to 1 if omitted. Use for per-page, per-minute, per-unit billing. ### Optional: - usageDate (string, ISO 8601) — when the event happened. Defaults to now. - metadata (object) — free-form key-value pairs. Stored but not used for billing or cost calculation. ## Important: Silent Failure Behavior The API returns HTTP 200 even when individual events fail validation. You MUST check the response body: ```json { "processed": 2, "successful": 1, "failed": 1, "results": { "success": [...], "failed": [{ "error": "Signal not found: typo-name" }] } } ``` If `failed > 0`, that event did NOT record. Read `results.failed[].error` for the reason. Common causes: signal name mismatch (including extra whitespace), customer external ID not found, unrecognized model (event still stores with cost = null). ## Important: Cost Status Flags - `stored: true` with a `totalCostUsd` value — event recorded, cost calculated. Everything worked. - `stored: true` with `NEEDS_COST_BACKFILL` — event recorded, but the model wasn't recognized. Cost is null. Use the model-mapping endpoint to fix, then costs backfill automatically. - `stored: false` — event failed validation entirely. Check the error message. ## Important: Never Break the Core Product MarginFront is billing infrastructure. If it is unavailable or returns an error, the host application must continue functioning. Always wrap MarginFront calls in error handling. On failure: log a warning and continue. The SDK does this automatically when fireAndForget is true (the default). ```typescript // GOOD — agent keeps running no matter what try { await mf.usage.record({ ... }); } catch (err) { console.warn('MarginFront tracking failed, continuing:', err.message); } // BETTER — use fireAndForget (default) and don't even think about it await mf.usage.record({ ... }); // never throws, never blocks ```