Skip to main content
The Graphman GraphQL API provides programmatic access to Graph Node management operations. It offers an alternative to the CLI for deployment management, status monitoring, and administrative tasks.

Overview

The GraphQL API enables you to:
  • Query deployment information and status
  • Pause and resume subgraph indexing
  • Restart deployments
  • Monitor long-running operations
  • Integrate Graph Node management into your tooling
The Graphman server should never be exposed externally. It provides privileged operations that could severely impact your indexer if accessed by an attacker.

Configuration

The Graphman GraphQL server is only started when the GRAPHMAN_SERVER_AUTH_TOKEN environment variable is set.

Environment Variables

GRAPHMAN_SERVER_AUTH_TOKEN
string
required
Authentication token for GraphQL requests. The server will not start without this variable.
GRAPHMAN_PORT
number
default:"8050"
Port number for the GraphQL server

Example Configuration

export GRAPHMAN_SERVER_AUTH_TOKEN="your-secure-token-here"
export GRAPHMAN_PORT=8050

# Start Graph Node with Graphman API enabled
graph-node --config config.toml

Authentication

All GraphQL requests must include the authentication token in the Authorization header:
curl -X POST http://127.0.0.1:8050/graphql \
  -H "Authorization: Bearer your-secure-token-here" \
  -H "Content-Type: application/json" \
  -d '{"query":"{ __typename }"}'

GraphQL Playground

When the server is running, access the interactive GraphQL playground at:
http://127.0.0.1:8050
The playground port matches your GRAPHMAN_PORT setting (default: 8050).

Setting Up Authentication in Playground

To use the playground, you must configure the authorization header:
  1. Open the playground in your browser
  2. Locate the HTTP Headers section at the bottom of the page
  3. Add the authorization header:
{
  "Authorization": "Bearer your-secure-token-here"
}
The playground is the best place to explore the full schema, available queries and mutations, and their documentation.

Available Operations

Deployment Info

Retrieve detailed information about one or multiple deployments.
query {
  deployment {
    info(deployment: { hash: "QmfWRZCjT8pri4Amey3e3mb2Bga75Vuh2fPYyNVnmPYL66" }) {
      id
      hash
      namespace
      shard
      active
      chain
      nodeId
      status {
        isPaused
        isSynced
        health
        earliestBlockNumber
        latestBlock {
          hash
          number
        }
        chainHeadBlock {
          hash
          number
        }
      }
    }
  }
}

Deployment Selection

You can query deployments using different selectors:
query {
  deployment {
    info(deployment: { hash: "QmfWRZCjT8pri4Amey3e3mb2Bga75Vuh2fPYyNVnmPYL66" }) {
      status { isPaused }
    }
  }
}

Status Fields

isPaused
boolean
Whether the deployment is currently paused
isSynced
boolean
Whether the deployment has synced to the current chain head
health
enum
Deployment health status: HEALTHY, UNHEALTHY, or FAILED
earliestBlockNumber
number
The earliest indexed block number
latestBlock
object
The most recently indexed block
chainHeadBlock
object
The current blockchain head block

Pause Deployment

Temporarily stops indexing for a deployment without removing any data.
mutation {
  deployment {
    pause(deployment: { hash: "QmfWRZCjT8pri4Amey3e3mb2Bga75Vuh2fPYyNVnmPYL66" }) {
      success
      message
    }
  }
}

Use Cases

Pause deployments during planned maintenance or RPC provider changes:
mutation {
  deployment {
    pause(deployment: { name: "author/subgraph-name" }) {
      success
    }
  }
}
Temporarily pause resource-intensive subgraphs during high-load periods:
mutation PauseMultiple {
  sg1: deployment {
    pause(deployment: { hash: "Qm...1" }) { success }
  }
  sg2: deployment {
    pause(deployment: { hash: "Qm...2" }) { success }
  }
}
Pause a deployment to investigate issues without affecting other subgraphs:
mutation {
  deployment {
    pause(deployment: { hash: "QmProblematic..." }) {
      success
      message
    }
  }
}
A deployment cannot be paused if it’s already in a paused state. Check the isPaused field before attempting to pause.

Resume Deployment

Resumes indexing for a previously paused deployment.
mutation {
  deployment {
    resume(deployment: { hash: "QmfWRZCjT8pri4Amey3e3mb2Bga75Vuh2fPYyNVnmPYL66" }) {
      success
      message
    }
  }
}

Example Workflow

# Step 1: Check current status
query {
  deployment {
    info(deployment: { hash: "Qm..." }) {
      status { isPaused }
    }
  }
}

# Step 2: Resume if paused
mutation {
  deployment {
    resume(deployment: { hash: "Qm..." }) {
      success
    }
  }
}

# Step 3: Verify resumed
query {
  deployment {
    info(deployment: { hash: "Qm..." }) {
      status { isPaused }
    }
  }
}

Restart Deployment

Pauses a deployment and automatically resumes it after a delay (default: 20 seconds). This is useful for forcing a fresh sync from a specific block.
This is a long-running operation. The mutation returns immediately with an execution ID that you can use to track progress.
mutation {
  deployment {
    restart(deployment: { hash: "QmfWRZCjT8pri4Amey3e3mb2Bga75Vuh2fPYyNVnmPYL66" }) {
      id
    }
  }
}

Tracking Execution Status

Use the returned execution ID to monitor the restart operation:
query {
  execution {
    info(id: "550e8400-e29b-41d4-a716-446655440000") {
      status
      errorMessage
      startedAt
      completedAt
    }
  }
}

Execution Status Values

PENDING
status
Operation is queued but not yet started
RUNNING
status
Operation is currently executing
SUCCEEDED
status
Operation completed successfully
FAILED
status
Operation failed with an error

Polling for Completion

async function waitForRestart(executionId) {
  while (true) {
    const response = await fetch('http://127.0.0.1:8050/graphql', {
      method: 'POST',
      headers: {
        'Authorization': 'Bearer your-token',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        query: `
          query {
            execution {
              info(id: "${executionId}") {
                status
                errorMessage
              }
            }
          }
        `
      })
    });
    
    const data = await response.json();
    const status = data.data.execution.info.status;
    
    if (status === 'SUCCEEDED') {
      console.log('Restart completed successfully');
      break;
    } else if (status === 'FAILED') {
      console.error('Restart failed:', data.data.execution.info.errorMessage);
      break;
    }
    
    // Wait 2 seconds before next poll
    await new Promise(resolve => setTimeout(resolve, 2000));
  }
}

Long-Running Operations

Some operations (like restart) execute asynchronously in the background. These operations:
  1. Return immediately with a unique execution ID
  2. Execute in the background
  3. Can be monitored using the execution.info query

Benefits

Non-Blocking

Your client doesn’t need to maintain a long-lived connection

Resumable

You can disconnect and check status later using the execution ID

Transparent

Full visibility into operation progress and errors

Reliable

Operations continue even if the client disconnects

Integration Examples

Python

import requests
import time

GRAPHMAN_URL = "http://127.0.0.1:8050/graphql"
AUTH_TOKEN = "your-secure-token-here"

def graphql_request(query, variables=None):
    headers = {
        "Authorization": f"Bearer {AUTH_TOKEN}",
        "Content-Type": "application/json"
    }
    
    response = requests.post(
        GRAPHMAN_URL,
        json={"query": query, "variables": variables},
        headers=headers
    )
    return response.json()

# Check deployment status
status_query = """
    query($hash: String!) {
        deployment {
            info(deployment: { hash: $hash }) {
                status {
                    isPaused
                    isSynced
                    health
                }
            }
        }
    }
"""

result = graphql_request(status_query, {
    "hash": "QmfWRZCjT8pri4Amey3e3mb2Bga75Vuh2fPYyNVnmPYL66"
})

print(result["data"]["deployment"]["info"][0]["status"])

# Pause deployment
pause_mutation = """
    mutation($hash: String!) {
        deployment {
            pause(deployment: { hash: $hash }) {
                success
                message
            }
        }
    }
"""

result = graphql_request(pause_mutation, {
    "hash": "QmfWRZCjT8pri4Amey3e3mb2Bga75Vuh2fPYyNVnmPYL66"
})

if result["data"]["deployment"]["pause"]["success"]:
    print("Deployment paused successfully")

Node.js

const fetch = require('node-fetch');

const GRAPHMAN_URL = 'http://127.0.0.1:8050/graphql';
const AUTH_TOKEN = 'your-secure-token-here';

async function graphqlRequest(query, variables = {}) {
  const response = await fetch(GRAPHMAN_URL, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${AUTH_TOKEN}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ query, variables }),
  });
  
  return await response.json();
}

// Restart deployment and wait for completion
async function restartDeployment(hash) {
  // Start restart
  const restartMutation = `
    mutation($hash: String!) {
      deployment {
        restart(deployment: { hash: $hash }) {
          id
        }
      }
    }
  `;
  
  const restartResult = await graphqlRequest(restartMutation, { hash });
  const executionId = restartResult.data.deployment.restart.id;
  
  console.log(`Restart initiated with ID: ${executionId}`);
  
  // Poll for completion
  const statusQuery = `
    query($id: String!) {
      execution {
        info(id: $id) {
          status
          errorMessage
        }
      }
    }
  `;
  
  while (true) {
    const statusResult = await graphqlRequest(statusQuery, { id: executionId });
    const { status, errorMessage } = statusResult.data.execution.info;
    
    if (status === 'SUCCEEDED') {
      console.log('Restart completed successfully');
      break;
    } else if (status === 'FAILED') {
      console.error(`Restart failed: ${errorMessage}`);
      throw new Error(errorMessage);
    }
    
    console.log(`Status: ${status}`);
    await new Promise(resolve => setTimeout(resolve, 2000));
  }
}

// Usage
restartDeployment('QmfWRZCjT8pri4Amey3e3mb2Bga75Vuh2fPYyNVnmPYL66')
  .then(() => console.log('Done'))
  .catch(err => console.error('Error:', err));

cURL

# Check deployment status
curl -X POST http://127.0.0.1:8050/graphql \
  -H "Authorization: Bearer your-secure-token-here" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "query($hash: String!) { deployment { info(deployment: { hash: $hash }) { status { isPaused isSynced health } } } }",
    "variables": {
      "hash": "QmfWRZCjT8pri4Amey3e3mb2Bga75Vuh2fPYyNVnmPYL66"
    }
  }'

# Pause deployment
curl -X POST http://127.0.0.1:8050/graphql \
  -H "Authorization: Bearer your-secure-token-here" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "mutation($hash: String!) { deployment { pause(deployment: { hash: $hash }) { success message } } }",
    "variables": {
      "hash": "QmfWRZCjT8pri4Amey3e3mb2Bga75Vuh2fPYyNVnmPYL66"
    }
  }'

# Resume deployment
curl -X POST http://127.0.0.1:8050/graphql \
  -H "Authorization: Bearer your-secure-token-here" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "mutation($hash: String!) { deployment { resume(deployment: { hash: $hash }) { success message } } }",
    "variables": {
      "hash": "QmfWRZCjT8pri4Amey3e3mb2Bga75Vuh2fPYyNVnmPYL66"
    }
  }'

Security Best Practices

The Graphman server should only be accessible from trusted internal networks:
  • Bind to localhost (127.0.0.1) only
  • Use firewall rules to restrict access
  • Never expose to the public internet
  • Consider using VPN or SSH tunnels for remote access
Change your GRAPHMAN_SERVER_AUTH_TOKEN periodically:
# Generate a secure token
openssl rand -hex 32

# Update environment variable
export GRAPHMAN_SERVER_AUTH_TOKEN="new-token-here"

# Restart Graph Node
systemctl restart graph-node
Generate cryptographically secure tokens:
# Good: Strong random token
openssl rand -base64 32

# Bad: Weak predictable token
echo "admin123"  # Never do this!
Log all Graphman API access and monitor for suspicious activity:
  • Track failed authentication attempts
  • Monitor unusual operation patterns
  • Alert on destructive operations
  • Maintain audit logs
  • Only grant Graphman API access to operators who need it
  • Use separate tokens for different automation systems
  • Implement token revocation when access is no longer needed

Error Handling

Common Errors

{
  "errors": [
    {
      "message": "Unauthorized",
      "extensions": {
        "code": "UNAUTHENTICATED"
      }
    }
  ]
}
Solution: Verify your Authorization header includes the correct token.
{
  "data": {
    "deployment": {
      "pause": {
        "success": false,
        "message": "Deployment not found"
      }
    }
  }
}
Solution: Check the deployment hash or name is correct using the info query.
{
  "data": {
    "deployment": {
      "pause": {
        "success": false,
        "message": "Deployment is already paused"
      }
    }
  }
}
Solution: Check current status before attempting pause/resume operations.
{
  "data": {
    "execution": {
      "info": null
    }
  }
}
Solution: Verify the execution ID is correct. Execution records may expire after completion.

Future Operations

Additional Graphman commands will be added to the GraphQL API over time. Always check the GraphQL playground for the latest schema and available operations.
Operations being considered for future releases:
  • Deployment assignment and unassignment
  • Unused deployment management
  • Chain block verification
  • Call cache management
  • Bulk operations on multiple deployments
Check the GraphQL playground regularly to discover new features as they become available.

See Also

Build docs developers (and LLMs) love