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

# Conventions

> Cross-cutting conventions for the Filed GraphQL API: custom scalars, IDs, pagination, sorting, and filtering

The Filed API uses a small set of conventions that apply to every operation:
custom GraphQL scalars, opaque identifiers, offset-based pagination, a shared
sort input, and typed filter inputs. This page is the single reference for those
conventions so callers and AI agents do not have to infer them. For the full
type detail of a specific operation, see [Clients](/apis/clients) and
[Tasks](/apis/tasks).

All requests go to:

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

## Scalars

The schema builds on the standard GraphQL scalars and adds two custom ones.
Both are declared at the top of the platform schema:

```graphql theme={null}
scalar Date
scalar JSON
```

### `ID`

The `ID` scalar is the type used for every identifiable object: clients, tasks,
workspace users, uploads, and so on. Treat it as an **opaque string**. Always
send it back exactly as you received it; never parse it, slice it, or assume a
specific length. The two concrete scalar declarations in the live schema are
`ID` (the built-in) and the custom `Date` and `JSON` below.

<Note>
  Filed `ID` values are **UUIDv7** strings, for example
  `019f0fb6-37b1-7800-b7bc-0d11288504b1`. You can confirm this from any example
  response in these docs: the first three segments encode a Unix timestamp
  (milliseconds) so IDs are roughly time-ordered, followed by random bits. This is
  an implementation detail you can rely on for ordering and debugging, but you
  should still round-trip the value as an opaque string and not construct IDs
  yourself.
</Note>

### `Date`

The `Date` scalar is an **ISO 8601 timestamp string** (RFC 3339), for example
`2025-07-04T17:21:43.123Z`. Every timestamp field in the schema (`createdAt`,
`startedAt`, `completedAt`, etc.) uses this scalar, even when the field name
does not contain the word `Date`. `startedAt` and `completedAt` on `Task` are
non-null `String` rather than the `Date` scalar, but they carry the same
ISO 8601 string format.

### `JSON`

The `JSON` scalar holds an arbitrary JSON value: an object, array, string,
number, boolean, or null. It is used wherever a field's value is structured
but not fixed by the schema, for example AI task results. The
`TaskTaxAdvisorResult.byDomain` field is a non-null `JSON` scalar that returns
a structured object whose shape is defined by the tax advisor task, not by the
GraphQL type system.

```graphql theme={null}
type TaskTaxAdvisorResult {
  taxYear: Int!
  returnType: ReturnType!
  summary: String!
  strategyTotal: Int!
  byDomain: JSON!
  bySavingsHorizon: JSON!
  estimatedSavingsCentsByHorizon: JSON!
}
```

<Tip>
  When you select a `JSON` field, you get the whole value back as-is. There is no
  sub-selection, so for deeply structured results you parse the JSON on the
  client. Keep your client's parser lenient: the object's keys can grow over time.
</Tip>

## Pagination

List fields use **offset-based pagination** with two optional integer
arguments, `offset` and `limit`. Both are plain `Int` scalars (nullable, so
you can omit either).

* `offset` is the number of items to skip before the first returned item. It is
  zero-based, so `offset: 0` (or omitting it) returns from the start.
* `limit` is the maximum number of items to return in a single response.
* The list is always a non-null list of non-null items, for example
  `[Client!]!` or `[Task!]!`. An empty page is an empty array, never `null`.

<Note>
  The Filed API does not currently expose a cursor-based `Connection` type or a
  `totalCount` field. Page through a list by walking `offset` forward in steps of
  `limit` until the returned list is shorter than `limit` (or empty). The
  `Workspace.tasks` and `Workspace.clients` fields both follow this shape.
</Note>

### Example: page through clients

```graphql theme={null}
query ListClients($offset: Int, $limit: Int) {
  me {
    ... on WorkspaceUser {
      workspace {
        clients(offset: $offset, limit: $limit) {
          id
          name
        }
      }
    }
  }
}
```

```json theme={null}
{
  "offset": 0,
  "limit": 25
}
```

Send the next request with `"offset": 25` and the same `limit` to fetch the
next page. Stop when fewer than `limit` items come back. See
[Clients](/apis/clients) for the full `Client` type and the `filters`/`sortBy`
arguments.

## Sorting

List fields that accept `sortBy` use the shared `SortBy` input type. It is a
single optional argument applied to the list before pagination.

```graphql theme={null}
input SortBy {
  field: String!
  order: SortByOrder!
}

enum SortByOrder {
  ASC
  DESC
}
```

`field` is the name of the field to sort by, as a string (for example
`"createdAt"`, `"name"`, `"startedAt"`). `order` is `ASC` for ascending or
`DESC` for descending. Both `field` and `order` are non-null inside `SortBy`,
so if you pass a `sortBy` value at all you must supply both. Omit the whole
`sortBy` argument to use the API's default order.

```json theme={null}
{
  "sortBy": { "field": "createdAt", "order": "DESC" }
}
```

The same `SortBy` input is reused by every list field that supports sorting:
`Workspace.clients`, `Workspace.tasks`, and `Workspace.workspaceUsers`.

## Filtering

List fields take a typed filter input named after the entity: `ClientFilters`
for clients, `TaskFilters` for tasks. Each input is a nullable argument, so
you can omit it entirely or pass only the keys you care about. Every key inside
the input is itself optional, and combining keys applies them as a logical AND.

### `ClientFilters`

```graphql theme={null}
input ClientFilters {
  ids: [ID!]
  status: [ClientStatus!]
  search: String
  assigneeIds: [ID!]
  assignedToMe: Boolean
}

enum ClientStatus {
  active
  archived
}
```

Use `ids` to fetch a known set of clients by ID (passing a single-element list
is how you [fetch one client](/apis/clients#fetch-a-single-client)). Use
`status` to filter by lifecycle state, `search` for free-text search over
client name and external ID, and `assigneeIds` or `assignedToMe` to filter by
assignee. Full field detail is on the [Clients](/apis/clients) page.

### `TaskFilters`

```graphql theme={null}
input TaskFilters {
  type: TaskType
  status: TaskStatus
  triggeredBy: ID
  search: String
}
```

Filter tasks by `type` (for example `BINDER` to follow a binder job), by
`status` (`RUNNING`, `COMPLETED`, `FAILED`), by the user who started the task
with `triggeredBy`, or with free-text `search`. Full field detail is on the
[Tasks](/apis/tasks) page.

<Note>
  `Client.tasks(type:, status:, triggeredBy:, limit:)` takes the same filtering
  concepts as inline scalar arguments (not a `TaskFilters` input) and does not
  take `offset` or `sortBy`. Use it when you want the tasks for one client; use
  `Workspace.tasks(filters:, sortBy:, limit:, offset:)` when you want tasks
  across the whole workspace.
</Note>

## Next steps

* [Making requests](/guides/making-requests) for the request anatomy and error
  model.
* [Clients](/apis/clients) and [Tasks](/apis/tasks) for the full type detail of
  each list field.
* [Authentication](/guides/authentication) to mint the `workspaceToken` these
  conventions assume.
