Chains API

Complete API reference for creating, managing, and executing multi-step AI workflows with conditional logic and data transformation.

Overview

The Chains API enables orchestration of complex workflows combining multiple prompts, API calls, and conditional logic. Each chain consists of ordered steps with input/output mapping between them.

All API requests require authentication via API key in the X-API-Key header. See the Authentication guide for details.

Queries

Get All Chains

query
chains

Retrieve all chains for the authenticated user

query GetChains {
  chains {
    id
    name
    description
    isActive
    requiredInputs
    createdAt
    updatedAt
    steps {
      id
      order
      type
      config
      inputMapping
      outputKey
    }
    intents {
      id
      name
      keywords
    }
  }
}

Get Single Chain

query
chain

Retrieve a specific chain by ID with all steps and configuration

query GetChain($id: ID!) {
  chain(id: $id) {
    id
    name
    description
    isActive
    requiredInputs
    createdAt
    updatedAt
    createdBy {
      id
      email
      name
    }
    steps {
      id
      order
      type
      promptId
      prompt {
        name
        latestVersion {
          content
          params
        }
      }
      config
      inputMapping
      outputKey
    }
    intents {
      id
      name
      keywords
      embedding
    }
    executions {
      id
      status
      output
      totalLatency
      totalCost
      createdAt
    }
  }
}
ParameterTypeDescription
id
required
ID!Unique identifier for the chain

Mutations

Create Chain

mutation
createChain

Create a new chain with metadata and input schema

mutation CreateChain($input: CreateChainInput!) {
  createChain(input: $input) {
    id
    name
    description
    isActive
    requiredInputs
    createdAt
  }
}
ParameterTypeDescription
name
required
stringUnique name for the chain
descriptionstringDescription of what the chain does
isActivebooleanWhether the chain is active (default: true)
requiredInputsJSONJSON Schema defining required input variables
intentTagsstring[]Keywords for intent routing
Example Request
json
{
  "input": {
    "name": "customer-support-analyzer",
    "description": "Analyzes customer support messages and generates appropriate responses",
    "isActive": true,
    "requiredInputs": {
      "type": "object",
      "properties": {
        "message": {
          "type": "string",
          "description": "Customer support message"
        }
      },
      "required": ["message"]
    },
    "intentTags": ["support", "customer-service", "help"]
  }
}

Add Chain Step

mutation
addChainStep

Add a step to an existing chain

mutation AddChainStep($input: AddChainStepInput!) {
  addChainStep(input: $input) {
    id
    order
    type
    promptId
    config
    inputMapping
    outputKey
  }
}
ParameterTypeDescription
chainId
required
ID!ID of the chain to add step to
order
required
numberExecution order (0-indexed)
type
required
StepTypePROMPT, API_CALL, CONDITION, or TRANSFORM
promptIdIDID of prompt to execute (for PROMPT type)
configJSONStep-specific configuration
inputMappingJSONHow to map previous outputs to this step
outputKeystringKey to store this step's output

Prompt Step Example

Add Sentiment Analysis Step
json
{
  "input": {
    "chainId": "cm9876543210",
    "order": 0,
    "type": "PROMPT",
    "promptId": "cm1234567890",
    "inputMapping": {
      "text": "{{message}}"
    },
    "outputKey": "sentiment_analysis",
    "config": {}
  }
}

API Call Step Example

Add External API Call Step
json
{
  "input": {
    "chainId": "cm9876543210",
    "order": 1,
    "type": "API_CALL",
    "config": {
      "url": "https://api.example.com/tickets",
      "method": "POST",
      "headers": {
        "Authorization": "Bearer {{apiKey}}",
        "Content-Type": "application/json"
      },
      "body": {
        "message": "{{message}}",
        "sentiment": "{{sentiment_analysis.sentiment}}",
        "confidence": "{{sentiment_analysis.confidence}}"
      }
    },
    "outputKey": "ticket_response"
  }
}

Conditional Step Example

Add Conditional Branch
json
{
  "input": {
    "chainId": "cm9876543210",
    "order": 2,
    "type": "CONDITION",
    "config": {
      "condition": "{{sentiment_analysis.sentiment}} == 'Negative'",
      "trueTag": "escalate",
      "falseTag": "standard"
    }
  }
}
Steps with matching tags will only execute when that condition path is taken. Use thetrueTag and falseTag to control flow.

Execute Chain

mutation
executeChain

Execute a chain with provided inputs

mutation ExecuteChain(
  $chainId: ID!
  $input: JSON!
) {
  executeChain(
    chainId: $chainId
    input: $input
  ) {
    output
    steps {
      order
      type
      output
      latency
      cost
      status
      error
    }
    totalLatency
    totalCost
    executionId
  }
}
ParameterTypeDescription
chainId
required
ID!ID of the chain to execute
input
required
JSON!Input values matching the chain's requiredInputs schema
Example Request
json
{
  "chainId": "cm9876543210",
  "input": {
    "message": "I need help with my recent order"
  }
}
Example Response
json
{
  "data": {
    "executeChain": {
      "output": "I'd be happy to help you with your order. Could you please provide your order number?",
      "steps": [
        {
          "order": 0,
          "type": "PROMPT",
          "output": "{\"sentiment\": \"Neutral\", \"confidence\": 0.75}",
          "latency": 1200,
          "cost": 0.0015,
          "status": "success",
          "error": null
        },
        {
          "order": 1,
          "type": "PROMPT",
          "output": "I'd be happy to help you with your order...",
          "latency": 1450,
          "cost": 0.0018,
          "status": "success",
          "error": null
        }
      ],
      "totalLatency": 2650,
      "totalCost": 0.0033,
      "executionId": "exec_chain_abc123"
    }
  }
}

Update Chain

mutation
updateChain

Update chain metadata and configuration

mutation UpdateChain(
  $id: ID!
  $input: UpdateChainInput!
) {
  updateChain(id: $id, input: $input) {
    id
    name
    description
    isActive
    requiredInputs
    updatedAt
  }
}
ParameterTypeDescription
id
required
ID!ID of the chain to update
namestringNew name for the chain
descriptionstringNew description
isActivebooleanUpdate active status
requiredInputsJSONUpdate input schema
intentTagsstring[]Update intent tags for routing

Delete Chain

mutation
deleteChain

Permanently delete a chain and all its steps

mutation DeleteChain($id: ID!) {
  deleteChain(id: $id)
}
Deletion is permanent and cannot be undone. All steps and execution history will be lost.

Update Chain Step

mutation
updateChainStep

Update an existing chain step

mutation UpdateChainStep(
  $id: ID!
  $input: UpdateChainStepInput!
) {
  updateChainStep(id: $id, input: $input) {
    id
    order
    type
    config
    inputMapping
    outputKey
  }
}

Delete Chain Step

mutation
deleteChainStep

Remove a step from a chain

mutation DeleteChainStep($id: ID!) {
  deleteChainStep(id: $id)
}

Step Types

ParameterTypeDescription
PROMPTStepTypeExecute an AI prompt with dynamic inputs from previous steps
API_CALLStepTypeCall an external API endpoint with configurable headers and body
CONDITIONStepTypeBranch execution based on a condition expression
TRANSFORMStepTypeTransform or manipulate data between steps

Intent Routing

Route Message (Keyword)

mutation
routeMessage

Route a user message to appropriate chain using keyword matching

mutation RouteMessage($input: RouteMessageInput!) {
  routeMessage(input: $input) {
    chain {
      id
      name
      description
    }
    intent
    extractedInputs
    rationale
  }
}
ParameterTypeDescription
userMessage
required
stringThe user's message to route
Example Request
json
{
  "input": {
    "userMessage": "I want to analyze my investment portfolio for risk"
  }
}
Example Response
json
{
  "data": {
    "routeMessage": {
      "chain": {
        "id": "cm1234567890",
        "name": "portfolio-risk-analyzer",
        "description": "Analyzes portfolio holdings for risk exposure"
      },
      "intent": "portfolio risk analysis",
      "extractedInputs": {},
      "rationale": "Matched keywords: portfolio, risk"
    }
  }
}

Route Message (Semantic)

mutation
routeMessageSemantic

Route using AI-powered semantic understanding with input extraction

mutation RouteMessageSemantic($input: RouteMessageInput!) {
  routeMessageSemantic(input: $input) {
    chain {
      id
      name
      description
    }
    intent
    extractedInputs
    rationale
    clarifyingQuestion
  }
}
Example Response
json
{
  "data": {
    "routeMessageSemantic": {
      "chain": {
        "id": "cm1234567890",
        "name": "portfolio-risk-analyzer",
        "description": "Analyzes portfolio holdings for risk exposure"
      },
      "intent": "assess portfolio volatility",
      "extractedInputs": {
        "concern": "volatility",
        "timeframe": "recently"
      },
      "rationale": "User is expressing concern about investment volatility, which indicates a need for risk analysis. The mention of 'lately' suggests recent market movements are causing concern.",
      "clarifyingQuestion": "Would you like me to analyze your portfolio's volatility over the last month, quarter, or year?"
    }
  }
}
Semantic routing uses AI to understand context, handle synonyms, extract inputs, and provide reasoning. It's more powerful but has a small cost per route.

Data Mapping

Use template syntax to reference previous step outputs:

{
  "inputMapping": {
    "customer_message": "{{message}}",
    "sentiment": "{{sentiment_analysis.sentiment}}",
    "confidence": "{{sentiment_analysis.confidence}}",
    "user_email": "{{user.email}}"
  }
}
Use dot notation to access nested properties from previous step outputs. The chain context accumulates all outputs as the workflow progresses.

Error Handling

Step Execution Errors

{
  "data": {
    "executeChain": {
      "output": null,
      "steps": [
        {
          "order": 0,
          "type": "PROMPT",
          "output": null,
          "latency": 150,
          "cost": 0,
          "status": "error",
          "error": "Prompt execution failed: Invalid API key for provider 'anthropic'"
        }
      ],
      "totalLatency": 150,
      "totalCost": 0,
      "executionId": "exec_chain_abc123"
    }
  }
}

When a step fails, the chain execution stops and returns the error. Previous successful steps are still recorded in the response.

Code Examples

JavaScript / TypeScript

Execute Chain with Error Handling
typescript
const apiKey = 'your-api-key'
const endpoint = 'https://api.promptforge.sh/graphql'

async function executeChain(chainId: string, input: any) {
  const response = await fetch(endpoint, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-API-Key': apiKey,
    },
    body: JSON.stringify({
      query: `
        mutation ExecuteChain($chainId: ID!, $input: JSON!) {
          executeChain(chainId: $chainId, input: $input) {
            output
            steps {
              order
              type
              status
              error
              latency
              cost
            }
            totalLatency
            totalCost
          }
        }
      `,
      variables: {
        chainId,
        input,
      },
    }),
  })

  const { data, errors } = await response.json()

  if (errors) {
    throw new Error(errors[0].message)
  }

  const result = data.executeChain

  // Check for step-level errors
  const failedStep = result.steps.find(s => s.status === 'error')
  if (failedStep) {
    throw new Error(`Step ${failedStep.order} failed: ${failedStep.error}`)
  }

  return result
}

// Usage
try {
  const result = await executeChain('cm9876543210', {
    message: 'I need help with my order',
  })

  console.log('Output:', result.output)
  console.log(`Total cost: $${result.totalCost}`)
  console.log(`Total time: ${result.totalLatency}ms`)
} catch (error) {
  console.error('Chain execution failed:', error)
}

Python

Route and Execute
python
import requests

api_key = 'your-api-key'
endpoint = 'https://api.promptforge.sh/graphql'

def route_and_execute(user_message: str):
    # Step 1: Route the message
    route_query = """
        mutation RouteMessageSemantic($input: RouteMessageInput!) {
          routeMessageSemantic(input: $input) {
            chain {
              id
              name
            }
            extractedInputs
          }
        }
    """

    route_response = requests.post(
        endpoint,
        headers={
            'Content-Type': 'application/json',
            'X-API-Key': api_key,
        },
        json={
            'query': route_query,
            'variables': {
                'input': {'userMessage': user_message},
            },
        },
    )

    route_result = route_response.json()

    if 'errors' in route_result:
        raise Exception(route_result['errors'][0]['message'])

    route_data = route_result['data']['routeMessageSemantic']

    if not route_data['chain']:
        raise Exception('No matching chain found')

    chain_id = route_data['chain']['id']
    extracted_inputs = route_data['extractedInputs']

    # Step 2: Execute the matched chain
    execute_query = """
        mutation ExecuteChain($chainId: ID!, $input: JSON!) {
          executeChain(chainId: $chainId, input: $input) {
            output
            totalCost
          }
        }
    """

    execute_response = requests.post(
        endpoint,
        headers={
            'Content-Type': 'application/json',
            'X-API-Key': api_key,
        },
        json={
            'query': execute_query,
            'variables': {
                'chainId': chain_id,
                'input': extracted_inputs,
            },
        },
    )

    execute_result = execute_response.json()

    if 'errors' in execute_result:
        raise Exception(execute_result['errors'][0]['message'])

    return execute_result['data']['executeChain']

# Usage
result = route_and_execute('I want to check my portfolio risk')
print(result['output'])

Best Practices

Keep Steps Focused - Each step should do one thing well. Break complex operations into multiple steps for better debugging and reusability.
Use Descriptive Output Keys - Name your output keys clearly (e.g., "sentiment_analysis" not "step1") to make data mapping more readable.
Test Steps Independently - Test prompts independently before adding them to chains to ensure they work correctly.
Monitor Costs - Long chains can accumulate costs quickly. Review step-by-step metrics to optimize expensive operations.
Handle Errors Gracefully - Always check step status in responses and implement proper error handling in production applications.

Next Steps

Execution API

Track and analyze execution history

Execution API →

Workflow Examples

See complete chain implementation examples

View Examples →