> ## Documentation Index
> Fetch the complete documentation index at: https://docs.marginfront.com/llms.txt
> Use this file to discover all available pages before exploring further.

# MCP Tools Reference

> All 36 MCP tools with parameters, return values, and example prompts

# MarginFront MCP Tools Reference

This is a complete list of the core MarginFront MCP tools. There are 36 tools total, organized into groups: read-only, write, diagnostic, destructive, canonical analytics, pricing setup, portal sessions, catalog discovery, and spend controls.

Your AI assistant calls these tools automatically when you ask it questions about your MarginFront data. You don't need to memorize tool names. Just ask in plain English and the AI picks the right tool.

Detailed parameters and examples for every tool live in the machine-readable [llms-mcp.txt](https://marginfront.com/llms-mcp.txt), which is the canonical source the MCP server and AI clients both read.

***

## Read-Only Tools (8)

These tools look things up without changing anything.

***

### 1. verify

**What it does:** Checks that your API key is valid and shows which organization it belongs to. This is the "hello world" of MCP -- call it first to make sure everything is wired up.

**Parameters:** None.

**What it returns:** Your organization name and a verified status.

**Example prompt:** "Verify my MarginFront connection"

***

### 2. list\_customers

**What it does:** Lists your customers with optional search and pagination. Good for browsing your customer list or finding a specific customer by name.

**Parameters:**

| Name   | Type   | Required | Default | Description                            |
| ------ | ------ | -------- | ------- | -------------------------------------- |
| page   | number | No       | 1       | Which page of results to show          |
| limit  | number | No       | 20      | How many results per page (1-100)      |
| search | string | No       | --      | Search by customer name or external ID |

**What it returns:** A list of customers with their names, MarginFront UUIDs, external IDs, and status.

**Example prompt:** "Show me my MarginFront customers"

***

### 3. get\_customer

**What it does:** Gets detailed information about one specific customer, including their subscriptions.

**Parameters:**

| Name       | Type   | Required | Description                                             |
| ---------- | ------ | -------- | ------------------------------------------------------- |
| customerId | string | Yes      | The customer's MarginFront UUID (not their external ID) |

**What it returns:** Full customer details -- name, email, phone, external ID, status, and all their subscriptions.

**Example prompt:** "Tell me about customer 7a2b3c4d-5e6f-7890-abcd-ef1234567890"

> **Note:** This tool needs the MarginFront UUID, not the external ID you use in your own system. Use `list_customers` first to find the UUID.

***

### 4. list\_invoices

**What it does:** Lists invoices with optional filters by status or customer.

**Parameters:**

| Name       | Type   | Required | Default | Description                                                                  |
| ---------- | ------ | -------- | ------- | ---------------------------------------------------------------------------- |
| status     | string | No       | --      | Filter by status: `"draft"`, `"pending"`, `"paid"`, `"overdue"`, or `"void"` |
| customerId | string | No       | --      | Filter by customer UUID                                                      |
| page       | number | No       | 1       | Which page of results                                                        |
| limit      | number | No       | 20      | Results per page (1-100)                                                     |

**What it returns:** A list of invoices showing status, amounts, customer name, and dates.

**Example prompt:** "Show me all pending invoices"

***

### 5. get\_invoice

**What it does:** Gets full details about one invoice, including every line item and payment history.

**Parameters:**

| Name      | Type   | Required | Description        |
| --------- | ------ | -------- | ------------------ |
| invoiceId | string | Yes      | The invoice's UUID |

**What it returns:** The complete invoice -- line items (what was billed), amounts, payment status, customer info, and dates.

**Example prompt:** "Show me the details on invoice 1a2b3c4d-5e6f-7890-abcd-ef1234567890"

***

### 6. list\_events

**What it does:** Lists usage events (the raw records of what your customers actually used) with optional filters.

**Parameters:**

| Name               | Type   | Required | Default | Description                                                                                              |
| ------------------ | ------ | -------- | ------- | -------------------------------------------------------------------------------------------------------- |
| page               | number | No       | 1       | Which page of results                                                                                    |
| limit              | number | No       | 20      | Results per page (1-100)                                                                                 |
| customerExternalId | string | No       | --      | Filter by customer external ID (the ID in your own system, e.g. `"acme-001"`). NOT the MarginFront UUID. |
| agentId            | string | No       | --      | Filter by agent UUID                                                                                     |
| signalId           | string | No       | --      | Filter by signal UUID                                                                                    |
| startDate          | string | No       | --      | Only show events after this date (ISO 8601 format, e.g. `"2026-04-01"`)                                  |
| endDate            | string | No       | --      | Only show events before this date (ISO 8601 format)                                                      |

**What it returns:** A list of events, each showing the model used, token counts, calculated cost, customer, and timestamp.

**Example prompt:** "What events were logged today?" or "Show me events for customer acme-001 this week."

***

### 7. get\_usage\_analytics

**What it does:** Gets aggregated usage analytics (totals and trends) for a date range. Unlike `list_events` which shows individual events, this gives you the big picture -- totals, breakdowns, and time-series data.

**Parameters:**

| Name      | Type   | Required | Default | Description                                                                            |
| --------- | ------ | -------- | ------- | -------------------------------------------------------------------------------------- |
| startDate | string | Yes      | --      | Start of the date range (ISO 8601, e.g. `"2026-04-01"`)                                |
| endDate   | string | Yes      | --      | End of the date range (ISO 8601, e.g. `"2026-04-12"`)                                  |
| groupBy   | string | No       | --      | How to break down the data: `"agent"`, `"customer"`, `"signal"`, `"model"`, or `"day"` |

**What it returns:** Summary totals (total cost, total events, total tokens) plus a breakdown grouped however you specified.

**Example prompt:** "Show me usage analytics for April grouped by customer"

***

### 8. list\_subscriptions

**What it does:** Lists customer subscriptions (which customer is on which pricing plan).

**Parameters:**

| Name       | Type   | Required | Default | Description                                                            |
| ---------- | ------ | -------- | ------- | ---------------------------------------------------------------------- |
| status     | string | No       | --      | Filter by status: `"active"`, `"canceled"`, `"past_due"`, `"trialing"` |
| customerId | string | No       | --      | Filter by customer UUID                                                |
| page       | number | No       | 1       | Which page of results                                                  |
| limit      | number | No       | 20      | Results per page (1-100)                                               |

**What it returns:** A list of subscriptions showing status, plan name, billing dates, and customer info.

**Example prompt:** "Show me all active subscriptions"

***

## Write Tools (5)

These tools create or modify data. They change things in MarginFront, so the AI will usually confirm before calling them.

***

### 9. record\_usage

**What it does:** Records a single usage event -- one measurement of a customer using your AI agent. This is how MarginFront learns what to bill for.

There are three patterns the same tool accepts:

* **Single-service LLM event** (chatbots, summarizers, etc.): pass top-level `model` + `modelProvider` + `inputTokens` + `outputTokens`.
* **Single-service non-LLM event** (SMS, web scraping, API calls, etc.): pass top-level `model` + `modelProvider` + `quantity`.
* **Multi-service event** (one outcome backed by multiple underlying services, e.g. one report that called Claude AND queried Google Maps): pass a `services[]` array, one entry per underlying service. Top-level `quantity` stays signal-level (default 1). Top-level `model` / `modelProvider` are omitted.

The single-service shape and multi-service shape are mutually exclusive. Send top-level `model` + `modelProvider` OR send `services[]`, never both, never neither. The MCP tool rejects with a clear English error before the request leaves the agent if you mix shapes.

**Parameters:**

| Name               | Type   | Required                                        | Default | Description                                                                                                                                                                                                                                                             |
| ------------------ | ------ | ----------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| customerExternalId | string | Yes                                             | --      | Your customer's ID in your system, e.g. `"acme-001"`                                                                                                                                                                                                                    |
| agentCode          | string | Yes                                             | --      | The agent/product code from your dashboard, e.g. `"cs-bot-v2"`                                                                                                                                                                                                          |
| signalName         | string | Yes                                             | --      | The metric being tracked, e.g. `"messages"` or `"pages_processed"`                                                                                                                                                                                                      |
| model              | string | Single-service shape (when no `services`)       | --      | The model identifier, e.g. `"gpt-4o"`, `"claude-sonnet-4-6"`, `"twilio-sms"`. Omit when sending `services[]`.                                                                                                                                                           |
| modelProvider      | string | Single-service shape (when no `services`)       | --      | The provider name in lowercase, e.g. `"openai"`, `"anthropic"`, `"twilio"`. Omit when sending `services[]`.                                                                                                                                                             |
| inputTokens        | number | No                                              | --      | Single-service: input tokens for an LLM call. Omit when sending `services[]`.                                                                                                                                                                                           |
| outputTokens       | number | No                                              | --      | Single-service: output tokens for an LLM call. Omit when sending `services[]`.                                                                                                                                                                                          |
| cacheReadTokens    | number | No                                              | --      | Single-service: prompt-cache read tokens (cache hits) for an LLM call. Priced at the cheaper cache-read rate instead of the full input rate. Omit when sending `services[]`.                                                                                            |
| cacheWriteTokens   | number | No                                              | --      | Single-service: prompt-cache write tokens (cache creation) for an LLM call. Priced at the cache-write rate. Omit when sending `services[]`.                                                                                                                             |
| quantity           | number | No                                              | 1       | Single-service: billing units for non-LLM. Multi-service: signal-level count (one report = 1).                                                                                                                                                                          |
| services           | array  | Multi-service shape (when no top-level `model`) | --      | One entry per underlying service contributing to this outcome. Each entry has its own `model`, `modelProvider`, and volume fields (`inputTokens`/`outputTokens`, plus optional `cacheReadTokens`/`cacheWriteTokens`, for LLM; `quantity` for non-LLM). Minimum 1 entry. |
| usageDate          | string | No                                              | now     | ISO 8601 date for backdating, e.g. `"2026-04-01T00:00:00Z"`                                                                                                                                                                                                             |
| metadata           | object | No                                              | --      | Custom key-value pairs stored with the event (not used for billing)                                                                                                                                                                                                     |

**What it returns:**

* For single-service: the event ID, calculated cost (in USD), and timestamp.
* For multi-service: the parent event ID, rolled-up `totalCostUsd` (sum across services), a `services[]` array showing per-service cost + status, and timestamp.

If any service in a multi-service event isn't in the pricing table, the parent's `totalCostUsd` stays null until ALL services are mapped (the cost rule). The `services[]` response array shows exactly which entries are unresolved so you can call `map_model` on the right one. Use `get_needs_attention` to see all unmapped models across all events.

**Example prompts:**

* Single-service: `"Record a usage event: customer acme-001 used cs-bot, signal messages, gpt-4o from openai, 500 input tokens, 120 output tokens"`
* Multi-service: `"Record one cold outreach for customer acme-001 on the outreach-bot. The outreach used Exa search (1 call), Hunter enrichment (1 call), Claude Opus to write the message (4500 input + 1200 output tokens, 1 call), and Pipedream to send (1 call). Track it as ONE event."`

> **Important:** If you get a "NEEDS\_COST\_BACKFILL" response, do NOT re-send the event. The event was saved. The model (or one of the services) just isn't in the pricing table yet. Use `get_needs_attention` to see which models need mapping, then `map_model` to fix them.

***

### 10. record\_usage\_batch

**What it does:** Records multiple usage events at once (1 to 100 per request). Each record has the same fields as `record_usage` -- including the choice between single-service shape (top-level `model` + `modelProvider`) and multi-service shape (`services[]`). You can mix all three patterns (single-service LLM, single-service non-LLM, multi-service) in the same batch.

**Parameters:**

| Name    | Type  | Required | Description                                                                                                                                                                                                               |
| ------- | ----- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| records | array | Yes      | An array of 1-100 usage records. Each record has the same fields as `record_usage` (see above). Each record independently picks single-service or multi-service shape. Mixing shapes WITHIN one record is still rejected. |

**What it returns:** A summary showing how many succeeded, how many failed, and per-record details for each. Successes include the same shape as `record_usage`. Failed records that were still saved (like NEEDS\_COST\_BACKFILL or MISSING\_VOLUME\_DATA) are flagged -- do NOT retry those. For multi-service failed records, the response includes a `servicesStatus[]` array so you see which specific service in the batch entry needs fixing.

**Example prompt:** "Record these for customer acme-001: 3 messages on cs-bot using gpt-4o from openai (200 input / 50 output each), and one cold outreach on outreach-bot that used Exa (1 call), Hunter (1 call), Claude Opus (4500/1200 tokens, 1 call), and Pipedream (1 call)."

***

### 11. create\_customer

**What it does:** Creates a new customer in MarginFront.

**Parameters:**

| Name       | Type   | Required | Default | Description                                           |
| ---------- | ------ | -------- | ------- | ----------------------------------------------------- |
| name       | string | Yes      | --      | Customer's display name, e.g. `"Acme Corp"`           |
| externalId | string | No       | --      | Your system's ID for this customer, e.g. `"acme-001"` |
| email      | string | No       | --      | Customer's email address                              |
| phone      | string | No       | --      | Customer's phone number                               |

**What it returns:** The newly created customer with their MarginFront UUID.

**Example prompt:** "Create a customer called Beta Corp with external ID beta-001"

> **Tip:** Always set `externalId` when creating a customer. That's the ID you'll use when recording usage events later, so it should match whatever ID you use for this customer in your own system.

***

### 12. generate\_invoice

**What it does:** Builds a draft invoice from a subscription's tracked usage. Reads the period's usage events, applies the subscription's pricing strategies, and writes a draft invoice with line items and totals — ready to preview, edit, or send.

This is the right tool when you want to "bill now" instead of waiting for the end of the billing period. The draft starts in `draft` status; nothing is sent to the customer until you (or the auto-finalize step) move it to `issued`.

**Parameters:**

| Name               | Type   | Required | Description                                                                 |
| ------------------ | ------ | -------- | --------------------------------------------------------------------------- |
| customerId         | string | Yes      | Customer UUID (the MarginFront UUID, not the external ID from your system)  |
| subscriptionId     | string | Yes      | Subscription UUID to bill for                                               |
| billingPeriodStart | string | No       | ISO 8601 date. Defaults to the subscription's current billing period start. |
| billingPeriodEnd   | string | No       | ISO 8601 date. Defaults to the subscription's current billing period end.   |

**What it returns:** The full draft invoice, including line items, totals, and the invoice UUID.

**Example prompt:** "Generate a draft invoice for Acme Corp's Growth Plan subscription using this period's usage"

***

### 13. send\_invoice

**What it does:** Emails an invoice to the customer with a "Pay Now" button that opens Stripe Checkout pre-filled with the invoice details. Use this after `generate_invoice` to actually deliver a draft, or to re-send an invoice that has already been issued. The customer's stored email address is used by default — pass `recipientEmail` to override (for example, to route the invoice to a different billing contact).

**Parameters:**

| Name           | Type   | Required | Default                                      | Description                                                                                 |
| -------------- | ------ | -------- | -------------------------------------------- | ------------------------------------------------------------------------------------------- |
| invoiceId      | string | Yes      | --                                           | The invoice's MarginFront UUID (from `list_invoices`, `get_invoice`, or `generate_invoice`) |
| recipientEmail | string | No       | customer's stored email                      | Override the destination address                                                            |
| subject        | string | No       | `Invoice {number} from {your business name}` | Custom subject line                                                                         |
| message        | string | No       | --                                           | Optional note shown in a callout above the invoice details                                  |

**What it returns:** A confirmation including the email provider's message ID (for delivery tracking) and the address the email was actually sent to (after applying any override).

**Example prompts:**

* "Email the latest draft invoice to Acme Corp"
* "Send invoice inv\_abc to [billing@customer.com](mailto:billing@customer.com) with the subject 'May invoice — auto-charge in 5 days'"

> **Side effect:** if the invoice is still a `draft` when you call this, sending it auto-finalizes the status to `issued`. This matches the dashboard Send button and the end-of-period auto-finalize step. Once the customer pays via the Stripe Checkout link, the invoice flips to `paid` automatically — no follow-up call needed.

***

## Diagnostic Tool (1)

This tool helps you find and fix data issues.

***

### 14. get\_needs\_attention

**What it does:** Finds usage events where the model+provider combination isn't in the pricing table. These events were saved (the data isn't lost), but their cost is null because MarginFront doesn't know how much that model costs.

**Parameters:**

| Name      | Type   | Required | Default     | Description                                     |
| --------- | ------ | -------- | ----------- | ----------------------------------------------- |
| startDate | string | No       | 30 days ago | Only look at events after this date (ISO 8601)  |
| endDate   | string | No       | now         | Only look at events before this date (ISO 8601) |

**What it returns:** Groups of unrecognized model+provider combinations, each with a count of how many events are affected.

**Example prompt:** "Are there any MarginFront events with unknown models?"

> **Important:** These events ARE saved -- they just have cost=null. Do NOT re-send them. Use `map_model` (below) to tell MarginFront what pricing to use, and it will backfill the costs automatically.

***

## Destructive Tool (1)

This tool modifies existing data. "Destructive" sounds scary, but it's actually a fix-it tool -- and it's safe to run more than once (it's idempotent, meaning running it twice produces the same result as running it once).

***

### 15. map\_model

**What it does:** Maps an unknown model to a known one in the pricing table, then backfills costs for all affected events. This creates a permanent, organization-scoped mapping -- once you map it, future events with the same model+provider will have their costs calculated automatically.

You tell it the "source" (the unknown model) and the "target" (the known model to price it as). You can identify the target two ways:

* By name: pass `targetModel` + `targetProvider` (e.g., map "gpt-4o-2024-08-06" to "gpt-4o" from "openai").
* By ID: pass `targetPricingId` (the UUID of the specific pricing table row).

**Parameters:**

| Name            | Type   | Required | Description                                                    |
| --------------- | ------ | -------- | -------------------------------------------------------------- |
| sourceModel     | string | Yes      | The unknown model name to map FROM, e.g. `"gpt-4o-2024-08-06"` |
| sourceProvider  | string | Yes      | The unknown provider to map FROM, e.g. `"openai"`              |
| targetPricingId | string | No\*     | UUID of the target pricing row to map TO                       |
| targetModel     | string | No\*     | Known model name to map TO, e.g. `"gpt-4o"`                    |
| targetProvider  | string | No\*     | Known provider to map TO, e.g. `"openai"`                      |

> \*You must provide either `targetPricingId` OR both `targetModel` + `targetProvider`. One or the other, not both.

**What it returns:** Confirmation of the mapping, how many events had their costs backfilled, and the mapping ID.

**Example prompt:** "Map model gpt-4o-2024-08-06 from openai to gpt-4o from openai"

> **Safe to run again:** If you accidentally run this twice with the same inputs, nothing bad happens. It's idempotent.

***

## Diagnostic Tools (2)

### 16. get\_missing\_volume

**What it does:** Lists usage events that landed in the `MISSING_VOLUME_DATA` state. events where the agent didn't send tokens (for LLM calls) or quantity (for non-LLM). The platform stored them anyway, waiting for the volume data to arrive.

**Parameters:**

| Name      | Type   | Required | Description                                               |
| --------- | ------ | -------- | --------------------------------------------------------- |
| startDate | string | No       | Only include events with usageDate after this (ISO 8601)  |
| endDate   | string | No       | Only include events with usageDate before this (ISO 8601) |

**What it returns:** A list of incomplete events. Each row includes event ID, customer, agent, signal, and the partial payload, so you can decide what volume to fill in with `fill_volume`.

**Example prompt:** "Show me any LLM events still missing tokens" or "Which events landed without quantity this month?"

***

### 17. fill\_volume

**What it does:** Supplies the missing volume data for a `MISSING_VOLUME_DATA` event. Once filled, the platform recalculates `usageCost` and flips the event to `PROCESSED`.

**Parameters:**

| Name         | Type   | Required | Description                                        |
| ------------ | ------ | -------- | -------------------------------------------------- |
| eventId      | string | Yes      | UUID of the incomplete event                       |
| inputTokens  | number | No       | LLM input tokens (for LLM events missing this)     |
| outputTokens | number | No       | LLM output tokens (for LLM events missing this)    |
| quantity     | number | No       | Non-LLM quantity (for non-LLM events missing this) |

**What it returns:** The updated event with the calculated `usageCost`, and its new `PROCESSED` state.

**Example prompt:** "Fill in 1500 input and 400 output tokens for event abc-123"

> **Safe to run again:** If the event is already PROCESSED, running fill\_volume on it returns the existing state without re-computing.

***

## Canonical Analytics Tools (3)

These tools expose MarginFront's single source of truth for revenue, cost, and MRR. They return the same numbers the dashboard KPI tiles display.

### 18. get\_customer\_revenue

**What it does:** Returns revenue, cost, and margin for a single customer over a date range. Use this when an AI agent needs to answer "how much has this customer paid us?" or "what's our margin on this account?" without loading the full analytics view.

**Parameters:**

| Name       | Type   | Required | Description                                                          |
| ---------- | ------ | -------- | -------------------------------------------------------------------- |
| customerId | string | Yes      | Customer UUID (not the external ID. use the MarginFront internal ID) |
| startDate  | string | Yes      | Window start (ISO 8601)                                              |
| endDate    | string | Yes      | Window end (ISO 8601)                                                |

**What it returns:** Revenue (billed invoiced amount over the window), cost (sum of usageCost for attributed events), and margin = revenue − cost. Also breaks down revenue by type (usage, recurring, seat, onetime).

**Example prompt:** "What's our revenue and margin for Acme Corp this quarter?"

***

### 19. get\_cost\_metrics

**What it does:** Returns the full cost breakdown across the organization (or filtered to a single customer / agent). Includes per-day, per-agent, per-customer, per-signal, per-plan, per-model splits. Optional prior-window trend comparison.

**Parameters:**

| Name               | Type    | Required | Description                                                        |
| ------------------ | ------- | -------- | ------------------------------------------------------------------ |
| startDate          | string  | Yes      | Window start (ISO 8601)                                            |
| endDate            | string  | Yes      | Window end (ISO 8601)                                              |
| customerId         | string  | No       | Filter to a single customer UUID                                   |
| agentId            | string  | No       | Filter to a single agent UUID                                      |
| includePriorWindow | boolean | No       | Compute prior-period cost + trend delta for the same window length |

**What it returns:** Total cost, event counts, and breakdown arrays (`byAgent`, `byCustomer`, `bySignal`, `byDay`, `byPlan`, `byModel`). When `includePriorWindow` is true, also returns `prior` with the same shape for the preceding equivalent period.

**Example prompt:** "Break down our AI costs by model for last month" or "Show cost trend for Deal Ops agent week over week."

***

### 20. get\_mrr

**What it does:** Returns Monthly Recurring Revenue using one of three canonical variants. MarginFront tracks three distinct MRR computations because "what's our MRR?" has three different right answers depending on what question you're asking.

**Parameters:**

| Name           | Type   | Required | Description                                                                                                                                                     |
| -------------- | ------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| variant        | string | No       | One of: `canonical` (default; last completed month invoice total), `runRate` (last 30 days of activity projected forward), `committed` (contractual floor only) |
| customerId     | string | No       | Filter to a single customer UUID                                                                                                                                |
| subscriptionId | string | No       | Filter to a single subscription UUID                                                                                                                            |

**What it returns:** The MRR amount for the requested variant + breakdown by revenue type (usage, recurring, seat, onetime).

**Example prompt:** "What was our MRR last month?" (defaults to `canonical`) or "What's our run-rate MRR if usage keeps trending?" (`runRate`) or "What's our committed MRR floor for forecasting?" (`committed`).

***

## Pricing Setup Tools (7)

### 21. create\_pricing\_plan

**What it does:** Creates a new pricing plan for an agent. A pricing plan is a container for pricing strategies (which are the per-signal billing rules).

**Parameters:**

| Name        | Type   | Required | Description                                                         |
| ----------- | ------ | -------- | ------------------------------------------------------------------- |
| name        | string | Yes      | Display name, e.g. `"Growth Plan"`                                  |
| description | string | No       | Human-readable description of what the plan covers                  |
| agentId     | string | No       | UUID of the agent this plan is scoped to (leave empty for org-wide) |

**What it returns:** The new plan with its UUID.

**Example prompt:** "Create a Growth plan for our Outreach Writer agent"

***

### 22. list\_pricing\_plans

**What it does:** Lists all pricing plans for the organization, with optional filtering by agent.

**Parameters:**

| Name    | Type   | Required | Description                                     |
| ------- | ------ | -------- | ----------------------------------------------- |
| agentId | string | No       | Filter to plans scoped to a specific agent UUID |

**What it returns:** Array of plans with their UUID, name, description, agent binding, and an embedded list of pricing strategies attached.

***

### 23. get\_pricing\_plan

**What it does:** Returns full details on a single pricing plan, including all its pricing strategies and their rates.

**Parameters:**

| Name   | Type   | Required | Description           |
| ------ | ------ | -------- | --------------------- |
| planId | string | Yes      | Plan UUID to retrieve |

**What it returns:** Plan with name, description, agent, and every pricing strategy (chargeType, pricingModel, rates, tiers, minimum commitments).

***

### 24. create\_pricing\_strategy

**What it does:** Creates a pricing strategy on an existing plan. A strategy is the per-signal rule: "for this metric, charge this way."

**Parameters:**

| Name              | Type   | Required | Description                                                               |
| ----------------- | ------ | -------- | ------------------------------------------------------------------------- |
| planId            | string | Yes      | Parent plan UUID                                                          |
| signalId          | string | Yes      | Signal (metric) UUID this strategy applies to                             |
| chargeType        | string | Yes      | One of: `usage`, `recurring`, `seat_based`, `onetime`                     |
| pricingModel      | string | Yes      | One of: `flat`, `tiered`, `volume`, `credit_pool` (only applies to usage) |
| rate              | number | Yes      | Per-unit rate in dollars (for flat + recurring + seat\_based + onetime)   |
| tiers             | array  | No       | Tier config for tiered/volume (array of `{upTo, rate}` objects)           |
| minimumCommitment | number | No       | Minimum number of units/seats committed (floor)                           |

**What it returns:** The new strategy's UUID and validated config.

***

### 25. list\_pricing\_strategies

**What it does:** Lists all pricing strategies on a plan.

**Parameters:**

| Name   | Type   | Required | Description                      |
| ------ | ------ | -------- | -------------------------------- |
| planId | string | Yes      | Plan UUID to list strategies for |

**What it returns:** Array of strategies with their config.

***

### 26. link\_plan\_to\_agent

**What it does:** Attaches an existing pricing plan to an agent. An agent can be attached to multiple plans (each pricing different customer tiers).

**Parameters:**

| Name    | Type   | Required | Description             |
| ------- | ------ | -------- | ----------------------- |
| planId  | string | Yes      | Plan UUID to attach     |
| agentId | string | Yes      | Agent UUID to attach to |

**What it returns:** The junction row confirming the link.

***

### 27. create\_subscription

**What it does:** Creates a subscription tying a customer to an agent + plan. Once created, events fired for this (customer, agent, signal) combination bill against this subscription's pricing strategies.

**Parameters:**

| Name         | Type   | Required | Description                                            |
| ------------ | ------ | -------- | ------------------------------------------------------ |
| name         | string | Yes      | Display name (e.g. `"Acme Corp: Growth Plan"`)         |
| customerId   | string | Yes      | Customer UUID                                          |
| agentId      | string | Yes      | Agent UUID                                             |
| planId       | string | Yes      | Pricing plan UUID                                      |
| billingCycle | string | Yes      | One of: `monthly`, `yearly`                            |
| billingModel | string | Yes      | One of: `usage`, `recurring`, `seat_based`, `hybrid`   |
| startDate    | string | No       | When the subscription becomes active (defaults to now) |

**What it returns:** New subscription with its UUID, scoped to the (customer, agent, plan) triple.

**Example prompt:** "Create a Growth Plan subscription for Acme Corp on the Outreach Writer agent, billed monthly, usage model."

***

## Portal Sessions (4)

These four tools let an AI assistant mint and manage one-time portal links — the URLs you send to your customers so they can see their own billing on a MarginFront-hosted page. See the [Portal Sessions API reference](/api-reference/portal-sessions) for the full plain-English explanation.

***

### 28. create\_portal\_session

**What it does:** Mints a one-time portal link for a customer. The URL is good for one hour and stops working the moment the customer opens it.

**Parameters:**

| Name               | Type      | Required         | Description                                                                                                              |
| ------------------ | --------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------ |
| customerId         | string    | One of these two | MarginFront's internal customer UUID                                                                                     |
| customerExternalId | string    | One of these two | Your system's customer ID                                                                                                |
| returnUrl          | string    | No               | Stored on the session for your records (the portal does NOT auto-redirect; this is informational)                        |
| features           | string\[] | No               | Subset of `["invoices", "subscriptions", "usage", "profile"]`. v1 always renders all four, so this is informational too. |

**What it returns:** The session ID, the URL to send your customer, the token, customer details, and the expiry timestamp.

**Example prompt:** "Send acme-001 a portal link"

***

### 29. get\_portal\_session

**What it does:** Looks up one portal session by ID. Use this to check whether a link has been opened or has expired. Does NOT return the `token` or `url` — those are only shown at creation.

**Parameters:**

| Name      | Type   | Required | Description                                                  |
| --------- | ------ | -------- | ------------------------------------------------------------ |
| sessionId | string | Yes      | The portal session ID returned from `create_portal_session`. |

**What it returns:** Session metadata — customer, expiry, redeem status.

**Example prompt:** "Has Acme opened the portal link I sent yesterday?"

***

### 30. list\_portal\_sessions

**What it does:** Lists portal sessions your organization has created. Useful for audit or support. Tokens are intentionally omitted from the response.

**Parameters:**

| Name           | Type    | Required | Default | Description                                             |
| -------------- | ------- | -------- | ------- | ------------------------------------------------------- |
| customerId     | string  | No       | --      | Filter to one customer's sessions (internal UUID).      |
| limit          | number  | No       | 10      | Max results (1-100).                                    |
| includeExpired | boolean | No       | false   | Set `true` to include expired or already-used sessions. |

**What it returns:** A list of session metadata records.

**Example prompt:** "Show me all portal links we sent Acme this month"

***

### 31. revoke\_portal\_session

**What it does:** Immediately invalidates a portal session. Use this if you sent a link to the wrong customer or need to cut access early. Hard delete — the session row is removed.

**Parameters:**

| Name      | Type   | Required | Description                      |
| --------- | ------ | -------- | -------------------------------- |
| sessionId | string | Yes      | The portal session ID to revoke. |

**What it returns:** A confirmation that the session was revoked.

**Example prompt:** "Cancel the portal link I sent Acme yesterday"

***

## Catalog Discovery (1)

This tool lets the AI look up canonical model and provider names from MarginFront's global service pricing catalog before firing usage events. Use it to avoid the "guess and check until cost resolves" cycle.

***

### 32. list\_catalog\_services

**What it does:** Browses the global service catalog — every model and non-LLM service MarginFront can calculate cost for. Filter by provider, service type, or free-text search to find the canonical `model` + `modelProvider` names to send with `record_usage` so cost auto-resolves on ingest. The catalog is read-only and global (not org-scoped).

**Parameters:**

| Name        | Type    | Required | Default | Description                                                                                        |
| ----------- | ------- | -------- | ------- | -------------------------------------------------------------------------------------------------- |
| provider    | string  | No       | --      | Lowercase provider name to filter by, e.g. `"openai"`, `"anthropic"`, `"google"`, `"twilio"`.      |
| serviceType | string  | No       | --      | Category, e.g. `"LLM"`, `"Embeddings"`, `"Compute"`, `"Web Search"`, `"SMS"`, `"Vector Database"`. |
| isApi       | boolean | No       | --      | `true` to return only non-LLM API entries, `false` for LLM-only. Omit to return both.              |
| search      | string  | No       | --      | Case-insensitive search across `canonicalName` and `displayName`.                                  |
| page        | number  | No       | 1       | 1-based page number.                                                                               |
| limit       | number  | No       | 50      | Results per page (1-100).                                                                          |

**What it returns:** Paginated catalog entries. Each entry includes `canonicalName` (what to send as `model`), `provider` (what to send as `modelProvider`), `serviceType`, per-unit `inputCost` / `outputCost`, `costUnit`, and `contextWindow` for LLMs.

**Example prompts:**

* "What canonical name should I use for GPT-4o when recording usage?"
* "List every Google service in the MarginFront catalog."
* "Find the catalog entry for Twilio SMS so I can record an event."

> **Tip:** Pair this with `record_usage` — look up the canonical name first, then fire the event using that exact name and provider. Cost resolves automatically without a `NEEDS_COST_BACKFILL` round trip. See the [Services Catalog reference](/api-reference/services) for the full field list.

***

## Spend Controls (4)

These tools read and manage **spend caps**: the limits your company sets on its own AI coding spend. They're the same caps the dashboard's Money tab shows. See the [Spend Controls API reference](/api-reference/spend-controls) for what scopes, modes, and the ceiling rule mean.

Reading works with any key. The three write tools need an API key that belongs to an **owner or finance** user; any other key gets a clear 403 explaining which role is required.

***

### 33. get\_spend\_controls

**What it does:** Reads everything about your spend controls in one call: the cap policies (each with its plain sentence), spend-so-far for a period, and coverage ("N of M developers armed").

**Parameters:**

| Name               | Type   | Required | Default | Description                                                                         |
| ------------------ | ------ | -------- | ------- | ----------------------------------------------------------------------------------- |
| period             | string | No       | month   | Which window the spend total covers: `"day"`, `"week"`, or `"month"`                |
| customerExternalId | string | No       | --      | A developer's `customerExternalId` (their email) to also get that developer's spend |

**What it returns:** The caps (each with its `sentence`), the spend read-back for the period, and the coverage counts. `spentUsd` is `null` when there's no priced usage yet: that's honest absence, not \$0.

**Example prompt:** "What are our spend caps and how much have we used this week?"

***

### 34. create\_spend\_cap

**What it does:** Creates a spend cap covering all AI tools. A developer cap can never be set higher than the whole-team ceiling; the server rejects the attempt with a plain message.

**Requires:** an owner or finance key.

**Parameters:**

| Name            | Type      | Required | Description                                                                                           |
| --------------- | --------- | -------- | ----------------------------------------------------------------------------------------------------- |
| scope           | string    | Yes      | `"org"` (a whole-team ceiling) or `"dev"` (one developer)                                             |
| scopeValue      | string    | For dev  | The developer's `customerExternalId` (their email). Omit for `"org"`.                                 |
| amountUsd       | number    | Yes      | Cap amount in US dollars, e.g. `200`                                                                  |
| period          | string    | Yes      | Reset cadence: `"day"`, `"week"`, or `"month"`. Windows roll at UTC.                                  |
| mode            | string    | Yes      | `"track"` (watch and alert, block nothing) or `"enforce"` (armed machines stop tool calls at the cap) |
| coolOffHours    | number    | No       | Hours to wait after a cap trips before the device re-checks                                           |
| alertThresholds | number\[] | No       | Alert ladder as whole percents of the cap. Default `[50, 80, 100]`.                                   |

**What it returns:** The response leads with the new cap's plain sentence (e.g. `Cap created: Stop AI spend at $200 for alice@acme.com per week`), followed by the full cap details.

**Example prompt:** "Cap Alice's AI coding spend at \$200 a week and enforce it"

***

### 35. update\_spend\_cap

**What it does:** Adjusts an existing cap's amount, period, mode, cool-off, or alert ladder. A cap's identity (who it governs) can't be changed: delete and recreate instead.

**Requires:** an owner or finance key.

**Parameters:**

| Name            | Type      | Required | Description                                    |
| --------------- | --------- | -------- | ---------------------------------------------- |
| id              | string    | Yes      | The cap's ID (from `get_spend_controls`)       |
| amountUsd       | number    | No       | New cap amount in US dollars                   |
| period          | string    | No       | New reset cadence                              |
| mode            | string    | No       | New enforcement posture                        |
| coolOffHours    | number    | No       | New cool-off window in hours. Send 0 to clear. |
| alertThresholds | number\[] | No       | New alert ladder as whole percents of the cap  |

**What it returns:** The response leads with the updated cap's plain sentence, followed by the full cap details.

**Example prompt:** "Raise the team AI spend cap to \$8,000"

***

### 36. delete\_spend\_cap

**What it does:** Deletes a cap. Deleting a whole-team ceiling is refused if it would leave a developer cap with nothing above it (the server says so plainly).

**Requires:** an owner or finance key.

**Parameters:**

| Name | Type   | Required | Description                              |
| ---- | ------ | -------- | ---------------------------------------- |
| id   | string | Yes      | The cap's ID (from `get_spend_controls`) |

**What it returns:** The response leads with the removed cap's plain sentence so you can confirm what was deleted.

**Example prompt:** "Remove the spend cap on [alice@acme.com](mailto:alice@acme.com)"
