Skip to content

04 — Frameworks

Markdown

Vercel AI SDK

The AI SDK's OpenAI-compatible provider takes a base URL, a key and, optionally, a fetch of your own. With Inferit's base URL, generateText, streamText and the rest work as with any provider.

1. Get an API key

Create a key in the Buy workspace (Quickstart, steps 1 to 6) and export it. The key spends your prepaid balance: test ITC on the testnet, a test token with no monetary value.

bash
export INFERIT_API_KEY='ik_...'

The base URL is https://api-production-c74b9.up.railway.app/v1. Any OpenAI-compatible client works with it (chat completions, streaming included).

2. Add Inferit as a provider

createOpenAICompatible from @ai-sdk/openai-compatible, with Inferit's base URL and your key. response.modelId is the model that answered.

chat.mjs
// npm i ai @ai-sdk/openai-compatible
import { createOpenAICompatible } from '@ai-sdk/openai-compatible';
import { generateText } from 'ai';

const inferit = createOpenAICompatible({
  name: 'inferit',
  baseURL: 'https://api-production-c74b9.up.railway.app/v1',
  apiKey: process.env.INFERIT_API_KEY,
});

const { text, response } = await generateText({
  model: inferit('qwen/qwen-2.5-14b-instruct'), // "auto": Inferit picks the model
  prompt: 'Say hello in five words.',
});
console.log(text);
console.log(response.modelId); // the model that answered

Model auto, or a named model

With "auto" as the model, Inferit picks the model: the best value on a published quality ranking for this request, at that model's cheapest healthy seller (Automatic routing). The response names the model that answered, in its model field and the x-inferit-model header.

Auto needs a ranked model with a live seller. GET /v1/routing lists the models it can choose from now in candidates_now; while that list is empty, a request with auto answers 503 no_eligible_model. Then name a catalog model with a live seller instead, such as qwen/qwen-2.5-14b-instruct, and Inferit picks the seller. The samples on this page send auto while it has a candidate, and that model otherwise.

Pay per request with x402

With no API key, the provider can pay for each request with x402. Leave out apiKey, so no Authorization header is sent and the API answers with a 402 quote, and pass the standard x402 v2 client's fetch as the provider's fetch: it signs the quote and resends the same body. Each payment is at least 0.01 ITC, is credited to the paying address's balance, and each request is charged its exact cost (agents.md, API reference). The client caps one payment at 1 ITC; that is a setting in your client, not a rule of the contract.

chat-x402.mts
// npm i ai @ai-sdk/openai-compatible @x402/fetch @x402/evm viem
import { createOpenAICompatible } from '@ai-sdk/openai-compatible';
import { wrapFetchWithPayment, x402Client } from '@x402/fetch';
import { ExactEvmScheme } from '@x402/evm/exact/client';
import { generateText } from 'ai';
import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts';

const account = privateKeyToAccount((process.env.AGENT_KEY ?? generatePrivateKey()) as `0x${string}`);

// Testnet only: Inferit's faucet gives this address 1,000 free test ITC (the claim costs nothing).
await fetch('https://api-production-c74b9.up.railway.app/v1/faucet', {
  method: 'POST',
  headers: { 'content-type': 'application/json' },
  body: JSON.stringify({ address: account.address }),
});

// The standard x402 v2 client pays only in tokens it was told about: allow ITC,
// and cap one payment at 1 ITC (1000000 base units, 6 decimals).
const ITC = { network: 'eip155:1874', asset: '0x2E672dFE33EA977FD064E01aDe7d8c73B3Be7fBB' } as const;
const client = new x402Client()
  .register('eip155:*', new ExactEvmScheme(account))
  .setSpendControls({ allowedAssets: [{ ...ITC, maxAmountPerPayment: '1000000' }] });
const paidFetch = wrapFetchWithPayment(fetch, client);

// No apiKey: the provider sends no Authorization header, so the API answers with
// a 402 quote, which paidFetch pays and retries with PAYMENT-SIGNATURE.
const inferit = createOpenAICompatible({ name: 'inferit', baseURL: 'https://api-production-c74b9.up.railway.app/v1', fetch: paidFetch });

const { text } = await generateText({
  model: inferit('qwen/qwen-2.5-14b-instruct'),
  prompt: 'Say hello in five words.',
  maxOutputTokens: 64, // the quote is the worst case for this body: a small limit keeps it small
});
console.log(text);

streamText works the same way: the payment is settled before the stream starts.

Checked

The API-key sample ran against the hosted testnet API on 2026-10-13, with a named model (auto had no candidate that day).

The x402 variant was run up to the API's 402 quote: the request reached the API with no Authorization header and the x402 client read the quote. The paid retry is the same exchange as on Agents.