> ## Documentation Index
> Fetch the complete documentation index at: https://help.statisfy.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Statisfy SDK Overview

> Embed Statisfy Digital Workers and onboarding Projects into your own web app with the @statisfy/ai-react and @statisfy/portal-react SDK packages.

The Statisfy SDK lets you embed Statisfy experiences — a **Digital Worker chat** and a **Project (onboarding) module** — directly into your own React application or customer portal. Your customers interact with their Statisfy data without ever leaving your product.

It ships as two packages, so you install only the surface you actually render: `@statisfy/ai-react` for Digital Worker chat, `@statisfy/portal-react` for the portal shell and projects.

<Note>
  The SDK is the programmatic counterpart to [Portals](/portals/overview). A Portal is a Statisfy-hosted site; the SDK lets you build the same experiences inside an app you host yourself.
</Note>

## What you can build

<CardGroup cols={2}>
  <Card title="Digital Worker chat" icon="comments">
    A full chat widget that talks to one of your Digital Workers — streaming replies, inline forms, conversation history, unread badges, and live replies from a human CSM.
  </Card>

  <Card title="Project module" icon="list-check">
    A read/write view of a customer's onboarding project: milestones, tasks, progress, and editable fields — as a pre-built component or composable primitives.
  </Card>
</CardGroup>

## Packages

Pick by what you render. Installing both is normal for a portal that also has chat.

| Package | Install it for | Main exports |
| - | - | - |
| `@statisfy/ai-react` | Digital Worker chat, onboarding, tool-call forms | `<DigitalWorkerChat>`, `<OnboardingModule>`, `<DefaultFormRenderer>`, `createDigitalWorkerClient` |
| `@statisfy/portal-react` | The customer-portal shell and onboarding projects | `<PortalAuthGate>`, `<PortalUserMenu>`, `<PortalAccountSwitcher>`, `<ImpersonationBanner>`, `<OnboardingProject>`, `<ProjectModule>`, `useProject`, `useComments` |

Both are ES Modules, peer-depend on `react` and `react-dom` (18 or 19), and are fully typed — every component, hook, and client method ships with type definitions.

**The connection layer is in both.** `<StatisfyProvider>`, `useStatisfyConfig`, `useResolvedFields`, `isFieldRef`, `fetchResolvedFields` and `DigitalWorkerError` are re-exported identically from each package, so a chat-only app never needs the portal package to wrap itself in a provider. Import them from whichever package you already use.

<Note>
  Both packages resolve a third package, `@statisfy/sdk-core`, at runtime. Each declares it as a **required peer dependency**, so npm 7 and newer installs it for you — you never import it directly, and you normally never name it. It exists so that an app rendering both surfaces shares **one** `<StatisfyProvider>` context; two copies would mean a chat that cannot see the provider your portal shell rendered. If your install skips peer dependencies (`legacy-peer-deps` in `.npmrc` or on the command line, or Yarn), install it yourself at the **same version** as the surface package — see [Getting Started](/sdk/getting_started#1-install).
</Note>

**Styles.** Each package ships its own stylesheet — `@statisfy/ai-react/styles.css` and `@statisfy/portal-react/styles.css`. Import one per package you use; both carry the same `--dw-*` token layer, so importing both is idempotent rather than conflicting. All rules sit inside `@layer` and are themeable via `--dw-*` variables and `data-dw-part` selectors (see [Theming](/sdk/theming)).

## How it fits together

```text theme={null}
Your app (React)
│
├─ <StatisfyProvider publishableKey getToken>           ← connection + auth, set once
│   │                                                     (in both packages)
│   ├─ <DigitalWorkerChat workerId=… />                 ← @statisfy/ai-react
│   └─ <OnboardingProject configId="onboarding" />      ← @statisfy/portal-react
│
└─ Statisfy Gateway (api.statisfy.com)
    ├─ /sdk/dw/v1/workers/{id}/…   (chat: messages, stream, conversations)
    └─ /sdk/v1/…                   (projects: config, projects, tasks)
```

You wrap your app once in [`<StatisfyProvider>`](/sdk/getting_started), which supplies authentication. The SDK already points at the Statisfy gateway, so you don't configure a URL. Every SDK component reads that shared config — they never take connection props themselves.

<Note>
  Inside a Statisfy-hosted Portal, components can take their settings from the portal's `portal.runtime.json` rather than props — pass a `configId` instead of a `workerId`. See [Portal Runtime Config](/sdk/portal_config).
</Note>

## Authentication model

The SDK authenticates each request with two pieces:

* **A bearer token** — a short-lived HS256 JWT, signed with your workspace's JWT secret. Your app supplies it through the provider's `getToken` callback; the SDK never mints or stores it.
* **A publishable key** — `pk_live_…` / `pk_test_…`, safe to ship in client-side code. It identifies your Statisfy tenant.

**Where that token comes from depends on how you're using the SDK** — the SDK itself doesn't care, it just calls `getToken`.

<Tabs>
  <Tab title="In your own app (vendored)">
    **Your backend mints the token.** It signs a short-lived HS256 JWT with your workspace's **JWT secret** and hands it to your frontend, which returns it from `getToken`. There is no Statisfy exchange endpoint in this path.

    The claims Statisfy requires are the standard `iat` / `exp` plus the end user's `email`, which is how the gateway resolves who is asking. Because your backend mints the token, the long-lived secret never leaves your server — see [Publishable Keys & Secrets](/admin/publishable_keys).
  </Tab>

  <Tab title="In a Statisfy Portal">
    **Statisfy mints the token.** A hosted portal has no backend of its own, so the customer signs in passwordless: Statisfy emails them a one-time code, and `POST /auth/verify` exchanges that code for a session token plus a rotating refresh token.

    You don't wire this up yourself — `<PortalAuthGate>` renders the sign-in form and owns the token lifecycle, then supplies `StatisfyProvider` internally. Portal templates ship with it already in place.

    That token carries `tenant_id`, `customer_id`, and `portal_id` claims, so the gateway scopes every request to exactly that customer — it never trusts a customer id sent from the browser.
  </Tab>
</Tabs>

<Warning>
  Only the **portal** path produces a token with a `customer_id` claim, and the project endpoints (`/sdk/v1/*`) require one — a vendor-minted token without it is rejected with `401 not_a_portal_session`. The Digital Worker chat endpoints work with either. So `OnboardingProject`, `ProjectModule`, and `useProject` are portal-session features today; chat is available to both.
</Warning>

<Warning>
  In the portal path, the bearer is the short-lived Statisfy session token returned by `/auth/verify` — never the refresh token, which is opaque and only ever sent to `/auth/token`. Never sign tokens in the browser: only the publishable key is safe client-side.
</Warning>

The full token lifecycle, headers, and error codes are in the [API Reference](/sdk/api_reference).

## Next steps

<CardGroup cols={2}>
  <Card title="Getting Started" icon="rocket" href="/sdk/getting_started">
    Install, wire up the provider, mint a token, and render your first component.
  </Card>

  <Card title="Digital Worker Chat" icon="comments" href="/sdk/digital_worker_chat">
    Embed the chat widget, render inline forms, and use the headless client.
  </Card>

  <Card title="Project Module" icon="list-check" href="/sdk/projects">
    Show and update a customer's onboarding project.
  </Card>

  <Card title="Theming" icon="palette" href="/sdk/theming">
    Restyle the widgets with `--dw-*` variables and `data-dw-part` selectors, and opt into dark mode.
  </Card>

  <Card title="Portal Runtime Config" icon="sliders" href="/sdk/portal_config">
    Configure components from `portal.runtime.json` and resolve per-customer `$field` values.
  </Card>

  <Card title="API Reference" icon="code" href="/sdk/api_reference">
    Endpoints, headers, error codes, and TypeScript types.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.