The ingest endpoint writes values to one or many metrics in a single request. It’s the right tool for a scheduled job that computes a whole scorecard. You need an API key with the metrics:write scope — see Create API keys.
Request
POST https://api.onclarion.com/v1/companies/:companyId/metrics/ingest
curl -X POST "https://api.onclarion.com/v1/companies/$COMPANY_ID/metrics/ingest" \
-H "x-api-key: clr_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"entries": [
{ "metric": "Weekly Revenue", "value": 89306 },
{ "metric": "Purchases", "value": 118, "weekOf": "2026-06-29" }
]
}'
Body
| Field | Type | Notes |
|---|---|---|
entries | array | Required and non-empty, or the request fails with 400. |
teamId | string or null | Optional default team for every entry that doesn’t set its own. |
Each entry
| Field | Type | Notes |
|---|---|---|
value | number | Required. Must be a JSON number, not a string. |
metric | string | Metric name, matched case-insensitively. |
metricId | string | Exact metric. Takes precedence over metric. |
teamId | string or null | Narrows a name to one team. null means the company-wide metric with no team. |
weekOf | ISO date | Backfills a specific period. Snaps to that day (UTC), that week’s Monday, or the 1st of that month, depending on the metric’s frequency. |
notes | string | Optional note stored with the value. |
Without weekOf, the value lands on the metric’s current period. Sending the same metric and period again updates the value instead of adding another, so the job is safe to re-run.
How a name finds its metric
Metric names aren’t unique — several teams can each have a “Revenue”, plus a company-wide one. A name is matched against the company’s non-archived metrics, narrowed by teamId if given:
- exactly one match: the value is written;
- no match:
unknown_metric; - more than one:
ambiguous_metric, and nothing is written for that entry. The result lists the candidates.
To skip matching entirely, send metricId. Every successful entry returns the metricId it landed on, so a name-based job can switch to ids after its first run.
Response
201 Created, with a result for every entry. One bad entry doesn’t fail the rest.
{
"processed": 1,
"skipped": [
{ "metric": "No Such Metric", "status": "unknown_metric" }
],
"results": [
{ "metric": "Pipeline Value", "status": "ok", "metricId": "cmmw8jsnm005vnutvzy33fdfw" },
{ "metric": "No Such Metric", "status": "unknown_metric" }
]
}
results covers every entry in order. skipped repeats the ones that didn’t write. An ambiguous entry looks like this:
{
"metric": "Active Accounts",
"status": "ambiguous_metric",
"candidates": [
{ "metricId": "clx1...", "teamId": "clt1...", "teamName": "Sales" },
{ "metricId": "clx3...", "teamId": null, "teamName": null }
]
}
status | Meaning |
|---|---|
ok | Written. metricId names the metric. |
unknown_metric | No live metric with that name or id in this company. |
ambiguous_metric | The name matched several metrics. Nothing written. |
invalid_value | value isn’t a number, weekOf can’t be parsed, or the entry names no metric. |
metric echoes what you sent: the name, the id, or (unidentified) if you sent neither.
Check the statuses, not only the HTTP code. A 201 with "processed": 0 means nothing was written. Have your job alert on any non-ok status.
Each call fires the metric.ingested webhook with the counts of processed and skipped entries.
Alternatives
For one number from a tool that can’t send headers, use a push URL. For hand entry, see Record metric values.