diff --git a/hpp-router/_MAINTAINERS.md b/hpp-router/_MAINTAINERS.md index cdccf72..92c31f5 100644 --- a/hpp-router/_MAINTAINERS.md +++ b/hpp-router/_MAINTAINERS.md @@ -27,5 +27,5 @@ Content is grounded in the [`hpp-router`](https://github.com/hpp-io/hpp-router) ## Follow-ups -- **Portal sign-up & API keys:** docs mention both the [HPP Router portal](https://router.hpp.io) and [HPP Hub](https://hub.hpp.io) for key issuance. +- **Portal sign-up & API keys:** docs currently mention [HPP Hub](https://hub.hpp.io) for key issuance. The Router Portal (`router.hpp.io`) will also support sign-up and key management — document once Portal sources are available. - **`audit` page:** not included yet; add when canonical audit/on-chain content is ready (see [hpp-router issue #93](https://github.com/hpp-io/hpp-router/issues/93)). diff --git a/hpp-router/api-reference/consumer-api.md b/hpp-router/api-reference/consumer-api.md index 8069096..b7caf51 100644 --- a/hpp-router/api-reference/consumer-api.md +++ b/hpp-router/api-reference/consumer-api.md @@ -5,7 +5,7 @@ description: HPP Router Consumer API — OpenAI-compatible endpoints, schemas, a # API Reference -HPP Router's request and response schemas are **OpenAI-compatible**, with HPP-specific extensions for smart routing headers and wallet payments (on-chain USDC.e). At a high level, you use the same patterns as the OpenAI Chat API — point your client at `https://router.hpp.io` and authenticate with your API key. +HPP Router's request and response schemas are **OpenAI-compatible**, with HPP-specific extensions for smart routing headers and prepaid quota. At a high level, you use the same patterns as the OpenAI Chat API — point your client at `https://router.hpp.io` and authenticate with your API key. ## OpenAPI Specification @@ -13,7 +13,8 @@ The complete Consumer API is documented using **OpenAPI 3.1**. The spec is the s | Format | Location | | --- | --- | -| **OpenAPI YAML** | [`consumer-v1.yaml`](./consumer-v1.yaml) | +| **YAML (bundled)** | [`consumer-v1.yaml`](./consumer-v1.yaml) in this repo | +| **YAML (source)** | [`hpp-router/openapi/consumer-v1.yaml`](https://github.com/hpp-io/hpp-router/blob/main/openapi/consumer-v1.yaml) | Import the spec into [Swagger UI](https://swagger.io/tools/swagger-ui/), [Postman](https://www.postman.com/), or an OpenAPI code generator to explore endpoints or produce client stubs. @@ -22,8 +23,7 @@ For live requests, use the [Router Playground](https://router.hpp.io/playground/ ## Base URL & auth - **Base URL:** `https://router.hpp.io` -- **Auth:** `apikey` header **or** `Authorization: Bearer ` for billed endpoints. `GET /llm/v1/models` does not require a key. - - For x402 wallet payments, keep the API key and also set `X-Payment-Rail: wallet`. Sign and retry with `PAYMENT-SIGNATURE` / `X-PAYMENT` after a `402`. See [Authentication](../authentication). +- **Auth:** `apikey` header **or** `Authorization: Bearer `. See [Authentication](../authentication). - **Version:** Consumer API `0.1.0`. ## Endpoints @@ -34,8 +34,7 @@ For live requests, use the [Router Playground](https://router.hpp.io/playground/ | `GET` | `/llm/v1/models` | [List available models](#get-llmv1models) | | `POST` | `/v1/images/generations` | [Generate images](#post-v1imagesgenerations) | | `GET` | `/api/usage` | [Get current consumer usage](#get-apiusage) | -| `GET` | `/api/quota-check` | [Check prepaid quota](#get-apiquotacheck) | -| `GET` | `/api/user/audit/:logId` | [Get user audit log](#get-apiuserauditlogid) | +| `GET` | `/api/quota-check` | [Check current consumer quota](#get-apiquota-check) | --- @@ -57,16 +56,10 @@ OpenAI-compatible chat completion endpoint with HPP smart-routing headers. Additional properties are allowed and passed through. -**Authentication:** Required. Use `apikey` header or `Authorization: Bearer ` for billing/usage tracking. - -For x402 wallet payments, append the `X-Payment-Rail: wallet` header and sign payments using the x402 protocol. - **Responses:** - `200` — `ChatCompletionResponse` (`application/json`) or an SSE stream (`text/event-stream`). Response headers include `X-HPP-Router-Resolved-Model`, `X-HPP-Router-Basket`, `X-HPP-Router-Rule-Id`, `X-HPP-Router-Rules-Version`, and `X-HPP-Router-Tier`. -- `401` — Authentication required. -- `402` — Payment required (for wallet rail). Response includes `PAYMENT-REQUIRED` header with payment specifications. -- `429`, `500` — error envelope. +- `400`, `401`, `429`, `500` — error envelope. See [Chat Completions](../guides/chat-completions) and [Smart Routing](../smart-routing). @@ -74,13 +67,9 @@ See [Chat Completions](../guides/chat-completions) and [Smart Routing](../smart- ## `GET /llm/v1/models` -Lists available models (OpenAI-compatible). **Authentication is optional** — Kong serves this route without `key-auth`. - -Each `Model` includes `id`, `object` (`"model"`), `owned_by`, optional catalog fields (`name`, `description`, `context`, `max_output`, `tool`, `structured`, `knowledge_cutoff`, `input_modalities`, `output_modalities`), and an optional `pricing` object. +Lists available models (OpenAI-compatible). Each `Model` has `id`, `object` (`"model"`), `owned_by`, and an optional `pricing` object (`input`, `output`, `cache_write`, `cache_read`). -`pricing.input` / `pricing.output` / `pricing.cache_write` / `pricing.cache_read` are **USD per token** (may be `null`). For `hpprouter/auto`, `pricing` is `null` — billing uses the resolved model. - -**Responses:** `200` — `ModelListResponse`; `500` — error envelope. +**Responses:** `200` — `ModelListResponse`; `401`, `500` — error envelope. See [Models & Pricing](../models-and-pricing). @@ -110,77 +99,23 @@ See [Image Generation](../guides/image-generation). ## `GET /api/usage` -Usage summary for the authenticated consumer. - -**Query params:** -- `rail` — optional filter: `wallet` or `quota`. When `rail=wallet`, response includes settlement fields and scopes request/token/cost stats to the wallet rail. +Usage and quota summary for the authenticated consumer. -**Response `200`** (`UsageResponse`): always `consumer_id`, `username`, `custom_id`, `quota`, `used`, `remaining`, `requests`, `total_tokens`, `total_cost`. With `?rail=wallet`, also `rail`, `spent_usdc_micro`, `settle_success_count`, `settle_failed_count`. +**Response `200`** (`UsageResponse`): `consumer_id`, `username`, `custom_id`, `quota`, `used`, `remaining`, `requests`, `total_tokens`, `total_cost`. **Errors:** `401`, `404`, `500`. -See [Usage & Settlement](../guides/usage-and-settlement). - --- ## `GET /api/quota-check` -Prepaid quota availability for the authenticated consumer (credit/quota rail). This is separate from on-chain wallet settlement. +Quota availability for the authenticated consumer. **Response `200`** (`QuotaCheckResponse`): `has_quota`, `quota`, `used`, `remaining`. -**Errors:** `401`, `503` (fail-closed when quota state cannot be verified), `500`. - -See [Usage & Settlement](../guides/usage-and-settlement#check-quota). - ---- - -## `GET /api/user/audit/:logId` - -Get a single audit log entry for the authenticated consumer. - -Access control: -- Personal consumers can only access their own logs -- Organization members can access any log from their organization's consumers - -**Path params:** -- `logId` — The audit log ID (UUID) - -**Query params:** -- `consumerId` — Filter by consumer (organization members only, must have access permission via `organization_members` table) - -**Response `200`:** - -```json -{ - "id": "log-xyz", - "consumer_id": "cons-123", - "provider": "openai", - "model": "gpt-4", - "prompt_tokens": 100, - "completion_tokens": 50, - "cache_creation_input_tokens": 0, - "cache_read_input_tokens": 0, - "total_tokens": 150, - "cost": 0.002, - "status": "success", - "blockchain_tx_hash": "0x...", - "payment_rail": "wallet", - "settle_status": "settled", - "settle_amount_micro": 25000, - "scope": "organization", - "organization": { - "id": "org-abc", - "name": "My Organization", - "consumerId": "cons-org-123", - "role": "admin" - } -} -``` - -**Errors:** `401` (not authenticated), `403` (no access to consumer), `404` (log not found), `500`. +**Errors:** `401`, `503`, `500`. -See [Usage & Settlement](../guides/usage-and-settlement) for more details. +See [Quota & Usage](../guides/quota-and-usage). --- diff --git a/hpp-router/api-reference/consumer-v1.yaml b/hpp-router/api-reference/consumer-v1.yaml index 4863a67..cde2429 100644 --- a/hpp-router/api-reference/consumer-v1.yaml +++ b/hpp-router/api-reference/consumer-v1.yaml @@ -64,10 +64,6 @@ paths: get: operationId: listModels summary: List available models - description: > - OpenAI-compatible model catalog with pricing and capability metadata. - Authentication is optional for this endpoint. - security: [] responses: "200": description: OpenAI-compatible model list. @@ -75,6 +71,8 @@ paths: application/json: schema: $ref: "#/components/schemas/ModelListResponse" + "401": + $ref: "#/components/responses/ErrorResponse" "500": $ref: "#/components/responses/ErrorResponse" /v1/images/generations: @@ -107,18 +105,6 @@ paths: get: operationId: getUsage summary: Get current consumer usage - description: > - Usage and prepaid quota summary for the authenticated consumer. - Pass `rail=wallet` to scope stats to the wallet payment rail and include - on-chain USDC.e settlement fields. - parameters: - - name: rail - in: query - required: false - schema: - type: string - enum: [wallet, quota] - description: Optional payment-rail filter. `wallet` adds settlement fields. responses: "200": description: Usage and quota summary for the authenticated consumer. @@ -294,66 +280,25 @@ components: const: model owned_by: type: string - name: - oneOf: - - type: string - - type: "null" - description: - oneOf: - - type: string - - type: "null" pricing: oneOf: - $ref: "#/components/schemas/ModelPricing" - type: "null" - context: - oneOf: - - type: number - - type: "null" - max_output: - oneOf: - - type: number - - type: "null" - tool: - oneOf: - - type: boolean - - type: "null" - structured: - oneOf: - - type: boolean - - type: "null" - knowledge_cutoff: - oneOf: - - type: string - - type: "null" - input_modalities: - type: array - items: - type: string - output_modalities: - type: array - items: - type: string ModelPricing: type: object - description: USD rates per token (multiply by 1_000_000 for $/1M). properties: input: type: number - description: USD per input token. output: type: number - description: USD per output token. cache_write: oneOf: - type: number - type: "null" - description: USD per cache-write token, when applicable. cache_read: oneOf: - type: number - type: "null" - description: USD per cache-read token, when applicable. ImageGenerationRequest: type: object required: @@ -430,37 +375,16 @@ components: - type: "null" quota: type: number - description: Prepaid quota limit (credit/quota rail snapshot). used: type: number - description: Prepaid quota consumed. remaining: type: number - description: Prepaid quota remaining. - rail: - type: string - enum: [wallet, quota] - description: Present when the request filtered by `?rail=`. - spent_usdc_micro: - type: number - description: > - Total USDC.e settled on-chain in atomic/micro units. - Present when `rail=wallet`. - settle_success_count: - type: integer - description: Successful on-chain settlements. Present when `rail=wallet`. - settle_failed_count: - type: integer - description: Failed on-chain settlements. Present when `rail=wallet`. requests: type: integer total_tokens: type: integer total_cost: type: number - description: > - Dollar cost. For `rail=wallet`, reflects wallet-settled spend from - usage logs rather than prepaid `used`. QuotaCheckResponse: type: object required: diff --git a/hpp-router/authentication.mdx b/hpp-router/authentication.mdx index aa6bd89..490eb0b 100644 --- a/hpp-router/authentication.mdx +++ b/hpp-router/authentication.mdx @@ -9,11 +9,11 @@ import CodePanel from '@site/src/components/CodePanel'; # Authentication -HPP Router uses **on-chain USDC.e payments** via x402 wallet. All requests require authentication with an API key for consumer identification. +Every request to HPP Router must be authenticated. The gateway uses the API key to identify the **consumer**, enforce per-consumer rate limits, and check the prepaid [quota](./guides/quota-and-usage) before forwarding the request to a provider. ## Getting an API key -API keys can be issued from the **[HPP Router portal](https://router.hpp.io)** and also through **[HPP Hub](https://hub.hpp.io)**. Treat the key like a password: keep it server-side and never commit it to source control. +API keys are issued through **[HPP Hub](https://hub.hpp.io)**, the HPP developer portal. Treat the key like a password: keep it server-side and never commit it to source control. ## Supported schemes @@ -23,13 +23,11 @@ HPP Router accepts two authentication schemes. Use whichever fits your client. - + ```bash showLineNumbers -curl https://router.hpp.io/llm/v1/chat/completions \ - -H "apikey: $HPPROUTER_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{"model":"openai/gpt-5","messages":[{"role":"user","content":"Hello"}]}' +curl https://router.hpp.io/llm/v1/models \ + -H "apikey: $HPPROUTER_API_KEY" ``` @@ -40,13 +38,11 @@ curl https://router.hpp.io/llm/v1/chat/completions \ - + ```bash showLineNumbers -curl https://router.hpp.io/llm/v1/chat/completions \ - -H "Authorization: Bearer $HPPROUTER_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{"model":"openai/gpt-5","messages":[{"role":"user","content":"Hello"}]}' +curl https://router.hpp.io/llm/v1/models \ + -H "Authorization: Bearer $HPPROUTER_API_KEY" ``` @@ -57,28 +53,15 @@ The Bearer scheme is what most OpenAI-compatible SDKs send by default, which is ## Which endpoints require auth -| Endpoint | Auth | Purpose | -| --- | --- | --- | -| `GET /llm/v1/models` | Optional | [List models](./models-and-pricing) | -| `POST /llm/v1/chat/completions` | Required (wallet: also `X-Payment-Rail: wallet`) | [Chat completions](./guides/chat-completions) | -| `POST /v1/images/generations` | Required (wallet: also `X-Payment-Rail: wallet`) | [Image generation](./guides/image-generation) | -| `GET /api/usage` | Required | [Usage summary](./guides/usage-and-settlement) | -| `GET /api/quota-check` | Required | [Check prepaid quota](./guides/usage-and-settlement#check-quota) | -| `GET /api/user/audit/:logId` | Required | [Get user audit log](./api-reference/consumer-api#get-apiuserauditlogid) | +All consumer endpoints are authenticated: -Billed endpoints require an API key so Kong can identify the consumer. Wallet payments still need the key; they additionally use the payment-rail header and x402 payment signature. - -For wallet payments, also include the `X-Payment-Rail: wallet` header. See [Chat Completions](./guides/chat-completions) for examples. - -## x402 Wallet - -HPP Router supports **x402 Wallet** for on-chain USDC.e payments. - -When you send a request with `X-Payment-Rail: wallet`, the gateway prompts your client to sign payment authorization using the x402 protocol. If no payment signature is present, the server responds with **`402`** and a `PAYMENT-REQUIRED` header (base64-encoded JSON) whose body includes an x402 `accepts` entry — typically `asset` (USDC.e contract), `amount` (atomic/micro units), `payTo`, network, and scheme metadata. - -For detailed information about the x402 payment flow, see: -- [x402 on HPP](/x402) -- [Wallet Payments Guide](./guides/chat-completions#wallet) +| Endpoint | Purpose | +| --- | --- | +| `POST /llm/v1/chat/completions` | [Chat completions](./guides/chat-completions) | +| `GET /llm/v1/models` | [List models](./models-and-pricing) | +| `POST /v1/images/generations` | [Image generation](./guides/image-generation) | +| `GET /api/usage` | [Usage summary](./guides/quota-and-usage) | +| `GET /api/quota-check` | [Quota check](./guides/quota-and-usage) | ## Errors @@ -91,5 +74,5 @@ A missing or invalid key returns **`401`**. See [Errors](./guides/errors) for th ## Security tips - Store the key in an environment variable or secret manager, never in client-side code. -- Rotate keys through the HPP Router portal or HPP Hub if a key may have been exposed. +- Rotate keys through HPP Hub if a key may have been exposed. - Prefer calling HPP Router from your backend so the key is never shipped to browsers or mobile apps. diff --git a/hpp-router/client-sdk/typescript.mdx b/hpp-router/client-sdk/typescript.mdx index 3ccdb04..485b645 100644 --- a/hpp-router/client-sdk/typescript.mdx +++ b/hpp-router/client-sdk/typescript.mdx @@ -110,18 +110,12 @@ See [Streaming](../guides/streaming) for the streaming-fallback behavior of `hpp ## Models -`models.list()` does **not** require an API key. - ```ts showLineNumbers -const catalogClient = new HppRouter({ - baseURL: 'https://router.hpp.io', -}); - -const models = await catalogClient.models.list(); +const models = await client.models.list(); console.log(models.data.data); ``` @@ -129,7 +123,7 @@ console.log(models.data.data); -## Usage & quota +## Usage and quota @@ -137,18 +131,17 @@ console.log(models.data.data); ```ts showLineNumbers const usage = await client.usage.get(); -console.log(usage.data); - -// Prepaid quota rail (still available alongside wallet settlement) const quota = await client.quota.check(); -console.log(quota.data); + +console.log(usage.data.remaining); +console.log(quota.data.has_quota); ``` -See [Usage & Settlement](../guides/usage-and-settlement) for more details. +See [Quota & Usage](../guides/quota-and-usage). ## Image generation diff --git a/hpp-router/guides/chat-completions.mdx b/hpp-router/guides/chat-completions.mdx index 37a3561..699798e 100644 --- a/hpp-router/guides/chat-completions.mdx +++ b/hpp-router/guides/chat-completions.mdx @@ -15,26 +15,15 @@ The chat completions endpoint is the core of HPP Router. It is OpenAI-compatible POST https://router.hpp.io/llm/v1/chat/completions ``` -## Payment methods - -HPP Router supports **x402 Wallet** for on-chain USDC.e payments. Set `X-Payment-Rail: wallet` and include your API key for authentication. - -See [Authentication](../authentication) for details. - -### Basic request (wallet) - -Include both the payment rail header and your API key: - - +## Basic request - - + + ```bash showLineNumbers curl -X POST https://router.hpp.io/llm/v1/chat/completions \ -H "apikey: $HPPROUTER_API_KEY" \ - -H "X-Payment-Rail: wallet" \ -H "Content-Type: application/json" \ -d '{ "model": "openai/gpt-5", @@ -50,8 +39,6 @@ curl -X POST https://router.hpp.io/llm/v1/chat/completions \ -The server will prompt for wallet payment authorization using the x402 protocol. - ## Request fields | Field | Type | Notes | @@ -102,4 +89,4 @@ The `usage` block drives [billing](../models-and-pricing). When you use `hpprout ## Errors -Requests are checked against your wallet balance before being forwarded. Insufficient funds return **`429`**; auth failures return **`401`**. Wallet requests may also return **`402 PAYMENT REQUIRED`** with payment instructions. See [Errors](./errors). +Requests are checked against your quota before being forwarded. Insufficient quota returns **`429`**; auth failures return **`401`**. See [Errors](./errors). diff --git a/hpp-router/guides/errors.md b/hpp-router/guides/errors.md index 28c2cb8..b2b1f4c 100644 --- a/hpp-router/guides/errors.md +++ b/hpp-router/guides/errors.md @@ -5,7 +5,7 @@ description: HTTP status codes and the error envelope returned by HPP Router. # Errors -HPP Router returns standard HTTP status codes and a JSON error envelope. Handle these in your client to distinguish auth, wallet balance, and upstream failures. +HPP Router returns standard HTTP status codes and a JSON error envelope. Handle these in your client to distinguish auth, quota, and upstream failures. ## Status codes @@ -13,9 +13,9 @@ HPP Router returns standard HTTP status codes and a JSON error envelope. Handle | --- | --- | --- | | `400` | Bad Request | Malformed body, or an unroutable/unsupported model. | | `401` | Unauthorized | Missing or invalid API key. See [Authentication](../authentication). | -| `429` | Too Many Requests / Insufficient Funds | Rate limit hit, or insufficient wallet balance. See [Wallet Payments](../authentication#x402-wallet) for details. | +| `429` | Too Many Requests / Quota Exceeded | Rate limit hit, or insufficient [quota](./quota-and-usage). | | `500` | Internal Server Error | Unexpected gateway or upstream error. | -| `503` | Service Unavailable | Wallet settlement could not be verified (fail-closed). | +| `503` | Service Unavailable | Quota state could not be verified (fail-closed). | ## Error envelope @@ -66,6 +66,6 @@ When using [`hpprouter/auto`](../smart-routing), you may encounter: ## Handling guidance - **`401`** — fix your API key; do not retry blindly. -- **`429`** — back off and retry; if it's an insufficient funds issue, bridge or top up **USDC.e** on HPP (see [Networks & token](/x402/networks-and-token) and the [Bridge guide](/community/bridge)). +- **`429`** — back off and retry; if it's a quota issue, top up via [HPP Hub](https://hub.hpp.io). - **`5xx`** with `retryable: true` — retry with exponential backoff. - **`5xx`** with `retryable: false` — surface the error; retrying will not help. diff --git a/hpp-router/guides/image-generation.mdx b/hpp-router/guides/image-generation.mdx index e29e34d..3050f50 100644 --- a/hpp-router/guides/image-generation.mdx +++ b/hpp-router/guides/image-generation.mdx @@ -17,18 +17,13 @@ POST https://router.hpp.io/v1/images/generations ## Request -### Wallet - -Include both the payment rail header and your API key: - - + ```bash showLineNumbers curl -X POST https://router.hpp.io/v1/images/generations \ -H "apikey: $HPPROUTER_API_KEY" \ - -H "X-Payment-Rail: wallet" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-image-1", @@ -75,19 +70,15 @@ The image is returned as base64 (`b64_json`). The `usage` block reports the toke ## Pricing (token-based) -Image generation is billed per token, like chat. For `openai/gpt-image-1`: +Image generation is billed per token, like chat: -- **Input (text tokens):** $5 per 1M tokens (`0.000005` / token) -- **Output (image tokens):** $40 per 1M tokens (`0.00004` / token) - -Confirm live rates with `GET /llm/v1/models`. +- **Input:** $10 per 1M tokens ($0.00001 / token) +- **Output:** $40 per 1M tokens ($0.00004 / token) Higher `quality` settings consume more **output tokens** — for example, `auto` can use roughly 15× the output tokens of `low`. Choose the lowest quality that meets your needs to control cost. -## Wallet payments - -All image generation requests require authentication with an API key. For wallet payments, include the `X-Payment-Rail: wallet` header. +## Quota management -- Requests are processed on-chain via x402 protocol. -- If wallet settlement fails, the endpoint returns **`402 PAYMENT REQUIRED`** with payment instructions. See [Errors](./errors). -- Usage is tracked automatically and settled on-chain after completion. +- Requests are checked against your [quota](./quota-and-usage) before being forwarded. +- If quota is insufficient, the endpoint returns **`429`** (quota exceeded). See [Errors](./errors). +- Usage is tracked automatically and deducted from your quota. diff --git a/hpp-router/guides/openai-sdk.mdx b/hpp-router/guides/openai-sdk.mdx index ddf64ee..849ea43 100644 --- a/hpp-router/guides/openai-sdk.mdx +++ b/hpp-router/guides/openai-sdk.mdx @@ -84,4 +84,4 @@ OpenAI SDKs send the key as `Authorization: Bearer `, which HPP Router acce ## When to prefer `@hpprouter/sdk` -The dedicated [TypeScript SDK](../client-sdk/typescript) returns smart-routing metadata (resolved model, basket, tier) alongside the response, and provides typed helpers for usage and images. Use it when you want first-class access to HPP Router-specific features; use the OpenAI SDK when you want a minimal-change drop-in. +The dedicated [TypeScript SDK](../client-sdk/typescript) returns smart-routing metadata (resolved model, basket, tier) alongside the response, and provides typed helpers for usage, quota, and images. Use it when you want first-class access to HPP Router-specific features; use the OpenAI SDK when you want a minimal-change drop-in. diff --git a/hpp-router/guides/quota-and-usage.mdx b/hpp-router/guides/quota-and-usage.mdx new file mode 100644 index 0000000..2ec85eb --- /dev/null +++ b/hpp-router/guides/quota-and-usage.mdx @@ -0,0 +1,108 @@ +--- +title: Quota & Usage +description: Check remaining quota and review usage with HPP Router's prepaid quota model. +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import CodePanel from '@site/src/components/CodePanel'; + +# Quota & Usage + +HPP Router uses a **prepaid quota** model: each consumer has a dollar-denominated quota, and every request is checked against the remaining balance *before* it reaches a provider. Token usage is then metered and deducted. + +## Quota model + +| Term | Meaning | +| --- | --- | +| `quota` | Total dollar allowance for the consumer. | +| `used` | Dollars already accrued from usage. | +| `remaining` | `quota − used` — headroom before the cap. | +| `has_quota` | `true` when `remaining > 0`. | + +When a request arrives, the gateway verifies the consumer has quota. If not, the request is rejected with **`429`** before any provider is called (fail-fast). See [Errors](./errors). + +## Check quota + +A lightweight pre-flight check for the authenticated consumer: + + + + + +```bash showLineNumbers +curl https://router.hpp.io/api/quota-check \ + -H "apikey: $HPPROUTER_API_KEY" +``` + + + + + +```json showLineNumbers +{ + "has_quota": true, + "quota": 100, + "used": 12.5, + "remaining": 87.5 +} +``` + +If the quota state cannot be verified (e.g. a backend datastore is unavailable), the endpoint may return **`503`**. The quota policy is **fail-closed**: when state cannot be trusted, requests are denied rather than allowed, to protect billing correctness. + +## Usage summary + +A fuller summary of consumption for the authenticated consumer: + + + + + +```bash showLineNumbers +curl https://router.hpp.io/api/usage \ + -H "apikey: $HPPROUTER_API_KEY" +``` + + + + + +```json showLineNumbers +{ + "consumer_id": "....", + "username": "alice", + "custom_id": "user-001", + "quota": 100, + "used": 12.5, + "remaining": 87.5, + "requests": 42, + "total_tokens": 18500, + "total_cost": 12.5 +} +``` + +| Field | Meaning | +| --- | --- | +| `consumer_id` | The authenticated consumer's id. | +| `username` / `custom_id` | Optional identifiers (may be `null`). | +| `quota` / `used` / `remaining` | The quota balance (see above). | +| `requests` | Number of requests recorded. | +| `total_tokens` | Total tokens consumed. | +| `total_cost` | Total dollar cost accrued. | + +## How usage is metered + +1. The response from the provider is captured asynchronously (no added latency). +2. Token usage is extracted from the response `usage` block. +3. Cost is computed from the [resolved model's pricing](../models-and-pricing). +4. The consumer's `used` value is updated and the request is logged. + +For `hpprouter/auto`, cost uses the **resolved** model's pricing, not a price for `auto`. See [Smart Routing](../smart-routing). + +## Performance note + +The quota-check path is backed by a short-lived in-memory cache to reduce database load under bursts of traffic, with concurrent lookups for the same consumer collapsed into a single read. Cached values are kept fresh for a few seconds and invalidated immediately when an admin changes a consumer's quota, so the figures you read stay accurate. + +## Local models + +Requests to local models (e.g. `ollama/*`) are tracked at **$0 cost**, but token usage is still recorded in your usage logs. diff --git a/hpp-router/guides/streaming.mdx b/hpp-router/guides/streaming.mdx index 287410b..4addf7c 100644 --- a/hpp-router/guides/streaming.mdx +++ b/hpp-router/guides/streaming.mdx @@ -19,18 +19,13 @@ Accept: text/event-stream ## REST (curl) -### Wallet (with API key) - -Include both the payment rail header and your API key: - - + ```bash showLineNumbers curl -N -X POST https://router.hpp.io/llm/v1/chat/completions \ -H "apikey: $HPPROUTER_API_KEY" \ - -H "X-Payment-Rail: wallet" \ -H "Content-Type: application/json" \ -d '{ "model": "openai/gpt-5", @@ -55,47 +50,16 @@ data: [DONE] ## TypeScript SDK -### Wallet (with API key) - -Include both the payment rail header and your API key: - - - -```ts showLineNumbers -import { HppRouter } from '@hpprouter/sdk'; - -const client = new HppRouter({ - apiKey: process.env.HPPROUTER_API_KEY!, - baseURL: 'https://router.hpp.io', -}); - -const { stream, meta } = await client.chat.stream({ - model: 'openai/gpt-5', - messages: [{ role: 'user', content: 'Stream a short answer.' }], -}); - -for await (const event of stream) { - console.log(event); -} - -console.log(meta.resolvedModel); -``` - - - + ```ts showLineNumbers import { HppRouter } from '@hpprouter/sdk'; -// Wallet rail is not a built-in SDK option — set X-Payment-Rail via defaultHeaders. const client = new HppRouter({ apiKey: process.env.HPPROUTER_API_KEY!, baseURL: 'https://router.hpp.io', - defaultHeaders: { - 'X-Payment-Rail': 'wallet', - }, }); const { stream, meta } = await client.chat.stream({ diff --git a/hpp-router/guides/usage-and-settlement.mdx b/hpp-router/guides/usage-and-settlement.mdx deleted file mode 100644 index f96aef9..0000000 --- a/hpp-router/guides/usage-and-settlement.mdx +++ /dev/null @@ -1,140 +0,0 @@ ---- -title: Usage & Settlement -description: Check prepaid quota, review usage, and inspect on-chain USDC.e settlement with HPP Router. ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; -import CodePanel from '@site/src/components/CodePanel'; - -# Usage & Settlement - -HPP Router uses **on-chain USDC.e payments** via x402 wallet for billed inference. All requests require authentication with an API key for consumer identification. - -Token usage is metered and, on the wallet rail, settled on-chain after the request completes. Prepaid **quota** balance checks remain available for consumers that still use the credit/quota rail. - -## Check quota - -A lightweight pre-flight check for the authenticated consumer's prepaid quota (independent of on-chain wallet settlement): - - - - - - - -```bash showLineNumbers -curl https://router.hpp.io/api/quota-check \ - -H "apikey: $HPPROUTER_API_KEY" -``` - - - - - -```json showLineNumbers -{ - "has_quota": true, - "quota": 100, - "used": 12.5, - "remaining": 87.5 -} -``` - -If the quota state cannot be verified (e.g. a backend datastore is unavailable), the endpoint may return **`503`**. The quota policy is **fail-closed**: when state cannot be trusted, requests are denied rather than allowed, to protect billing correctness. - -## Usage summary - -A summary of consumption for the authenticated consumer. The default response always includes prepaid quota fields (`quota`, `used`, `remaining`). Pass `?rail=wallet` to scope stats to the wallet payment rail and include on-chain settlement fields. - -### Default (quota fields) - - - - - -```bash showLineNumbers -curl https://router.hpp.io/api/usage \ - -H "apikey: $HPPROUTER_API_KEY" -``` - - - - - -```json showLineNumbers -{ - "consumer_id": "....", - "username": "alice", - "custom_id": "user-001", - "quota": 100, - "used": 12.5, - "remaining": 87.5, - "requests": 42, - "total_tokens": 18500, - "total_cost": 12.5 -} -``` - -### Wallet rail (`?rail=wallet`) - - - - - -```bash showLineNumbers -curl "https://router.hpp.io/api/usage?rail=wallet" \ - -H "apikey: $HPPROUTER_API_KEY" -``` - - - - - -```json showLineNumbers -{ - "consumer_id": "....", - "username": "alice", - "custom_id": "user-001", - "quota": 100, - "used": 12.5, - "remaining": 87.5, - "rail": "wallet", - "spent_usdc_micro": 2500000, - "settle_success_count": 3, - "settle_failed_count": 0, - "requests": 42, - "total_tokens": 18500, - "total_cost": 12.5 -} -``` - -| Field | Meaning | -| --- | --- | -| `consumer_id` | The authenticated consumer's id. | -| `username` / `custom_id` | Optional identifiers (may be `null`). | -| `quota` / `used` / `remaining` | Prepaid quota snapshot (always present). | -| `rail` | Present when filtered, e.g. `"wallet"`. | -| `spent_usdc_micro` | Total USDC.e settled on-chain (atomic/micro units). Present when `rail=wallet`. | -| `settle_success_count` | Successful on-chain settlements (`rail=wallet`). | -| `settle_failed_count` | Failed settlements (`rail=wallet`). | -| `requests` | Number of requests recorded (scoped by `rail` when set). | -| `total_tokens` | Total tokens consumed (scoped by `rail` when set). | -| `total_cost` | Dollar cost; for `rail=wallet`, reflects wallet-settled spend from usage logs. | - -## How usage is metered - -1. The response from the provider is captured asynchronously (no added latency). -2. Token usage is extracted from the response `usage` block. -3. Cost is computed from the [resolved model's pricing](../models-and-pricing). -4. The request is logged; on the wallet rail, settlement proceeds via x402. On the quota rail, the consumer's `used` value is updated. - -For `hpprouter/auto`, cost uses the **resolved** model's pricing, not a price for `auto`. See [Smart Routing](../smart-routing). - -## Performance note - -The usage endpoint is backed by a short-lived in-memory cache to reduce database load under bursts of traffic, with concurrent lookups for the same consumer collapsed into a single read. Cached values are kept fresh for a few seconds and invalidated immediately when an admin changes a consumer's quota, so the figures you read stay accurate. - -## Local models - -Requests to local models (e.g. `ollama/*`) are tracked at **$0 cost**, but token usage is still recorded in your usage logs. diff --git a/hpp-router/guides/vision-multimodal.mdx b/hpp-router/guides/vision-multimodal.mdx index 44a8bfc..6cd5dd5 100644 --- a/hpp-router/guides/vision-multimodal.mdx +++ b/hpp-router/guides/vision-multimodal.mdx @@ -15,18 +15,13 @@ Vision-capable models accept images alongside text in the same chat completion r Use an array of content parts in a message, mixing `text` and `image_url`: -### Wallet (with API key) - -Include both the payment rail header and your API key: - - + ```bash showLineNumbers curl -X POST https://router.hpp.io/llm/v1/chat/completions \ -H "apikey: $HPPROUTER_API_KEY" \ - -H "X-Payment-Rail: wallet" \ -H "Content-Type: application/json" \ -d '{ "model": "openai/gpt-4o", diff --git a/hpp-router/intro.md b/hpp-router/intro.md index 9c1e7f9..03170c8 100644 --- a/hpp-router/intro.md +++ b/hpp-router/intro.md @@ -6,7 +6,7 @@ description: What HPP Router is, how requests flow through the gateway, and wher # HPP Router -**HPP Router** is an OpenAI-compatible LLM API gateway for the HPP ecosystem. It sends each request to the right model across providers, enforces wallet-based on-chain payments per consumer, and tracks usage — all behind a single API key and a single base URL. +**HPP Router** is an OpenAI-compatible LLM API gateway for the HPP ecosystem. It sends each request to the right model across providers, enforces a prepaid quota per consumer, and tracks usage — all behind a single API key and a single base URL. ``` https://router.hpp.io @@ -16,28 +16,29 @@ https://router.hpp.io - **One API, many models.** Call OpenAI, Anthropic, Moonshot, or local Ollama models through one OpenAI-compatible endpoint. Switch models by changing a single `model` string. - **Smart routing.** Use the virtual model [`hpprouter/auto`](/hpp-router/smart-routing) and let the gateway pick a cost-appropriate model per request based on configurable rules. -- **On-chain wallet payments** — Every request is tracked for usage and settled on-chain via x402 (USDC.e). Token usage is metered and billed at the resolved model's pricing. +- **Prepaid quota & usage tracking.** Every request is checked against the consumer's remaining quota before it reaches a provider, and token usage is metered and billed against the [resolved model's pricing](/hpp-router/models-and-pricing). - **Drop-in compatibility.** Existing OpenAI SDK code works by pointing the base URL at `https://router.hpp.io` and using your HPP Router API key. ## How a request flows ``` -Client → Kong Gateway (key-auth, rate-limiting) +Client → Kong Gateway (key-auth, rate-limiting, quota check) → llm-router (resolves provider/model, incl. hpprouter/auto) → upstream provider (OpenAI / Anthropic / Ollama) → response captured for async usage logging - → PostgreSQL (usage logs, blockchain settlement) + → PostgreSQL (consumer quotas, usage logs) ``` 1. A request arrives with your API key. 2. The gateway authenticates the consumer and applies rate limits. -3. The router resolves the target `provider/model` — or, for `hpprouter/auto`, classifies the request and picks a model from rules. -4. The upstream provider is called and the response is returned to you. If x402 wallet payment is used (`X-Payment-Rail: wallet`), the server will prompt for on-chain payment authorization. -5. Token usage is extracted asynchronously (no added latency) and settled on-chain via x402 protocol. +3. The quota layer verifies the consumer still has available quota (fail-fast otherwise). +4. The router resolves the target `provider/model` — or, for `hpprouter/auto`, classifies the request and picks a model from rules. +5. The upstream provider is called and the response is returned to you. +6. Token usage is extracted asynchronously (no added latency) and deducted from the consumer's quota. ## Where HPP Router fits in the HPP ecosystem -HPP Router is the **model router** layer of the HPP stack — an AI-native L2 built for agents. It routes inference requests across the network (including HPP Coder). API keys can be issued from the **[HPP Router portal](https://router.hpp.io)** and also through **[HPP Hub](https://hub.hpp.io)** (see also the [HPP Hub guide](/hub)). +HPP Router is the **model router** layer of the HPP stack — an AI-native L2 built for agents. It routes inference requests across the network (including HPP Coder), and API keys are issued through **[HPP Hub](https://hub.hpp.io)** (see also the [HPP Hub guide](/hub)). ## Next steps diff --git a/hpp-router/models-and-pricing.mdx b/hpp-router/models-and-pricing.mdx index d311fbb..d2db73c 100644 --- a/hpp-router/models-and-pricing.mdx +++ b/hpp-router/models-and-pricing.mdx @@ -1,6 +1,6 @@ --- title: Models & Pricing -description: Discover available models and understand HPP Router's token-based, on-chain USDC.e billing. +description: Discover available models and understand HPP Router's token-based, prepaid billing. --- import Tabs from '@theme/Tabs'; @@ -9,64 +9,41 @@ import CodePanel from '@site/src/components/CodePanel'; # Models & Pricing -HPP Router exposes models from multiple providers behind one OpenAI-compatible API. Billing is **token-based** and settled on-chain via x402 wallet (USDC.e). +HPP Router exposes models from multiple providers behind one OpenAI-compatible API. Billing is **token-based** and deducted from your prepaid [quota](./guides/quota-and-usage). ## Listing models -Use the OpenAI-compatible models endpoint to discover what's available, including the virtual `hpprouter/auto` model. **No API key is required** for this endpoint. +Use the OpenAI-compatible models endpoint to discover what's available, including the virtual `hpprouter/auto` model: - + ```bash showLineNumbers -curl https://router.hpp.io/llm/v1/models +curl https://router.hpp.io/llm/v1/models \ + -H "apikey: $HPPROUTER_API_KEY" ``` -The response is an OpenAI-style list with pricing and capability metadata. `pricing.*` values are **USD per token** (multiply by `1_000_000` for the familiar $/1M figure): +The response is an OpenAI-style list. Each model may include a `pricing` object: ```json showLineNumbers { "object": "list", "data": [ - { - "id": "hpprouter/auto", - "object": "model", - "owned_by": "hpprouter", - "name": "Auto", - "description": "Smart routing picks a provider and model based on your request.", - "pricing": null, - "context": null, - "max_output": null, - "tool": null, - "structured": null, - "knowledge_cutoff": null, - "input_modalities": [], - "output_modalities": [] - }, { "id": "openai/gpt-5", "object": "model", "owned_by": "openai", - "name": "GPT-5", - "description": null, "pricing": { - "input": 0.00000125, - "output": 0.00001, + "input": 1.25, + "output": 10, "cache_write": null, - "cache_read": 1.25e-7 - }, - "context": 272000, - "max_output": 128000, - "tool": true, - "structured": true, - "knowledge_cutoff": null, - "input_modalities": ["text", "image"], - "output_modalities": ["text"] + "cache_read": null + } } ] } @@ -76,18 +53,12 @@ The response is an OpenAI-style list with pricing and capability metadata. `pric | --- | --- | | `id` | Model identifier — use this as the request `model`. | | `owned_by` | Provider that owns the model. | -| `name` / `description` | Display name and short description (may be `null`). | -| `pricing` | `null` for `hpprouter/auto` (billed at the resolved model). | -| `pricing.input` | USD **per input token**. | -| `pricing.output` | USD **per output token**. | -| `pricing.cache_write` / `cache_read` | USD **per cache token**, when applicable (may be `null`). | -| `context` / `max_output` | Context window and max output tokens, when known. | -| `tool` / `structured` | Tool calling / structured output support (may be `null`). | -| `knowledge_cutoff` | Knowledge cutoff date string, when known. | -| `input_modalities` / `output_modalities` | Accepted / produced modalities (e.g. `text`, `image`). | +| `pricing.input` | Price per 1M input tokens (USD). | +| `pricing.output` | Price per 1M output tokens (USD). | +| `pricing.cache_write` / `cache_read` | Cache pricing per 1M tokens, when applicable (may be `null`). | :::note -The models list is the source of truth for what is currently enabled. The example rates below are illustrative and may change. +The models list is the source of truth for what is currently enabled. The examples below are illustrative pricing taken from the gateway documentation and may change. ::: ## Model identifiers @@ -106,10 +77,8 @@ Specify a model as **`provider/model`**, or use the virtual smart-routing model: ## How billing works -- API `pricing.*` values are **USD per token**. Human-readable $/1M ≈ `pricing.input × 1_000_000`. -- When using **$/1M** rates from the table below, cost ≈ `(prompt_tokens × input_rate + completion_tokens × output_rate) / 1,000,000`. -- When plugging API `pricing.*` values directly, omit the `/ 1,000,000` and also include cache tokens when present: - `(prompt_tokens × input) + (completion_tokens × output) + (cache_write_tokens × cache_write) + (cache_read_tokens × cache_read)`. +- Pricing is **per million tokens**, split into **input** (prompt) and **output** (completion) rates. +- Cost for a request ≈ `(prompt_tokens × input_rate + completion_tokens × output_rate) / 1,000,000`. - The `usage` block in each response reports the token counts used for billing. - Local models (e.g. `ollama/*`) are tracked at **$0 cost**, but token usage is still logged. @@ -118,17 +87,17 @@ Specify a model as **`provider/model`**, or use the virtual smart-routing model: | Model | Input (per 1M) | Output (per 1M) | | --- | --- | --- | | `openai/gpt-5` | $1.25 | $10 | -| `openai/gpt-image-1` (image generation) | $5 | $40 | +| `gpt-image-1` (image generation) | $10 | $40 | See [Image Generation](./guides/image-generation) for how image quality affects output-token usage. ## Billing with smart routing -When you request `hpprouter/auto`, billing uses the **resolved** model's pricing — not a price for `auto` itself (`pricing` is `null` on the models list). The resolved model is returned in the `X-HPP-Router-Resolved-Model` response header and recorded in your usage logs. See [Smart Routing](./smart-routing) for details. +When you request `hpprouter/auto`, billing uses the **resolved** model's pricing — not a price for `auto` itself. The resolved model is returned in the `X-HPP-Router-Resolved-Model` response header and recorded in your usage logs. See [Smart Routing](./smart-routing) for details. -## Checking your usage +## Checking your quota and usage -- `GET /api/quota-check` — check prepaid quota remaining for the authenticated consumer. -- `GET /api/usage` — usage summary (requests, total tokens, total cost); use `?rail=wallet` for on-chain settlement fields. +- `GET /api/quota-check` — remaining quota for the authenticated consumer. +- `GET /api/usage` — usage summary (requests, total tokens, total cost, remaining quota). -See [Usage & Settlement](./guides/usage-and-settlement). +See [Quota & Usage](./guides/quota-and-usage). diff --git a/hpp-router/quickstart.mdx b/hpp-router/quickstart.mdx index e63c075..c61c185 100644 --- a/hpp-router/quickstart.mdx +++ b/hpp-router/quickstart.mdx @@ -13,8 +13,7 @@ Send the same chat completion request using the stack you prefer. All examples t ## Prerequisites -- An **HPP Router API key** from the [HPP Router portal](https://router.hpp.io) or [HPP Hub](https://hub.hpp.io) (required for Kong authentication) -- x402 wallet payments for on-chain USDC.e transactions (wallet payment rail: `X-Payment-Rail: wallet`) +- An **HPP Router API key** from [HPP Hub](https://hub.hpp.io) - Base URL: `https://router.hpp.io` Store your key in an environment variable: @@ -72,7 +71,7 @@ console.log(completion.choices[0].message); ``` - + ```bash showLineNumbers curl -X POST https://router.hpp.io/llm/v1/chat/completions \ @@ -139,4 +138,4 @@ When you use `hpprouter/auto`, the model used for billing is returned in the `X- - [Authentication](./authentication) — API key vs. Bearer token. - [Models & Pricing](./models-and-pricing) — discover available models. -- [Guides](./guides/chat-completions) — chat, streaming, vision, images, and errors. +- [Guides](./guides/chat-completions) — chat, streaming, vision, images, quota, and errors. diff --git a/hpp-router/smart-routing.mdx b/hpp-router/smart-routing.mdx index d923ed6..c486938 100644 --- a/hpp-router/smart-routing.mdx +++ b/hpp-router/smart-routing.mdx @@ -19,7 +19,7 @@ When you send `model: "hpprouter/auto"`, the gateway classifies the request and - + ```bash showLineNumbers curl -sS -D /tmp/headers.txt -o /tmp/out.json \ @@ -77,7 +77,7 @@ To read `X-HPP-Router-*` headers from browser JavaScript, the gateway must expos ## Billing -Billing always uses the **resolved** model's pricing and the upstream `usage`. The resolved model is recorded in your [usage logs](./guides/usage-and-settlement). +Billing always uses the **resolved** model's pricing and the upstream `usage` — there is no separate price for `hpprouter/auto`. The resolved model is recorded in your [usage logs](./guides/quota-and-usage). ## Notes for client apps diff --git a/sidebarsRouter.ts b/sidebarsRouter.ts index 7af082a..094c0f1 100644 --- a/sidebarsRouter.ts +++ b/sidebarsRouter.ts @@ -19,7 +19,7 @@ const sidebars: SidebarsConfig = { 'guides/streaming', 'guides/vision-multimodal', 'guides/image-generation', - 'guides/usage-and-settlement', + 'guides/quota-and-usage', 'guides/errors', 'guides/openai-sdk', ],