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

# Embed the binder in your product

> Show a client's binder inside your own site as a chromeless iframe, authenticated with a workspace token

The binder (Documents, Forms, and Leadsheets) can be shown inside your own
product as an `<iframe>`, with none of the Filed app's sidebar or top bar. This
is a different integration path from the rest of these guides: instead of
calling the GraphQL API yourself, you send the visitor's browser to a Filed URL
that signs them in and renders the binder UI directly.

```mermaid theme={null}
flowchart LR
  A["Your server"] -->|"1. exchange API key"| B["workspaceToken"]
  B -->|"2. build sign-in URL"| C["iframe src=<br/>/sign-in/token"]
  C -->|"3. sets cookies,<br/>redirects"| D["/embed/workspaces/:id/<br/>clients/:id/binder"]
```

<Note>
  This is a UI embed, not a GraphQL operation. The visitor's browser (inside the
  iframe) authenticates with a cookie, not a `Bearer` header, so none of the
  requests here go through your own backend.
</Note>

## 1. Get a workspace token

Exchange an API key for a `workspaceToken` exactly as described in
[Authentication](/guides/authentication): call
`exchangeSurfaceRefreshTokenForAccessTokens` from your server, and keep the API
key itself on your server. Never send the API key to the browser, only the
short-lived `workspaceToken`.

<Warning>
  The `workspaceToken` is a bearer credential for the workspace: anyone who has it
  can read and write whatever the token's access level allows. Mint it on your
  server, right before rendering the page that embeds the iframe, and never log it.
</Warning>

## 2. Build the sign-in URL

Point the iframe's `src` at `/sign-in/token` on the Filed app domain, with the
token and the embed path you want the visitor to land on:

```
https://web.apps.filed.com/sign-in/token?workspace_token=<jwt>&redirect=<path>
```

<ParamField query="workspace_token" type="string" required>
  The `workspaceToken` from step 1. Must decode to a payload containing a
  `workspaceId` claim, otherwise the visitor is sent to the sign-in page instead.
</ParamField>

<ParamField query="redirect" type="string" required>
  Where to send the browser after the cookie is set. Must be a same-origin
  relative path starting with `/` (not `//`), URL-encoded since it contains `/`.
  For an embed, this is the binder path from step 3.
</ParamField>

<Info>
  `/sign-in/token` also accepts a `user_token` parameter for a different, unrelated
  flow: signing in as a specific user rather than pinning a workspace. It is not
  used for embedding the binder.
</Info>

## 3. Point the iframe at the embed path

`redirect` should point at the chromeless binder:

```
/embed/workspaces/{workspaceId}/clients/{clientId}/binder
```

This renders the same three tabs as the in-app binder, Documents, Forms, and
Leadsheets, with no sidebar and no breadcrumbs. Append `/docs`, `/forms`, or
`/leads2` to land on a specific tab; the bare path redirects to `/docs`.

```html theme={null}
<iframe
  src="https://web.apps.filed.com/sign-in/token?workspace_token=YOUR_WORKSPACE_TOKEN&redirect=%2Fembed%2Fworkspaces%2FYOUR_WORKSPACE_ID%2Fclients%2FYOUR_CLIENT_ID%2Fbinder"
  style="width: 100%; height: 100%; border: 0"
></iframe>
```

## Token expiry

Like every `workspaceToken`, the one used here expires after about 30 minutes.
When it does, the binder shows its own "session expired" state inside the
iframe rather than redirecting out (there is nowhere sensible to redirect an
iframe to on another site). Mint a fresh `workspaceToken`, build a new
`/sign-in/token` URL, and reload the iframe's `src` to recover.

<Tip>
  Rebuild and reset the iframe `src` on an interval shorter than 30 minutes (for
  example every 20) so visitors rarely see the expired state.
</Tip>

## Next steps

* **Authentication**: review how API keys, `workspaceToken`s, and access levels
  work in [Authentication](/guides/authentication).
* **Browse the binder over the API**: to read binder data yourself (files,
  missing items, search) instead of embedding the UI, see
  [Browse a client's binder](/guides/recipes/browse-the-binder).
