Skip to main content

Overview

The Hireflix API is built using GraphQL, a modern query language for APIs. Unlike REST, GraphQL uses a single endpoint where you describe exactly what data you need — no more, no less. In this tutorial, you’ll learn:
  • The difference between queries and mutations
  • What union types are and how to use __typename
  • How to interpret success and error responses

Queries vs. Mutations

In GraphQL, every request is either a query or a mutation.

Query

Goal: Fetch data without making changes.Examples: Listing positions or fetching interview results.

Mutation

Goal: Make changes to data.Examples: Inviting a candidate, archiving a position, or deleting an interview.

Example: Query

Let’s look at this example queyr which fetches a list of open positions:
query GetPositions {
  positions {
    id
    name
    archived
  }
}
Here’s what each part means:
  1. query GetPositions
    • The keyword query tells GraphQL you’re requesting data rather than changing it.
    • GetPositions is an operation name. You can think of it like a label for your query. It’s optional but useful for debugging or when running multiple queries.
  2. positions
    • This is the root field being requested from the Hireflix API.
    • Each GraphQL API defines a schema describing which root fields are available — in this case, positions returns a list of Position objects (each representing a job).
  3. { id name archived }
    • Inside the curly braces { ... } you specify exactly which fields you want to retrieve for each position. You can only request fields defined by the schema for the Position type.
    • GraphQL only returns the fields you explicitly request: nothing more, nothing less. If you add tags or createdAt, they’ll appear in the response.

Response structure for a query:

The shape of the response matches the query:
  • The top-level data key always wraps your requested fields.
  • Each object under positions contains exactly the fields you asked for — no hidden data or unused properties.
{
  "data": {
    "positions": [
      { "id": "68d53cf0a3d3c03c50f103c3", "name": "Sales Manager", "archived": null },
      { "id": "68d53cf0a3d3c03c50f103c4", "name": "Marketing Lead", "archived": 1760271725833 }
    ]
  }
}

Example: Mutation

Invite a new candidate to an interview:
mutation InviteCandidate {
  inviteCandidateToInterview(
    input: {
      candidate: {
        email: "jane.doe@example.com"
        firstName: "Jane"
        lastName: "Doe"
      }
      positionId: "68d53cf0a3d3c03c50f103c3"
    }
  ) {
    id
    url
  }
}
Let’s break this down:
  1. mutation InviteCandidateToInterview
    • The keyword mutation tells GraphQL you want to change data. For example, creating, updating, or deleting something.
    • InviteCandidateToInterview is the operation name (optional, but helpful for identifying the mutation later).
  2. inviteCandidateToInterview(...)
    • This is the mutation field. Think of it as a function exposed by the API.
    • The parentheses ( ... ) contain the arguments the mutation expects.
      • Here, it accepts a single argument named input, which bundles all the required parameters like email, firstName, and lastName to invite a candidate.
      • The way the arguments are structured is determined by the mutation field. Each mutation has a different set of input parameters.
  3. Selection set: (the { ... } after the mutation)
    • This part defines what data you want back from the mutation. Even when you’re modifying data, you can decide what to return, just like a query. In this case, we want to receive the interview ID and the interview url so we can use it in our frontend.

Example: Mutation With Union Type

Some mutations use the Union Type notation (... on Type), which GraphQL provides. It allows you to better interpret the returned object, which improves error handling.
mutation InviteCandidateToInterview {
  inviteCandidateToInterview(
    input: {
      candidate: {
        email: "jane.doe@example.com"
        firstName: "Jane"
        lastName: "Doe"
      }
      positionId: "68d53cf0a3d3c03c50f103c3"
    }
  ) {
    __typename
    ... on InterviewType {
      id
      url {
        public
        short
      }
    }
    ... on InterviewAlreadyExistsInPositionError {
      code
      message
    }
	... on ExceededInvitesThisPeriodError {
      code
      message
    }
  }
}
Now this mutation uses a union type. That means it can return one of several result types:
  • InterviewType — success (interview created).
  • InterviewAlreadyExistsInPositionError — candidate already invited.
  • ExceededInvitesThisPeriodError — plan limit reached.
You can determine which result you received by checking the __typename field. This is why many Hireflix queries include it. It helps you detect whether the operation succeeded or failed. In GraphQL, even when a mutation fails, the API still returns an HTTP 200 response. Errors are instead reported in one of two ways:
  • Through an errors array (for most operations), or
  • As an error object identified by its __typename (for union-type mutations).
Because of this, you should not rely on HTTP status codes like 400 to detect errors. Always inspect the response body instead. Response example (success)
{
  "data": {
    "inviteCandidateToInterview": {
      "__typename": "InterviewType",
      "id": "68d4164f19367e041b2030c0",
      "url": {
        "public": "https://app.hireflix.com/HQ2oCyTN",
        "short": "https://hflx.io/c/HQ2oCyTN"
      }
    }
  }
}
Response example (candidate already exists)
{
  "data": {
    "inviteCandidateToInterview": {
      "__typename": "InterviewAlreadyExistsInPositionError",
      "code": 409,
      "message": "Candidate already invited to this position."
    }
  }
}

Summary

  • Queries → Fetch data.
  • Mutations → Modify data.
  • Union Types → Let a single mutation return either a success or error type.
  • __typename → Use this field to determine the result type at runtime.
The Hireflix API uses __typename extensively for predictable integrations, especially for handling invite, archive, or delete operations.