Agents and integrations

SDKs, MCP and frameworks.

Pay and call from TypeScript, the AI SDK, any OpenAI-compatible client, MCP, or the command line.

0.1.1SDK version@usdf/sdk
—MCP tools
—Models
On this page

The USDF SDK pays per request from a wallet, with no account, or charges a key. It also reads receipts, quotes and the account. Any OpenAI chat completions client works with a key.

ClientInstallPays withFits
@usdf/sdknpm install @usdf/sdk viemA wallet, per request, or a keyApps and agents in TypeScript
@usdf/sdk/ainpm install @usdf/sdk aiA wallet or a keyThe AI SDK
openai, TypeScript and Pythonnpm install openai, pip install openaiA keyExisting OpenAI code
LangChainpip install langchain-openai, npm install @langchain/openaiA keyLangChain apps
MCPNothing: a URLA key, or a payment per callMCP clients and agents
Command linenpx @usdf/sdkA keyThe terminal

Samples use <model>, the first available chat model, and read the key from USDF_API_KEY.

With a wallet, run pays each request per request. With new USDF({ apiKey }) it charges the prepaid balance instead.

One request

TypeScript
Install
npm install @usdf/sdk viem
Code
import { USDF } from "@usdf/sdk";
import { privateKeyToAccount } from "viem/accounts";
const wallet = privateKeyToAccount(process.env.PAYER_KEY as `0x${string}`);
const usdf = new USDF({ wallet }); // or new USDF({ apiKey: process.env.USDF_API_KEY })
const result = await usdf.run("<model>", "Hello");

The client's methods:

MethodWhat it does
run(model, prompt)One prompt, returning { text, receipt }. Streams with onText.
chat.completions.createA chat completion, plain or streamed, with its receipt.
embeddings.createEmbeddings.
batches.createA batch job; get, result and wait follow it.
quote, balanceThe worst case of a request before it runs, and what is left.
models.list, pricingThe models serving now, and the full price sheet.
tools.list, tools.callTools on the same balance.
receipts.get, receipts.list, receipts.attestationReceipts, and the provider's signed receipt for a private request.
keys.limits, update, pause, resumeA key's caps, allowlist, pause and flags.
account.*The overview, activity, settings and analytics.
links.*USDF links: create, list, get, claim, cancel.
agents.*Create, fund, limit and pay agents.
zap.quote, pool.readPay with any token, and the USDF/USDG pool.

It reads these environment variables:

VariableMeaning
USDF_API_KEYThe API key, when no wallet is given.
USDF_BASE_URLThe gateway. Default https://api.usdf.fi.
USDF_SESSION_TOKENA session, for account calls.
USDF_RPC_URLThe chain RPC the SDK reads the Permit2 allowance from.
USDF_MAX_AMOUNTThe most it signs for one request, in units. Default 1000000, 1 USDF. A larger quote is refused before signing, with amount_over_limit: raise it, or lower max_tokens.
USDF_PAY_TOThe payee it pays, when not the gateway's own wallet.

The SDK signs only on the gateway's chain, in USDF or USDG, to the gateway's wallet, up to its maximum amount. Anything else in a 402 is refused before signing.

npm: @usdf/sdk@0.1.1

@usdf/sdk/ai is a provider for the AI SDK. usdf(model) charges USDF_API_KEY.

Generate text

TypeScript
Install
npm install @usdf/sdk ai
Code
import { generateText } from "ai";
import { usdf } from "@usdf/sdk/ai"; // charges USDF_API_KEY; createUSDF({ wallet }) from "@usdf/sdk/ai" pays per request from a wallet
const model = usdf("<model>");
const result = await generateText({ model, prompt: "Hello" });

createUSDF({ wallet }) pays per request from a wallet instead. The receipt is at providerMetadata.usdf.receipt.

Point any OpenAI client at https://api.usdf.fi/v1 with a key.

The openai package

Install
npm install openai
Code
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.usdf.fi/v1",
  apiKey: process.env.USDF_API_KEY,
});

const completion = await client.chat.completions.create({
  model: "<model>",
  messages: [{ role: "user", content: "Hello" }],
  max_tokens: 256,
});
console.log(completion.choices[0].message.content);

// The receipt is an extra field the SDK's types do not declare.
const { receipt } = completion as unknown as {
  receipt: { request_id: string; cost: { usdf: string } };
};
console.log(receipt.request_id, receipt.cost.usdf, "USDF");

The AI SDK's OpenAI-compatible provider

Works with a key. With the @ai-sdk/openai provider instead, call .chat(…): its default model uses the Responses API, which is not served.

createOpenAICompatible

TypeScript
Install
npm install @ai-sdk/openai-compatible@3.0.54 ai@7.0.112
Code
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
import { generateText } from "ai";

const usdf = createOpenAICompatible({
  name: "usdf",
  baseURL: "https://api.usdf.fi/v1",
  apiKey: process.env.USDF_API_KEY,
});

const { text, response } = await generateText({
  model: usdf("<model>"),
  prompt: "Hello",
  maxOutputTokens: 256,
});
console.log(text, response.id);

ChatOpenAI reaches the gateway with a key and the base URL.

ChatOpenAI

Install
npm install @langchain/openai
Code
import { ChatOpenAI } from "@langchain/openai";

const llm = new ChatOpenAI({
  model: "<model>",
  apiKey: process.env.USDF_API_KEY,
  maxTokens: 256,
  configuration: { baseURL: "https://api.usdf.fi/v1" },
});
const reply = await llm.invoke("Hello");
console.log(reply.content);

The MCP server is at POST https://api.usdf.fi/mcp. It speaks stateless streamable HTTP: one JSON-RPC message per POST, and no session.

Its tools, read live:

ToolWhat it doesAccess
———

Every tool works with a key. Without one, three behave differently:

ToolWith a keyWith no key
chatCharged to the key's balance.Paid per call. The payment requirements come back as an isError result; pay with _meta["x402/payment"], a payment argument, or the PAYMENT-SIGNATURE header.
receiptThe key's own requests.The public receipt of any request id.
balanceThe key's balance and budget.With { address }: that wallet's USDF, USDG and Permit2 allowance.
list_models, quote, list_tools, quote_toolThe same.The same.

Limits

chat is not streamed to the client, so its limits keep an answer inside a client's wait:

LimitValue
chat max_tokens4096 at most
Deadline55 seconds; 10 minutes with a progress token. In the TypeScript SDK, pass onprogress with resetTimeoutOnProgress: true.
MessagesOne JSON-RPC message per POST. Batches are refused.
Request body256 KiB
Response1 MiB
Rate limit—

A call cut at its deadline returns the text produced so far. With a key, it is billed for that output. Paid per call, the payment stands.

Client configuration

Name the server usdf. A client that takes a URL and headers reads the key from the environment:

Clients that take a URL and headers

{
  "mcpServers": {
    "usdf": {
      "url": "https://api.usdf.fi/mcp",
      "headers": { "Authorization": "Bearer ${env:USDF_API_KEY}" }
    }
  }
}

A client that runs local servers reaches it through the mcp-remote bridge:

Clients that run local servers

{
  "mcpServers": {
    "usdf": {
      "command": "npx",
      "args": ["-y", "mcp-remote@0.14.3", "https://api.usdf.fi/mcp", "--header", "Authorization:${USDF_AUTH}"],
      "env": { "USDF_AUTH": "Bearer sk_..." }
    }
  }
}

From code

The MCP TypeScript SDK

TypeScript
Install
npm install @modelcontextprotocol/sdk@1.30.0
Code
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";

const transport = new StreamableHTTPClientTransport(new URL("https://api.usdf.fi/mcp"), {
  requestInit: { headers: { Authorization: `Bearer ${process.env.USDF_API_KEY}` } },
});
const client = new Client({ name: "my-agent", version: "1.0.0" });
await client.connect(transport);

const { tools } = await client.listTools();
console.log(tools.map((t) => t.name));

const quote = await client.callTool({
  name: "quote",
  arguments: { model: "<model>", prompt: "Hello", max_tokens: 256 },
});
console.log(JSON.stringify(quote.structuredContent));

// With onprogress the SDK sends a progress token: the gateway reports progress
// as it works and allows the call up to 10 minutes. resetTimeoutOnProgress is
// what makes the client keep waiting.
const chat = await client.callTool(
  { name: "chat", arguments: { model: "<model>", messages: [{ role: "user", content: "Hello" }], max_tokens: 256 } },
  undefined,
  { timeout: 60_000, resetTimeoutOnProgress: true, onprogress: (p) => console.log("still generating", p.progress) },
);
console.log(JSON.stringify(chat.structuredContent));
await client.close();

The SDK ships one command, usdf. Run it with npx @usdf/sdk.

npx @usdf/sdk balance
npx @usdf/sdk keys
npx @usdf/sdk run <model> "Hello" --cost
npx @usdf/sdk receipts
# installed with npm install -g @usdf/sdk, the command is usdf: usdf balance

The commands:

CommandWhat it does
loginStores a key (--key sk_…) or a session (--token - reads it from stdin) for the gateway.
logoutForgets the stored session.
balanceWhat is available, held and left on the key.
keys [list|create|revoke|limits|pause|resume]Manages keys.
run <model> "<prompt>" [--cost]Streams an answer. --cost prints the receipt's cost.
receipts, receipt <id>Lists receipts, or shows one.
pricing, models, quote, authReads the sheet, the models, a quote and the sign-in setup.
poolThe USDF/USDG pool: price, tick and reserves. No key.

Every command takes --json. The command signs nothing, so it cannot pay per request; use the SDK for that.

Files an agent can read to find its way:

FileWhat it is
/skill.mdThe agent skill: buying USDF, a capped key, calling, receipts, paying per request.
/llms.txtWhat USDF is and where every surface lives.
/v1/catalog, /signer, /signatureThe signed model catalog.
/tokenlist.jsonA token list with USDF.
/usdf.pngThe USDF logo.

See also SDKs, MCP and CLI.

Next: platforms and providers