# Upsert Metric — Eppo

> Create or update a metric in Eppo. Omit metricId to create a new metric; provide metricId to update an existing one. Use this when the user wants to define a new KPI/metric or update the definition of an existing metric. Use List Metrics…

- Key: `eppo-upsert-metric`
- Type: Action (Write)
- Version: 0.0.2
- App: Eppo (`eppo`) — https://pipedream.com/apps/eppo.md
- This page (HTML): https://pipedream.com/apps/eppo/actions/upsert-metric
- Hints: open-world
- Source: https://github.com/PipedreamHQ/pipedream/blob/master/components/eppo/actions/upsert-metric/upsert-metric.mjs

## Description

Create or update a metric in Eppo. Omit `metricId` to create a new metric; provide `metricId` to update an existing one. Use this when the user wants to define a new KPI/metric or update the definition of an existing metric. Use **List Metrics** to find the numeric `metricId` for an update and to look up the `entityId` from existing metrics. `entityId` is required — find it in the `entity_id` field of any existing metric returned by **List Metrics**. The `minimumDetectableEffect` is a decimal representing the smallest meaningful relative change (e.g. `0.05` for 5%). Provide exactly one metric definition: `numerator` (standard or ratio metrics), `percentile`, or `funnelAggregation`. For ratio metrics, also provide `denominator`. Set `denominator` to the JSON literal `null` for non-ratio metrics. IMPORTANT: `metric_event_measure_id` is a data-source ID from your Eppo data pipeline configuration — obtain it from your Eppo workspace's data integration settings. It is NOT the same as a metric ID or aggregation ID. The Eppo API requires the full numerator/percentile/funnel definition even for metadata-only updates. [See the documentation - Create Metric](https://eppo.cloud/api/docs#/Metrics/createMetric) and [See the documentation - Update Metric](https://eppo.cloud/api/docs#/Metrics/updateMetric)

## Props

| Prop | Type | Required | Description |
|---|---|---|---|
| `metricId` | `integer` | No | The numeric ID of an existing metric to update. Omit this field to create a new metric. Use List Metrics to discover metric IDs. |
| `entityId` | `integer` | Yes | The numeric entity type ID this metric measures (e.g. user, session). Use List Metrics to find the entity_id from any existing metric — all metrics in the same workspace typically share the same entity ID. |
| `name` | `string` | Yes | The display name for the metric. |
| `description` | `string` | Yes | A description of what this metric measures. |
| `type` | `string` | No | The type of metric. |
| `displayStyle` | `string` | Yes | Whether to format the metric as a percent in the Eppo UI. Valid values: decimal or percent. |
| `minimumDetectableEffect` | `string` | Yes | The smallest relative change considered meaningful, as a decimal. Example: 0.05 for 5%. Used to calculate required sample sizes. |
| `numerator` | `string` | No | JSON object for the numerator aggregation. Required for standard and ratio metrics; omit or set to null for funnel and percentile metrics. Requires metric_event_measure_id and operation. Valid operations: count, sum, countDistinct, timeTo, retention, conversion, threshold, countDistinctValue, lastValue, firstValue. filters is an array of objects with metric_event_dimension_id, operation (EQUALS or DOES_NOT_EQUAL), and values. Set retention_threshold_days when operation is retention; set conversion_threshold_days when operation is conversion; set threshold_metric_settings when operation is threshold. Example: {"metric_event_measure_id": 123, "operation": "count", "filters": []}. |
| `denominator` | `string` | No | JSON object for the denominator aggregation on ratio metrics. Use the same shape as numerator. Set to the JSON literal null for non-ratio metrics. Example: {"metric_event_measure_id": 456, "operation": "count", "filters": []}. |
| `percentile` | `string` | No | JSON object for percentile metrics. Requires metric_event_measure_id, filters (array), and percentile_value (0.01–0.99). Example: {"metric_event_measure_id": 123, "filters": [], "percentile_value": 0.95}. |
| `funnelAggregation` | `string` | No | JSON object for funnel metrics. Requires funnel_steps, an ordered array of objects each with metric_event_measure_id. Optional fields: conversion_time_from (experimentAssignment or firstEvent), conversion_time_value, and conversion_time_units (days, hours, minutes, or seconds). Example: {"funnel_steps": [{"metric_event_measure_id": 123}, {"metric_event_measure_id": 456}], "conversion_time_value": 7, "conversion_time_units": "days"}. |
| `desiredChange` | `string` | No | The desired direction of change. Use increase if higher values are better, or decrease if lower values are better. If omitted, the metric inherits the desired change from the underlying fact. |
| `teamId` | `integer` | No | The numeric ID of the team to assign this metric to. Omit to leave the team assignment unchanged on update. |

## Run it

**MCP**

```ts
import { Client } from "@modelcontextprotocol/sdk/client/index.js"
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"
import { PipedreamClient } from "@pipedream/sdk"

const pd = new PipedreamClient({
  projectId: process.env.PIPEDREAM_PROJECT_ID!,
  clientId: process.env.PIPEDREAM_CLIENT_ID!,
  clientSecret: process.env.PIPEDREAM_CLIENT_SECRET!,
  projectEnvironment: "production",
})

const accessToken = await pd.rawAccessToken

const transport = new StreamableHTTPClientTransport(
  new URL("https://remote.mcp.pipedream.net/v3"),
  {
    requestInit: {
      headers: {
        Authorization: `Bearer ${accessToken}`,
        "x-pd-project-id": process.env.PIPEDREAM_PROJECT_ID!,
        "x-pd-environment": "production",
        "x-pd-external-user-id": "{external_user_id}", // any stable ID for this user in your system
        "x-pd-app-slug": "eppo",
      },
    },
  },
)

const mcp = new Client({ name: "my-agent", version: "1.0.0" })
await mcp.connect(transport)

const { tools } = await mcp.listTools()

// listTools() hands your model this tool's input schema, so it can
// fill the arguments itself:
const result = await mcp.callTool({
  name: "eppo-upsert-metric",
  arguments: {
    metricId: 10,
    entityId: 10,
  },
})
```

**TypeScript**

```ts
import { PipedreamClient } from "@pipedream/sdk"

const pd = new PipedreamClient({
  projectId: process.env.PIPEDREAM_PROJECT_ID!,
  clientId: process.env.PIPEDREAM_CLIENT_ID!,
  clientSecret: process.env.PIPEDREAM_CLIENT_SECRET!,
  projectEnvironment: "production",
})

const result = await pd.actions.run({
  id: "eppo-upsert-metric",
  externalUserId: "{external_user_id}", // any stable ID for this user in your system
  configuredProps: {
    eppo: { authProvisionId: "apn_xxxxxxx" },
    metricId: 10,
    entityId: 10,
  },
})

console.log(result)
```

**cURL**

```bash
curl -X POST https://api.pipedream.com/v1/connect/{project_id}/actions/run \
  -H "Content-Type: application/json" \
  -H "X-PD-Environment: production" \
  -H "Authorization: Bearer {access_token}" \
  -d '{
    "external_user_id": "{external_user_id}",
    "id": "eppo-upsert-metric",
    "configured_props": {
      "eppo": { "authProvisionId": "apn_xxxxxxx" },
      "metricId": 10,
      "entityId": 10
    }
  }'
```

---

- App: https://pipedream.com/apps/eppo.md · All apps: https://pipedream.com/apps
