# Introduction
URL: /docs
***
## title: Introduction
# Echo
Echo is billing infrastructure for AI applications that turns your OpenAI imports into revenue-generating user accounts across React, Next.js, Node.js, and CLI tools.
## Why use Echo?
Building AI apps means handling payments, user auth, usage tracking, and API key management. Each user needs their own balance, every LLM call needs metering, and you're stuck building Stripe flows instead of features.
Echo standardizes AI billing like Clerk standardized auth. Drop in our SDK, set your markup percentage, and your existing OpenAI code instantly gets user accounts with usage-based billing. No payment processing, no surprise bills, no exposed API keys.
Result: Your users get one universal balance that works across all Echo-powered apps, creating network effects that grow your user base while you focus on building.
For example, here's how you can add complete user management and LLM billing to your app:
```tsx
import { EchoProvider, EchoTokens, useEchoModelProviders } from '@merit-systems/echo-react-sdk';
import { generateText } from 'ai';
function App() {
return (
{/* Complete user management - handles auth, billing, sign-out */}
);
}
function ChatComponent() {
const { openai } = useEchoModelProviders();
const handleGenerate = async () => {
const { text } = await generateText({
model: openai('gpt-5'),
prompt: 'Hello world'
});
return text;
};
return ;
}
export default App
```
**Three integration patterns:**
* [**React SDK**](/docs/react-sdk) — OAuth2 + PKCE for secure client-side LLM calls
* [**Next.js SDK**](/docs/next-sdk) — Server-side auth with automatic token management
* [**TypeScript SDK**](/docs/typescript-sdk) — API keys for backends and CLI tools
The React and Next.js SDKs are opinionated wrappers around the TypeScript SDK, providing framework-specific patterns while the TypeScript SDK offers direct API access for maximum flexibility.
),
docsLink: '/docs/getting-started/react',
liveExampleLink: 'https://example.com/react-demo',
githubLink: 'https://github.com/Merit-Systems/echo-react-example',
},
{
title: 'Next.js',
icon: (
),
docsLink: '/docs/getting-started/next-js',
liveExampleLink: 'https://example.com/nextjs-demo',
githubLink: 'https://github.com/Merit-Systems/echo-nextjs-example',
},
{
title: 'CLI',
icon: (
{'>'}
),
docsLink: '/docs/getting-started/cli',
githubLink: 'https://github.com/Merit-Systems/echo/tree/master/echo-typescript-cli-example',
},
]}
/>
# API Reference
URL: /docs/advanced/api-reference
***
title: API Reference
description: V1 API reference for programmatic access to Echo
-------------------------------------------------------------
import { Callout } from 'fumadocs-ui/components/callout';
# API Reference
The Echo V1 API provides programmatic access for SDKs, CLI tools, and applications. All endpoints are prefixed with `/api/v1/`.
All API endpoints use JSON request/response format. Most endpoints require authentication via API keys or JWT tokens.
## Authentication
The V1 API supports two authentication methods:
### API Keys
API keys are the primary authentication method for programmatic access. Include your API key in the request header:
```http
Authorization: Bearer your_api_key_here
```
### JWT Tokens
JWT tokens are used for OAuth flows and temporary access. Include JWT tokens in either header:
```http
Authorization: Bearer your_jwt_token_here
```
or
```http
X-Echo-Token: your_jwt_token_here
```
## Applications
### List User Apps
```http
GET /api/v1/apps
```
List all Echo apps owned by the authenticated user.
**Authentication:** API key or JWT token required
**Response Type:**
```typescript
{
apps: PublicEchoApp[]
}
```
### Get App Details
```http
GET /api/v1/apps/{id}
```
Get detailed app information for programmatic access.
**Authentication:** API key or JWT token required\
**Path Parameters:**
* `id` (UUID) - App ID
**Response Type:** Returns a `PublicEchoApp` with detailed statistics
## Balance & Billing
### Get User Balance
```http
GET /api/v1/balance
```
Get authenticated user's credit balance.
**Authentication:** API key or JWT token required\
**Query Parameters:**
* `echoAppId` (UUID, optional) - Get app-specific balance instead of global
**Response Type:**
For app-specific balance queries, returns:
### Get Free Tier Balance
```http
POST /api/v1/balance/free
```
Get user's free tier spending information for a specific app.
**Authentication:** API key or JWT token required
**Request Body:**
```typescript
{
echoAppId: string
}
```
**Response Type:**
```typescript
{
spendPoolBalance: {
available: number;
total: number;
used: number;
};
userSpendInfo: UserSpendInfo;
}
```
## Payments
### Create Payment Link
```http
POST /api/v1/stripe/payment-link
```
Generate Stripe payment link for credit purchases.
**Authentication:** API key or JWT token required
**Request Body:**
```typescript
{
amount: number;
successUrl?: string;
}
```
**Response Type:**
```typescript
{
paymentUrl: string;
sessionId: string;
expiresAt: string;
}
```
Payment amounts are in USD. The `successUrl` parameter is optional and will redirect users after successful payment.
## Models & Capabilities
### Get Supported Models
```http
GET /api/v1/supported-models
```
Get list of supported AI models with pricing information.
**Authentication:** None required
**Response Type:**
```typescript
{
models: SupportedModel[];
models_by_provider: Record;
}
```
**SupportedModel Interface:**
```typescript
interface SupportedModel {
id: string;
name: string;
provider: string;
inputPrice: number;
outputPrice: number;
contextLength: number;
}
```
## User Management
### Get User Info
```http
GET /api/v1/user
```
Get authenticated user profile information.
**Authentication:** API key or JWT token required
**Response Type:**
```typescript
{
id: string;
email: string;
name: string | null;
createdAt: string;
updatedAt: string;
totalPaid: number;
totalSpent: number;
}
```
### Register Referral Code
```http
POST /api/v1/user/referral
```
Apply a referral code for credits on a specific app.
**Authentication:** API key or JWT token required
**Request Body:**
```typescript
{
echoAppId: string;
code: string;
}
```
**Response Type:**
```typescript
{
success: boolean;
message: string;
creditsAwarded?: number;
}
```
## Error Responses
All endpoints return appropriate HTTP status codes and JSON error responses:
```json
{
"error": "string",
"message": "string",
"statusCode": "number"
}
```
### Common Status Codes
* `200 OK` - Success
* `201 Created` - Resource created
* `400 Bad Request` - Invalid request data
* `401 Unauthorized` - Authentication required
* `403 Forbidden` - Insufficient permissions
* `404 Not Found` - Resource not found
* `500 Internal Server Error` - Server error
All endpoints require HTTPS in production environments. UUID parameters are validated for proper format.
# Authorized Callback Urls
URL: /docs/advanced/callback-urls
***
title: Authorized Callback Urls
description: How to authorize callback URLs for your app correctly
------------------------------------------------------------------
# Authorized Callback URLs
Authorized callback URLs specify where users can be redirected after authentication. This is a critical security feature that prevents unauthorized redirects.
## Configuration
**Set your callback URL to your application's homepage URL.** This should be the deployed URL where your application is hosted in production.
Examples:
* `https://myapp.com`
* `https://myapp.vercel.app`
* `https://subdomain.mycompany.com`
## Development
**Localhost URLs are always allowed** for development purposes. You don't need to explicitly add localhost URLs to your authorized callback list.
## Next SDK Caveat
**Very important** - When productionizing your application with the Next SDK, you will need to append `/api/echo/callback` to your app's homepage route when inputting the correct authorized callback URL.
For example:
* If your app is hosted at `https://myapp.com`
* Set your authorized callback URL to `https://myapp.com/api/echo/callback`
# How Echo Works
URL: /docs/advanced/how-echo-works
***
title: How Echo Works
description: Technical architecture guide for Echo's proxy layer, authentication, and billing system
----------------------------------------------------------------------------------------------------
import { Callout } from 'fumadocs-ui/components/callout';
# How Echo Works
Echo is a proxy layer that handles authentication, metering, and billing for LLM applications. This guide explains the technical architecture and integration patterns.
## System Overview & Architecture
Echo operates as a three-layer stack that sits between your application and LLM providers:
```mermaid
graph TB
A[Your Application] --> B[Echo SDK]
B --> C[Echo Proxy Layer]
C --> D[OpenAI/Anthropic/Claude]
C --> E[Billing & Analytics]
C --> F[User Management]
```
### Core Components
**Echo Control** (`echo-control`)
* Web dashboard for app management, user analytics, billing
* PostgreSQL database with Prisma ORM
* NextAuth sessions for web UI authentication
**Echo Server** (`echo-server`)
* API proxy that intercepts LLM requests
* Handles authentication validation and usage metering
* Routes requests to appropriate LLM providers
* Records transactions and calculates costs in real-time
**SDK Ecosystem**
* `echo-typescript-sdk`: Universal client for all platforms
* `echo-react-sdk`: OAuth2+PKCE for client-side LLM calls
* `echo-next-sdk`: Server-side integration patterns
### Request Flow
Every LLM request follows this path:
1. **Authentication**: SDK includes API key or JWT token
2. **Validation**: Echo proxy validates credentials and permissions
3. **Routing**: Request forwarded to appropriate LLM provider
4. **Metering**: Response tokens counted and costs calculated
5. **Billing**: Transaction recorded with user/app attribution
6. **Response**: LLM response returned to your application
Echo acts as a transparent proxy. Your application uses standard OpenAI SDK patterns but gains billing, analytics, and user management automatically.
## The Proxy Layer
Echo Server handles the complex middleware between your app and LLM providers. Here's how each component works:
### Request Interception
All LLM requests route through Echo's proxy endpoints:
```typescript
// Your app calls this
const response = await openai.chat.completions.create({
model: "gpt-4",
messages: [{ role: "user", content: "Hello" }]
});
// Echo intercepts at https://echo.router.merit.systems/v1/chat/completions
// Validates auth, meters usage, forwards to OpenAI, records billing
```
The proxy preserves OpenAI's API contract while injecting billing logic:
```typescript
// echo-server/src/routes/chat/completions.ts
export async function handleChatCompletion(request: AuthenticatedRequest) {
// 1. Extract and validate authentication
const { user, echoApp } = request.auth;
// 2. Forward to LLM provider
const llmResponse = await provider.chat.completions.create(request.body);
// 3. Calculate costs from token usage
const cost = calculateTokenCost(llmResponse.usage, request.body.model);
// 4. Record transaction
await recordTransaction({
userId: user.id,
echoAppId: echoApp.id,
cost,
tokens: llmResponse.usage
});
return llmResponse;
}
```
## Authentication & Security Architecture
Echo supports two distinct authentication patterns optimized for different use cases:
### API Key Authentication (Backend/Server-Side)
Traditional server-side pattern for backend applications:
```typescript
// Your server code
import { EchoClient } from '@merit-systems/echo-typescript-sdk';
const client = new EchoClient({
apiKey: process.env.ECHO_API_KEY // Scoped to specific Echo app
});
const response = await client.models.chatCompletion({
model: "gpt-4",
messages: [{ role: "user", content: "Hello" }]
});
```
API key validation flow:
1. Extract key from `Authorization: Bearer ` header
2. Hash and lookup in database with app association
3. Validate key is active and app is not archived
4. Attach user and app context to request
### OAuth2 + PKCE Authentication (Frontend/Client-Side)
Pattern that enables secure LLM calls directly from browsers:
```typescript
// React component - no API keys needed
import { useEchoOpenAI } from '@merit-systems/echo-react-sdk';
function ChatComponent() {
const { openai, isReady } = useEchoOpenAI();
// This runs in the browser with user-scoped JWT tokens
const response = await openai.chat.completions.create({
model: "gpt-4",
messages: [{ role: "user", content: "Hello" }]
});
}
```
OAuth2 + PKCE flow eliminates API key exposure:
1. **Authorization Request**: User redirects to Echo OAuth endpoint
2. **User Consent**: User authorizes your app to access their Echo balance
3. **Code Exchange**: Your app exchanges authorization code for JWT tokens
4. **Token Usage**: Short-lived JWTs authenticate LLM requests
5. **Automatic Refresh**: SDK handles token renewal transparently
This dual authentication model supports both traditional backend patterns and modern frontend architectures while maintaining security and proper billing attribution.
# Advanced
URL: /docs/advanced
***
title: Advanced
description: Advanced topics
----------------------------
* **[How Echo Works](/docs/advanced/how-echo-works)** - Technical architecture guide for Echo's proxy layer, authentication, and billing system.
* **[API Reference](/docs/advanced/api-reference)** - Complete V1 API reference for programmatic access to Echo endpoints.
# Cookbook
URL: /docs/cookbook
***
title: Cookbook
description: Echo examples Cookbook.
------------------------------------
*Coming soon.*
# TypeScript CLI
URL: /docs/getting-started/cli
***
title: TypeScript CLI
description: Build AI CLI apps with Echo's billing infrastructure
-----------------------------------------------------------------
import { Step, Steps } from 'fumadocs-ui/components/steps';
# TypeScript CLI with Echo
Create CLI tools that generate revenue from AI usage. Echo handles user authentication, billing, and AI provider access through a simple API key flow.
### Install SDKs
```sh
npm i @merit-systems/echo-typescript-sdk ai enquirer open
```
```sh
yarn add @merit-systems/echo-typescript-sdk ai enquirer open
```
```sh
pnpm add @merit-systems/echo-typescript-sdk ai enquirer open
```
```sh
bun add @merit-systems/echo-typescript-sdk ai enquirer open
```
### Create Echo App
Go to [echo.merit.systems/new](https://echo.merit.systems/new) to get your `app_id`.
### Set up authentication
```typescript title="cli.ts"
import { EchoClient, createEchoOpenAI } from '@merit-systems/echo-typescript-sdk';
import { generateText } from 'ai';
import { prompt } from 'enquirer';
import { open } from 'open';
const APP_ID = 'your-echo-app-id';
// Get API key from user
console.log('Opening Echo to create your API key...');
await open(`https://echo.merit.systems/app/${APP_ID}/keys`);
const { apiKey } = await prompt({
type: 'input',
name: 'apiKey',
message: 'Enter your API key:'
});
```
### Create AI provider
```typescript title="cli.ts"
// Create Echo client for balance/payments
const echo = new EchoClient({ apiKey });
// Create OpenAI provider with Echo billing
const openai = createEchoOpenAI(
{ appId: APP_ID },
async () => apiKey
);
```
### Make AI calls
```typescript title="cli.ts"
// Generate text with automatic billing
const { text } = await generateText({
model: openai('gpt-4'),
prompt: 'Explain quantum computing in simple terms',
});
console.log(text);
```
### Add balance checking
```typescript title="cli.ts"
// Check user's balance
const balance = await echo.balance.getBalance();
console.log(`Balance: $${balance.balance}`);
// Create top-up link if needed
if (balance.balance < 1) {
const payment = await echo.payments.createPaymentLink({
amount: 10,
});
console.log('Low balance. Opening payment link...');
await open(payment.url);
}
```
### Run your CLI
```sh
npx tsx cli.ts
```
### Prosper.
## Next Steps
For detailed documentation and advanced features, see the [TypeScript SDK overview](/docs/typescript-sdk).
# Next.js
URL: /docs/getting-started/next-js
***
title: Next.js
description: Use Echo to make monetized AI Next.js apps.
--------------------------------------------------------
import { Step, Steps } from 'fumadocs-ui/components/steps';
import { File, Folder, Files } from 'fumadocs-ui/components/files';
# Getting Started with Next.js
### Install the Echo Next SDK
```sh
npm i @merit-systems/echo-next-sdk
```
```sh
yarn add @merit-systems/echo-next-sdk
```
```sh
pnpm add @merit-systems/echo-next-sdk
```
```sh
bun add @merit-systems/echo-next-sdk
```
### Install Vercel AI SDK
```sh
npm i ai
```
```sh
yarn add ai
```
```sh
pnpm add ai
```
```sh
bun add ai
```
### Create an Echo App
Go to [echo.merit.systems/new](https://echo.merit.systems/new) to get an `app_id`.
### Add Echo configuration file
```typescript title="src/echo/index.ts" lineNumbers
import Echo from "@merit-systems/echo-next-sdk";
export const { handlers, isSignedIn, openai, anthropic } = Echo({
appId: "YOUR_ECHO_APP_ID", // from previous step
});
```
### Add Echo Routes
```typescript title="src/app/api/echo/[...echo]/route.ts" lineNumbers
import { handlers } from "@/echo";
export const { GET, POST } = handlers;
```
### Sign In From Client
Create an action in the front-end that redirects users to authorize your application with [echo.merit.systems](echo.merit.systems).
```tsx title="app/page.tsx" lineNumbers
import { signIn, isSignedIn } from "@merit-systems/echo-next-sdk/client";
export default Home() {
if (!isSignedIn()) {
return
}
return (
Monetization Activated 📈
)
}
```
Sign in will hit the route we setup in [Step 4](http://echo.merit.systems/docs/getting-started/next-js#add-echo-routes) and redirect from the server.
### Use `generateText` / `streamText` from the server
Echo is a standard [Vercel AI SDK](https://ai-sdk.dev/docs/introduction) provider.
Add [Vercel AI SDK server routes](https://ai-sdk.dev/docs/ai-sdk-ui/completion) with Echo providers.
```typescript title="app/api/completion/route.ts" lineNumbers
// [!code ++:1]
import { openai } from "@/echo";
import { convertToModelMessages, streamText } from "ai";
export async function POST(req: Request) {
const { messages } = await req.json();
const result = streamText({
model: openai("gpt-5"),
messages: convertToModelMessages(messages),
});
return result.toUIMessageStreamResponse();
}
```
### `useChat()` from the client
```tsx title="app/components/chat.tsx" lineNumbers
"use client";
import { useChat } from "@ai-sdk/react";
import { useState } from "react";
export default function Chat() {
const [input, setInput] = useState("");
const { messages, sendMessage } = useChat();
return (
{messages.map((message) => (
{JSON.stringify(message)}
))}
setInput(e.currentTarget.value)} />
);
}
```
Then add use it on the authenticated page.
```tsx title="app/page.tsx" lineNumbers
// [!code ++:1]
import Chat from "./components/chat";
import { signIn, isSignedIn } from "@merit-systems/echo-next-sdk/client";
export default Home() {
if (!isSignedIn()) {
return
}
// [!code ++:1]
return ;
// [!code --:3]
return (
Monetization Activated 📈
)
}
```
### Prosper
## Next Steps
For detailed documentation and advanced features, see the [Next.js SDK overview](/docs/next-sdk).
# React
URL: /docs/getting-started/react
***
title: React
description: Integrate Echo into your React application
-------------------------------------------------------
import { Step, Steps } from 'fumadocs-ui/components/steps';
# Getting Started with Echo in React
### Create a React app using Vite
Run the following commands to create a new React app using Vite.
```sh lineNumbers
npm create vite@latest echo-react -- --template react-ts
cd echo-react
npm install
npm run dev
```
```sh lineNumbers
yarn create vite echo-react --template react-ts
cd echo-react
yarn install
yarn dev
```
```sh lineNumbers
pnpm create vite echo-react --template react-ts
cd echo-react
pnpm install
pnpm dev
```
```sh lineNumbers
bun create vite echo-react --template react-ts
cd echo-react
bun install
bun dev
```
### Install `@merit-systems/echo-react-sdk` and `ai`
The Echo React SDK gives you access to prebuilt components, hooks and helpers to make LLM billing and calling easier.
The [Vercel AI SDK](https://ai-sdk.dev/docs/introduction) is the standard SDK for interacting with AI in Typescript.
Run the following commands to install the dependencies.
```sh lineNumbers
npm i @merit-systems/echo-react-sdk ai
```
```sh lineNumbers
yarn add @merit-systems/echo-react-sdk ai
```
```sh lineNumbers
pnpm add @merit-systems/echo-react-sdk ai
```
```sh lineNumbers
bun add @merit-systems/echo-react-sdk ai
```
### Setup your Echo App
1. In the Echo dashboard navigate to [**Create App**](https://echo.merit.systems/new).
2. Copy your `app_id` and paste it into your `.env` file.
The final result should resemble the following:
```sh title=".env" lineNumbers
VITE_ECHO_APP_ID=b30f0f78-4000-8000-000000000000
```
### Import your Echo App ID
In your `main.tsx` file, import your app id.
Include your App ID from the prior step.
```tsx title="main.tsx" lineNumbers
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.tsx'
// [!code ++:1]
const APP_ID = import.meta.env.VITE_ECHO_APP_ID;
// [!code ++:3]
if (!APP_ID) {
throw new Error('Add your Echo App ID to .env');
}
createRoot(document.getElementById('root')!).render(
,
)
```
### `` component
The `` component provides session and user context to Echo's hooks and components. It's recommended to wrap
your entire app at the entry point with `` to make Echo globally available.
Pass your Echo App ID as a prop to ``.
```tsx title="main.tsx" lineNumbers
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.tsx'
// [!code ++:1]
import { EchoProvider } from '@merit-systems/echo-react-sdk';
const APP_ID = import.meta.env.VITE_ECHO_APP_ID;
if (!APP_ID) {
throw new Error('Add your Echo App ID to .env');
}
createRoot(document.getElementById('root')!).render(
// [!code ++:1]
// [!code ++:1]
,
)
```
### `` component
`` is a React component that can be placed anywhere in your app. When a user clicks
it will redirect to authenticate with [echo.merit.systems](echo.merit.systems). After authentication,
Echo can manage all LLM calls.
```tsx title="src/App.tsx" lineNumbers
// [!code ++:1]
import { EchoSignIn } from '@merit-systems/echo-react-sdk';
function App() {
return (
<>
// [!code ++:1]
AI Coming Soon
>
);
}
export default App;
```
### `useEcho()` hook
The `useEcho()` hook surfaces everything you need to show Echo state to your users.
```tsx title="src/App.tsx" lineNumbers
// [!code ++:1]
import { EchoSignIn, useEcho } from '@merit-systems/echo-react-sdk';
function App() {
// [!code ++:1]
const { isAuthenticated, user, balance, signOut } = useEcho();
return (
<>
// [!code ++:9]
{!isAuthenticated && "Sign in to continue"}
{isAuthenticated && (
Welcome, {user?.name}!
Email: {user?.email}
Balance: {balance?.balance}
)}
AI Coming Soon
>
);
}
export default App;
```
### `generateText()` from OpenAI
Create a new component and use the Vercel AI SDK with Echo models.
```tsx title="src/App.tsx" lineNumbers
import { EchoSignIn, useEcho } from '@merit-systems/echo-react-sdk';
// [!code ++:1]
import AIComponent from './AIComponent';
function App() {
const { isAuthenticated, user, balance, signOut } = useEcho();
return (
<>
{!isAuthenticated && "Sign in to continue"}
{isAuthenticated && (
Welcome, {user?.name}!
Email: {user?.email}
Balance: {balance?.balance}
)}
// [!code --:1]
AI Coming Soon
// [!code ++:1]
{isAuthenticated && }
>
);
}
export default App;
```
AI SDK's [`generateText()`](https://ai-sdk.dev/docs/reference/ai-sdk-core/generate-text) is used to generate a single response from the model.
`useEchoModelProviders()` routes the requests through Echo.
```tsx title="src/AIComponent.tsx" lineNumbers
// [!code ++:100]
import { useState } from 'react';
import { generateText } from 'ai';
import { useEchoModelProviders } from '@merit-systems/echo-react-sdk';
export default function AIComponent() {
const [result, setResult] = useState("");
const { openai } = useEchoModelProviders();
const handleGen = async () => {
const { text } = await generateText({
model: openai('gpt-5-nano'),
messages: [
{ role: 'user', content: 'Two sentences. What is the cleanest way to make $1M?' }
]
});
setResult(text);
};
return (
{result}
);
}
```
### Switch to `streamText()`
The AI SDK [`streamText()`](https://ai-sdk.dev/docs/reference/ai-sdk-core/stream-text) function is used to incrementally show the response from the model.
```tsx title="src/AIComponent.tsx" lineNumbers
import { useState } from 'react';
// [!code --:1]
import { generateText } from 'ai';
// [!code ++:1]
import { streamText } from 'ai';
import { useEchoModelProviders } from '@merit-systems/echo-react-sdk';
export default function AIComponent() {
const [result, setResult] = useState("");
const { openai } = useEchoModelProviders();
const handleGen = async () => {
// [!code ++:2]
setResult("Thinking...");
const { text } = await streamText({
// [!code --:1]
const { text } = await generateText({
model: openai('gpt-5-nano'),
messages: [
{ role: 'user', content: 'Two sentences. What is the cleanest way to make $1M?' }
]
});
// [!code ++:3]
for await (const chunk of textStream) {
setResult(prev => prev + chunk);
}
};
return (
{result}
);
}
```
### Enjoy the fruits of your labor.
Run your project with the following command.
```sh lineNumbers
npm run dev
```
```sh lineNumbers
yarn dev
```
```sh lineNumbers
pnpm dev
```
```sh lineNumbers
bun dev
```
Visit your app's homepage at [`http://localhost:5173`](http://localhost:5173). Sign in and click "Generate Wisdom".
## Next Steps
For detailed documentation and advanced features, see the [React SDK overview](/docs/react-sdk).
# Templates
URL: /docs/getting-started/templates
***
title: Templates
description: Get started quickly with Echo using pre-built templates
--------------------------------------------------------------------
import { Step, Steps } from 'fumadocs-ui/components/steps';
The easiest way to get started with Echo is to use one of our pre-built templates.
## React
The React template is a simple application that uses Vite and `echo-react-sdk`. Uniquely Echo does not require
a server to make API calls because it handles Oauth directly in the browser.
### Create an Echo App
Go to [echo.merit.systems/new](https://echo.merit.systems/new) to get an `app_id`.
### Create a React app using Vite
Run the following commands to create a new React app using Vite.
```sh lineNumbers
npx echo-start@latest --template react --app-id YOUR_ECHO_APP_ID
```
```sh lineNumbers
yarn dlx echo-start@latest --template react --app-id YOUR_ECHO_APP_ID
```
```sh lineNumbers
pnpx echo-start@latest --template react --app-id YOUR_ECHO_APP_ID
```
```sh lineNumbers
bunx echo-start@latest --template react --app-id YOUR_ECHO_APP_ID
```
## Next.js
The Next.js template is a full-stack application that uses the Next.js framework with the `echo-next-sdk`.
### Create an Echo app
Go to [echo.merit.systems/new](https://echo.merit.systems/new) to get an `app_id`.
### Create a Next.js app
Run the following commands to create a new Next.js app.
```sh lineNumbers
npx echo-start@latest --template next --app-id YOUR_ECHO_APP_ID
```
```sh lineNumbers
yarn dlx echo-start@latest --template next --app-id YOUR_ECHO_APP_ID
```
```sh lineNumbers
pnpx echo-start@latest --template next --app-id YOUR_ECHO_APP_ID
```
```sh lineNumbers
bunx echo-start@latest --template next --app-id YOUR_ECHO_APP_ID
```
# Claiming Profits
URL: /docs/money/claiming-profits
***
title: Claiming Profits
description: Get paid through Echo's core features
--------------------------------------------------
## Markups
Both Echo Apps and Users have strategies to monetize on Echo.
Apps earn a mark-up on each transaction, which is set by the app owner. This represents a percent upcharge on each token that passes through the application.
The mark-up earned can be claimed only when a Github user or repository has been associated with the app. This can be done in the app's settings page.
Once this is done, users can find their pending claims available on the [markup earnings page](https://echo.merit.systems/owner/earnings/markup).
## Claims
Claims are processed on a daily basis and paid out via [the Terminal](https://terminal.merit.systems). The funds will be sent to the github User or Repository which is set on the Echo app
at the time of payout. If no Github account is set, the transfer will not be made on that day. You will be able to claim or redistribute your funds through the terminal once they are transferred.
For more information on the Terminal, please see the [docs](https://www.merit.systems/docs/terminal).
## Referrals
User referrals will allow app owners to incentivize users to market their application. App owners can agree to pay, for example, 5% of profit
to a referrer. Therefore, if a user signs up via a referral link, the creator of the referral link will earn 5% of all profits generated in the lifetime of the user.
This feature is in early beta and may not work as expected. Please reach out in the [discord](https://discord.com/invite/JuKt7tPnNc) if you are interested in setting up referrals for your application.
### Discord
Please reach out in our [discord](https://discord.com/invite/JuKt7tPnNc) if you have any questions about how claims work, where your claimed funds are, or are experiencing any issues.
We are actively looking for feedback on our claims system and would love to hear your thoughts.
# Client
URL: /docs/next-sdk/client
***
title: Client
description: Echo's Next.js SDK client-side functionality.
----------------------------------------------------------
Echo maintains authentication using HTTP Cookies. The browser does not have access
to these so login state needs to be handled by server components.
# Client-Side Sign In
In your application you can use the `signIn` method to initiate server-side Echo sign-in.
```typescript
"use client"
import { signIn } from "@merit-systems/echo-next-sdk/client";
export default SignInButton() {
return
}
```
# Fetching information from the Echo API
The client side Echo API allows you to serve all the Echo API endpoints with the
echo client directly through your routes. This means that all token handling is
directly supported.
## Handlers
```typescript
import handlers from '@/echo';
export { GET, POST } = handlers;
```
Exporting these routes will expose the echo client proxy route:
* `api/echo/proxy/:path*`
On the client side, you can use the `useEcho` hook to get the echo client.
```typescript
import { useEcho } from '@merit-systems/echo-next-sdk/client';
const echoClient = useEcho();
```
Then you can invoke the echo client directly in a `useEffect`
or whatever external data fetching strategy you are using.
```typescript
import { useEffect } from 'react';
// get balance
useEffect(() => {
const balance = echoClient.balance.getBalance();
}, [echoClient]);
// create a payment link
useEffect(() => {
const paymentLink = echoClient.payments.createPaymentLink({
amount: 10,
description: 'Credits',
});
}, [echoClient]);
// get user info
useEffect(() => {
const user = echoClient.users.getUserInfo();
}, [echoClient]);
```
The rest of the supported methods are documented in the [TypeScript SDK](../typescript-sdk).
# Overview
URL: /docs/next-sdk
***
title: Overview
description: Echo Next.js SDK overview.
---------------------------------------
Echo's Next.js SDK handles authentication between your web app and Echo.
Get started quickly with the Next.js [quickstart guide](https://echo.merit.systems/docs/getting-started/next-js).
* [Server](./next-sdk/server): Next.js App Router server routes and authentication logic.
* [Client](./next-sdk/client): Client-side utilities for Echo authentication.
# Server
URL: /docs/next-sdk/server
***
title: Server
description: Echo's Next.js SDK server-side functionality.
----------------------------------------------------------
Echo's Next.js SDK will handle all authentication logic out of the box.
Configure Echo with the Echo constructor.
```typescript title="src/echo/index.ts"
import Echo from "@merit-systems/echo-next-sdk";
export const {
// Echo Auth Routes
handlers,
// Server-side utils
getUser, isSignedIn,
// AI Providers
openai, anthropic, google
} = Echo({
appId: "ECHO_APP_ID",
});
```
By re-exporting the Echo constructor results, you can use throughout your server logic.
The `Echo` constructor takes the following configuration params.
## Handlers
```typescript
import handlers from '@/echo';
export { GET, POST } = handlers;
```
Exporting these routes will expose default authentication routes which can be used from the client. In most cases your code will not need to touch these routes.
* `api/echo/signin`
* `api/echo/callback`
* `api/echo/refresh`
**Very important** - When productionizing your application, you will need to append `/api/echo/callback` to your app's homepage route when inputting the correct authorized
callback Url.
## Server Utilities
```typescript
import { getUser, isSignedIn } from "@/echo";
export default async function Page() {
const signedIn = await isSignedIn();
if (!signedIn) {
return ;
} else {
const user = await getUser();
return ;
}
}
```
## AI Providers
Echo's Next.js SDK provides a thin wrapper around the Vercel AI SDK.
Echo follows their [recommended pattern](https://ai-sdk.dev/docs/getting-started/nextjs-app-router#create-a-route-handler) with a small diff, to route through Echo
instead of the model provider.
```typescript
// [!code --:1]
import { openai } from '@ai-sdk/openai';
// [!code ++:1]
import { openai } from "@/echo";
import { streamText, UIMessage, convertToModelMessages } from 'ai';
// Allow streaming responses up to 30 seconds
export const maxDuration = 30;
export async function POST(req: Request) {
const { messages }: { messages: UIMessage[] } = await req.json();
const result = streamText({
model: openai('gpt-5'),
messages: convertToModelMessages(messages),
});
return result.toUIMessageStreamResponse();
}
```
# Components
URL: /docs/react-sdk/components
***
title: Components
description: Pre-built UI components for authentication and payments
--------------------------------------------------------------------
import { Callout } from 'fumadocs-ui/components/callout';
# Components
**Recommended Approach**: For most applications, use `` as your primary component. It handles the complete user lifecycle including authentication, balance display, token purchases, and sign-out functionality in a single, polished interface.
## EchoTokens
The `` button component handles authentication, balance display, token purchases, and sign-out in one component.
```tsx
import { EchoTokens } from '@merit-systems/echo-react-sdk';
// Complete user management - handles everything
console.log('New balance:', balance)}
onError={(error) => console.error('Error:', error)}
/>
```
### What EchoTokens Handles
* **Authentication**: Shows sign-in button when user is not authenticated
* **Balance Display**: Shows user's available credits (free tier + paid)
* **Token Purchases**: Modal with purchase options and Stripe integration
* **Sign Out**: Built-in sign-out button in the purchase modal
* **Avatar Support**: Optional user profile picture display
* **Error Handling**: Comprehensive error states and messaging
### Usage Patterns
```tsx
// Basic usage - handles everything automatically
// With avatar and custom purchase amount
// Custom styling and callbacks
{
console.log('Purchase successful!', balance);
// Refresh your app state, show success message, etc.
}}
onError={(error) => {
console.error('Operation failed:', error);
// Handle errors, show user feedback, etc.
}}
/>
// Custom button wrapper
```
### Props
```typescript
import type { EchoTokensProps } from '@merit-systems/echo-react-sdk';
```
#### EchoTokensProps
***
## Individual Components
**Most apps should use `` instead** - The individual components below are provided for advanced use cases where you need granular control. EchoTokens handles the complete user flow automatically.
### EchoSignIn
Drop-in component for user authentication with customizable styling and callbacks.
```tsx
import { EchoSignIn } from '@merit-systems/echo-react-sdk';
// Default styled button
console.log('Signed in:', user)}
onError={(error) => console.error('Sign in failed:', error)}
/>
// Custom children (renders as clickable wrapper)
```
**Consider using `` instead** - It includes sign-in functionality plus balance management and token purchases in a single component.
#### Props
```typescript
import type { EchoSignInProps } from '@merit-systems/echo-react-sdk';
```
### EchoSignOut
Component for user sign-out with customizable styling and callbacks.
```tsx
import { EchoSignOut } from '@merit-systems/echo-react-sdk';
// Default styled button
console.log('Signed out successfully')}
onError={(error) => console.error('Sign out failed:', error)}
/>
// Custom children (renders as clickable wrapper)
```
**Consider using `` instead** - It includes a sign-out button in the credits modal, providing a complete user management experience.
#### Props
```typescript
import type { EchoSignOutProps } from '@merit-systems/echo-react-sdk';
```
### Logo
Echo logo component with customizable variants.
```tsx
import { Logo } from '@merit-systems/echo-react-sdk';
```
# Hooks
URL: /docs/react-sdk/hooks
***
title: Hooks
description: Core hooks for authentication, model providers, and platform integration
-------------------------------------------------------------------------------------
# Hooks
## useEcho
Primary hook for accessing authentication state, user information, and core functionality.
```tsx
import { useEcho } from '@merit-systems/echo-react-sdk';
function AuthComponent() {
const {
user,
isAuthenticated,
isLoading,
error,
signIn,
signOut,
token,
getToken
} = useEcho();
if (isLoading) {
return
Loading...
;
}
if (error) {
return
Error: {error}
;
}
if (!isAuthenticated) {
return ;
}
return (
Welcome {user?.name || user?.email}!
);
}
```
### EchoContextValue
The context value provided by EchoProvider, accessible via `useEcho()`.
```typescript
import type { EchoContextValue } from '@merit-systems/echo-react-sdk';
```
#### EchoContextValue
### EchoUser
User information from OAuth2 authentication.
```typescript
import type { EchoUser } from '@merit-systems/echo-react-sdk';
const { user } = useEcho();
```
#### EchoUser
## useEchoClient
Provides access to the Echo TypeScript SDK client for platform operations.
```tsx
import { useEchoClient } from '@merit-systems/echo-react-sdk';
const echoClient = useEchoClient({
apiUrl: 'https://echo.merit.systems'
});
// Access all TypeScript SDK functionality
const apps = await echoClient.apps.listEchoApps();
const balance = await echoClient.balance.getBalance();
```
`useEchoClient` provides a full [Echo TypeScript SDK](/docs/typescript-sdk) client instance, automatically authenticated using the current user's token.
**Common operations:**
* `echoClient.apps.*` - [App management](/docs/typescript-sdk#clientapps---app-management)
* `echoClient.balance.*` - [Balance operations](/docs/typescript-sdk#clientbalance---balance-management)
* `echoClient.payments.*` - [Payment links](/docs/typescript-sdk#clientpayments---payment-management)
* `echoClient.models.*` - [Model information](/docs/typescript-sdk#clientmodels---model-information)
* `echoClient.users.*` - [User operations](/docs/typescript-sdk#clientusers---user-management)
## useEchoModelProviders
Access LLM model providers for direct AI integration.
```tsx
import { useEchoModelProviders } from '@merit-systems/echo-react-sdk';
import { generateText } from 'ai';
function AIComponent() {
const { openai, anthropic } = useEchoModelProviders();
const handleGenerate = async () => {
const { text } = await generateText({
model: openai('gpt-4'),
prompt: 'Hello world'
});
return text;
};
return ;
}
```
## Balance Management
The `useEcho` hook provides balance management functionality:
```tsx
const { balance, freeTierBalance, refreshBalance, createPaymentLink } = useEcho();
```
**balance** - Current account balance
```tsx
Balance: ${balance?.balance || 0}
Total Spent: ${balance?.totalSpent || 0}
```
**freeTierBalance** - Free tier usage information
```tsx
```
**refreshBalance()** - Manually refresh balance data
```tsx
```
**createPaymentLink()** - Create Stripe payment links
```tsx
const paymentUrl = await createPaymentLink(25, 'Credits', '/success');
window.location.href = paymentUrl;
```
# Image Generation
URL: /docs/react-sdk/image-generation
***
title: Image Generation
description: Generate images using DALL-E with Echo's React SDK
---------------------------------------------------------------
# Image Generation
Generate images directly in the browser using Echo's model providers with the [Vercel AI SDK `generateImage`](https://ai-sdk.dev/docs/reference/ai-sdk-core/generate-image).
```tsx {11,16}
import { useEchoModelProviders } from '@merit-systems/echo-react-sdk';
import { experimental_generateImage as generateImage } from 'ai';
function ImageGenerator() {
const { openai } = useEchoModelProviders();
const [imageUrl, setImageUrl] = useState(null);
const [isGenerating, setIsGenerating] = useState(false);
const handleGenerate = async () => {
setIsGenerating(true);
const result = await generateImage({
model: openai.image('dall-e-3'),
prompt: 'A futuristic cityscape at sunset',
size: '1024x1024',
});
if (result.image) {
setImageUrl(`data:image/png;base64,${result.image.base64}`);
}
setIsGenerating(false);
};
return (
{imageUrl && (
)}
);
}
```
Image generation uses the `experimental_generateImage` function which may change in future Vercel AI SDK versions.
# Overview
URL: /docs/react-sdk
***
title: Overview
description: React SDK for direct LLM integration with OAuth2 + PKCE authentication
-----------------------------------------------------------------------------------
# React SDK
The Echo React SDK enables React applications to call LLMs directly from the browser without API keys or backend servers.
Most AI SDKs require API keys which must be secured in a server-side environment. Echo does not.
`echo-react-sdk` handles the Oauth and billing complexity, allowing your React client to make direct secure calls to AI resources.
```tsx
import { useEchoModelProviders } from '@merit-systems/echo-react-sdk';
import { generateText } from 'ai';
function ChatComponent() {
const { openai } = useEchoModelProviders();
const handleGenerate = async () => {
// Direct AI calls from the browser - no API keys needed!
const { text } = await generateText({
model: openai('gpt-5-nano'),
prompt: 'Hello!'
});
return text;
};
return ;
}
```
## Architecture
The React SDK implements a secure OAuth2 + PKCE flow that eliminates API key management:
1. **User Authentication**: OAuth2 + PKCE flow with your Echo app
2. **JWT Token Exchange**: Receive short-lived JWTs with LLM access scope
3. **Direct LLM Calls**: Use tokens directly with OpenAI-compatible endpoints
4. **Automatic Refresh**: Seamless token renewal in the background
This architecture provides:
* **No API key exposure** - Tokens are scoped to individual users
* **Security** - Short-lived tokens with automatic refresh
* **User-scoped billing** - Each user's usage is tracked separately
* **Direct client calls** - No backend proxy required
## Installation
```bash
npm install @merit-systems/echo-react-sdk openai
```
```bash
pnpm add @merit-systems/echo-react-sdk openai
```
```bash
yarn add @merit-systems/echo-react-sdk openai
```
```bash
bun add @merit-systems/echo-react-sdk openai
```
## Quick Start
Wrap your app with `EchoProvider` and start making direct LLM calls:
```tsx title="App.tsx"
import { EchoProvider, EchoSignIn, useEcho, useEchoModelProviders } from '@merit-systems/echo-react-sdk';
import { generateText } from 'ai';
function App() {
return (
);
}
function ChatApp() {
const { isAuthenticated } = useEcho();
const { openai } = useEchoModelProviders();
if (!isAuthenticated) {
return ;
}
const handleGenerate = async () => {
const { text } = await generateText({
model: openai('gpt-5-nano'),
prompt: 'Why did the chicken cross the road?'
});
console.log(text);
};
return ;
}
export default App;
```
## Documentation Sections
* **[Provider](/docs/react-sdk/provider)** - EchoProvider setup and configuration
* **[Components](/docs/react-sdk/components)** - Pre-built UI components for authentication and payments
* **[Hooks](/docs/react-sdk/hooks)** - Core hooks for authentication, model providers, and platform integration
* **[LLM Integration](/docs/react-sdk/llm-integration)** - AI SDK integration and direct model access patterns
* **[Image Generation](/docs/react-sdk/image-generation)** - Generate images using DALL-E with Echo's React SDK
* **[useChat Hook](/docs/react-sdk/use-chat)** - Advanced chat interfaces with streaming and tool usage
# LLM Integration
URL: /docs/react-sdk/llm-integration
***
title: LLM Integration
description: AI SDK integration and direct model access patterns
----------------------------------------------------------------
# LLM Integration
## Vercel AI SDK Integration (Recommended)
The Echo React SDK provides first-class integration with the [Vercel AI SDK](https://ai-sdk.dev/) for the best developer experience.
### `useEchoModelProviders` Hook
Get AI SDK-compatible providers for OpenAI, Anthropic, and Google models for use with [`generateText`](https://ai-sdk.dev/docs/reference/ai-sdk-core/generate-text) or [`streamText`](https://ai-sdk.dev/docs/reference/ai-sdk-core/stream-text).
```tsx title="AIComponent.tsx" lineNumbers
import { useEchoModelProviders } from '@merit-systems/echo-react-sdk';
import { generateText, streamText } from 'ai';
function AIComponent() {
const { openai, anthropic, google } = useEchoModelProviders();
const handleGenerate = async () => {
const { text } = await generateText({
model: openai('gpt-5'),
prompt: 'Write a haiku about coding'
});
setResult(text);
};
const handleStream = async () => {
const { textStream } = await streamText({
model: openai('gpt-5'),
prompt: 'Write a story about space exploration'
});
setResult('');
for await (const delta of textStream) setResult(prev => prev + delta);
};
return (
<>
{result}
>
);
}
```
**Provider Required**: The `useEchoModelProviders` hook must be used within an [`EchoProvider`](/docs/react-sdk/provider) component.
## Custom Chat Hook
For advanced chat interfaces, see our [dedicated useChat documentation](/docs/react-sdk/chat).
## Raw Client Access (Advanced)
For lower-level control, you can create raw clients using your Echo JWT.
```tsx
import { OpenAI } from 'openai';
function RawOpenAIExample() {
const { token } = useEcho();
// This is what happens under the hood
const openai = new OpenAI({
apiKey: token, // Your JWT token acts as the API key
baseURL: 'https://echo.router.merit.systems', // Echo's proxy endpoint
dangerouslyAllowBrowser: true // Safe because token is user-scoped
});
const handleChat = async () => {
const response = await openai.chat.completions.create({
model: 'gpt-5',
messages: [{ role: 'user', content: 'Hello!' }]
});
return response.choices[0].message.content;
};
return ;
}
```
# Provider
URL: /docs/react-sdk/provider
***
title: Provider
description: EchoProvider setup and configuration
-------------------------------------------------
# Provider
## EchoProvider Setup
The `EchoProvider` component wraps your application and manages OAuth2 + PKCE authentication flow state.
```tsx
import { EchoProvider } from '@merit-systems/echo-react-sdk';
function App() {
return (
);
}
```
### EchoAuthConfig
```typescript
import type { EchoAuthConfig } from '@merit-systems/echo-react-sdk';
```
#### EchoAuthConfig
# useChat Hook
URL: /docs/react-sdk/use-chat
***
title: useChat Hook
description: Build chat interfaces with Echo's useChat hook and streaming AI responses
--------------------------------------------------------------------------------------
# useChat Hook
Echo provides a `useChat` hook which is a wrapper around the [Vercel AI SDK](https://ai-sdk.dev/docs/reference/ai-sdk-core/use-chat) `useChat` hook and provides niceties for
creating an Echo-powered chat experience.
```tsx title="App.tsx"
import {
EchoChatProvider,
EchoSignIn,
useEcho,
useEchoModelProviders,
} from "@merit-systems/echo-react-sdk";
import { type ModelMessage, streamText } from "ai";
import { z } from "zod";
import { ChatInterface } from "./ChatInterface.tsx";
function App() {
const { isAuthenticated } = useEcho();
const { openai } = useEchoModelProviders();
const chatFn = async ({
modelMessages,
abortSignal,
}: {
modelMessages: ModelMessage[];
abortSignal: AbortSignal | undefined;
}) => {
const result = streamText({
model: openai("gpt-4o"),
messages: modelMessages,
abortSignal,
tools: {
getWeather: {
description: "Get current weather for a location",
inputSchema: z.object({ location: z.string() }),
execute: async ({ location }: { location: string }) =>
`Weather in ${location}: 72°F and sunny`,
},
},
});
return result.toUIMessageStream();
};
if (!isAuthenticated) return ;
return (
);
}
export default App;
```
```tsx title="ChatInterface.tsx"
import { useChat } from "@merit-systems/echo-react-sdk";
import { useState } from "react";
export function ChatInterface() {
const { messages, sendMessage, status } = useChat();
const [input, setInput] = useState("");
return (
);
}
```
## `useChat` Props
# Anthropic Provider
URL: /docs/providers/anthropic
***
title: Anthropic Provider
description: Claude models with Echo billing integration
--------------------------------------------------------
# Anthropic Provider
The Anthropic provider gives you access to Claude models through the Vercel AI SDK with automatic Echo billing integration.
## Supported Models
All Anthropic models are supported via the `AnthropicModel` type:
# Gemini Provider
URL: /docs/providers/gemini
***
title: Gemini Provider
description: Google Gemini models with Echo billing integration
---------------------------------------------------------------
# Gemini Provider
The Gemini provider gives you access to Google's Gemini models through the Vercel AI SDK with automatic Echo billing integration.
## Supported Models
All Gemini models are supported via the `GeminiModel` type:
## ⚠️ Gemini Limitations
**Important:** Gemini is currently only supported via the `/chat/completions` endpoint. This means:
* Direct Gemini API streaming may not work as expected
* For the most reliable streaming experience, ensure your implementation uses the chat completions interface
* To enable this, you should use the OpenAI Provider, which will hit Gemini's supported chat/completions endpoint.
* For more information, see Google's documentation [here](https://cloud.google.com/vertex-ai/generative-ai/docs/samples/generativeaionvertexai-gemini-chat-completions-non-streaming).
* Streaming will be supported through the Vercel interface for Gemini as soon as possible.
```typescript
const result = streamText({
model: openai.chat('gemini-2.0-flash'),
messages: convertToModelMessages(messages),
});
return result.toUIMessageStreamResponse();
```
To instantiate `openai.chat` in this example, see the following guides:
For React applications, see [React SDK LLM Integration](/docs/react-sdk/llm-integration)
For server-side usage, see [Next.js SDK LLM Integration](/docs/next-sdk/llm-integration)
# OpenAI Provider
URL: /docs/providers/openai
***
title: OpenAI Provider
description: GPT models with Echo billing integration
-----------------------------------------------------
# OpenAI Provider
The OpenAI provider gives you access to GPT models through the Vercel AI SDK with automatic Echo billing integration.
## Supported Models
All OpenAI models are supported via the `OpenAIModel` type:
## Additional Features
### Responses API Support
The OpenAI Responses API is fully supported through Echo's OpenAI provider.
```typescript
const result = streamText({
model: openai.responses('gpt-4o'),
messages: convertToModelMessages(messages),
});
```
### Image Generation with GPT-image-1
Echo also supports OpenAI's image generation capabilities through the GPT-image-1 model:
```typescript
const result = await generateImage({
model: openai.image('gpt-image-1'),
prompt,
});
```
To instantiate `openai.responses` in these examples, see the following guides:
For React applications, see [React SDK LLM Integration](/docs/react-sdk/llm-integration)
For server-side usage, see [Next.js SDK LLM Integration](/docs/next-sdk/llm-integration)
# Authentication
URL: /docs/typescript-sdk/authentication
***
title: Authentication
description: API keys, token providers, and OAuth integration patterns
----------------------------------------------------------------------
# Authentication
Echo supports multiple authentication methods to fit different use cases, from simple API keys to OAuth2 flows.
## API Key Authentication
### Direct API Key
Simplest method for server-side applications:
```typescript
import { EchoClient } from '@merit-systems/echo-typescript-sdk';
const echo = new EchoClient({
apiKey: 'your-api-key'
});
```
### ApiKeyTokenProvider
For more control over token management:
```typescript
import { EchoClient, ApiKeyTokenProvider } from '@merit-systems/echo-typescript-sdk';
const tokenProvider = new ApiKeyTokenProvider('your-api-key');
const echo = new EchoClient({
tokenProvider
});
```
## OAuth Token Provider
For dynamic token management (used by React/Next.js SDKs):
```typescript
import { EchoClient, OAuthTokenProvider } from '@merit-systems/echo-typescript-sdk';
const tokenProvider = new OAuthTokenProvider({
getTokenFn: async () => {
// Return current access token
return getCurrentAccessToken();
},
refreshTokenFn: async () => {
// Refresh and return new token
return await refreshAccessToken();
}
});
const echo = new EchoClient({ tokenProvider });
```
## Token Provider Interface
All token providers implement the `TokenProvider` interface:
```typescript
import type { TokenProvider } from '@merit-systems/echo-typescript-sdk';
```
### TokenProvider
## Creating Custom Token Providers
```typescript
import type { TokenProvider } from '@merit-systems/echo-typescript-sdk';
class CustomTokenProvider implements TokenProvider {
async getToken(): Promise {
// Your custom token retrieval logic
return await getTokenFromCustomSource();
}
async refreshToken(): Promise {
// Your custom token refresh logic
return await refreshTokenFromCustomSource();
}
}
const echo = new EchoClient({
tokenProvider: new CustomTokenProvider()
});
```
# Client
URL: /docs/typescript-sdk/client
***
title: Client
description: EchoClient setup, configuration, and environment management
------------------------------------------------------------------------
# Client
The `EchoClient` is your gateway to the Echo platform, providing access to all platform resources and operations.
## Basic Setup
```typescript
import { EchoClient } from '@merit-systems/echo-typescript-sdk';
const echo = new EchoClient({
apiKey: 'your-api-key'
});
```
## Configuration Options
```typescript
import type { EchoClientOptions } from '@merit-systems/echo-typescript-sdk';
```
### EchoClientOptions
## Environment Configuration
### Using Environment Variables
```typescript
// Automatically uses ECHO_API_KEY and ECHO_BASE_URL if available
const echo = new EchoClient();
// Or explicitly set via environment
process.env.ECHO_API_KEY = 'your-api-key';
process.env.ECHO_BASE_URL = 'https://echo.merit.systems';
```
### Configuration Precedence
1. **Explicit options** - Passed directly to constructor
2. **Environment variables** - `ECHO_API_KEY`, `ECHO_BASE_URL`
3. **Defaults** - `https://echo.merit.systems`
## Resource Access
The client provides access to all platform resources:
```typescript
const echo = new EchoClient({ apiKey: 'your-key' });
// Resource modules
echo.apps // App management
echo.balance // Account balance
echo.payments // Payment operations
echo.models // Supported models
echo.users // User information
```
## Error Handling
```typescript
import { EchoError } from '@merit-systems/echo-typescript-sdk';
try {
const balance = await echo.balance.getBalance();
} catch (error) {
if (error instanceof EchoError) {
console.log('Echo API Error:', error.code, error.message);
} else {
console.log('Network Error:', error);
}
}
```
## Advanced Configuration
### Custom Base URL
```typescript
const echo = new EchoClient({
apiKey: 'your-key',
baseUrl: 'https://custom-echo-instance.com'
});
```
### With Token Provider
```typescript
import { ApiKeyTokenProvider } from '@merit-systems/echo-typescript-sdk';
const tokenProvider = new ApiKeyTokenProvider('your-api-key');
const echo = new EchoClient({
tokenProvider
});
```
For OAuth and advanced authentication patterns, see the [Authentication](/docs/typescript-sdk/authentication) section.
# Overview
URL: /docs/typescript-sdk
***
title: Overview
description: Foundation SDK for direct Echo platform access and AI provider integration
---------------------------------------------------------------------------------------
# TypeScript SDK
The Echo TypeScript SDK is the foundational SDK that provides direct API access to the Echo platform. It serves as the base for the React and Next.js SDKs, offering maximum flexibility for server-side applications, CLI tools, and custom integrations.
## Use Cases
* **Server-side applications** - API routes, backends, microservices
* **CLI tools** - Command-line applications with AI billing
* **Custom integrations** - When you need direct platform control
* **Foundation for other SDKs** - React and Next.js SDKs are built on this
## Installation
```bash
npm install @merit-systems/echo-typescript-sdk
```
```bash
pnpm add @merit-systems/echo-typescript-sdk
```
```bash
yarn add @merit-systems/echo-typescript-sdk
```
```bash
bun add @merit-systems/echo-typescript-sdk
```
## Quick Start
### Platform Operations
```typescript
import { EchoClient } from '@merit-systems/echo-typescript-sdk';
const echo = new EchoClient({
apiKey: 'your-api-key'
});
// Check balance and create payment links
const balance = await echo.balance.getBalance();
const paymentLink = await echo.payments.createPaymentLink({
amount: 10,
description: 'Credits'
});
```
### AI Integration
```typescript
import { createEchoOpenAI } from '@merit-systems/echo-typescript-sdk';
import { generateText } from 'ai';
// Create AI provider with Echo billing
const openai = createEchoOpenAI(
{ appId: 'your-echo-app-id' },
async () => 'your-api-key'
);
// Generate text with automatic billing
const { text } = await generateText({
model: openai('gpt-4'),
prompt: 'Hello world'
});
```
## Documentation Sections
* **[Client](/docs/typescript-sdk/client)** - EchoClient setup, configuration, and environment management
* **[Authentication](/docs/typescript-sdk/authentication)** - API keys, token providers, and OAuth integration patterns
* **[Resources](/docs/typescript-sdk/resources)** - Platform operations: apps, balance, payments, users, models
## Architecture
The TypeScript SDK consists of two main components:
1. **Platform Client** - `EchoClient` for account, billing, and app management
2. **AI Providers** - Factory functions that create Vercel AI SDK compatible providers with Echo billing
This separation allows you to use platform operations independently or combine them with AI functionality as needed.
# Resources
URL: /docs/typescript-sdk/resources
***
title: Resources
description: Platform operations - apps, balance, payments, users, models
-------------------------------------------------------------------------
# Resources
The EchoClient provides access to platform resources through dedicated modules. Each resource handles a specific domain of Echo platform operations.
## Apps Resource
Manage your Echo applications and retrieve app information.
```typescript
const apps = await echo.apps.listEchoApps();
const app = await echo.apps.getEchoApp('app-id');
const appUrl = echo.apps.getAppUrl('app-id');
```
### Methods
* **`listEchoApps()`** - List all your Echo applications
* **`getEchoApp(appId)`** - Get specific application details
* **`getAppUrl(appId)`** - Generate application URL
### Types
```typescript
import type { EchoApp } from '@merit-systems/echo-typescript-sdk';
```
#### EchoApp
## Balance Resource
Check account balance and free tier usage across applications.
```typescript
const balance = await echo.balance.getBalance();
const freeBalance = await echo.balance.getFreeBalance('app-id');
```
### Methods
* **`getBalance()`** - Get total account balance across all apps
* **`getFreeBalance(echoAppId)`** - Get free tier balance for specific app
### Types
```typescript
import type { Balance, FreeBalance, UserSpendInfo } from '@merit-systems/echo-typescript-sdk';
```
#### Balance
#### FreeBalance
#### UserSpendInfo
## Payments Resource
Handle payment links and credit purchases through Stripe integration.
```typescript
const paymentLink = await echo.payments.createPaymentLink({
amount: 25,
description: 'Echo Credits'
});
const paymentUrl = await echo.payments.getPaymentUrl(10, 'Quick Top-up');
```
### Methods
* **`createPaymentLink(request)`** - Create detailed payment link with options
* **`getPaymentUrl(amount, description?, successUrl?)`** - Quick payment URL generation
### Types
```typescript
import type {
CreatePaymentLinkRequest,
CreatePaymentLinkResponse
} from '@merit-systems/echo-typescript-sdk';
```
#### CreatePaymentLinkRequest
#### CreatePaymentLinkResponse
## Models Resource
Get information about supported LLM models, pricing, and capabilities.
```typescript
const chatModels = await echo.models.listSupportedChatModels();
const imageModels = await echo.models.listSupportedImageModels();
```
### Methods
* **`listSupportedChatModels()`** - Get all supported chat models with pricing and metadata
* **`listSupportedImageModels()`** - Get all supported image models with pricing and metadata
### Types
```typescript
import type {
SupportedModel,
SupportedImageModel
} from '@merit-systems/echo-typescript-sdk';
```
#### SupportedModel
#### SupportedImageModel
## Users Resource
Manage user information and referral code registration.
```typescript
const user = await echo.users.getUserInfo();
const referralResult = await echo.users.registerReferralCode('app-id', 'REFERRAL123');
```
### Methods
* **`getUserInfo()`** - Get current user information and spending data
* **`registerReferralCode(echoAppId, code)`** - Register referral code for benefits
### Types
```typescript
import type {
User,
RegisterReferralCodeRequest,
RegisterReferralCodeResponse
} from '@merit-systems/echo-typescript-sdk';
```
#### User
#### RegisterReferralCodeRequest
#### RegisterReferralCodeResponse
## Example Usage
### Complete Platform Operations
```typescript
import { EchoClient } from '@merit-systems/echo-typescript-sdk';
const echo = new EchoClient({ apiKey: process.env.ECHO_API_KEY });
async function platformDemo() {
// Check user and balance
const user = await echo.users.getUserInfo();
const balance = await echo.balance.getBalance();
console.log(`User: ${user.email}, Balance: $${balance.balance}`);
// Create payment link if balance is low
if (balance.balance < 5) {
const payment = await echo.payments.createPaymentLink({
amount: 20,
description: 'Account Top-up'
});
console.log(`Payment link: ${payment.url}`);
}
// List available models
const chatModels = await echo.models.listSupportedChatModels();
const imageModels = await echo.models.listSupportedImageModels();
console.log(`Available chat models: ${chatModels.length}`);
console.log(`Available image models: ${imageModels.length}`);
// Get app information
const apps = await echo.apps.listEchoApps();
console.log(`Your apps: ${apps.length}`);
}
```