Usage API and SDKs
Query current and historical Browser, Web Fetch, and official proxy quota usage.
Availability
Use a deployment that has enabled the usage API and an SDK release that includes client.usage. Older SDK versions may not expose these methods. Confirm availability in your target environment before integrating.
Authentication and requests
Send API-Key and Project-Id headers from a trusted server. The key must belong to the specified project. Both endpoints accept GET only, with no query parameters or request body. No browser session is needed. Do not send duplicate authentication headers or put credentials in URLs, browser bundles, or logs.
Set LEXMOUNT_BASE_URL to the API origin for your deployed environment, without /v1 or another path:
export LEXMOUNT_BASE_URL='https://api.lexmount.com'
export LEXMOUNT_API_KEY='YOUR_API_KEY'
export LEXMOUNT_PROJECT_ID='YOUR_PROJECT_ID'
curl --silent --show-error \
-H "API-Key: $LEXMOUNT_API_KEY" \
-H "Project-Id: $LEXMOUNT_PROJECT_ID" \
"$LEXMOUNT_BASE_URL/v1/usage/current"
curl --silent --show-error \
-H "API-Key: $LEXMOUNT_API_KEY" \
-H "Project-Id: $LEXMOUNT_PROJECT_ID" \
"$LEXMOUNT_BASE_URL/v1/usage/history"Current usage
GET /v1/usage/current returns HTTP 200 with { "request_id": "...", "data": {...} }.
| data field | Type | Meaning |
|---|---|---|
project_id | string | Requested project |
as_of | string | Query timestamp, RFC 3339 |
timezone | string | Asia/Shanghai, used for quota boundaries |
plan | string | Effective plan identifier |
period_start, period_end | string | Start-inclusive, end-exclusive period timestamps |
usage | object | Used counters listed below |
limits | object | Base allowance: browser_ms, webfetch_count, official_proxy_bytes |
remaining | object | Same fields as limits; includes eligible bonus/purchased credits |
Read remaining directly: it can exceed the base limit and is not necessarily limits - usage.
| usage field | Unit | Meaning |
|---|---|---|
browser_ms | milliseconds | Browser usage; divide by 1000 for seconds |
webfetch_count | requests | Web Fetch usage |
official_proxy_upload_bytes | bytes | Official proxy upload |
official_proxy_download_bytes | bytes | Official proxy download |
official_proxy_total_bytes | bytes | Upload plus download |
Web Search, captcha, local proxy, and external proxy usage are not included in these counters.
Historical usage
GET /v1/usage/history returns HTTP 200 with the same request_id/data envelope.
| data field | Type | Meaning |
|---|---|---|
project_id, as_of, timezone | string | Same meanings as current usage |
window_start | string | Query time minus 365 days |
retained_since | string | Ledger retention boundary |
accounting_basis | string | retained_reset_adjusted |
periods | array | Newest first, including the current period |
Each period contains period_start, period_end, plan, coverage, and usage. Usage has the five counters above, or is null.
Periods intersect the past 365 days and follow quota anchors and plan transitions, not fixed calendar months. The response is not guaranteed to contain 12 entries. The oldest period can start before window_start. Custom date ranges, pagination, and project overrides are not supported.
Free and dedicated Web Fetch plans aggregate the identity's currently associated projects. It need not equal usage from the requested project alone; member project IDs are not exposed. Paid project quotas aggregate only the requested project.
If any part of a period precedes the retention boundary, its coverage is outside_retention and usage is null. Never display this as zero. Fully retained empty periods have coverage: "retained" and zero counters.
History reflects retained, reset-adjusted quota records, not immutable invoices or historical wallet balances. Administrative resets/deletions, delayed reports, and current identity membership can affect totals. The current period remains in progress.
Example of an unavailable period (illustrative, not an actual account response):
{
"period_start": "2025-10-31T16:00:00.000Z",
"period_end": "2025-11-30T16:00:00.000Z",
"plan": "free",
"coverage": "outside_retention",
"usage": null
}Errors and rate limits
| HTTP status | Meaning |
|---|---|
| 400 | Invalid query parameters or duplicate security-sensitive headers |
| 401 | Missing or invalid key |
| 403 | Project/key mismatch or disallowed account/project state |
| 404 | Unknown endpoint |
| 405 | Unsupported method; use GET |
| 429 | Rate limit exceeded |
| 503 | Usage service temporarily unavailable |
Gateway errors use this shape:
{
"request_id": "example-request-id",
"error": {
"code": "invalid_request",
"message": "Usage queries do not accept query parameters.",
"details": {}
}
}Earlier Kong authentication/rate-limit rejections can have a different body. Check HTTP status before reading optional error fields. Gateway responses include Cache-Control: no-store and X-Request-Id.
Default limits are 2 requests/second and 30/minute per consumer per Kong node, configurable by the deployment. This is not a global cross-node quota. Reduce polling after 429 and respect Retry-After when present.
Node.js SDK
Use a release containing the usage resource. The configured origin is used directly, without session-region discovery.
import { Lexmount } from 'lexmount';
const client = new Lexmount({
apiKey: process.env.LEXMOUNT_API_KEY!,
projectId: process.env.LEXMOUNT_PROJECT_ID!,
baseURL: process.env.LEXMOUNT_BASE_URL!,
});
const current = await client.usage.current();
console.log(current.usage.browser_ms, current.remaining.webfetch_count);
const history = await client.usage.history();
for (const period of history.periods) {
if (period.usage === null) {
console.log(period.period_start, 'History unavailable');
} else {
console.log(period.period_start, period.usage);
}
}
const response = await client.usage.current({
withResponse: true, requestTimeoutMs: 30000, maxRetries: 2,
});
console.log(response.request_id, response.status_code, response.data);Default calls return data directly. withResponse: true includes data/request_id/status_code/headers. JavaScript timeouts use milliseconds.
Python SDK
import os
from lexmount import Lexmount
with Lexmount(
api_key=os.environ['LEXMOUNT_API_KEY'],
project_id=os.environ['LEXMOUNT_PROJECT_ID'],
base_url=os.environ['LEXMOUNT_BASE_URL'],
) as client:
current = client.usage.current()
print(current.usage.browser_ms, current.remaining.webfetch_count)
history = client.usage.history()
for period in history.periods:
if period.usage is None:
print(period.period_start, 'History unavailable')
else:
print(period.period_start, period.usage)
response = client.usage.current(
with_response=True, request_timeout=30.0, max_retries=2,
)
print(response.request_id, response.status_code, response.data)Python returns dataclasses with attribute access. with_response=True returns SDKResponse; Python timeouts use seconds.
import asyncio
import os
from lexmount import AsyncLexmount
async def main():
async with AsyncLexmount(
api_key=os.environ['LEXMOUNT_API_KEY'],
project_id=os.environ['LEXMOUNT_PROJECT_ID'],
base_url=os.environ['LEXMOUNT_BASE_URL'],
) as client:
current = await client.usage.current()
history = await client.usage.history()
print(current.usage, len(history.periods))
asyncio.run(main())Both SDKs default to a 30-second request timeout and 2 retries (allowed range 0–5). Network errors, timeouts and HTTP 429/502/503/504 use bounded backoff; other statuses are not automatically retried. Choose a polling interval appropriate for the API's rate limits.
