Request Logs
Endpoint
Section titled “Endpoint”GET https://api.bve.me/admin/request-logsAuthorization: Bearer admin_bve_YOUR_ADMIN_KEYReturns a sampled log of recent API requests. The gateway records approximately 1% of all requests (streaming and non-streaming) to this table, providing a representative sample without the storage cost of logging every call.
Query parameters
Section titled “Query parameters”| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
key_id | string | No | — | Filter by API key UUID (exact match) |
model | string | No | — | Filter by model ID, e.g. gpt-4o (exact match) |
endpoint | string | No | — | Filter by gateway endpoint path, e.g. /v1/chat/completions (exact match) |
request_id | string | No | — | Exact lookup by BVE request UUID — the same UUID returned in the X-Request-Id response header. Returns the single sampled log entry for that request, or an empty result if not in the 1% sample. |
error_code | string | No | — | Filter to only requests that were rejected with this error code (exact match). Common values: rate_limit_exceeded, model_not_allowed, invalid_request_error, authentication_error. Returns only sampled gateway-rejection rows; rows with no error code (successful requests) are excluded. |
status_range | string | No | — | HTTP status class filter. Accepted values: 2xx (successful), 4xx (client errors), 5xx (server errors). Returns 400 validation_error for any other value. |
search | string | No | — | Free-text substring filter applied across endpoint, model, and key_name columns (case-insensitive LIKE match, truncated to 200 chars). |
since | string | No | — | Return only entries at or after this ISO 8601 timestamp (e.g., 2026-05-01T00:00:00Z). Passing an invalid timestamp returns 400 validation_error. |
until | string | No | — | Return only entries at or before this ISO 8601 timestamp. Combine with since for a bounded time window. Passing an invalid timestamp returns 400 validation_error. |
min_latency_ms | integer | No | — | Return only entries where latency_ms is at or above this value (non-negative integer). Use to isolate slow requests. |
max_latency_ms | integer | No | — | Return only entries where latency_ms is at or below this value (non-negative integer). Combine with min_latency_ms for a range filter. Returns 400 validation_error if min > max. |
min_upstream_latency_ms | integer | No | — | Return only entries where upstream_latency_ms is at or above this value. Useful for isolating requests where Fuelix itself was slow (as distinct from gateway overhead). |
max_upstream_latency_ms | integer | No | — | Return only entries where upstream_latency_ms is at or below this value. Returns 400 validation_error if min > max. |
sort_by | string | No | created_at | Sort field. Accepted values: created_at, latency_ms, upstream_latency_ms, status. Returns 400 validation_error for any other value. |
sort_dir | string | No | desc | Sort direction. Accepted values: asc, desc. Returns 400 validation_error for any other value. |
limit | integer | No | 100 | Max entries to return (1–500) |
offset | integer | No | 0 | Number of entries to skip. Use with ?limit= for cursor-free pagination. |
All parameters are optional and combinable. For example, ?key_id=<uuid>&status_range=4xx&since=2026-05-01T00:00:00Z returns only client-error requests for a specific key since May 1.
Response (200)
Section titled “Response (200)”{ "total": 412, "stats": { "avg_latency_ms": 843, "max_latency_ms": 4210, "p50_latency_ms": 720, "p95_latency_ms": 3100, "total_tokens": 128450, "error_count": 15, "client_error_count": 12, "server_error_count": 3, "error_rate": 0.036 }, "logs": [ { "id": "660e8400-e29b-41d4-a716-446655440001", "key_id": "550e8400-e29b-41d4-a716-446655440000", "key_name": "production-app", "request_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "model": "gpt-4o", "endpoint": "/v1/chat/completions", "status": 200, "prompt_tokens": 128, "completion_tokens": 64, "latency_ms": 1234, "upstream_latency_ms": 1180, "error_code": null, "created_at": "2026-05-21T12:00:00.000Z" } ]}Response fields
Section titled “Response fields”| Field | Type | Description |
|---|---|---|
total | integer | Total number of sampled log entries matching the current filters (ignores limit/offset). Use for pagination UI. |
stats | object | Aggregate statistics computed across all matching rows (not limited by limit/offset). See Stats object fields. |
logs | array | Array of log entry objects (see below). |
Stats object fields
Section titled “Stats object fields”| Field | Type | Description |
|---|---|---|
avg_latency_ms | number | null | Mean gateway-to-upstream latency across matching rows. null if no rows. |
max_latency_ms | number | null | Maximum latency among matching rows. null if no rows. |
p50_latency_ms | number | null | Median (50th percentile) latency. null if no rows. |
p95_latency_ms | number | null | 95th percentile latency — use this for tail-latency alerting. null if no rows. |
total_tokens | integer | Sum of prompt_tokens + completion_tokens across all matching rows. |
error_count | integer | Number of rows where the HTTP status is 4xx or 5xx. |
client_error_count | integer | Number of rows where the HTTP status is 4xx (bad API key, quota exceeded, model blocked, validation error). |
server_error_count | integer | Number of rows where the HTTP status is 5xx (upstream failures, gateway errors). |
error_rate | number | error_count / total — fraction of sampled requests that resulted in an error. 0 if no rows. |
The stats object covers all rows matching the current filter set, regardless of limit/offset. It is computed in a parallel query alongside the logs page fetch, adding no extra latency.
Log entry fields
Section titled “Log entry fields”| Field | Type | Description |
|---|---|---|
id | string | UUID of the log entry |
key_id | string | UUID of the API key that made the request |
key_name | string | null | Human-readable name of the API key (null if the key has no name set) |
request_id | string | null | The X-Request-Id UUID assigned to the request and forwarded to Fuelix. Use this to correlate a sampled log row with Fuelix-side traces or with the X-Request-Id response header your client received. Null for requests logged before migration 0005. |
model | string | null | Model ID from the upstream response body |
endpoint | string | Gateway path (e.g. /v1/chat/completions) |
status | integer | HTTP status code returned to the client |
prompt_tokens | integer | Prompt token count from the upstream response |
completion_tokens | integer | Completion token count from the upstream response |
latency_ms | integer | Total gateway round-trip latency in ms (request received → upstream response body received). |
upstream_latency_ms | integer | null | Time Fuelix spent generating the response in ms — i.e. total latency minus gateway overhead. null for requests that were rejected by the gateway before reaching Fuelix (auth errors, quota, model filter). |
error_code | string | null | Gateway-level rejection code when the request was blocked before reaching Fuelix. Common values: rate_limit_exceeded (429 quota hit), model_not_allowed (403 key/global block), invalid_request_error (400 validation failure), authentication_error (401 bad key). null for successfully proxied requests. |
created_at | string | ISO 8601 timestamp |
cURL examples
Section titled “cURL examples”All recent logs
Section titled “All recent logs”curl "https://api.bve.me/admin/request-logs" \ -H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"Logs for a specific key
Section titled “Logs for a specific key”curl "https://api.bve.me/admin/request-logs?key_id=550e8400-e29b-41d4-a716-446655440000" \ -H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"Logs since a timestamp
Section titled “Logs since a timestamp”curl "https://api.bve.me/admin/request-logs?since=2026-05-01T00:00:00Z" \ -H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"Logs within a date range
Section titled “Logs within a date range”Combine since and until to query a bounded time window:
curl "https://api.bve.me/admin/request-logs?since=2026-05-01T00:00:00Z&until=2026-05-31T23:59:59Z" \ -H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"Most recent 10 entries
Section titled “Most recent 10 entries”curl "https://api.bve.me/admin/request-logs?limit=10" \ -H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"Filter by model
Section titled “Filter by model”curl "https://api.bve.me/admin/request-logs?model=gpt-4o" \ -H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"Filter by error code
Section titled “Filter by error code”Use ?error_code= to find all sampled gateway-rejection logs of a specific type:
# All sampled rate-limit rejections (RPM/RPD/monthly quotas)curl "https://api.bve.me/admin/request-logs?error_code=rate_limit_exceeded" \ -H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"
# All sampled model-not-allowed rejections for a specific keycurl "https://api.bve.me/admin/request-logs?key_id=550e8400-e29b-41d4-a716-446655440000&error_code=model_not_allowed" \ -H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"Filter by HTTP status class
Section titled “Filter by HTTP status class”Use ?status_range= to isolate successful, client-error, or server-error requests:
# Only 2xx (successful) requestscurl "https://api.bve.me/admin/request-logs?status_range=2xx" \ -H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"
# Only 4xx (client errors, e.g. invalid requests, quota exceeded)curl "https://api.bve.me/admin/request-logs?status_range=4xx" \ -H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"
# Only 5xx (gateway or upstream failures)curl "https://api.bve.me/admin/request-logs?status_range=5xx" \ -H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"Free-text search
Section titled “Free-text search”Use ?search= to filter by a substring across endpoint, model, and key_name:
# All logs where endpoint, model, or key name contains "embedding"curl "https://api.bve.me/admin/request-logs?search=embedding" \ -H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"Filter by endpoint
Section titled “Filter by endpoint”curl "https://api.bve.me/admin/request-logs?endpoint=/v1/chat/completions" \ -H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"Look up a request by its trace ID
Section titled “Look up a request by its trace ID”Each API response includes an X-Request-Id header. If a client reports an error with that ID, pass it as ?request_id= to do an exact server-side lookup (result is empty if the request was not in the 1% sample):
# The client received X-Request-Id: a1b2c3d4-e5f6-7890-abcd-ef1234567890curl "https://api.bve.me/admin/request-logs?request_id=a1b2c3d4-e5f6-7890-abcd-ef1234567890" \ -H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"Filter by gateway latency
Section titled “Filter by gateway latency”Use ?min_latency_ms= and ?max_latency_ms= to find slow or fast requests by total round-trip latency:
# All sampled requests that took more than 3 secondscurl "https://api.bve.me/admin/request-logs?min_latency_ms=3000" \ -H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"
# Requests between 1 and 5 secondscurl "https://api.bve.me/admin/request-logs?min_latency_ms=1000&max_latency_ms=5000" \ -H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"Filter by upstream (Fuelix) latency
Section titled “Filter by upstream (Fuelix) latency”Use ?min_upstream_latency_ms= to isolate requests where the model itself was slow, separate from gateway overhead:
# Requests where Fuelix took more than 2 secondscurl "https://api.bve.me/admin/request-logs?min_upstream_latency_ms=2000" \ -H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"
# gpt-4o requests with slow upstream, sorted slowest firstcurl "https://api.bve.me/admin/request-logs?model=gpt-4o&min_upstream_latency_ms=2000&sort_by=upstream_latency_ms&sort_dir=desc" \ -H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"Sort results
Section titled “Sort results”Use ?sort_by= with ?sort_dir= to control ordering. The default is sort_by=created_at&sort_dir=desc (most recent first):
# Slowest requests first (by total latency)curl "https://api.bve.me/admin/request-logs?sort_by=latency_ms&sort_dir=desc" \ -H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"
# Fastest requests first (by total latency)curl "https://api.bve.me/admin/request-logs?sort_by=latency_ms&sort_dir=asc" \ -H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"
# Sort by HTTP status code ascending (group 2xx before 4xx before 5xx)curl "https://api.bve.me/admin/request-logs?sort_by=status&sort_dir=asc" \ -H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"Valid sort_by values: created_at, latency_ms, upstream_latency_ms, status.
Combine model, endpoint, and time filters
Section titled “Combine model, endpoint, and time filters”curl "https://api.bve.me/admin/request-logs?model=gpt-4o&endpoint=/v1/chat/completions&since=2026-05-01T00:00:00Z" \ -H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"Paginate through logs
Section titled “Paginate through logs”Use ?limit= and ?offset= together for cursor-free pagination:
# Page 1 — first 50 entriescurl "https://api.bve.me/admin/request-logs?limit=50&offset=0" \ -H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"
# Page 2 — next 50 entriescurl "https://api.bve.me/admin/request-logs?limit=50&offset=50" \ -H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"Combine with any filter parameter to paginate filtered results:
curl "https://api.bve.me/admin/request-logs?model=gpt-4o&limit=50&offset=50" \ -H "Authorization: Bearer admin_bve_YOUR_ADMIN_KEY"- Entries are inserted with 1% probability per request. At 100 RPM a key produces roughly 1 sampled row per minute.
- Token counts are always accurate for sampled rows because the gateway buffers or tees the response body before sampling.
latency_msis total gateway round-trip time from request received to last byte of the upstream response. It includes gateway overhead (auth, quota checks, model filter) plus Fuelix response time.upstream_latency_msisolates Fuelix’s own response time (the Fuelix-side clock, not including network). It isnullwhen the request was rejected by the gateway before reaching Fuelix (auth, quota, model filter errors).request_idisnullfor rows logged before D1 migration 0005 (which added the column). All rows written after that migration include the UUID.- The
X-Request-Idheader is also returned on every API response so clients can record it for support requests. - The default sort order is
sort_by=created_at&sort_dir=desc(most recent first). Explicitsort_byandsort_diroverride this. - The
statsaggregate is computed over all rows matching the current filters regardless ofsort_by/sort_dir/limit/offset. - Request log rows are pruned by the daily cron job after 90 days.