← Back to Fusion Home

Fusion API

Docs

GraphQL API Documentation

Schema Organization

The GraphQL schema is organized by resource in a modular structure for better maintainability and discoverability:

graphql/
├── schema.graphql              # Root schema with imports
├── shared/
│   ├── interfaces.graphql      # Common interfaces (Node, Timestamped)
│   └── errors.graphql          # Error types (ValidationError)
├── user/
│   ├── types.graphql           # User type definition
│   ├── queries.graphql         # user, users queries
│   ├── mutations.graphql       # createUser, updateUser
│   └── inputs.graphql          # User inputs and payloads
├── party/
│   ├── types.graphql           # Party, PartyType, PartySubtype, PartyIdentifier
│   ├── queries.graphql         # party, parties, partyTypes, partySubtypes
│   ├── mutations.graphql       # createParty, updateParty, subscribePartyToProduct
│   └── inputs.graphql          # Party inputs and payloads
├── product/
│   ├── types.graphql           # Product, ProductAccount, PartyProduct
│   ├── queries.graphql         # products
│   └── inputs.graphql          # Product inputs (future)
└── party-group/
    ├── types.graphql           # PartyGroup, PartyGroupMember
    ├── queries.graphql         # partyGroup, partyGroups
    ├── mutations.graphql       # createPartyGroup, addPartyToGroup
    └── inputs.graphql          # Party group inputs and payloads

Design Principles

  1. Modular by Resource: Each business domain (User, Party, Product, etc.) has its own folder
  2. Consistent Naming: Generic filenames (types.graphql, queries.graphql, mutations.graphql, inputs.graphql)
  3. Shared Interfaces: Common patterns like Node and Timestamped are defined once and reused
  4. Self-Documenting: All types and fields include descriptive comments

Reference Data Queries

Reference data types (PartyType, PartySubtype, Product) are stored in the database and can be queried dynamically. This allows the API to discover valid values without hardcoding them in validation rules.

Query Available Party Types

query GetPartyTypes {
    partyTypes {
        data {
            id
            name
            description
        }
    }
}

Example Response:

{
    "data": {
        "partyTypes": {
            "data": [
                {
                    "id": 1,
                    "name": "person",
                    "description": "An individual human"
                },
                {
                    "id": 2,
                    "name": "organization",
                    "description": "A company, office, or group"
                },
                {
                    "id": 3,
                    "name": "system",
                    "description": "An external system (MLS, API, etc.)"
                }
            ]
        }
    }
}

Query Party Subtypes

query GetPartySubtypes {
    partySubtypes {
        data {
            id
            name
            description
            partyType {
                name
            }
        }
    }
}

# Or filter by party type
query GetSubtypesForPerson {
    partySubtypes(party_type_id: 1) {
        data {
            name
            description
        }
    }
}

Query Products

query GetProducts {
    products {
        data {
            id
            name
        }
    }
}

Pagination Strategy

The API uses a hybrid pagination approach that balances consistency with pragmatism:

All queries support pagination parameters:

Example:

query GetParties {
    parties(first: 25, page: 2) {
        data {
            id
            name
        }
        paginatorInfo {
            currentPage
            lastPage
            total
            hasMorePages
        }
    }
}

Validation

Input validations are database-driven where possible:

This ensures the API accepts any valid values added to the database without requiring schema changes.

Example Queries

Get All Users

query GetAllUsers {
    users(first: 10, page: 1) {
        data {
            id
            email
            auth0_sub
            party {
                id
                name
                first_name
                last_name
            }
            created_at
            updated_at
        }
        paginatorInfo {
            currentPage
            lastPage
            total
            hasMorePages
        }
    }
}

Get a Single User

query GetUser {
    user(id: "a094247a-6885-47dc-86b5-d8df3d8988dd") {
        id
        email
        auth0_sub
        party {
            name
        }
    }
}

query GetUserFromSub {
    user(auth0_sub: "auth0|jason-auth0-sub") {
        id
        email
        auth0_sub
        party {
            name
        }
    }
}

query GetUserFromEmail {
    user(email: "jason.welch@elmstreet.com") {
        id
        email
        auth0_sub
        party {
            name
        }
    }
}

Update a User

mutation UpdateUser {
    updateUser(
        id: "a094247a-6885-47dc-86b5-d8df3d8988dd"
        input: { email: "jason.welch@elmstreet.com" }
    ) {
        user {
            id
            email
            auth0_sub
            party {
                id
            }
        }
        success
        errors {
            field
            message
        }
    }
}

Create a Party

First, discover available party types and subtypes:

query {
    partyTypes {
        data {
            name
            description
        }
    }
    partySubtypes {
        data {
            name
            description
            partyType {
                name
            }
        }
    }
}

Then create the party:

mutation {
    createParty(
        input: {
            party_type: "person"
            party_subtype: "agent"
            first_name: "Lee"
            last_name: "Ralls"
            user: {
                auth0_sub: "auth0|sub-for-lee-raalls"
                email: "lee.ralls@elmstreet.com"
            }
        }
    ) {
        party {
            id
            first_name
            last_name
            partyType {
                name
            }
            partySubtype {
                name
            }
            user {
                id
                email
                auth0_sub
            }
        }
        success
        errors {
            field
            message
        }
    }
}

Subscribe a Party to a Product

mutation SubscribeParty {
    subscribePartyToProduct(
        partyId: "a0d46520-92e6-41b6-860a-c1df703606a9"
        input: { product: "IDX Broker", account_id: "12345", role: "owner" }
    ) {
        partyProduct {
            id
            role
            product {
                name
            }
            party {
                id
            }
        }
        success
        errors {
            field
            message
        }
    }
}

Get a Party with Products

query GetParty {
    party(id: "a0d46520-92e6-41b6-860a-c1df703606a9") {
        id
        name
        partyType {
            id
            name
        }
        partyProducts {
            role
            product {
                name
            }
            productAccount {
                product_account_id
                product_account_id_type
            }
        }
    }
}

List Parties with Filtering

query GetFilteredParties {
    parties(
        first: 20
        party_type_id: 1
        name: "Smith"
        orderBy: [{ column: "last_name", order: ASC }]
    ) {
        data {
            id
            name
            first_name
            last_name
            partyType {
                name
            }
        }
        paginatorInfo {
            total
            hasMorePages
        }
    }
}

Create a Party Group

mutation CreateGroup {
    createPartyGroup(
        input: {
            name: "Elite Team"
            description: "Top performing agents"
            created_by_party_id: "a0d46520-92e6-41b6-860a-c1df703606a9"
        }
    ) {
        partyGroup {
            id
            name
            description
            createdBy {
                name
            }
        }
        success
        errors {
            field
            message
        }
    }
}

Add Party to Group

mutation AddMember {
    addPartyToGroup(
        input: {
            party_group_id: "b1d46520-92e6-41b6-860a-c1df703606a9"
            party_id: "a0d46520-92e6-41b6-860a-c1df703606a9"
            role: "member"
            status: "active"
        }
    ) {
        partyGroupMember {
            id
            role
            status
            party {
                name
            }
            partyGroup {
                name
            }
        }
        success
        errors {
            field
            message
        }
    }
}

Error Handling

All mutations return a consistent payload structure:

type CreatePartyPayload {
    party: Party # The created entity (null if errors)
    success: Boolean! # Whether the operation succeeded
    errors: [ValidationError!]! # Validation errors (empty if success)
}

type ValidationError {
    field: String # Field that caused the error (if field-specific)
    message: String! # Human-readable error message
}

Example Error Response:

{
    "data": {
        "createParty": {
            "party": null,
            "success": false,
            "errors": [
                {
                    "field": "party_type",
                    "message": "The selected party_type is invalid."
                }
            ]
        }
    }
}

Best Practices

  1. Query Reference Data First: Before creating parties or products, query partyTypes and partySubtypes to discover valid values
  2. Use Pagination: All list queries support pagination - specify first and page parameters
  3. Request Only What You Need: GraphQL allows you to request exactly the fields you need - this improves performance
  4. Check Success Field: Always check the success field in mutation responses before using the returned entity
  5. Handle Errors: Check the errors array for validation issues and display them to users

Schema Validation

To validate the schema after making changes:

php artisan lighthouse:validate-schema

GraphiQL

Access the interactive GraphQL explorer at /graphiql to explore the schema, run queries, and see documentation.