Skip to main content

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: For non-LLM events, 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 new agentCode or signalName, MarginFront creates them automatically. The same goes for customerExternalId. 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.
Why 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, so quantity changes each time.
Why 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.length is 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, quantity does 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 a services 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.
ONE event shows up in your dashboard. Cost rolls up across all three services: Google Search (mapped to your 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 three mf.usage.record calls (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. With services[], 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.
Use 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 sets inputTokens, 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_pricing catalog supports it (audit in progress).
  • Compare “calls per outcome” against “tokens per outcome” in your own reporting.
If you don’t care about call counts, omit 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 own services[] entry. Each becomes a distinct cost line. Use this when you want per-call resolution.
Option B: aggregate into one entry with summed tokens and quantity = call count. Cleaner if you don’t need per-call resolution.
Both produce the same rolled-up parent cost.

What you pick vs what MarginFront calculates

For non-LLM events, here’s what’s yours to define and what MarginFront handles:

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):
All three fields (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.
This is especially important for non-LLM tools where the work is already done (SMS already sent, PDF already generated) — there’s no point blocking on the tracking call.

Reading back what you earned

You sent events. Now you want numbers: revenue, cost, margin, MRR. Three canonical paths, all point to the same data.

Via SDK (inside your app)

Via REST (from any language or curl)

Via MCP (from an AI agent like Claude, Cursor, or Copilot)

If you’ve connected MarginFront’s MCP server to your AI coding assistant, the agent can call canonical analytics tools directly:
All three paths return the same canonical numbers. Pick whichever fits your workflow.