Skip to main content
This quickstart walks a new integrator through the golden path: from an API key to a client whose documents have been ingested into its binder. Each step links to the detailed reference page for full type detail rather than duplicating it. All requests go to:
https://router.apps.filed.com/graphql
Uploads (step 3) go to a separate host:
https://web.apps.filed.com/api/uploads
1
Get a token
2
Create a workspace-scoped API key in the Filed web app and exchange it for a short-lived workspaceToken. This is the only call you make without a Bearer token.
3
curl -X POST https://router.apps.filed.com/graphql \
  -H "Content-Type: application/json" \
  -d '{
    "query": "mutation ExchangeApiKey($apiKey: String!) { exchangeSurfaceRefreshTokenForAccessTokens(refreshToken: $apiKey) { userToken workspaceToken } }",
    "variables": { "apiKey": "YOUR_API_KEY" }
  }'
4
Save the returned workspaceToken; you send it as Authorization: Bearer YOUR_WORKSPACE_TOKEN on every later request. Full details, including access levels and key expiry, are in Authentication.
5
Confirm it works
6
Run me with the workspaceToken to confirm the token works and to see which workspace it is scoped to. me returns the Me union, which resolves to WorkspaceUser for a workspaceToken, so select fields with an inline fragment:
7
curl -X POST https://router.apps.filed.com/graphql \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_WORKSPACE_TOKEN" \
  -d '{ "query": "query Me { me { __typename ... on WorkspaceUser { id role user { id name email } workspace { id name } } } }" }'
8
A successful response shows your workspace id and name. If you get an UNAUTHENTICATED error, re-exchange your API key for a fresh token (they last about 30 minutes).
9
Upload a document
10
Filed does not accept file bytes over GraphQL. Stage each file with the resumable tus upload endpoint first, then pass the returned upload ID to createClient (next step). A minimal upload is two requests: a POST that creates the upload and returns its location, then a PATCH that sends the bytes.
11
# 1. Create the upload. Metadata values are base64-encoded.
#    filename=w2_1040.pdf  filetype=application/pdf  intent=client-document
LOCATION=$(curl -sS -D - -o /dev/null -X POST https://web.apps.filed.com/api/uploads \
  -H "Authorization: Bearer YOUR_WORKSPACE_TOKEN" \
  -H "Tus-Resumable: 1.0.0" \
  -H "Upload-Length: $(wc -c < w2_1040.pdf)" \
  -H "Upload-Metadata: filename dzJfMTA0MC5wZGY=,filetype YXBwbGljYXRpb24vcGRm,intent Y2xpZW50LWRvY3VtZW50" \
  | tr -d '\r' | awk '/^Location:/ {print $2}')

UPLOAD_ID="${LOCATION##*/}"

# 2. Send the bytes.
curl -sS -X PATCH "$LOCATION" \
  -H "Authorization: Bearer YOUR_WORKSPACE_TOKEN" \
  -H "Tus-Resumable: 1.0.0" \
  -H "Upload-Offset: 0" \
  -H "Content-Type: application/offset+octet-stream" \
  --data-binary @w2_1040.pdf
12
The upload ID is the last path segment of the upload’s Location URL. Keep it for the next step. Full tus details, including chunking and retries, are in Uploading documents.
13
Create a client with the document
14
Pass the upload ID to createClient to create a client and kick off binder ingestion in one call. The mutation returns { client { id }, taskId }: the client.id identifies the new client, and the taskId is the binder ingestion task you poll next.
15
curl -X POST https://router.apps.filed.com/graphql \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_WORKSPACE_TOKEN" \
  -d '{
    "query": "mutation CreateClient($input: CreateClientInput!) { createClient(input: $input) { client { id name externalId status returnType taxYear } taskId } }",
    "variables": {
      "input": {
        "name": "Jane Taxpayer",
        "externalId": "PMS-10432",
        "returnType": "F1040",
        "taxYear": 2025,
        "uploadIds": ["YOUR_UPLOAD_ID"]
      }
    }
  }'
16
{
  "data": {
    "createClient": {
      "client": {
        "id": "018f9c2a-3d5f-7a10-b2c4-9e8d7f6a5b4c",
        "name": "Jane Taxpayer",
        "externalId": "PMS-10432",
        "status": "active",
        "returnType": "F1040",
        "taxYear": 2025
      },
      "taskId": "018f9c2b-1a2b-7c3d-8e4f-5a6b7c8d9e0f"
    }
  }
}
17
Save both client.id and taskId. If you created the client without documents, taskId is null and there is nothing to poll. Full input and return type details are in Clients.
18
Poll the binder task
19
Filed ingests the staged documents into the client’s binder as a background task of type BINDER. Read the task through the client’s tasks(type: BINDER) field and poll until status is COMPLETED (or FAILED).
20
curl -X POST https://router.apps.filed.com/graphql \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_WORKSPACE_TOKEN" \
  -d '{
    "query": "query ClientTaskStatus($clientId: ID!, $type: TaskType) { me { ... on WorkspaceUser { workspace { clients(filters: { ids: [$clientId] }) { tasks(type: $type) { id status startedAt completedAt errorMessage subTasks { type status } } } } } } }",
    "variables": { "clientId": "YOUR_CLIENT_ID", "type": "BINDER" }
  }'
21
{
  "data": {
    "me": {
      "workspace": {
        "clients": [
          {
            "tasks": [
              {
                "id": "018f9c2b-1a2b-7c3d-8e4f-5a6b7c8d9e0f",
                "status": "COMPLETED",
                "startedAt": "2026-07-04T09:15:00.000Z",
                "completedAt": "2026-07-04T09:17:42.000Z",
                "errorMessage": null,
                "subTasks": [
                  { "type": "CONVERT_DOCUMENTS", "status": "COMPLETED" },
                  { "type": "CLASSIFY_SUBDOCS", "status": "COMPLETED" },
                  { "type": "EXTRACT_SUBDOCS", "status": "COMPLETED" },
                  { "type": "EXPORT_AND_INDEX", "status": "COMPLETED" }
                ]
              }
            ]
          }
        ]
      }
    }
  }
}
22
Poll on an interval (for example every few seconds) until status is no longer RUNNING. COMPLETED means the documents are filed in the binder; FAILED means ingestion did not succeed, and errorMessage explains why.
23
There is no task(id:) query; you read a task through its client. Full task, filter, and result type details are in Tasks.

Next steps