# Create or Update Metric

Creates a metric for widgets, or updates the fields sent for an existing metric. Omitted fields keep their current values, so repeating the same request does not change the metric. Changing between the string format and a numeric format clears the latest value. Shares the metric account allowance of 300 requests per minute and is not a billable metric update.

```http
PUT https://activitysmith.com/api/metrics/{key}
```

## Authentication

Use your [API key](/docs/api-keys) in the request header.

```http
Authorization: Bearer $YOUR_API_KEY
```

## Parameters

### key

path parameter. Required.

Metric key. Lowercase letters, numbers, dots, underscores, and dashes are allowed.

Type: string

**Min Length**: `1`; **Max Length**: `64`; **Pattern**: `^[a-z0-9][a-z0-9_.-]{0,63}$`

## Request examples

```bash cURL
curl -X PUT "https://activitysmith.com/api/metrics/mrr" \
  -H "Authorization: Bearer $YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "label": "MRR",
    "format": "currency",
    "currency_code": "USD"
  }'
```

## Body

Content type: `application/json`

### Schema: MetricUpsertRequest

Metric definition. Omitted fields keep their current values, or use defaults for a new metric: a label made from the key and the number format.

| Field | Type | Presence | Description | Constraints |
| --- | --- | --- | --- | --- |
| `label` | string | Optional | Name shown on the widget. | **Min Length**: `1`; **Max Length**: `80` |
| `format` | string | Optional | How widgets display the value: number (1,234), currency (requires currency_code), percent (send 99.9 to show 99.9%), unit (a number with a unit suffix, such as 120 ms), or string (text up to 64 characters). Defaults to number for a new metric. | **Enum**: `["number","currency","percent","unit","string"]` |
| `currency_code` | string | Optional | 3-letter ISO 4217 currency code, such as USD. Required for the currency format. | **Pattern**: `^[A-Za-z]{3}$` |
| `unit` | string | Optional | Unit suffix for the unit format, such as ms or GB. | **Max Length**: `16` |
| `unit_spacing` | string | Optional | For the unit format: none shows 120ms, space shows 120 ms. | **Enum**: `["none","space"]` |

**Additional Properties**: `false`

```json
{
  "label": "MRR",
  "format": "currency",
  "currency_code": "USD"
}
```

## Responses

### 200

Metric updated

Content type: `application/json`

### Schema: MetricResponse

| Field | Type | Presence | Description | Constraints |
| --- | --- | --- | --- | --- |
| `metric` | `Metric` | Required |  |  |

**Additional Properties**: `false`

**updated**

```json
{
  "metric": {
    "public_id": "x8Kq2mVn4pLr7sTw9yZa",
    "key": "mrr",
    "label": "MRR",
    "format": "currency",
    "currency_code": "USD",
    "unit": null,
    "unit_spacing": "none",
    "latest_value": null,
    "latest_value_at": null,
    "created_at": "2026-10-26T09:00:00.000Z",
    "updated_at": "2026-10-26T09:00:00.000Z"
  }
}
```

### 201

Metric created

Content type: `application/json`

Schema: [MetricResponse](#schema-metricresponse)

**created**

```json
{
  "metric": {
    "public_id": "x8Kq2mVn4pLr7sTw9yZa",
    "key": "mrr",
    "label": "MRR",
    "format": "currency",
    "currency_code": "USD",
    "unit": null,
    "unit_spacing": "none",
    "latest_value": null,
    "latest_value_at": null,
    "created_at": "2026-10-26T09:00:00.000Z",
    "updated_at": "2026-10-26T09:00:00.000Z"
  }
}
```

### 400

Bad request (invalid key or definition)

Content type: `application/json`

### Schema: MetricError

| Field | Type | Presence | Description | Constraints |
| --- | --- | --- | --- | --- |
| `error` | string | Required |  |  |
| `message` | string | Optional |  |  |

**Additional Properties**: `true`

**missing currency**

```json
{
  "error": "currency_code is required for currency metrics"
}
```

### 409

Metric limit reached

Content type: `application/json`

Schema: [MetricError](#schema-metricerror)

**limit reached**

```json
{
  "error": "Metric limit reached",
  "code": "metric_limit_reached",
  "message": "This account already has 100 metrics. Delete unused metrics before adding more."
}
```

### 429

Rate limit exceeded

Content type: `application/json`

### Schema: RateLimitError

| Field | Type | Presence | Description | Constraints |
| --- | --- | --- | --- | --- |
| `code` | string | Optional |  | **Enum**: `["rate_limited"]` |
| `error` | string | Required |  |  |
| `message` | string | Required |  |  |

**Additional Properties**: `false`

**rate limited**

```json
{
  "error": "Rate limit exceeded",
  "message": "Too many requests, please try again later."
}
```

[Download the OpenAPI specification](/openapi.json)
