> ## 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.

# Services Catalog

> List the canonical model + provider names MarginFront recognizes for cost calculation

# Services Catalog

The **services catalog** is MarginFront's record of every model and non-LLM service it can calculate cost for. When you fire a usage event with `model` and `modelProvider`, MarginFront looks up the catalog entry that matches and uses its rate to compute cost.

> **Use this endpoint to discover canonical names BEFORE firing events.** If your service is in the catalog, send `model: '<canonicalName>'` and `modelProvider: '<provider>'` and cost auto-resolves on ingest. If not, the event still lands but cost stays null (`NEEDS_COST_BACKFILL`). The [`POST /v1/events/map-model`](./usage-events) endpoint can then redirect an unknown name to an existing catalog entry. It cannot create new rates.

The catalog is global. It is not org-scoped. Every authenticated caller sees the same entries.

The catalog is read-only via the API. Entries are managed by an internal sync script that pulls from OpenRouter, LiteLLM, and a hand-curated list of non-LLM services.

***

## List services

Returns paginated catalog entries. Filter by provider, service type, LLM-vs-non-LLM, or full-text search.

**Method & URL:**

```
GET /v1/services
```

**Headers:**

```
x-api-key: mf_sk_...
```

**Query parameters:**

| Field         | Type    | Description                                                                                           |
| ------------- | ------- | ----------------------------------------------------------------------------------------------------- |
| `provider`    | string  | Filter by lowercase provider name (e.g. `openai`, `google`, `anthropic`, `twilio`). Case-insensitive. |
| `serviceType` | string  | Filter by category (e.g. `LLM`, `Geocoding`, `Compute`, `Web Search`, `Vector Database`, `SMS`).      |
| `isApi`       | boolean | Filter to non-LLM API entries only (`true`) or LLM-only (`false`). Omit for both.                     |
| `search`      | string  | Case-insensitive search across `canonicalName` and `displayName`.                                     |
| `page`        | integer | 1-based page number. Defaults to `1`.                                                                 |
| `limit`       | integer | Page size, 1 to 100. Defaults to `50`.                                                                |

**Example: list every Google service**

```bash theme={null}
curl "https://api.marginfront.com/v1/services?provider=google" \
  -H "x-api-key: $MF_API_SECRET_KEY"
```

**Example: find every non-LLM API in the Compute category**

```bash theme={null}
curl "https://api.marginfront.com/v1/services?serviceType=Compute&isApi=true" \
  -H "x-api-key: $MF_API_SECRET_KEY"
```

**Example: search by name**

```bash theme={null}
curl "https://api.marginfront.com/v1/services?search=cloud-run" \
  -H "x-api-key: $MF_API_SECRET_KEY"
```

**Response:**

```json theme={null}
{
  "data": [
    {
      "id": "df3c1acd-fdc4-4f6c-9d84-99697ffb76a2",
      "externalId": "api/cloud-run-cpu-second",
      "canonicalName": "cloud-run-cpu-second",
      "displayName": "Google Cloud Run vCPU",
      "provider": "google",
      "serviceType": "Compute",
      "inputCost": "0.024",
      "outputCost": null,
      "costUnit": "1K vCPU-seconds",
      "contextWindow": null,
      "source": "curated",
      "isApi": true,
      "isActive": true
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 50,
    "total": 9,
    "totalPages": 1
  }
}
```

**Field reference:**

| Field           | Description                                                                                                                                                                                  |
| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`            | UUID of the catalog entry. Pass to `GET /v1/services/:id` for the full record.                                                                                                               |
| `externalId`    | Source-specific identifier (e.g. `openai/gpt-4o`, `api/cloud-run-cpu-second`, `litellm/anthropic/claude-sonnet-4-20250514`). Useful for tracing where the entry came from.                   |
| `canonicalName` | The lowercase name to send as `model` in your usage events. This is what the cost lookup matches against.                                                                                    |
| `displayName`   | Human-readable name for UI surfaces. Not used for matching.                                                                                                                                  |
| `provider`      | Lowercase provider name to send as `modelProvider`.                                                                                                                                          |
| `serviceType`   | Category label (e.g. `LLM`, `Geocoding`, `Compute`).                                                                                                                                         |
| `inputCost`     | Per-unit cost on the input side. Returned as a string-formatted decimal so JS Number precision can't truncate fractional cents. `null` when the service does not publish an input-side rate. |
| `outputCost`    | Per-unit cost on the output side (LLM output tokens). `null` for non-LLM services.                                                                                                           |
| `costUnit`      | Unit the rates are denominated in (e.g. `1M tokens`, `1K requests`, `1K vCPU-seconds`).                                                                                                      |
| `contextWindow` | LLM context window size in tokens. `null` for non-LLM.                                                                                                                                       |
| `source`        | Where the entry came from: `openrouter`, `litellm`, or `curated`.                                                                                                                            |
| `isApi`         | `true` for non-LLM API entries (Cloud Run, Twilio, Google Places, etc.). `false` for LLM models.                                                                                             |
| `isActive`      | `false` if the entry has been deactivated. The list endpoint filters these out by default.                                                                                                   |

***

## Get a single service

```
GET /v1/services/:serviceId
```

Returns the full record for one catalog entry by its UUID. Same shape as one row in the list response.

**Example:**

```bash theme={null}
curl "https://api.marginfront.com/v1/services/df3c1acd-fdc4-4f6c-9d84-99697ffb76a2" \
  -H "x-api-key: $MF_API_SECRET_KEY"
```

**Errors:**

| Code  | Cause                                                     |
| ----- | --------------------------------------------------------- |
| `404` | The catalog entry does not exist or has been deactivated. |
| `401` | Missing or invalid API key.                               |

***

## Using the catalog in your integration

Pattern that avoids the `NEEDS_COST_BACKFILL` cycle:

1. Before adding a new service to your code, call `GET /v1/services?search=<your-service-name>` (or `?provider=<provider>`).
2. If the response has a matching entry, use its `canonicalName` as `model` and its `provider` as `modelProvider`.
3. Fire usage events. Cost auto-resolves on ingest.

If no matching entry exists, two paths:

* **Map an existing entry.** If your service is similar to one in the catalog (e.g. a Google Places sub-endpoint mapping to the bundled `google-places` entry), use `POST /v1/events/map-model` to redirect your unknown name to the existing entry. Cost backfills retroactively for events already saved with `cost = null`.
* **Catalog gap.** If nothing in the catalog represents your service accurately, fire events anyway. Events are saved with `cost = null` and `eventStatus = NEEDS_COST_BACKFILL`. Email `team@marginfront.com` with the service name and your provider's pricing page; we'll add it to the catalog.

***

## Programmatic access

The same catalog is available via:

* **Node SDK**: `client.services.list(...)` and `client.services.get(id)`. Documented in the [SDK reference](/sdk/types-reference).
* **MCP**: the `list_catalog_services` tool. Documented in the [MCP tools reference](/mcp/tools).
