Usage
Two endpoints to see what your store has consumed and project what you'll need next month.
GET /v1/usage
Current calendar month, grouped by endpoint type.
Auth: platform key with usage:read.
Response 200
{
"data": {
"period": "2026-04",
"tier": "enterprise",
"usage": {
"request": { "total": 31, "billable": 0 },
"signup": { "total": 3, "billable": 2 }
},
"limits": {
"requests_per_month": -1,
"signups_per_month": -1,
"webhooks_per_month": -1,
"requests_per_minute": 600
}
}
}
Field reference
| Field | Meaning |
|---|---|
period | Always YYYY-MM — the current month in Africa/Algiers time (UTC+01:00, no DST). Totals are month-to-date, counted from the 1st at 00:00. |
tier | Your current rate-limit tier — always enterprise (the API is Enterprise-only). |
usage.<group>.total | All requests in that group, including duplicates / rejections. |
usage.<group>.billable | Only counted requests (e.g. duplicate signups don't bill). |
limits | The effective limits — tier_limits overridden by any per-store override. -1 means unlimited. |
usage is sparse — only groups with recorded activity this calendar month appear (in practice request, plus signup / event for public-key traffic). If the store has no usage at all, usage serialises as an empty JSON array [], not an object. Default missing groups to zero client-side and tolerate []; a strictly-typed deserialiser will otherwise fail.
Endpoint groups
| Group | What counts |
|---|---|
request | Every call that passed key authentication, counted before the request is processed — so 4xx/5xx responses and scope rejections count too. Always billable: 0. GET /v1/ping is unauthenticated and never counted, and cache hits (X-Cache: HIT) are not counted either. |
signup | Each /v1/signups call. Duplicates are counted in total but not billable. |
event | Each /v1/events call. Only newly-recorded events are counted — duplicates (same store + nonce) are dropped and appear in neither total nor billable. This differs from signup. |
webhook | Reserved. Outbound deliveries are not metered at v1, so this group never appears in the response. |
GET /v1/usage/history
Hourly rollups over a date range — useful for charts and trend analysis.
Auth: platform key with usage:read.
Query parameters
| Param | Type | Default | Notes |
|---|---|---|---|
from | ISO date | 7 days ago | Inclusive |
to | ISO date | now | Exclusive |
Range cap: 90 days. from is inclusive and to is exclusive, and both are floored to the top of the hour for the query — the from / to echoed in the response are your inputs as parsed, unfloored. Common date and date-time formats are accepted (2026-04-01, 2026-04-01T12:00:00Z, -7 days, …); an unparseable value or to earlier than from returns 400 bad_request ("from/to must be valid date strings, to >= from"), and a range over 90 days returns 400 ("range too large (max 90 days)").
period_hour buckets are whole hours, stamped in Africa/Algiers time (UTC+01:00) at the moment each call is counted.
Errors
| HTTP | Code | Cause |
|---|---|---|
| 400 | bad_request | "from/to must be valid date strings, to >= from" |
| 400 | bad_request | "range too large (max 90 days)" |
| 403 | forbidden | "Missing scope: usage:read" |
usage:read is one of the few scopes v1 actually enforces. It is granted by default on every minted platform key, so it only bites keys that support issued with a reduced scope set.
Request
curl 'https://api.dzbuild.app/v1/usage/history?from=2026-04-01&to=2026-05-01' \
-H "Authorization: Bearer $DZ_KEY"
Response 200
{
"data": {
"from": "2026-04-01T00:00:00+01:00",
"to": "2026-05-01T00:00:00+01:00",
"rows": [
{ "period_hour": "2026-04-30 19:00:00", "endpoint_group": "request", "count": 26, "billable_count": 0 },
{ "period_hour": "2026-04-30 20:00:00", "endpoint_group": "request", "count": 5, "billable_count": 0 },
{ "period_hour": "2026-04-30 20:00:00", "endpoint_group": "signup", "count": 3, "billable_count": 2 }
]
}
}
Rows are returned in ascending period_hour order. Hours with zero usage in any group are omitted (sparse).
Plotting tips
- Daily aggregates: group rows by the first 10 characters of
period_hour(the date prefix). - Stacked area: group by
endpoint_group, then by hour for the X-axis. - Quota burn rate: divide
signup.billable_countcumulative by the elapsed fraction of the month, project to month-end.
A simple Python example:
import collections, datetime, requests, os
r = requests.get('https://api.dzbuild.app/v1/usage/history',
params={'from': '2026-04-01', 'to': '2026-05-01'},
headers={'Authorization': f"Bearer {os.environ['DZ_KEY']}"})
rows = r.json()['data']['rows']
by_day = collections.defaultdict(lambda: collections.Counter())
for row in rows:
day = row['period_hour'][:10]
by_day[day][row['endpoint_group']] += row['count']
for day, counts in sorted(by_day.items()):
print(day, dict(counts))