Send custom data: metrics and events
Push your own metrics and events into VerOps with POST /v1/custom/metrics and POST /v1/custom/events. Full body parameter tables with validation, request and response examples, the 202 success and error statuses, the 1 to 1000 batch limit, and best practices for batching, timestamps, and label cardinality.
Overview
The custom-data endpoints let you push your own telemetry into VerOps and have it stored alongside everything else in your organization. There are two shapes:
| Shape | Use it for | Send with |
|---|---|---|
| Metric | A named numeric sample over time — a gauge, a counter reading, a measured latency. | POST /v1/custom/metrics |
| Event | A structured record in a named dataset with free-form JSON attributes — a deploy, an audit entry, a business event. | POST /v1/custom/events |
Both endpoints accept a batch of 1 to 1000 items per call, require the API scope, and respond 202 Accepted with a count of how many items were accepted.
Send metrics
Method and path: POST /v1/custom/metrics
Auth: API key with the API scope.
Body: a JSON object with a metrics array (1 to 1000 entries).
| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
name |
string | Yes | Non-empty | The metric name, for example orders.count. |
value |
number | Yes | Must be finite (no NaN or infinity) | The sample value. |
ts |
number or string | No | Epoch millis or ISO-8601 | Sample time. Defaults to now if omitted. |
labels |
object | No | String keys to string values | Dimensions you can filter and group by later, for example {"region":"us"}. |
source |
string | No | Defaults to "custom" |
A label identifying where the sample came from. |
Request example:
curl -X POST https://api.verops.io/v1/custom/metrics \
-H "X-Api-Key: $KEY" -H "Content-Type: application/json" \
-d '{
"metrics": [
{"name": "orders.count", "value": 42, "labels": {"region": "us"}},
{"name": "checkout.latency_ms", "value": 128.4, "ts": 1700000000000},
{"name": "queue.depth", "value": 7, "ts": "2023-11-14T22:13:20Z", "source": "billing"}
]
}'
Success response — 202 Accepted:
{"accepted": 3}
Errors:
| Status | Code | When |
|---|---|---|
| 400 | bad_request |
Empty array, more than 1000 items, a missing name or value, or a non-finite value. |
| 401 | unauthorized |
Missing or invalid key. |
| 403 | forbidden |
Key lacks the API scope. |
| 429 | rate_limited |
Rate limit exceeded. |
| 500 / 503 | internal_error / unavailable |
Transient server-side error — retry with backoff. |
Send events
Method and path: POST /v1/custom/events
Auth: API key with the API scope.
Body: a JSON object with an events array (1 to 1000 entries).
| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
dataset |
string | Yes | Non-empty | The named dataset the event belongs to, for example audit or deploys. |
name |
string | No | — | A short event name, for example login or release. |
ts |
number or string | No | Epoch millis or ISO-8601 | Event time. Defaults to now if omitted. |
attributes |
object | No | Any JSON object | Free-form structured detail. Nesting and mixed value types are allowed. |
Request example:
curl -X POST https://api.verops.io/v1/custom/events \
-H "X-Api-Key: $KEY" -H "Content-Type: application/json" \
-d '{
"events": [
{"dataset": "audit", "name": "login",
"attributes": {"user": "alice", "ip": "10.0.0.1", "mfa": true}},
{"dataset": "deploys", "name": "release", "ts": "2023-11-14T22:13:20Z",
"attributes": {"service": "checkout", "version": "1.8.2"}}
]
}'
Success response — 202 Accepted:
{"accepted": 2}
Errors: same set as POST /v1/custom/metrics. A 400 is returned for an empty array, more than 1000 items, or an event missing its required dataset.
Batch limits
- Each call accepts 1 to 1000 items (metrics or events).
- To send more, split into multiple calls of up to 1000 each.
- The
acceptedcount in the response confirms how many items were taken.
Best practice: Batch aggressively. Sending 1000 metrics in one call is far kinder to your rate limit than 1000 single-metric calls. Buffer on your side and flush in batches.
Warning: These endpoints are append-only and not idempotent. If a call times out you cannot know whether it landed — a blind retry may record the batch twice. For counters and gauges a duplicate is usually acceptable; if exact-once matters, de-duplicate on read using your own id in the labels or attributes.
Common pitfalls
- Label cardinality. Labels are for dimensions with a bounded set of values (region, environment, tier). Do not put unbounded values like a user id, request id, or timestamp in a label — that explodes the number of series and slows every later query. High-cardinality detail belongs in an event
attributesobject, not a metric label. - Timestamps in the wrong unit.
tsis epoch milliseconds, not seconds. A seconds value (10 digits) lands decades in the past. Send milliseconds (13 digits) or an ISO-8601 string. - Non-finite values.
NaNand infinity are rejected with400. Guard against divide-by-zero before you send. - Oversized batches. More than 1000 items in one array is a
400— chunk your data.