SIGNALS Documentation
API Reference

Usage & Metering

Read aggregated API and webhook usage, request logs, and endpoint metering metadata.

Usage & Metering API

Read aggregated API and webhook usage, browse request log entries, and discover endpoint metering metadata. These meta endpoints support the API Console and external monitoring integrations.

All endpoints in this document require Sanctum bearer authentication and are declared with price weight 0 — they are logged but do not consume weighted metering units.

Unit weighting matrix

Every /api/v1 request consumes a fixed number of units based on the endpoint's declared #[PriceWeight]. Weights reflect the worst-case query plan, not the average request. There are no weights at 5 or 7.

Weight Class Description Examples
0 Meta / introspection Logged but excluded from weighted totals GET /usage, GET /endpoints, GET /request_logs, GET /schema
1 Simple read Show a resource; index with standard pagination GET /accounts/{id}, GET /countries
2 Complex read / simple write Index with heavy filters/includes; search; POST/PATCH a single resource GET /catalogue_items, GET /search, POST /addresses
3 Write with side effects Fires events, webhooks, or projections Rental item changes, status transitions, flightcase pack/seal
4 Compound operation Multi-entity writes, quote/document generation, bulk reads, semantic / AI search POST /documents/generate, GET /search/semantic, rental convert / quick book-out
6 Availability Scans asset calendars across a date range GET /availability/calendar, /gantt, /shortages, /timeline, product/asset availability
8 Heavy computation Shortage resolution, fleet-wide availability, bulk imports/exports GET /warehouses/{id}/availability, POST /shortage_resolutions, POST /imports, POST /exports

Tie-breaker

If an endpoint can be cheap or expensive depending on query parameters, it is priced at its worst-case plan. For example, a list that accepts deep Ransack filters and relation includes is weight 2, even when most callers page a small unfiltered set.

What is metered

Metering covers token-authenticated traffic only: requests to /api/v1 and calls made through the MCP server, including plugin-bridged MCP tools — every programmatic surface drains the same per-token unit throughput bucket. Web-UI sessions are deliberately not metered: a human working the interface is paced by the interface itself, whereas programmatic callers can issue expensive work in unbounded loops, and it is that traffic the budget exists to shape. Commercial metering and plan quotas layer on top of this same enforcement point rather than introducing a second one, so the scope above holds for them too.

Prefer webhooks over polling

Polling expensive endpoints burns units quickly. Prefer outbound webhooks for change notification.

Example: Polling an availability endpoint at weight 6 every 30 seconds is roughly 17,280 units/day (6 × 2 × 60 × 24) — over 500,000 units/month, before any other traffic. Subscribe to webhook events instead.

Endpoints

MethodURLSummaryAbilityWeight
GET/api/v1/endpointsList all registered API endpoints with metering metadatasystem:read0
GET/api/v1/request_logsList request log entries with optional filtering and paginationapi-log:read0
GET/api/v1/usageReturn grouped API usage aggregates for the requested windowapi-usage:read0
GET/api/v1/usage/exportExport usage aggregates as CSV (async)api-usage:read0

Authentication

Requires a Sanctum bearer token with the ability shown above. Requests without the required ability receive 403.

List Usage

GET /api/v1/usage

Returns grouped aggregates from the usage_daily rollup table.

Query parameters

Parameter Default Description
window 7d Date preset: 24h, 7d, 30d, or custom
from — Required when window=custom. Start date (Y-m-d)
to — Required when window=custom. End date (Y-m-d), must be on or after from
channel — Filter by metering channel: api, webhook_sent, or webhook_received
dimension endpoint Grouping: token, endpoint, resource, day, or status
token_id — Filter API-channel rows to a specific personal access token ID

Response

{
    "usage": [
        {
            "key": "api.v1.accounts.index",
            "label": null,
            "request_count": 142,
            "weighted_units": 284
        }
    ],
    "meta": {
        "totals": {
            "request_count": 1250,
            "weighted_units": 980
        },
        "window": {
            "preset": "7d",
            "from": "2026-06-25T00:00:00+00:00",
            "to": "2026-07-01T14:30:00+00:00"
        },
        "dimension": "endpoint"
    }
}
Field Description
usage[].key Group key — route name, token ID, resource name, date, or status class depending on dimension
usage[].label Human label when available (e.g. token name for token dimension)
usage[].request_count Total requests in the window
usage[].weighted_units Sum of price weights (weight-0 traffic contributes 0)
meta.totals Window totals across all groups
meta.window Resolved date window

Export Usage

GET /api/v1/usage/export

Accepts the same query parameters as GET /api/v1/usage. Dispatches an ExportApiUsage job and returns 202 Accepted with a job identifier. The CSV is delivered asynchronously (same export pipeline as the Usage dashboard).

List Request Logs

GET /api/v1/request_logs

Returns paginated detail rows from request_logs (API requests, outbound webhook deliveries, and inbound webhook receipts).

Filters (Ransack)

Parameter Description
q[route_name_eq]=api.v1.accounts.index Exact route name (API channel)
q[status_code_eq]=200 HTTP status code
q[personal_access_token_id_eq]=3 Token ID (API channel)
q[channel_eq]=api Metering channel: api, webhook_sent, webhook_received
q[created_at_gteq]=2026-07-01 Created on or after
q[created_at_lteq]=2026-07-01 Created on or before

Sorts

Parameter Description
sort=created_at Newest first (default when sort omitted)
sort=-created_at Oldest first
sort=status_code By status
sort=route_name By route name

Pagination

Standard offset pagination: ?page=2&per_page=20.

Response

{
    "request_logs": [
        {
            "id": 1,
            "channel": "api",
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "method": "GET",
            "uri": "/api/v1/accounts",
            "route_name": "api.v1.accounts.index",
            "resource": "accounts",
            "operation": "index",
            "personal_access_token_id": 3,
            "user_id": 1,
            "ability": "accounts:read",
            "status_code": 200,
            "duration_ms": 45,
            "request_bytes": 0,
            "response_bytes": 2048,
            "price_weight": 2,
            "weighted_units": 2,
            "ip_address": "127.0.0.1",
            "user_agent": "Signals-Explorer/1.0",
            "created_at": "2026-07-01T14:30:00Z"
        }
    ],
    "meta": {
        "total": 500,
        "per_page": 20,
        "page": 1
    }
}

Detail log CSV export is available from the API Console Request Log UI (not exposed as a REST endpoint).

List Endpoints

GET /api/v1/endpoints

Returns every registered v1 route with metering metadata from ApiEndpointCatalogue and PriceWeightResolver.

Response

{
    "endpoints": [
        {
            "name": "api.v1.accounts.index",
            "method": "GET",
            "uri": "/api/v1/accounts",
            "resource": "accounts",
            "operation": "index",
            "ability": "accounts:read",
            "price_weight": 2
        },
        {
            "name": "api.v1.usage.index",
            "method": "GET",
            "uri": "/api/v1/usage",
            "resource": null,
            "operation": null,
            "ability": "api-usage:read",
            "price_weight": 0
        }
    ]
}

Use this catalogue to discover required abilities and price weights before integrating. Weights of 0 indicate endpoints that are logged but excluded from weighted metering totals. The OpenAPI reference at /docs/api also surfaces each operation's unit cost as Cost: N units and the x-signals-units extension property.

Metering channels

Channel Source Default units
api LogApiRequest middleware on /api/v1/* Endpoint #[PriceWeight]
webhook_sent DeliverWebhook job (first delivery attempt) 1 (per event via WebhookEventRegistry)
webhook_received InboundWebhookController (valid signature only) Source-configured weight (0–4)