Integrate MarginFront with Non-LLM Tools
Not everything your agent does is an LLM call. Your agent might send SMS messages via Twilio, scrape web pages, generate PDFs, send emails, process images, or transcribe audio. MarginFront tracks all of it through the same event endpoint. What this does for you: Every tool your agent uses — LLM or not — shows up in one dashboard. You see the full cost picture, not just the AI part.How non-LLM events differ from LLM events
Same endpoint (POST /v1/usage/record), same SDK method (mf.usage.record()). The difference is which fields carry the “how much” information:
| Event type | ”How much” field | Example |
|---|---|---|
| LLM | inputTokens + outputTokens | 523 input tokens, 117 output tokens |
| Non-LLM | quantity | 1 SMS sent, 12 pages scraped |
model and modelProvider are descriptive labels you choose. Use something readable — they’ll show up in your dashboard and analytics. inputTokens and outputTokens are always optional; leave them out for non-LLM work.
Prerequisites
You don’t need to create the agent or signal first. When you fire your first event with a newagentCodeorsignalName, MarginFront creates them automatically. The same goes forcustomerExternalId. You can rename and enrich any of them in the dashboard later.
Example 1: Twilio SMS
Your agent sends a text message to a customer’s phone number. You want to track each SMS as one unit of usage.model: 'sms-send'? For non-LLM services, model is just a label that helps you identify what happened when you look at the dashboard later. Pick something readable. Other good options: 'outbound-sms', 'sms-notification', 'transactional-sms'.
Example 2: Web scraping (variable quantity)
Your research agent scrapes a website and returns multiple pages of content. The number of pages varies per job, soquantity changes each time.
modelProvider: 'internal'? If the tool is something you built (not a third-party service), use 'internal' as the provider. MarginFront won’t find it in any pricing table, so the cost will be null — which is fine. You’re tracking the signal quantity for billing purposes, not calculating LLM costs.
Fire ONE event when the whole scrape job finishes — not one event per page.quantity: pages.lengthis how you tell MarginFront this one job handled N pages. Looping to fire one event per page would multiply your invoice, flood your analytics, and burn API calls for no reason. Same rule for minutes of audio, images in a batch, messages in a thread — one event per outcome,quantitydoes the counting. See Choosing your signal name and quantity for the full rule.
Example 3: PDF generation
Your reporting agent generates a multi-page PDF for a customer. You bill by the number of pages in the report.Example 4: Email sending (via Resend, SendGrid, etc.)
Example 5: Mixing LLM and non-LLM in one workflow
Real agents often use multiple services for a single business outcome. A place-report agent generates a report about a location by searching Google for context, then asking Gemini to analyze + write it, then calling the Places API to attach map metadata. From the customer’s perspective that’s ONE report about ONE place. From your cost perspective three underlying services contributed: a search API, an LLM, and a non-LLM map lookup. Track it as ONE event with aservices array. Each entry becomes a per-service cost line under one parent event. The dashboard shows one event with a rolled-up total; the Cost-by-service chart splits it across the three services.
service_pricing if you’ve added it, null until then), Gemini tokens (calculated from the catalog), and Google Maps Places (same as Search). The “Cost by service” chart on the Cost tab shows where the total split.
One outcome, one event. The most common mistake here is firing threemf.usage.recordcalls (one per service). That used to be the workaround before multi-service shipped: it triplicated the report on your dashboard, made margin math harder, and could have multi-counted the customer’s invoice when all three events shared a signal. Withservices[], you fire one event per business outcome regardless of how many underlying services contributed.
When to use services[] vs single-service shape
Use the single-service shape (top-level model + modelProvider) when one event uses one underlying service. This is the 90% case for chatbots: an agent answers one question with GPT-4o, sends one SMS, transcribes one audio file.
services[] when one event is backed by multiple underlying services contributing to the same business outcome (the place-report example above is three services; cold-outreach pipelines are often four or more).
The two shapes are mutually exclusive: send model + modelProvider OR send services[], never both, never neither. If you mix shapes, MarginFront rejects the request with a clear error pointing at the fix.
LLM services can carry tokens AND quantity together
The Gemini entry in the example above setsinputTokens, outputTokens, AND quantity: 1 simultaneously. That’s intentional. LLM services[] entries can carry all three, which lets you:
- Track the call count alongside token totals (e.g., when retries or chain-of-thought intermediate prompts cause one outcome to trigger multiple LLM calls).
- Layer per-call pricing on top of per-token pricing once your
service_pricingcatalog supports it (audit in progress). - Compare “calls per outcome” against “tokens per outcome” in your own reporting.
quantity on LLM entries. Cost calculation is tokens-only for LLM services today; per-call pricing is on the roadmap.
Multiple calls of the same model in one event
If your agent makes two Gemini calls for one report (a draft pass + a refinement pass that both contribute to the same outcome), you have two equally valid ways to record it: Option A: list each call as its ownservices[] entry. Each becomes a distinct cost line. Use this when you want per-call resolution.
quantity = call count. Cleaner if you don’t need per-call resolution.
What you pick vs what MarginFront calculates
For non-LLM events, here’s what’s yours to define and what MarginFront handles:| Field | You set it | MarginFront calculates it |
|---|---|---|
model | Yes — pick a descriptive label | No |
modelProvider | Yes — the service name or 'internal' | No |
quantity | Yes — how many units of work | No |
inputTokens | Optional (leave out for non-LLM) | No |
outputTokens | Optional (leave out for non-LLM) | No |
| Service cost | No | Yes, if model+provider is in the pricing table. Otherwise null. |
| Revenue | No | Yes, from pricing plan: quantity x price_per_unit |
Including tokens AND quantity
Some events straddle both worlds. For example, an image generation call uses tokens (for the prompt) but also produces a quantity (number of images):quantity, inputTokens, outputTokens) are always optional. Use whichever ones are relevant to the work that happened.
Cost tracking for non-LLM tools
MarginFront’s built-in catalog covers 300+ LLM models plus a curated set of non-LLM services (Twilio SMS and voice, Google Maps, SendGrid, Hunter, Exa, and more). If your non-LLM tool isn’t in the catalog yet, the model+provider won’t match anything. That’s fine:- The event saves with
cost = null(never dropped, never zero). - Revenue is still calculated from your pricing plan (
quantity x price_per_unit). - If you want MarginFront to calculate the actual cost of a non-LLM tool (e.g., the SMS provider you use), open the Needs Attention flow on the dashboard and map your model name to its catalog entry. Cost-side mapping is optional. Many users only care about the revenue side for non-LLM tools.
Fire-and-forget still applies
Just like with LLM events, the SDK’s default fire-and-forget mode means:- If MarginFront is down, events retry automatically from a local buffer.
- If there’s a validation error, the SDK logs a warning and moves on.
- Your agent never stalls waiting for MarginFront.

