GraphQL Integration
The Manager provides a comprehensive GraphQL API for programmatic access to all platform features.
Complete API Reference
See the API Reference for complete GraphQL schema documentation, all queries, mutations, and detailed examples.
Quick Start
Endpoint
POST http://your-manager-host:8080/queryGraphQL Playground
Interactive schema explorer (development mode only):
GET http://localhost:8080/gqlAuthentication
Include authentication token in request headers:
Authorization: Bearer <your-token>Use either:
- Personal Access Token - Sent as a Bearer token, for CLI tools and scripts
- OAuth session - When requests come through the Productify proxy
Machine user tokens are not accepted on the GraphQL endpoint; they are limited to the REST (/api/machine/*) and ESB endpoints.
See Authentication for details.
Client Setup
JavaScript/TypeScript
const graphqlClient = async (query, variables = {}) => {
const response = await fetch("http://localhost:8080/query", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.MANAGER_TOKEN}`,
},
body: JSON.stringify({ query, variables }),
});
const { data, errors } = await response.json();
if (errors) {
throw new Error(errors[0].message);
}
return data;
};Python
import requests
import os
def graphql_client(query, variables=None):
response = requests.post(
'http://localhost:8080/query',
json={'query': query, 'variables': variables or {}},
headers={
'Authorization': f'Bearer {os.getenv("MANAGER_TOKEN")}'
}
)
result = response.json()
if 'errors' in result:
raise Exception(result['errors'][0]['message'])
return result['data']Go
package main
import (
"bytes"
"encoding/json"
"net/http"
"os"
)
type GraphQLRequest struct {
Query string `json:"query"`
Variables map[string]interface{} `json:"variables,omitempty"`
}
func GraphQLClient(query string, variables map[string]interface{}) (map[string]interface{}, error) {
reqBody, _ := json.Marshal(GraphQLRequest{
Query: query,
Variables: variables,
})
req, _ := http.NewRequest("POST", "http://localhost:8080/query", bytes.NewBuffer(reqBody))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+os.Getenv("MANAGER_TOKEN"))
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
var result map[string]interface{}
json.NewDecoder(resp.Body).Decode(&result)
return result, nil
}Common Patterns
Query with Variables
const query = `
query GetTenant($projectId: ID!, $slug: String!) {
tenant(projectId: $projectId, slug: $slug) {
id
name
applications {
id
name
}
}
}
`;
const data = await graphqlClient(query, {
projectId: "project-123",
slug: "my-tenant",
});Create Resource
Applications are project-level since the Wave 3 re-architecture — created against a project, then enabled per tenant (they no longer belong to a single tenant). See Multi-tenancy and the Migration Guide.
const mutation = `
mutation CreateApplication($projectId: ID!, $input: CreateApplicationInput!) {
createApplication(projectId: $projectId, input: $input) {
id
name
slug
}
}
`;
const result = await graphqlClient(mutation, {
projectId: "project-uuid",
input: {
name: "My App",
slug: "my-app",
description: "Application description",
},
});Error Handling
try {
const data = await graphqlClient(query, variables);
console.log("Success:", data);
} catch (error) {
console.error("GraphQL Error:", error.message);
// Handle specific error codes
if (error.message.includes("NOT_FOUND")) {
// Resource not found
} else if (error.message.includes("UNAUTHORIZED")) {
// Authentication failed
}
}Best Practices
Use Variables
Always use variables instead of hardcoding values:
// [NO] Avoid hardcoding
const query = `
query {
tenant(projectId: "abc-123", slug: "my-tenant") { name }
}
`;
// [OK] Use variables
const query = `
query GetTenant($projectId: ID!, $slug: String!) {
tenant(projectId: $projectId, slug: $slug) { name }
}
`;
const data = await graphqlClient(query, {
projectId: "abc-123",
slug: "my-tenant",
});Request Only Needed Fields
GraphQL allows precise field selection - use it:
// [NO] Over-fetching
const query = `
query {
applications(tenantSlug: "tenant", filters: [], order: {...}, pagination: {...}) {
id name slug description createdAt updatedAt
tenant { id name slug type createdAt updatedAt }
endpoints { id name url enabled createdAt }
triggers { id name cronExpression enabled }
}
}
`;
// [OK] Request only what you need
const query = `
query {
applications(tenantSlug: "tenant", filters: [], order: {...}, pagination: {...}) {
id
name
}
}
`;Use Fragments for Reusability
const fragments = `
fragment ApplicationFields on Application {
id
name
slug
}
`;
const query = `
${fragments}
query GetApplications($tenantSlug: String!) {
applications(tenantSlug: $tenantSlug, filters: [], order: {...}, pagination: {...}) {
...ApplicationFields
}
}
`;Handle Pagination
async function getAllApplications(tenantSlug) {
const allApps = [];
let offset = 0;
const limit = 50;
while (true) {
const data = await graphqlClient(
`
query GetApplications($tenantSlug: String!, $limit: Int!, $offset: Int!) {
applications(
tenantSlug: $tenantSlug
filters: []
order: { field: "name", direction: ASC }
pagination: { limit: $limit, offset: $offset }
) {
id
name
}
}
`,
{ tenantSlug, limit, offset }
);
if (data.applications.length === 0) break;
allApps.push(...data.applications);
offset += limit;
}
return allApps;
}GraphQL Tools
Apollo Client (JavaScript)
npm install @apollo/client graphqlimport { ApolloClient, InMemoryCache, gql } from "@apollo/client";
const client = new ApolloClient({
uri: "http://localhost:8080/query",
cache: new InMemoryCache(),
headers: {
authorization: `Bearer ${process.env.MANAGER_TOKEN}`,
},
});
const { data } = await client.query({
query: gql`
query GetTenants($projectSlug: String!) {
tenants(projectSlug: $projectSlug, filters: [], order: {...}, pagination: {...}) {
id
name
}
}
`,
variables: { projectSlug: "my-project" },
});urql (React)
npm install urql graphqlimport { createClient, useQuery } from "urql";
const client = createClient({
url: "http://localhost:8080/query",
fetchOptions: {
headers: {
authorization: `Bearer ${process.env.MANAGER_TOKEN}`,
},
},
});
function TenantsList() {
const [result] = useQuery({
query: `
query GetTenants($projectSlug: String!) {
tenants(projectSlug: $projectSlug, filters: [], order: {...}, pagination: {...}) {
id name
}
}
`,
variables: { projectSlug: "my-project" },
});
return <div>{/* render */}</div>;
}See Also
- API Reference - Complete GraphQL schema documentation
- Authentication - Authentication methods