Skip to main content

TypeScript SDK — @hpprouter/sdk

@hpprouter/sdk is the official TypeScript client for the HPP Router Consumer API. It wraps every consumer endpoint with typed helpers and surfaces HPP Router-specific smart-routing metadata alongside each response.

Installation​

npm install @hpprouter/sdk

Creating a client​

import { HppRouter } from '@hpprouter/sdk';

const client = new HppRouter({
apiKey: process.env.HPPROUTER_API_KEY!,
baseURL: 'https://router.hpp.io',
});

Chat completions​

const completion = await client.chat.send({
model: 'hpprouter/auto',
messages: [{ role: 'user', content: 'Hello!' }],
});

console.log(completion.data.choices);
console.log(completion.meta.resolvedModel); // smart-routing metadata

Responses expose two parts:

  • data — the OpenAI-compatible response body (choices, usage, …).
  • meta — HPP Router metadata derived from the X-HPP-Router-* headers (e.g. resolvedModel).

Streaming​

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);

See Streaming for the streaming-fallback behavior of hpprouter/auto.

Wallet (x402) payment rail​

HPP Router supports two payment rails for chat:

RailHow to enableBilling
quota (default)Omit wallet optionsPrepaid API-key credit
walletpaymentRail: 'wallet' + paymentSignerOn-chain x402 (upto / Permit2)

When paymentRail is wallet and the gateway returns HTTP 402, the SDK calls your paymentSigner with the parsed challenge body, then retries once with the returned headers (typically PAYMENT-SIGNATURE; X-PAYMENT is also accepted).

Do not rely on setting X-Payment-Rail only through defaultHeaders — that bypasses the SDK's 402 loop and surfaces HppRouterPaymentRequiredError immediately.

Non-streaming​

Signing uses the x402 upto scheme (Permit2), not a plain EIP-3009 transferWithAuthorization. Implement paymentSigner with @x402/core + @x402/evm (for example UptoEvmScheme) and your wallet (server key, Privy, MetaMask, …). Asset, network, amount, and payTo come from accepts[0] in the 402 body — do not hardcode the token.

npm install @hpprouter/sdk @x402/core @x402/evm viem
import { HppRouter } from '@hpprouter/sdk';
import type { X402PaymentRequired } from '@hpprouter/sdk';

// Replace signPayment with your UptoEvmScheme / wallet wiring.
async function myPaymentSigner(
paymentRequired: X402PaymentRequired,
): Promise<Record<string, string>> {
const encoded = await signPayment(paymentRequired);
return { 'PAYMENT-SIGNATURE': encoded };
}

const client = new HppRouter({
apiKey: process.env.HPPROUTER_API_KEY!,
baseURL: 'https://router.hpp.io',
paymentRail: 'wallet',
paymentSigner: myPaymentSigner,
});

const result = await client.chat.send({
model: 'openai/gpt-5',
messages: [{ role: 'user', content: 'Hello' }],
});

console.log(result.data.choices);

You can also override the rail per request:

await client.chat.send(
{ model: 'openai/gpt-5', messages: [{ role: 'user', content: 'Hello' }] },
{ paymentRail: 'wallet', paymentSigner: myPaymentSigner },
);

Streaming + settle metadata​

On the wallet rail, the gateway may emit an x402 settle event after content ends. Use the done promise:

const { stream, done } = await client.chat.stream({
model: 'openai/gpt-5',
messages: [{ role: 'user', content: 'Hello' }],
});

for await (const event of stream) {
const delta = event.choices?.[0]?.delta?.content;
if (delta) process.stdout.write(delta);
}

const finalMeta = await done;
if (finalMeta.x402) {
console.log('Settled tx:', finalMeta.x402.tx);
console.log('Amount (micro units):', finalMeta.x402.amount);
}
import {
HppRouterPaymentRequiredError,
HppRouterPaymentSignerError,
HppRouterQuotaError,
} from '@hpprouter/sdk';

try {
await client.chat.send({
model: 'openai/gpt-5',
messages: [{ role: 'user', content: 'Hi' }],
});
} catch (err) {
if (err instanceof HppRouterPaymentRequiredError) {
// 402 with no usable signer / challenge handling
console.error(err.paymentRequired?.accepts);
} else if (err instanceof HppRouterPaymentSignerError) {
// Signer threw (wallet locked, user rejected, …)
console.error(err.message, err.cause);
} else if (err instanceof HppRouterQuotaError) {
// 429 on the quota rail
console.error(err.message);
}
}

See Chat Completions and Errors for the HTTP-level 402 flow.

Models​

models.list() does not require an API key.

const catalogClient = new HppRouter({
baseURL: 'https://router.hpp.io',
});

const models = await catalogClient.models.list();
console.log(models.data.data);

Usage & quota​

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);

See Usage & Settlement for more details.

Image generation​

const image = await client.images.generate({
model: 'gpt-image-1',
prompt: 'A serene mountain landscape at sunset',
size: '1024x1024',
quality: 'auto',
});

console.log(image.data.data);

See Image Generation.

Choosing between the SDK and the OpenAI SDK​

Use caseRecommended
First-class smart-routing metadata, typed usage/quota/image helpers@hpprouter/sdk
Minimal-change migration of existing OpenAI SDK codeOpenAI SDK (drop-in)

Reference​

The SDK is generated against the Consumer API OpenAPI contract.