Analytics
Reference for GET /v1/analytics: analysis volume, share of valid, invalid and review results, p50 and p95 times, credits and most frequent rejection reasons, grouped by type, day, template or metadata, as JSON or CSV.
GET /v1/analytics summarises the analyses of a period: how many there were, what share came out valid, invalid or
for review, how long they took, how many credits they spent and why they are most often rejected. It's the same
information as the Analytics section of the dashboard, so you can take it to your own
dashboard or a spreadsheet.
GET /v1/analytics?from=2026-09-01&to=2026-09-30&group_by=type
Authorization: Bearer ck_live_…It uses a secret key and covers only the key's mode: with ck_live_… real analyses, with ck_test_… test ones.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
from | date YYYY-MM-DD | 29 days before to | First day (included), in UTC. |
to | date YYYY-MM-DD | today | Last day (included), in UTC. |
group_by | type | day | template | metadata.<key> | type | How analyses are grouped in groups. |
format | json | csv | json | csv downloads a file instead of JSON. |
group_by | groups[].key | groups[].label | Order |
|---|---|---|---|
type | Detected type (es_dni…) | Type name in the Accept-Language language | Most analyses first |
day | Day YYYY-MM-DD (UTC) | The same day | Chronological; days without analyses don't appear |
template | Template id (tpl_…) | Template name | Most analyses first |
metadata.<key> | Value of that metadata key (metadata.club_id) | The same value | Most analyses first |
Analyses with no value for the grouping (no type, no template or no such metadata key) are grouped under key: null
with a label such as "No template". At most 500 groups.
Response
{
"object": "analytics",
"from": "2026-09-01",
"to": "2026-09-30",
"group_by": "type",
"mode": "live",
"totals": {
"count": 1240, "completed": 1228, "failed": 12,
"valid": 1015, "invalid": 131, "review": 82,
"valid_rate": 0.8265, "invalid_rate": 0.1067, "review_rate": 0.0668,
"avg_ms": 3120, "p50_ms": 2410, "p95_ms": 7800,
"credits": 1412.4
},
"groups": [
{ "key": "es_dni", "label": "Spanish ID card (DNI)", "count": 802, "completed": 798, "failed": 4, "valid": 701, "invalid": 61, "review": 36, "valid_rate": 0.8784, "invalid_rate": 0.0764, "review_rate": 0.0451, "avg_ms": 2380, "p50_ms": 2100, "p95_ms": 4300, "credits": 802 }
],
"top_reasons": [
{ "code": "not_expired", "severity": "error", "count": 58, "example": "The document expired on 03/02/2026." },
{ "code": "low_confidence", "severity": "warning", "count": 41, "example": "The document number could not be read reliably." }
]
}| Field | Description |
|---|---|
count | Analyses created in the period (including those still processing). |
completed, failed | Finished and failed. Failed ones are not charged. |
valid, invalid, review | Completed with that verdict. If a person reviewed the analysis, their decision counts (verdict.final_status). |
valid_rate, invalid_rate, review_rate | Share from 0 to 1 of the completed analyses with a verdict (those without one, such as a generic without expect, don't count). |
avg_ms, p50_ms, p95_ms | Processing time (from start to end of the analysis) of completed ones: mean, median and 95th percentile. null if there is no data. |
credits | Credits spent. In test, 0. |
top_reasons[] | The 10 most frequent warning and error reasons in verdict.reasons: code, severity, count and a real example message (example). The code values are in Verdicts. |
Analyses whose results were already deleted by retention still count: the minimal record (type, verdict, credits, metadata) is kept for analytics.
CSV
With format=csv the response is an analytics-<mode>-<grouping>-<from>-<to>.csv file ready for Excel: ;
separator, comma decimals, UTF-8 BOM, one row per group (key, group, totals, percentages, mean time, p95 and credits)
and a final total row. Column headers follow the Accept-Language language.
curl -G https://api.constaia.com/v1/analytics \
-H "Authorization: Bearer $CONSTAIA_API_KEY" \
-H "Accept-Language: en" \
--data-urlencode "from=2026-09-01" \
--data-urlencode "to=2026-09-30" \
--data-urlencode "group_by=metadata.club_id" \
--data-urlencode "format=csv" \
-o analytics-september.csvExamples
curl -G https://api.constaia.com/v1/analytics \
-H "Authorization: Bearer $CONSTAIA_API_KEY" \
--data-urlencode "from=2026-09-01" \
--data-urlencode "to=2026-09-30" \
--data-urlencode "group_by=template"Ideas
- Compare templates:
group_by=templateshows which setup rejects more or sends more to review. - Per customer or event: store their id in
metadatawhen analysing and group withgroup_by=metadata.<key>. - Watch quality: if
review_rategoes up orlow_qualityshows up intop_reasons, review your capture instructions or use the widget, which warns about blurry photos before uploading. - Cost:
creditsper group, together withGET /v1/usagefor the daily detail.
Errors
| HTTP | code | When |
|---|---|---|
422 | invalid_parameter | A date isn't a valid YYYY-MM-DD or group_by isn't one of the accepted values (param says which). |
Next steps
Balance and usage
Reference for GET /v1/balance and GET /v1/usage: pack credits, free tier, reservations and daily usage by document type, with examples.
Webhook endpoints
Reference for /v1/webhook-endpoints: create, list, retrieve and delete the URLs that receive Constaia events, with their whsec_ secret and mode.