InlayDocs

Quickstart

From approved access and a published agent to a session-backed chat in your app.

Start with an approved account, publish an agent, then connect it to your own authenticated app. Code generation is optional; the generic hook is enough for the first integration.

Access, workspace, and key

  1. Request access on the homepage. Onboarding is manual; wait for access approval and the deployment and SDK installation details before continuing.
  2. Sign in to the dashboard supplied during onboarding (the hosted dashboard is app.inlayai.com). Select the intended workspace in the workspace switcher. API routes call this workspace a tenant.
  3. Open API Keys at /<tenant_id>/api-keys, create a named key, and store the one-time-revealed inlay_sk_... value in your server's secret store. A key belongs to the selected workspace, not to a single agent.

If your workspace is missing, have onboarding resolve membership before creating keys or agents elsewhere. Do not put a secret key in a browser env variable, a generated client, or a source-control commit.

Publish an agent

Open Agents in that workspace, create or open an agent, and test its draft on the canvas. For this first chat, use an agent that accepts a user message and replies with assistant text, without client tools that need handlers. Use a model available in your deployment; provider setup must be complete before a test run can succeed.

Click Publish and note the agent UUID and published version. A saved draft is not the release contract your app should depend on. Follow Versions and publishing for the draft, publish, and rollback workflow.

Install the SDK

Use Node.js 20 or later and a Next.js App Router application with React. The source example uses React 19. The integration below needs @inlayai/sdk, @inlayai/react, and @inlayai/next from the same release.

Onboarded app: use the package source, versions, and registry credentials provided during onboarding. Package names in these docs are import names, not a promise that an unqualified public npm install is available. If no installation details were supplied, ask for them rather than guessing a registry, download URL, or CLI package.

Source checkout: if onboarding gives you access to this monorepo, the included projects/inlay/sdk/examples/next-chat app already declares local package dependencies. Install the repository's pinned Rust toolchain with rustup, plus wasm-pack and pnpm 10.28.0 on your PATH, then run from the monorepo root:

rustup target add wasm32-unknown-unknown
pnpm -C projects/inlay/sdk/packages/sdk run build:wasm
pnpm -C projects/inlay/sdk install
pnpm -C projects/inlay/sdk --filter '@inlayai/*' --fail-if-no-match build
pnpm -C projects/inlay/sdk install

Run build:wasm before the first install: it invokes wasm-pack without needing npm dependencies. The install runs the local React package's prepublishOnly tests, which load that generated WASM. The full build then creates the JavaScript packages and WASM assets; the second install refreshes pnpm's local package copies after the build. This is a source-development path, not a public SDK distribution mechanism. After configuring the example's environment and replacing its development auth stub, run pnpm -C projects/inlay/sdk --filter inlay-next-chat-example dev.

For your own app, the two excerpts below show the server/client split. They omit imports and your app-specific auth implementation; add the imports described with each excerpt.

Environment

VariableWhereWhat
INLAY_SECRET_KEYserver onlyThe workspace key used to mint sessions.
NEXT_PUBLIC_INLAY_AGENT_IDbrowserThe published agent UUID from the same workspace.

Keep local secrets in an uncommitted .env.local; configure the equivalent secrets in your deployment. The SDK defaults to https://app.inlayai.com. For staging or self-hosting, explicitly pass baseUrl to both mintSession and useInlayChat. You can read it from INLAY_API_URL on the server and NEXT_PUBLIC_INLAY_API_URL in the browser, but those two functions do not read the variables for you. The CLI uses --base-url (or INLAY_API_URL), not a baseUrl flag.

The full next-chat example has an additional server-side INLAY_AGENT_ID for its session restriction and a .env.example that targets localhost. Set both agent IDs to the same UUID and both API URLs to your intended deployment; do not reuse its local defaults for hosted onboarding.

Mint a session on the server

Your secret key is a server credential — it can start runs for anyone. It must never reach the browser.

mintSession exchanges it for a short-lived, user-scoped session, which is safe to hand to the client. In app/page.tsx, import mintSession from @inlayai/next and Chat from ./chat.

Implement getUserId() using your application's server-verified login. It must reject or redirect unauthenticated visitors before minting, and return a stable user ID. Never accept that ID from an unchecked request parameter or use a shared demo ID for real users: it scopes their conversations, memory, and billing.

// app/page.tsx — a Server Component.
export default async function Page() {
  const session = await mintSession({
    secretKey: process.env.INLAY_SECRET_KEY!,
    userId: await getUserId(),
  });

  return <Chat session={session} />;
}

The minimal mint permits any agent in the key's workspace. For an app that should run only this agent, also pass agentIds: [yourAgentId] to mintSession. Mint per authenticated request; do not cache one user's session for everyone.

A plain Session does not refresh itself. For longer-lived pages, pass an authenticated server action as the session provider, or pair createSessionRoute and createSessionProvider. The transport re-calls a provider after a 401 and retries. Recheck your app's login on every mint, including refreshes.

Render the conversation

In app/chat.tsx, keep "use client" first, then import useInlayChat from @inlayai/react and the Session type from @inlayai/sdk.

// app/chat.tsx — a Client Component.
"use client";

export function Chat({ session }: { session: Session }) {
  const { snapshot, send, canSend } = useInlayChat({
    agentId: process.env.NEXT_PUBLIC_INLAY_AGENT_ID!,
    session,
  });

  // send() RESOLVES on a run failure by default — the reason lands on
  // `snapshot.error` (failures: "reject" restores the rejection; see
  // failure-handling.md). Misuse errors reject either way; the catch covers them.
  const showFailure = (e: unknown) => console.error(e);

  return (
    <>
      {snapshot.rows.map((row, i) => (
        <p key={row.id}>{row.type === "assistant" ? row.content : null}</p>
      ))}

      <button disabled={!canSend} onClick={() => void send("hello").catch(showFailure)}>
        Send
      </button>
    </>
  );
}

That is the whole loop: snapshot.rows is what happened, send adds to it, and canSend tells you when a send is possible.

The split you just wrote — mint on the server, hook in a client component — is the recommended shape, but it is not forced: the hook also runs called directly in Server Components (it renders idle there). See Server and shared components.

What you just got

  • Streaming. Assistant text arrives token by token, revealed at a steady pace rather than in whatever bursts the network delivered.
  • Reconnect-safe ordering. Rows carry server-assigned identity, so a reopened conversation replays in exactly the order it happened.
  • Reactivity that does not cost the whole page. Content, topology, and per-node views are separate subscriptions.

Verify the integration

Send a message as a signed-in user and confirm an assistant row appears. Open Observability in the same workspace to inspect the conversation and the agent version that ran. See the operator guide.

If minting fails, check the key, workspace, API origin, and your auth helper. If a run fails, render snapshot.error as well as handling rejected calls; Failure handling explains the distinction. Do not solve an auth error by exposing the secret key to the browser.

Next

Rendering row.content for every row is the quickstart shortcut. A real UI wants outputs, tool calls and turns to look different — The timeline.

Once the generic integration works, optionally generate a version-pinned typed client. The CLI is not required to mint sessions or use useInlayChat.

On this page