> ## Documentation Index
> Fetch the complete documentation index at: https://hireflixsl.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> Learn how the GraphQL query language works to interact with Hireflix.

# Understanding GraphQL Basics

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

<Card title="Query" icon="magnifying-glass" horizontal>
  **Goal:** Fetch data without making changes.

  **Examples:** Listing positions or fetching interview results.
</Card>

<Card title="Mutation" icon="database" horizontal>
  **Goal:** Make changes to data.

  **Examples:** Inviting a candidate, archiving a position, or deleting an interview.
</Card>

### Example: Query

Let's look at this example queyr which fetches a list of open positions:

```graphql theme={null}
query GetPositions {
  positions {
    id
    name
    archivedAtISO
  }
}
```

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.

```json theme={null}
{
  "data": {
    "positions": [
      { "id": "68d53cf0a3d3c03c50f103c3", "name": "Sales Manager", "archivedAtISO": null },
      { "id": "68d53cf0a3d3c03c50f103c4", "name": "Marketing Lead", "archivedAtISO": "2026-07-08T13:27:37.333Z" }
    ]
  }
}
```

### Example: Mutation

Invite a new candidate to an interview:

```graphql theme={null}
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.

```graphql theme={null}
mutation InviteCandidateToInterview {
  inviteCandidateToInterview(
    input: {
      candidate: {
        email: "jane.doe@example.com"
        firstName: "Jane"
        lastName: "Doe"
      }
      positionId: "68d53cf0a3d3c03c50f103c3"
    }
  ) {
    __typename
    ... on InterviewType {
      id
      urls {
        public
        short
        private
      }
    }
    ... 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)**

```json theme={null}
{
  "data": {
    "inviteCandidateToInterview": {
      "__typename": "InterviewType",
      "id": "68d4164f19367e041b2030c0",
      "urls": {
        "public": "https://app.hireflix.com/HQ2oCyTN",
        "short": "https://hflx.io/c/HQ2oCyTN"
      }
    }
  }
}
```

**Response example (candidate already exists)**

```json theme={null}
{
  "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.

<Tip>
  The Hireflix API uses `__typename` extensively for predictable integrations, especially for handling invite, archive, or delete operations.
</Tip>
