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.
X-API-Key header. See the Authentication guide for details.Queries
Get All Chains
chainsRetrieve 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
chainRetrieve 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
}
}
}| Parameter | Type | Description |
|---|---|---|
idrequired | ID! | Unique identifier for the chain |
Mutations
Create Chain
createChainCreate a new chain with metadata and input schema
mutation CreateChain($input: CreateChainInput!) {
createChain(input: $input) {
id
name
description
isActive
requiredInputs
createdAt
}
}| Parameter | Type | Description |
|---|---|---|
namerequired | string | Unique name for the chain |
description | string | Description of what the chain does |
isActive | boolean | Whether the chain is active (default: true) |
requiredInputs | JSON | JSON Schema defining required input variables |
intentTags | string[] | Keywords for intent routing |
{
"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
addChainStepAdd a step to an existing chain
mutation AddChainStep($input: AddChainStepInput!) {
addChainStep(input: $input) {
id
order
type
promptId
config
inputMapping
outputKey
}
}| Parameter | Type | Description |
|---|---|---|
chainIdrequired | ID! | ID of the chain to add step to |
orderrequired | number | Execution order (0-indexed) |
typerequired | StepType | PROMPT, API_CALL, CONDITION, or TRANSFORM |
promptId | ID | ID of prompt to execute (for PROMPT type) |
config | JSON | Step-specific configuration |
inputMapping | JSON | How to map previous outputs to this step |
outputKey | string | Key to store this step's output |
Prompt Step Example
{
"input": {
"chainId": "cm9876543210",
"order": 0,
"type": "PROMPT",
"promptId": "cm1234567890",
"inputMapping": {
"text": "{{message}}"
},
"outputKey": "sentiment_analysis",
"config": {}
}
}API Call Step Example
{
"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
{
"input": {
"chainId": "cm9876543210",
"order": 2,
"type": "CONDITION",
"config": {
"condition": "{{sentiment_analysis.sentiment}} == 'Negative'",
"trueTag": "escalate",
"falseTag": "standard"
}
}
}trueTag and falseTag to control flow.Execute Chain
executeChainExecute 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
}
}| Parameter | Type | Description |
|---|---|---|
chainIdrequired | ID! | ID of the chain to execute |
inputrequired | JSON! | Input values matching the chain's requiredInputs schema |
{
"chainId": "cm9876543210",
"input": {
"message": "I need help with my recent order"
}
}{
"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
updateChainUpdate chain metadata and configuration
mutation UpdateChain(
$id: ID!
$input: UpdateChainInput!
) {
updateChain(id: $id, input: $input) {
id
name
description
isActive
requiredInputs
updatedAt
}
}| Parameter | Type | Description |
|---|---|---|
idrequired | ID! | ID of the chain to update |
name | string | New name for the chain |
description | string | New description |
isActive | boolean | Update active status |
requiredInputs | JSON | Update input schema |
intentTags | string[] | Update intent tags for routing |
Delete Chain
deleteChainPermanently delete a chain and all its steps
mutation DeleteChain($id: ID!) {
deleteChain(id: $id)
}Update Chain Step
updateChainStepUpdate an existing chain step
mutation UpdateChainStep(
$id: ID!
$input: UpdateChainStepInput!
) {
updateChainStep(id: $id, input: $input) {
id
order
type
config
inputMapping
outputKey
}
}Delete Chain Step
deleteChainStepRemove a step from a chain
mutation DeleteChainStep($id: ID!) {
deleteChainStep(id: $id)
}Step Types
| Parameter | Type | Description |
|---|---|---|
PROMPT | StepType | Execute an AI prompt with dynamic inputs from previous steps |
API_CALL | StepType | Call an external API endpoint with configurable headers and body |
CONDITION | StepType | Branch execution based on a condition expression |
TRANSFORM | StepType | Transform or manipulate data between steps |
Intent Routing
Route Message (Keyword)
routeMessageRoute a user message to appropriate chain using keyword matching
mutation RouteMessage($input: RouteMessageInput!) {
routeMessage(input: $input) {
chain {
id
name
description
}
intent
extractedInputs
rationale
}
}| Parameter | Type | Description |
|---|---|---|
userMessagerequired | string | The user's message to route |
{
"input": {
"userMessage": "I want to analyze my investment portfolio for risk"
}
}{
"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)
routeMessageSemanticRoute using AI-powered semantic understanding with input extraction
mutation RouteMessageSemantic($input: RouteMessageInput!) {
routeMessageSemantic(input: $input) {
chain {
id
name
description
}
intent
extractedInputs
rationale
clarifyingQuestion
}
}{
"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?"
}
}
}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}}"
}
}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
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
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'])