Skip to main content
After a client’s documents have been ingested, 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 reference page; this recipe sequences them rather than re-documenting the types. Everything uses a workspaceToken (see Authentication) and goes to the single GraphQL endpoint:
https://router.apps.filed.com/graphql
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.

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 for the full SubDocumentsFilter arguments.
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
            }
          }
        }
      }
    }
  }
}
{
  "clientId": "018f9c2a-3d5f-7a10-b2c4-9e8d7f6a5b4c",
  "filter": { "unreviewed": true }
}
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 }
    }
  }'
{
  "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"
                }
              ]
            }
          }
        ]
      }
    }
  }
}
Save each subdocument’s id. It is the value you pass as documentPath when creating a document message or signing off on a file later.

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 for the full BinderMissingItemsFilter argument. binder.openMissingItemsCount gives you the open count without fetching the list, which is the cheap query for a badge.
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
            }
          }
        }
      }
    }
  }
}
{
  "clientId": "018f9c2a-3d5f-7a10-b2c4-9e8d7f6a5b4c",
  "filter": { "status": "OPEN" }
}
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" }
    }
  }'
{
  "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"
                }
              ]
            }
          }
        ]
      }
    }
  }
}

3. Ignore or restore a missing item

When a reviewer dismisses a missing item, move it from OPEN to IGNORED with ignoreBinderMissingItem. When they change their mind, move it back to OPEN with restoreBinderMissingItem. Both mutations take the missing-item id (from step 2) and a workspaceId: String!, and return the updated BinderMissingItem with its new status.
Unlike the binder read fields, these two mutations take the workspaceId explicitly. Use the same workspace ID the workspaceToken was issued for.
mutation IgnoreBinderMissingItem($id: ID!, $workspaceId: String!) {
  ignoreBinderMissingItem(id: $id, workspaceId: $workspaceId) {
    id
    status
  }
}
{
  "id": "018f9c2c-5d6e-7f20-9a33-7c4d5e6f7090",
  "workspaceId": "019f0fb6-3001-7900-b7bc-0d11288504b1"
}
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"
    }
  }'
{
  "data": {
    "ignoreBinderMissingItem": {
      "id": "018f9c2c-5d6e-7f20-9a33-7c4d5e6f7090",
      "status": "IGNORED"
    }
  }
}
To undo, call restoreBinderMissingItem with the same id and workspaceId; the item’s status returns to OPEN.
mutation RestoreBinderMissingItem($id: ID!, $workspaceId: String!) {
  restoreBinderMissingItem(id: $id, workspaceId: $workspaceId) {
    id
    status
  }
}
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"
    }
  }'
{
  "data": {
    "restoreBinderMissingItem": {
      "id": "018f9c2c-5d6e-7f20-9a33-7c4d5e6f7090",
      "status": "OPEN"
    }
  }
}
After either mutation, refetch the 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.

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 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.
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
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
{
  "clientId": "018f9c2a-3d5f-7a10-b2c4-9e8d7f6a5b4c",
  "query": "W-2",
  "limit": 20
}
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
    }
  }'
{
  "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
                            }
                          }
                        ]
                      }
                    ]
                  }
                ]
              }
            }
          }
        ]
      }
    }
  }
}

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. 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.
  • 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 for that flow.
  • Badge counts: for a quick badge without fetching the full missing-items list, read binder.messageCounts via Read message counts.
  • Full reference: every binder field, type, and mutation is documented on Binder.