English
English
English
English
Two endpoints, meant to be used together. You list the metrics in your environment to find the one you want and learn what its numbers mean, then you ask for what every agent scored on it between two dates.
That pairing is the intended flow — the ids you pass to metric-scores come from metrics, and so does the answer to "is this figure in euros or in cents".
GET /integrations/api/v1/metricsNo parameters. You get every metric in your environment, in the same order the Metrics page in the admin shows them.
{
"metrics": [
{
"id": 1,
"name": "Sales",
"unit": null,
"value_unit": "raw",
"display_mode": "number",
"lower_is_better": false,
"can_rank": true
},
{
"id": 2,
"name": "Contract value",
"unit": "euro",
"value_unit": "euros",
"display_mode": "currency",
"lower_is_better": false,
"can_rank": true
}
]
}| Field | Meaning |
|---|---|
id | The metric_id you pass to metric-scores and to the goal endpoints. |
name | The metric's name as it appears throughout SalesDash. |
unit | The label a metric is shown with in the interface — uur, euro, sales. Free text, chosen in the admin, and null if nobody set one. Do not do arithmetic based on this. |
value_unit | The unit the value numbers are actually in. This is the one to trust — see below. |
display_mode | How SalesDash formats the metric: number, percentage, currency, duration, score, ratio or raw. null means nobody has chosen one yet. |
lower_is_better | true when a smaller number is a better result — average handling time, cost per lead. |
can_rank | Whether the metric can be scored per agent. false means it only exists at organisation level, and metric-scores will refuse it. |
unit is a label, value_unit is the unit These two disagree more often than you would expect, and it is deliberate. unit is the word your colleagues chose to see next to the figure; value_unit is what the raw number in the API is measured in.
value_unit | The value you get back |
|---|---|
euros | Euros, already converted — 181942 is €181.942,00. |
seconds | Seconds, even when the metric is labelled uur. Divide by 3600 yourself for hours. |
fraction | A fraction, not a percentage — a 42% conversion rate arrives as 0.42. |
raw | A plain count or score, in no particular unit. |
null | SalesDash is not claiming a unit. Most ratio metrics are null, because a ratio's unit comes from the two metrics it divides rather than from anything on the metric itself — a ratio formatted as a duration (average handling time, say) is the exception and reports seconds. For a null, read value_formatted instead of doing arithmetic, or ask whoever configured the ratio. |
Every response that carries a number also carries its value_unit, so you never have to remember which metric was which.
Occasionally a metric's configuration is broken — a ratio whose underlying metric was deleted, or a metric nobody finished setting up. Listing everything else is more useful than failing outright, so such a metric is still listed, marked:
{
"id": 14,
"name": "Cost per booked demo",
"unit": null,
"value_unit": null,
"display_mode": null,
"lower_is_better": false,
"can_rank": null,
"unavailable": true
}can_rank: null is not the same as false. false says this metric is organisation-level; null says nobody could read this metric, so nobody knows. Skip a metric with unavailable, and fix it in the admin — asking for its scores gives you a 422.
Two things have to be true before a metric can be scored
can_rank must be true and display_mode must not be null. They are separate because they are separate problems: one is a metric that was never meant to be ranked per person, the other is a metric that just needs a display mode set. Check both before you call metric-scores.
GET /integrations/api/v1/metric-scores?metric_id=2&start_date=2026-08-01&end_date=2026-08-25| Parameter | Required | Notes |
|---|---|---|
metric_id | yes | From the list above. |
start_date | yes | YYYY-MM-DD. |
end_date | yes | YYYY-MM-DD, on or after start_date. |
Both dates are inclusive — the example above covers all of 25 August. The format is strict on purpose: a loose 2026 would otherwise be read as a time on today's date and you would get a one-minute window back without being told.
{
"metric": {
"id": 2,
"name": "Contract value",
"unit": "euro",
"value_unit": "euros",
"display_mode": "currency",
"lower_is_better": false
},
"date_range": {
"start": "2026-08-01",
"end": "2026-08-25"
},
"scores": [
{
"rank": 1,
"agent_id": 22,
"name": "Tamara Wilson",
"team_id": 2,
"value": 181942,
"value_formatted": "€181.942,00"
},
{
"rank": 2,
"agent_id": 7,
"name": "Lily Davis",
"team_id": 2,
"value": 104930,
"value_formatted": "€104.930,00"
}
]
}value is the number to calculate with, in value_unit. value_formatted is the same number written the way SalesDash writes it on a dashboard — use it when you are putting the figure straight in front of a person, and you will match what they see elsewhere in SalesDash.
Every currently-active agent, and only those. Someone who left is not in the list even if they sold something inside the window. Everyone still active is, including those who scored nothing — they come back with 0. There is no page size and no top-N: you asked for the metric's scores, so you get the whole team.
Ranks are consecutive. Two agents on the same value get two different ranks, in no meaningful order between them. If ties matter to you, group on value yourself.
A zero can mean "nothing happened", and on a lower-is-better metric that wins
An active agent with no activity in the window scores 0. On a metric where lower is better — average handling time, cost per lead — that 0 takes rank 1, ahead of everyone who did the work.
This is how ranking behaves everywhere in SalesDash, dashboards included, so the API is not doing anything unusual here. But if you are publishing a lower-is-better ranking somewhere people will read it, drop or flag the zero-value rows yourself first.
A 422 on this endpoint is almost always about the metric rather than the request:
can_rank: false) — there is no per-agent number to give you.unavailable.Filtering your list on can_rank: true and a non-null display_mode avoids all three.