> ## 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.

# Browse a client's binder

> List the files in a client's binder, check the missing-item checklist, ignore or restore an item, and search across the binder

After a client's documents have been [ingested](/guides/recipes/onboard-a-client),
the binder is the place to browse what Filed filed: the uploaded files
(subdocuments), the missing-item checklist the run produced, and a search
surface across bookmarks, annotations, and document contents. This recipe walks
through the real call sequence a reviewer-facing integration uses to browse a
client's binder.

Every operation here is documented on the [Binder](/apis/binder) reference page;
this recipe sequences them rather than re-documenting the types. Everything uses
a **`workspaceToken`** (see [Authentication](/guides/authentication)) and goes to
the single GraphQL endpoint:

```
https://router.apps.filed.com/graphql
```

<Note>
  The binder belongs to a client, so there is no top-level `binder` query. Reach
  it through
  `me { ... on WorkspaceUser { workspace { clients(filters: { ids: [$clientId] }) { binder { ... } } } } }`.
  The `workspaceToken` already identifies the workspace, so you never pass a
  workspace ID to read the binder.
</Note>

```mermaid theme={null}
flowchart LR
  A["Client ID"] --> B["1. List files<br/>(subdocuments)"]
  A --> C["2. Check missing items<br/>(missingItems + openMissingItemsCount)"]
  C --> D["3. Ignore / restore<br/>an item"]
  A --> E["4. Search<br/>(binder.search)"]
  B --> F["subdocument id =<br/>documentPath for<br/>annotations & sign-offs"]
  E --> F
```

## 1. List the files in the binder

Read `binder.subdocuments` to list the files Filed filed for the client. This is
the most common read against the binder and backs the binder's Documents screen.
Pass a `SubDocumentsFilter` to narrow to unreviewed, flagged, or files under one
parent document; pass `null` to list everything. See
[List the files in a binder](/apis/binder#list-the-files-in-a-binder) for the full
`SubDocumentsFilter` arguments.

```graphql theme={null}
query GetClientBinderSubdocuments($clientId: ID!, $filter: SubDocumentsFilter) {
  me {
    ... on WorkspaceUser {
      id
      workspace {
        clients(filters: { ids: [$clientId] }) {
          id
          binder {
            id
            subdocuments(filter: $filter) {
              id
              fileName
              type
              issuer
              taxYear
              status
              category
            }
          }
        }
      }
    }
  }
}
```

```json theme={null}
{
  "clientId": "018f9c2a-3d5f-7a10-b2c4-9e8d7f6a5b4c",
  "filter": { "unreviewed": true }
}
```

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST https://router.apps.filed.com/graphql \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer YOUR_WORKSPACE_TOKEN" \
    -d '{
      "query": "query GetClientBinderSubdocuments($clientId: ID!, $filter: SubDocumentsFilter) { me { ... on WorkspaceUser { id workspace { clients(filters: { ids: [$clientId] }) { id binder { id subdocuments(filter: $filter) { id fileName type issuer taxYear status category } } } } } } }",
      "variables": {
        "clientId": "018f9c2a-3d5f-7a10-b2c4-9e8d7f6a5b4c",
        "filter": { "unreviewed": true }
      }
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json theme={null}
  {
    "data": {
      "me": {
        "id": "019f0fb6-37b1-7800-b7bc-0d11288504b1",
        "workspace": {
          "clients": [
            {
              "id": "018f9c2a-3d5f-7a10-b2c4-9e8d7f6a5b4c",
              "binder": {
                "id": "018f9c2a-4b6f-7a10-b2c4-9e8d7f6a5b4d",
                "subdocuments": [
                  {
                    "id": "018f9c2a-7b1e-7c3d-9a4e-2f6b1c8d0e5a",
                    "fileName": "1099-INT-Acme-Broker.pdf",
                    "type": "1099-INT",
                    "issuer": "Acme Broker",
                    "taxYear": 2025,
                    "status": "ingested",
                    "category": "income"
                  }
                ]
              }
            }
          ]
        }
      }
    }
  }
  ```
</ResponseExample>

<Tip>
  Save each subdocument's `id`. It is the value you pass as `documentPath` when
  [creating a document message](/apis/document-messages#annotations) or
  [signing off](/apis/leadsheets#sign-off-on-a-sheet-or-row) on a file later.
</Tip>

## 2. Check the missing-item checklist

Read `binder.missingItems` to list the missing-document checklist the run
produced: forms the run expected to find but did not. Each item carries a
`severity` (`CRITICAL`, `MEDIUM`, `LOW`), a `status` (`OPEN`, `IGNORED`,
`RESOLVED`), and a `reason`. Filter by status to read only the open items, which
is what a reviewer-facing UI shows first. See
[List missing items](/apis/binder#list-missing-items) for the full
`BinderMissingItemsFilter` argument.

`binder.openMissingItemsCount` gives you the open count without fetching the
list, which is the cheap query for a badge.

```graphql theme={null}
query GetClientBinderMissingItems($clientId: ID!, $filter: BinderMissingItemsFilter) {
  me {
    ... on WorkspaceUser {
      id
      workspace {
        clients(filters: { ids: [$clientId] }) {
          id
          binder {
            id
            openMissingItemsCount
            missingItems(filter: $filter) {
              id
              item
              formType
              issuer
              taxYear
              severity
              reason
              status
              category
            }
          }
        }
      }
    }
  }
}
```

```json theme={null}
{
  "clientId": "018f9c2a-3d5f-7a10-b2c4-9e8d7f6a5b4c",
  "filter": { "status": "OPEN" }
}
```

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST https://router.apps.filed.com/graphql \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer YOUR_WORKSPACE_TOKEN" \
    -d '{
      "query": "query GetClientBinderMissingItems($clientId: ID!, $filter: BinderMissingItemsFilter) { me { ... on WorkspaceUser { id workspace { clients(filters: { ids: [$clientId] }) { id binder { id openMissingItemsCount missingItems(filter: $filter) { id item formType issuer taxYear severity reason status category } } } } } } }",
      "variables": {
        "clientId": "018f9c2a-3d5f-7a10-b2c4-9e8d7f6a5b4c",
        "filter": { "status": "OPEN" }
      }
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json theme={null}
  {
    "data": {
      "me": {
        "id": "019f0fb6-37b1-7800-b7bc-0d11288504b1",
        "workspace": {
          "clients": [
            {
              "id": "018f9c2a-3d5f-7a10-b2c4-9e8d7f6a5b4c",
              "binder": {
                "id": "018f9c2a-4b6f-7a10-b2c4-9e8d7f6a5b4d",
                "openMissingItemsCount": 1,
                "missingItems": [
                  {
                    "id": "018f9c2c-5d6e-7f20-9a33-7c4d5e6f7090",
                    "item": "W-2 from Initech",
                    "formType": "W-2",
                    "issuer": "Initech",
                    "taxYear": 2025,
                    "severity": "CRITICAL",
                    "reason": "Expected a W-2 from Initech but no matching document was found in the binder.",
                    "status": "OPEN",
                    "category": "income"
                  }
                ]
              }
            }
          ]
        }
      }
    }
  }
  ```
</ResponseExample>

## 3. Ignore or restore a missing item

When a reviewer dismisses a missing item, move it from `OPEN` to `IGNORED` with
[`ignoreBinderMissingItem`](/apis/binder#ignore-a-missing-item). When they change
their mind, move it back to `OPEN` with
[`restoreBinderMissingItem`](/apis/binder#restore-a-missing-item). Both mutations
take the missing-item `id` (from step 2) and a `workspaceId: String!`, and
return the updated `BinderMissingItem` with its new `status`.

<Warning>
  Unlike the binder read fields, these two mutations take the `workspaceId`
  explicitly. Use the same workspace ID the `workspaceToken` was issued for.
</Warning>

```graphql theme={null}
mutation IgnoreBinderMissingItem($id: ID!, $workspaceId: String!) {
  ignoreBinderMissingItem(id: $id, workspaceId: $workspaceId) {
    id
    status
  }
}
```

```json theme={null}
{
  "id": "018f9c2c-5d6e-7f20-9a33-7c4d5e6f7090",
  "workspaceId": "019f0fb6-3001-7900-b7bc-0d11288504b1"
}
```

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST https://router.apps.filed.com/graphql \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer YOUR_WORKSPACE_TOKEN" \
    -d '{
      "query": "mutation IgnoreBinderMissingItem($id: ID!, $workspaceId: String!) { ignoreBinderMissingItem(id: $id, workspaceId: $workspaceId) { id status } }",
      "variables": {
        "id": "018f9c2c-5d6e-7f20-9a33-7c4d5e6f7090",
        "workspaceId": "019f0fb6-3001-7900-b7bc-0d11288504b1"
      }
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json theme={null}
  {
    "data": {
      "ignoreBinderMissingItem": {
        "id": "018f9c2c-5d6e-7f20-9a33-7c4d5e6f7090",
        "status": "IGNORED"
      }
    }
  }
  ```
</ResponseExample>

To undo, call `restoreBinderMissingItem` with the same `id` and `workspaceId`;
the item's `status` returns to `OPEN`.

```graphql theme={null}
mutation RestoreBinderMissingItem($id: ID!, $workspaceId: String!) {
  restoreBinderMissingItem(id: $id, workspaceId: $workspaceId) {
    id
    status
  }
}
```

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST https://router.apps.filed.com/graphql \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer YOUR_WORKSPACE_TOKEN" \
    -d '{
      "query": "mutation RestoreBinderMissingItem($id: ID!, $workspaceId: String!) { restoreBinderMissingItem(id: $id, workspaceId: $workspaceId) { id status } }",
      "variables": {
        "id": "018f9c2c-5d6e-7f20-9a33-7c4d5e6f7090",
        "workspaceId": "019f0fb6-3001-7900-b7bc-0d11288504b1"
      }
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json theme={null}
  {
    "data": {
      "restoreBinderMissingItem": {
        "id": "018f9c2c-5d6e-7f20-9a33-7c4d5e6f7090",
        "status": "OPEN"
      }
    }
  }
  ```
</ResponseExample>

<Tip>
  After either mutation, refetch the
  [List missing items](/apis/binder#list-missing-items) query so the open count
  and the list agree. The web app optimistically updates `openMissingItemsCount`
  in its cache, then refetches to confirm.
</Tip>

## 4. Search the binder

Read `binder.search` to search across bookmarks (subdocuments by file name,
issuer, type, or category), annotations, marks, and document contents in one
call. Pass the `clientId`, the `query` string, and an optional `limit` (defaults
to `20`). See [Search the binder](/apis/binder#search-the-binder) for the full
`BinderSearchResults` shape.

The web app debounces the input and requires at least two characters before
firing the query; mirror that to avoid noisy partial queries.

```graphql theme={null}
query BinderSearch($clientId: ID!, $query: String!, $limit: Int = 20) {
  me {
    ... on WorkspaceUser {
      id
      workspace {
        clients(filters: { ids: [$clientId] }) {
          id
          binder {
            id
            search(query: $query, limit: $limit) {
              bookmarks {
                matchedField
                snippet
                subdocument {
                  id
                  fileName
                  type
                  issuer
                  category
                  pageRange
                }
              }
              annotations {
                matchedField
                snippet
                isReply
                message {
                  id
                  type
                  subDocumentPath
                  pageNumber
                  content
                  createdBy
                  createdAt
                }
              }
              marks {
                matchedField
                snippet
                isReply
                message {
                  id
                  type
                  subDocumentPath
                  pageNumber
                  content
                  createdBy
                  createdAt
                }
              }
              contents {
                snippet
                subdocument {
                  id
                  fileName
                  type
                  issuer
                  category
                  pageRange
                  canonicalPath
                }
                pages {
                  pageNumber
                  fieldMatches {
                    fieldName
                    value
                    bbox {
                      xMin
                      yMin
                      xMax
                      yMax
                      pageNumber
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
```

```json theme={null}
{
  "clientId": "018f9c2a-3d5f-7a10-b2c4-9e8d7f6a5b4c",
  "query": "W-2",
  "limit": 20
}
```

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST https://router.apps.filed.com/graphql \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer YOUR_WORKSPACE_TOKEN" \
    -d '{
      "query": "query BinderSearch($clientId: ID!, $query: String!, $limit: Int = 20) { me { ... on WorkspaceUser { id workspace { clients(filters: { ids: [$clientId] }) { id binder { id search(query: $query, limit: $limit) { bookmarks { matchedField snippet subdocument { id fileName type issuer category pageRange } } annotations { matchedField snippet isReply message { id type subDocumentPath pageNumber content createdBy createdAt } } marks { matchedField snippet isReply message { id type subDocumentPath pageNumber content createdBy createdAt } } contents { snippet subdocument { id fileName type issuer category pageRange canonicalPath } pages { pageNumber fieldMatches { fieldName value bbox { xMin yMin xMax yMax pageNumber } } } } } } } } } } }",
      "variables": {
        "clientId": "018f9c2a-3d5f-7a10-b2c4-9e8d7f6a5b4c",
        "query": "W-2",
        "limit": 20
      }
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json theme={null}
  {
    "data": {
      "me": {
        "id": "019f0fb6-37b1-7800-b7bc-0d11288504b1",
        "workspace": {
          "clients": [
            {
              "id": "018f9c2a-3d5f-7a10-b2c4-9e8d7f6a5b4c",
              "binder": {
                "id": "018f9c2a-4b6f-7a10-b2c4-9e8d7f6a5b4d",
                "search": {
                  "bookmarks": [
                    {
                      "matchedField": "TYPE",
                      "snippet": "W-2",
                      "subdocument": {
                        "id": "018f9c2a-9c1e-7c3d-9a4e-2f6b1c8d0e6a",
                        "fileName": "W-2-Initech.pdf",
                        "type": "W-2",
                        "issuer": "Initech",
                        "category": "income",
                        "pageRange": [1]
                      }
                    }
                  ],
                  "annotations": [
                    {
                      "matchedField": "BODY",
                      "snippet": "W-2 from Initech looks correct",
                      "isReply": false,
                      "message": {
                        "id": "018f9c2d-1a2b-7c3d-9a4e-2f6b1c8d0e7a",
                        "type": "annotation",
                        "subDocumentPath": "018f9c2a-9c1e-7c3d-9a4e-2f6b1c8d0e6a",
                        "pageNumber": 1,
                        "content": { "body": "W-2 from Initech looks correct" },
                        "createdBy": "019f0fb6-37b1-7800-b7bc-0d11288504b1",
                        "createdAt": "2026-07-04T16:20:00.000Z"
                      }
                    }
                  ],
                  "marks": [],
                  "contents": [
                    {
                      "snippet": "Wages: 52,000.00",
                      "subdocument": {
                        "id": "018f9c2a-9c1e-7c3d-9a4e-2f6b1c8d0e6a",
                        "fileName": "W-2-Initech.pdf",
                        "type": "W-2",
                        "issuer": "Initech",
                        "category": "income",
                        "pageRange": [1],
                        "canonicalPath": "clients/018f9c2a-3d5f-7a10-b2c4-9e8d7f6a5b4c/source_docs/018f9c2a-9c1e-7c3d-9a4e-2f6b1c8d0e6a/canonical.json"
                      },
                      "pages": [
                        {
                          "pageNumber": 1,
                          "fieldMatches": [
                            {
                              "fieldName": "wages",
                              "value": "52000.00",
                              "bbox": {
                                "xMin": 88,
                                "yMin": 412,
                                "xMax": 220,
                                "yMax": 428,
                                "pageNumber": 1
                              }
                            }
                          ]
                        }
                      ]
                    }
                  ]
                }
              }
            }
          ]
        }
      }
    }
  }
  ```
</ResponseExample>

## Next steps

From here you can go deeper on the binder's related surfaces:

* **Annotations and sign-offs**: when search surfaces an annotation you want to
  reply to, or you want to leave a new note on a file, use the
  [Document messages API](/apis/document-messages#annotations). Sign-offs on a
  leadsheet sheet or row use the same `createDocumentMessage` mutation with
  `type: "activity"`, `markType: "signoff"`; see
  [Sign off on a sheet or row](/apis/leadsheets#sign-off-on-a-sheet-or-row).
* **Leadsheets and review**: the binder also carries a `leadsheets` field that
  returns the leadsheets tree for a `TAX_PREP` or `TAX_REVIEW` run. See
  [Read a client's leadsheets](/apis/leadsheets#read-a-clients-leadsheets) for
  that flow.
* **Badge counts**: for a quick badge without fetching the full missing-items
  list, read `binder.messageCounts` via
  [Read message counts](/apis/binder#read-message-counts).
* **Full reference**: every binder field, type, and mutation is documented on
  [Binder](/apis/binder).
