# 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: ( Next.js ), 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

Free Credits Remaining: ${freeTierBalance?.userSpendInfo.amountLeft || 0}

``` **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 && ( Generated image )}
); } ``` 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 (
{messages.map((message) => (
{message.role === "user" ? "User: " : "AI: "} {message.parts.map((part, index) => part.type === "text" ? ( {part.text} ) : null, )}
))}
{ e.preventDefault(); if (input.trim()) { sendMessage({ text: input }); setInput(""); } }} > setInput(e.target.value)} disabled={status !== "ready"} placeholder="Say something..." />
); } ``` ## `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}`); } ```