Reports usage samples from the device collector.
Reports usage samples from the device collector.
POST /v1/link/usage
| Address | https://api.hanzo.ai/v1/link/usage |
| Method | POST |
| Operation | post_link_usage |
| Auth | Authorization: Bearer $HANZO_API_KEY |
Reports usage samples from the device collector.
It ingests a batch of usage samples and answers with how many were accepted, whether history was durably stored, and the links they refreshed. A report also REFRESHES one link per distinct (machine, provider, account) it names, so a running collector keeps the accounts overview current without a separate registration call.
A caller can only ever report for THEMSELVES: org and subject come from the validated bearer, never from the body, so no sample can be attributed to another user or tenant. History is FAIL-SOFT and stored says which happened — a warehouse outage still accepts the report and refreshes the links rather than failing the device, and answers 202 either way. Send either one sample inline or up to 256 in samples; an empty batch or an over-long one is 400, as is a provider, window class or kind outside the closed vocabulary — an unrecognized window is refused rather than rewritten, because a silently reclassified sample would fill a dashboard with a class nobody reported.
Request
43 fields, body application/json (required).
| Field | In | Type | Required | Description |
|---|---|---|---|---|
account | body | string | — | |
cachedInputTokens | body | integer | — | |
confidence | body | string | — | |
costCents | body | integer | — | |
costLimitCents | body | integer | — | |
currency | body | string | — | |
inputTokens | body | integer | — | |
kind | body | string | — | |
lane | body | string | — | |
machine | body | string | — | |
outputTokens | body | integer | — | |
plan | body | string | — | |
provider | body | string | — | |
requests | body | integer | — | |
resetsAt | body | string | — | |
samples | body | readingReq[] | — | Samples is the batch form, up to 256 samples; leave it empty to send one sample inline on the same fields. |
samples[].account | body | string | — | Account is the provider-side account the sample belongs to. |
samples[].cachedInputTokens | body | integer | — | CachedInputTokens is the window's cached-prompt-token count. |
samples[].confidence | body | string | — | Confidence says how real the counters are, as the meter graded itself. |
samples[].costCents | body | integer | — | CostCents is the window's spend in cents, as the provider's meter states it. |
samples[].costLimitCents | body | integer | — | CostLimitCents is the window's spend cap in cents, when the meter knows one. |
samples[].currency | body | string | — | Currency is the ISO currency the cost fields are stated in. |
samples[].inputTokens | body | integer | — | InputTokens is the window's prompt-token count. |
samples[].kind | body | string | — | Kind is subscription or apikey; anything else is refused. |
samples[].lane | body | string | — | Lane names the meter's own lane label for this measurement. |
samples[].machine | body | string | — | Machine is the machine the collector observed the account on. |
samples[].outputTokens | body | integer | — | OutputTokens is the window's completion-token count. |
samples[].plan | body | string | — | Plan is the provider plan label the account is on. |
samples[].provider | body | string | — | Provider is the AI provider whose meter reported this sample. |
samples[].requests | body | integer | — | Requests is the window's request count. |
samples[].resetsAt | body | string | — | ResetsAt is when the window resets, RFC 3339, bounded. |
samples[].synthetic | body | boolean | — | Synthetic marks a sample the collector derived rather than observed. |
samples[].totalTokens | body | integer | — | TotalTokens is the window's total token count. |
samples[].usedPct | body | number | — | UsedPct is how much of the window's allowance is consumed, clamped 0..100. |
samples[].window | body | string | — | Window is the window class, one of 6h, day, week, month; anything else is refused rather than silently reclassified. |
samples[].windowMinutes | body | integer | — | WindowMinutes is the window's length as the meter reported it. |
samples[].windowStart | body | string | — | WindowStart is when the measured window opened, RFC 3339, bounded to a sane interval around now. |
synthetic | body | boolean | — | |
totalTokens | body | integer | — | |
usedPct | body | number | — | |
window | body | string | — | |
windowMinutes | body | integer | — | |
windowStart | body | string | — |
Response
| Status | Body | Meaning |
|---|---|---|
202 | ingestResp | accepted |
202 body — 18 fields.
| Field | In | Type | Always | Description |
|---|---|---|---|---|
accepted | body | integer | — | Accepted is how many samples this report landed. |
links | body | linkView[] | — | Links is the link row each distinct (machine, provider, account) in the batch refreshed. |
links[].account | body | string | — | Account is the provider-side account identifier, when the collector knows it. |
links[].billing | body | string | — | Billing is how this account's inference bills — plan (the user's own subscription, metered here for visibility only) or commerce (the gateway path). |
links[].createdAt | body | string | — | CreatedAt is when the link was first registered, RFC 3339 UTC. |
links[].host | body | string | — | Host is the machine's human hostname label, from its most recent report. |
links[].id | body | string | — | ID is the link's opaque handle ("link_" + 32 hex chars). |
links[].kind | body | string | — | Kind is how the account authenticates: subscription or apikey. |
links[].lastSeen | body | string | — | LastSeen is when the account last reported, RFC 3339 UTC. |
links[].machine | body | string | — | Machine is the stable machine identifier the collector reports. |
links[].os | body | string | — | OS is the machine's operating system label. |
links[].plan | body | string | — | Plan is the provider plan label (e.g. |
links[].provider | body | string | — | Provider is the AI provider this account belongs to (claude, openai, hanzo…). |
links[].status | body | string | — | Status is linked or revoked. |
links[].updatedAt | body | string | — | UpdatedAt is when the link was last refreshed, RFC 3339 UTC. |
links[].usage | body | any | — | Usage is the last good usage snapshot, clamped and re-serialized to known fields at ingest. |
links[].user | body | string | — | User is the owning subject — the validated caller who registered the link. |
stored | body | boolean | — | Stored reports whether history was durably written; false means the warehouse was unavailable and only the link rows were refreshed. |
Failure carries the platform error shape — see Errors.
Examples
hanzo links usage createimport { Configuration, LinkApi } from 'hanzoai';
const api = new LinkApi(new Configuration({ accessToken: process.env.HANZO_API_KEY }));
const { data } = await api.postLinkUsage({ account: "<account>", cachedInputTokens: 0 });from hanzoai.cloud import ApiClient, Configuration
from hanzoai.cloud.api import LinkApi
client = ApiClient(Configuration(access_token=os.environ["HANZO_API_KEY"]))
result = LinkApi(client).post_link_usage(account="<account>", cached_input_tokens=0)cfg := cloud.NewConfiguration()
cfg.AddDefaultHeader("Authorization", "Bearer "+os.Getenv("HANZO_API_KEY"))
client := cloud.NewAPIClient(cfg)
resp, _, err := client.LinkAPI.PostLinkUsage(context.Background()).Execute()
if err != nil {
return err
}use hanzo_cloud::apis::{configuration::Configuration, link_api};
let mut cfg = Configuration::new();
cfg.bearer_access_token = std::env::var("HANZO_API_KEY").ok();
let result = link_api::post_link_usage(&cfg, Default::default()).await?;import ai.hanzo.cloud.ApiClient;
import ai.hanzo.cloud.api.LinkApi;
ApiClient client = new ApiClient();
client.setRequestInterceptor(b -> b.header("Authorization", "Bearer " + System.getenv("HANZO_API_KEY")));
var result = new LinkApi(client).postLinkUsage();The method above is the one at the current release of the document. [email protected] (npm) and [email protected] (PyPI) were generated from an earlier release, where this operation carried a different id, so it spells the method differently — regenerating the clients is what makes the two agree. SDKs →
curl -X POST https://api.hanzo.ai/v1/link/usage \
-H "Authorization: Bearer $HANZO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"account": "<account>",
"cachedInputTokens": 0
}'The door reaches link through the link tool, which names its 11 operations with its own verbs — this one among them, under a name only the door declares. describe explains any of them:
curl -X POST https://api.hanzo.ai/v1/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "describe",
"arguments": {
"op": "list_links"
}
}
}'How is this guide?