Skip to content

Get daily metrics history for a deployment

GET
/v1/apps/{appName}/deployments/{deploymentName}/metrics/history
curl --request GET \
--url https://api.aetherpush.com/v1/apps/example/deployments/example/metrics/history \
--header 'Authorization: Bearer <token>'

Returns per-day, per-label series snapshotted from Redis into Postgres. History starts the day the snapshot job first ran for this deployment and cannot be backfilled. Active is an end-of-snapshot gauge. Download and install counters are returned as same-day cumulatives plus deltas against the previous calendar day. A missing previous day yields a null delta rather than a lifetime spike.

from and to are UTC dates (YYYY-MM-DD). When omitted, the range is the last 30 days, then clamped to the app owner’s retention_days and to historyStartsAt. Out-of-range dates are clamped. Malformed dates or from after to return 400.

This endpoint does not read Redis. An empty series is 200. Requires the metrics.read app permission.

appName
required
string
deploymentName
required
string
from
string format: date
to
string format: date

Daily metrics history.

Media typeapplication/json
object
from
required
string format: date
to
required
string format: date
historyStartsAt
required
string | null format: date
days
required
Array<object>
object
date
required
string format: date
labels
required

Keyed by package label (e.g. v3) or by the binary version a report was counted under (e.g. 1.0.0). Keys are restricted to [0-9A-Za-z.+-], so a key never carries a control character or the : separator.

object
key
additional properties
object
active
required
integer
downloaded
required
integer
installed
required
integer
failed
required
integer
downloadedDelta
required
integer | null
installedDelta
required
integer | null
failedDelta
required
integer | null

Example

{
"from": "2026-08-01",
"to": "2026-08-26",
"historyStartsAt": "2026-08-20",
"days": [
{
"date": "2026-08-20",
"labels": {
"v12": {
"active": 100,
"downloaded": 500,
"installed": 480,
"failed": 12,
"downloadedDelta": null,
"installedDelta": null,
"failedDelta": null
}
}
}
]
}

Malformed from/to, or from after to.

Media typeapplication/json
Error

Standard error envelope. code is the stable machine identifier for client branching and i18n. The wording of error is a human-readable fallback and is not part of the contract. Specialized responses keep narrower code enums where clients already branch on them.

object
error
required

Human-readable error message.

string
code
required

Stable machine code. Prefer this over matching on error. The values this API can answer with are listed in the ApiErrorCode schema of the raw document at https://api.aetherpush.com/openapi.yaml. The field stays an open string here so that a release adding a value does not invalidate this response.

string
requestId

Unique identifier for the request, also exposed as the X-Request-Id response header.

string

Example

{
"error": "The requested resource was not found.",
"code": "not_found",
"requestId": "req_abc123"
}

Unauthenticated.

Media typeapplication/json
Error

Standard error envelope. code is the stable machine identifier for client branching and i18n. The wording of error is a human-readable fallback and is not part of the contract. Specialized responses keep narrower code enums where clients already branch on them.

object
error
required

Human-readable error message.

string
code
required

Stable machine code. Prefer this over matching on error. The values this API can answer with are listed in the ApiErrorCode schema of the raw document at https://api.aetherpush.com/openapi.yaml. The field stays an open string here so that a release adding a value does not invalidate this response.

string
requestId

Unique identifier for the request, also exposed as the X-Request-Id response header.

string

Example

{
"error": "The requested resource was not found.",
"code": "not_found",
"requestId": "req_abc123"
}

The API key’s scopes do not grant read, which answers required_scopes. A refusal raised before the route is reached, such as a request that did not arrive through the trusted edge, answers a plain error instead.

Media typeapplication/json
One of:
Error

Standard error envelope. code is the stable machine identifier for client branching and i18n. The wording of error is a human-readable fallback and is not part of the contract. Specialized responses keep narrower code enums where clients already branch on them.

object
error
required

Human-readable error message.

string
code
required

Stable machine code. Prefer this over matching on error. The values this API can answer with are listed in the ApiErrorCode schema of the raw document at https://api.aetherpush.com/openapi.yaml. The field stays an open string here so that a release adding a value does not invalidate this response.

string
requestId

Unique identifier for the request, also exposed as the X-Request-Id response header.

string

Examples

The API key's scopes do not grant read

{
"error": "Insufficient permissions",
"code": "insufficient_scopes",
"required_scopes": [
"read"
],
"requestId": "req_abc123"
}

App or deployment not found.

Media typeapplication/json
Error

Standard error envelope. code is the stable machine identifier for client branching and i18n. The wording of error is a human-readable fallback and is not part of the contract. Specialized responses keep narrower code enums where clients already branch on them.

object
error
required

Human-readable error message.

string
code
required

Stable machine code. Prefer this over matching on error. The values this API can answer with are listed in the ApiErrorCode schema of the raw document at https://api.aetherpush.com/openapi.yaml. The field stays an open string here so that a release adding a value does not invalidate this response.

string
requestId

Unique identifier for the request, also exposed as the X-Request-Id response header.

string

Example

{
"error": "The requested resource was not found.",
"code": "not_found",
"requestId": "req_abc123"
}

The tenant’s per-minute management API budget is spent. Retry-After and X-RateLimit-* say when to retry. This is not a plan quota: quota 429s use the Error envelope and do not set Retry-After.

Media typeapplication/json
RateLimitError

Returned with HTTP 429 when an endpoint-specific rate limit is hit, including the per-tenant management API budget. Not the process-wide address limiter (see GlobalAddressRateLimitErrorResponse). retryAfterSeconds indicates how long the client should wait before retrying, and matches the Retry-After header when that header is set. code names the limit that fired so clients can translate without matching on error.

object
error
required
string
code
required
string
retryAfterSeconds
required
integer
>= 1
requestId
string

Example

{
"error": "Rate limit exceeded",
"code": "tenant_rate_limit_exceeded",
"retryAfterSeconds": 60
}
Retry-After
integer
>= 1

Seconds until the tenant window resets.