Steerd API

GraphQL

The same resources and projections through one GraphQL endpoint.

The Public API also exposes a GraphQL interface as an alternative to REST. It mirrors the same resources and returns the same public projections.

Endpoint & authentication

  • Operations: POST /api/public/v1/graphql
  • Interactive playground: GET /api/public/v1/graphiql (GraphiQL, public; no key required to load the UI)

Operations require a bearer token:

Authorization: Bearer strd_<key>

In GraphiQL, paste the whole header into the Headers editor to run authenticated operations, e.g. Authorization: Bearer strd_YOUR_KEY.

Schema & resources

The schema mirrors the REST resources: organizations, contacts, projects, employees, cvs, tasks, activities, assignments, time_entries, and a search(q) query. Responses are the same public projections as REST (no team_id, and so on).

Three resources are REST-only, for two different reasons:

  • files and attachments, because their uploads and downloads are binary and do not fit GraphQL.
  • trips, which is read-only everywhere and reachable over REST and MCP but has no GraphQL fields at all.

Use the REST endpoints for those three.

Pagination (cursor connections)

List fields use cursor connection pagination:

{
  contacts(first: 10, after: "…") {
    nodes { id firstName email }
    pageInfo { endCursor hasNextPage }
  }
}
  • first: page size, max 500 (per-resource defaults match the REST limit defaults).
  • after: an opaque cursor from a previous pageInfo.endCursor; omit for the first page.

Paginate by inspecting pageInfo.hasNextPage; if true, pass pageInfo.endCursor as the next after and repeat.

Mutations & write scope

Mutations require a write-scoped key. A read-only key attempting a mutation returns HTTP 200 with a forbidden error:

{
  "errors": [
    { "message": "This API key lacks the required scope", "extensions": { "code": "forbidden" } }
  ]
}
Mutation example
mutation CreateContact {
  createContact(input: { firstName: "Jane", lastName: "Doe", email: "jane@example.com" }) {
    id firstName lastName email createdAt
  }
}

Errors

GraphQL operations always return HTTP 200; errors appear in the errors array with the same codes as REST under extensions.code:

{ "errors": [ { "message": "…", "extensions": { "code": "bad_request" } } ] }

Abuse limits

  • Query depth: maximum nesting level is 10.
  • Query complexity: total budget is 10000. List fields cost roughly min(first, 500) × childComplexity; scalar and object fields cost childComplexity + 1. Wide or deeply nested queries may hit the ceiling.
  • Page size: first is clamped to 1 to 500.

On this page