aethexDocs

API Reference

Usage API

Programmatically read your usage and configure webhook alerts when usage crosses a threshold. Use this API for billing reconciliation, per-resource cost attribution, budget monitoring, and product analytics.Reads. usage:read scope; covers GET /usage, /usage/summary, /usage/daily, /usage/monthly, and the trigger listing endpoints.Trigger management. usage:write scope; create, update, rotate the webhook secret, and replay firings.Data freshness. Usage rows commit within seconds of request completion; rollups typically reflect activity within a minute. Voice-call duration is captured at end-of-call (agent-active time), not in real time during the call.

Base URL
https://api.aethexai.com/api/v1
Endpoints
10
Scopes
usage:readusage:write
GET/usage

Lifetime totals across every metered resource, plus a per-bucket request count.

Get Usage Summary

Lifetime totals across every metered resource on this account. Returns request counts, token totals, audio seconds, and a per-resource-type breakdown.Field semantics. total_request_duration_ms is HTTP wall-clock and applies only to synchronous resources (agent_chat, tts, transcription); voice calls are not HTTP requests, so their length appears under total_voice_seconds (agent-active time, captured at end-of-call). total_audio_seconds is the broader sum across every resource type that records audio. by_resource_type is keyed by resource bucket (voice_call, transcription, tts, agent_chat) with per-bucket request counts.Requires the usage:read scope.

Path & Query

1
  • api_key_idstring (uuid)optional

    Restrict the figures to usage logged against this one API key. Always scoped to your workspace: a key id belonging to another tenant, or one that does not exist, returns zeros rather than an error.

Errors

2
401Unauthorized

Missing or invalid API key.

Send X-API-Key: '<'api_key'>' with a key that has the usage:read scope.

403Forbidden

API key lacks the usage:read scope.

Issue a new key with usage:read (and usage:write if you also need to manage triggers).

GET/usage/summary

Identical to `GET /usage`; kept as a convenience alias.

Get Usage Summary (Alias)

Alias for GET /usage returning the same payload. Requires the usage:read scope.

Path & Query

1
  • api_key_idstring (uuid)optional

    Restrict the figures to usage logged against this one API key. Always scoped to your workspace: a key id belonging to another tenant, or one that does not exist, returns zeros rather than an error.

Errors

2
401Unauthorized

Missing or invalid API key.

Send X-API-Key: '<'api_key'>'.

403Forbidden

API key lacks the usage:read scope.

Issue a key with usage:read.

GET/usage/daily

Per-day rollup over a rolling window, defaulting to the last 30 days.

Get Daily Usage

Per-day rollup over a rolling calendar-day window in UTC. Returns exactly days entries — one per day, newest first — with days that had no activity zero-filled so the response is chart-ready without client-side gap handling. Each entry has the date, request count, prompt / completion / total tokens, request duration (HTTP-shaped resources only), voice_seconds (agent-active time, captured at end-of-call), audio_seconds, and input characters. Requires the usage:read scope.

Path & Query

2
  • daysintegeroptional

    Length of the rolling window in calendar days. Defaults to 30. Must be between 1 and 365 inclusive; values outside that range return 422.

  • api_key_idstring (uuid)optional

    Restrict the figures to usage logged against this one API key. Always scoped to your workspace: a key id belonging to another tenant, or one that does not exist, returns zeros rather than an error.

Errors

3
401Unauthorized

Missing or invalid API key.

Send X-API-Key: '<'api_key'>'.

403Forbidden

API key lacks the usage:read scope.

Issue a key with usage:read.

422Unprocessable Entity

days is outside the 1..365 range.

Pass an integer between 1 and 365 inclusive.

GET/usage/monthly

Per-month rollup; each bucket is anchored to the first-of-month in UTC.

Get Monthly Usage

Per-month rollup, with each bucket anchored to the first of the month in UTC. Same fields as GET /usage/daily rolled up to monthly buckets, over the full retention period for the account.

Path & Query

1
  • api_key_idstring (uuid)optional

    Restrict the figures to usage logged against this one API key. Always scoped to your workspace: a key id belonging to another tenant, or one that does not exist, returns zeros rather than an error.

Errors

2
401Unauthorized

Missing or invalid API key.

Send X-API-Key: '<'api_key'>'.

403Forbidden

API key lacks the usage:read scope.

Issue a key with usage:read.

POST/usage/triggers

Register a webhook to fire when usage crosses a threshold for the period.

Create Usage Trigger

Register a webhook that fires once per period when usage crosses a threshold. The trigger re-arms at the next period boundary.Prerequisite. Rotate a webhook secret via POST /usage/webhook-secret/rotate before creating your first trigger; every callback is HMAC-SHA256 signed with this account-wide secret.Callback URL. event_callback_url must be HTTPS and resolve to a public IP; we check at create time and again at delivery time.Requires the usage:write scope.

Request body

5
  • resource_typestringrequired

    Bucket to monitor. One of voice_call, transcription, tts, agent_chat, all. all matches every resource type within the selected threshold_type.

  • threshold_valuenumber (decimal)required

    Threshold value. Must be > 0, max 38 digits / 6 decimal places.

  • threshold_typestringoptional

    How threshold_value is interpreted. One of count (default; number of requests in the period) or credits_used (raw credits deducted in the period).

  • periodstringoptional

    Rolling window. One of monthly (default; calendar month, UTC) or daily (calendar day, UTC).

  • event_callback_urlstringrequired

    HTTPS URL that receives the signed POST when the threshold fires. Must resolve to a public IP; checked at create time and again at delivery time.

Errors

8
400No webhook secret

Your account has no webhook_secret configured, so the trigger cannot sign callbacks.

Call POST /usage/webhook-secret/rotate first to generate one, then retry.

422Invalid callback URL format

event_callback_url failed schema validation: URL does not start with https:// or contains whitespace. Returned as code: "validation_error" with the failing field in the detail array.

Use a valid HTTPS URL with no whitespace.

400Callback URL blocked

event_callback_url was rejected at the URL-policy step. Common causes: hostname resolved to a private, loopback, or cloud-metadata IP; URL contained credentials (user:pass@host) or a fragment (#...); port was not 443. Returned as code: "bad_request".

Use a publicly-resolvable HTTPS URL on your own domain.

503URL validation temporarily unavailable

DNS resolution failed while validating event_callback_url. Two distinct causes share this status: the resolver is briefly unavailable (transient — safe to retry) OR the hostname is unresolvable (typo / DNS not configured — retries will keep failing). Returned as code: "service_unavailable".

Verify the hostname resolves publicly (e.g. dig +short your-host.example.com); typoed or unresolvable hostnames also surface here. If the hostname is valid, retry with exponential backoff — persistent failures with a verified hostname indicate a resolver outage; contact support with the request_id.

401Unauthorized

Missing or invalid API key.

Send X-API-Key: '<'api_key'>'.

403Forbidden

API key lacks the usage:write scope.

Issue a key with usage:write.

409Trigger cap reached

You are already at the per-account maximum of active triggers.

PATCH is_active: false on an unused trigger to free a slot before creating a new one.

422Invalid field

resource_type, threshold_type, or period is not in the allowed set, or threshold_value is out of bounds.

Use one of the documented values above.

GET/usage/triggers

Return every usage trigger configured for the account, active or not.

List Usage Triggers

Returns all usage alert triggers configured for the calling account, including deactivated ones (so you can re-activate via PATCH rather than creating a new trigger). Requires the usage:read scope.

Errors

2
401Unauthorized

Missing or invalid API key.

Send X-API-Key: '<'api_key'>'.

403Forbidden

API key lacks the usage:read scope.

Issue a key with usage:read.

PATCH/usage/triggers/:trigger_id

Re-tune `is_active` / `threshold_value` / `event_callback_url`; trigger shape is immutable.

Update Usage Trigger

Partial update on a trigger. Only is_active, threshold_value, and event_callback_url are editable. resource_type, threshold_type, and period are immutable; create a new trigger if you need a different shape. Set is_active: false to soft-disable without deleting firing history. Re-activating re-checks the active-trigger cap. event_callback_url is re-validated on update. Empty body is a valid no-op. Requires the usage:write scope.

Path & Query

1
  • trigger_idstringrequired

    Trigger UUID

Request body

3
  • is_activebooleanoptional

    Soft-disable without deleting history. Re-activating re-checks the active-trigger cap.

  • threshold_valuenumber (decimal)optional

    Decimal, > 0, max 38 digits / 6 decimal places.

  • event_callback_urlstringoptional

    HTTPS URL; replaces the current URL atomically.

Errors

8
422Invalid callback URL format

event_callback_url failed schema validation: URL does not start with https:// or contains whitespace. Returned as code: "validation_error" with the failing field in the detail array.

Use a valid HTTPS URL with no whitespace.

400Callback URL blocked

event_callback_url was rejected at the URL-policy step. Common causes: hostname resolved to a private, loopback, or cloud-metadata IP; URL contained credentials (user:pass@host) or a fragment (#...); port was not 443. Returned as code: "bad_request".

Use a publicly-resolvable HTTPS URL on your own domain.

503URL validation temporarily unavailable

DNS resolution failed while validating event_callback_url. Two distinct causes share this status: the resolver is briefly unavailable (transient — safe to retry) OR the hostname is unresolvable (typo / DNS not configured — retries will keep failing). Returned as code: "service_unavailable".

Verify the hostname resolves publicly (e.g. dig +short your-host.example.com); typoed or unresolvable hostnames also surface here. If the hostname is valid, retry with exponential backoff — persistent failures with a verified hostname indicate a resolver outage; contact support with the request_id.

401Unauthorized

Missing or invalid API key.

Send X-API-Key: '<'api_key'>'.

403Forbidden

API key lacks the usage:write scope.

Issue a key with usage:write.

404Trigger not found

The trigger does not exist or is not owned by the calling account.

Verify the trigger ID via GET /usage/triggers.

409Active-trigger cap reached

Re-activating would push you over the active-trigger cap.

Deactivate another trigger before re-activating this one.

422Invalid field

threshold_value is out of bounds.

Send a value within the documented bounds.

POST/usage/webhook-secret/rotate

Generate a new account-wide HMAC-SHA256 secret used to sign every trigger webhook.

Rotate Usage Webhook Secret

Generates (or replaces) the account-level webhook signing secret. The plaintext secret is returned once in this response; store it before the request returns. We never expose it again. The returned value is a 64-character lowercase hex string ready to drop into an HMAC-SHA256 verifier.Signature format. Every trigger callback ships an X-Aethex-Signature header of the form t=<unix_timestamp>,v1=<hex_hmac> and an X-Aethex-Event: usage.threshold.crossed header. To verify: HMAC-SHA256 the string "<t>.<raw_body>" with your secret and compare against v1 in constant time. Reject callbacks where t is more than 5 minutes off your clock to mitigate replay.Rotation impact. Takes effect immediately; in-flight callbacks signed with the old secret will fail verification. Rotate during low-traffic windows, and use POST /usage/triggers/{id}/firings/{firing_id}/redeliver to replay any callbacks that fail during the cutover.Requires the usage:write scope.

Errors

2
401Unauthorized

Missing or invalid API key.

Send X-API-Key: '<'api_key'>'.

403Forbidden

API key lacks the usage:write scope.

Issue a key with usage:write.

GET/usage/triggers/:trigger_id/firings

Audit log of threshold crossings for a single trigger, newest first.

List Trigger Firings

Audit log of threshold crossings for this trigger, newest first.One row per crossing, not per delivery attempt. When you redeliver a firing, attempt_count increments and delivery_status / http_status / last_error reflect the latest attempt; no new row is inserted. This makes "did this period's crossing eventually deliver?" a single-row lookup.delivery_status is delivered (final 2xx), failed (every retry exhausted), or pending (in flight).Requires the usage:read scope.

Path & Query

2
  • trigger_idstringrequired

    Trigger UUID

  • limitintegeroptional

    Max rows to return. Clamped to 1..200; defaults to 50.

Errors

3
401Unauthorized

Missing or invalid API key.

Send X-API-Key: '<'api_key'>'.

403Forbidden

API key lacks the usage:read scope.

Issue a key with usage:read.

404Trigger not found

The trigger does not exist or is not owned by the calling account.

Verify the trigger ID via GET /usage/triggers.

POST/usage/triggers/:trigger_id/firings/:firing_id/redeliver

Re-attempt webhook delivery for one firing, replaying the original payload bytes.

Redeliver Trigger Firing

Re-attempts webhook delivery for a single firing, replaying the same payload bytes. The X-Aethex-Signature header carries a fresh timestamp and signature on each attempt, so HMACs will differ across attempts even though the payload is byte-identical. Updates the existing audit row in place rather than inserting a new firing: attempt_count accumulates across redeliveries, and delivery_status / http_status / last_error reflect the most recent attempt. Requires the usage:write scope.

Path & Query

2
  • trigger_idstringrequired

    Trigger UUID

  • firing_idstringrequired

    Firing UUID (from GET /usage/triggers/{trigger_id}/firings)

Errors

4
400No webhook secret

Your account has no webhook_secret configured, so the redelivery cannot be signed.

Call POST /usage/webhook-secret/rotate to generate one, then retry.

401Unauthorized

Missing or invalid API key.

Send X-API-Key: '<'api_key'>'.

403Forbidden

API key lacks the usage:write scope.

Issue a key with usage:write.

404Trigger or firing not found

Either the trigger or the firing does not exist, or one of them is not owned by the calling account.

Verify both IDs via GET /usage/triggers and GET /usage/triggers/{trigger_id}/firings.