Skip to content

Workflow Status#

The GET /api/:correlationId/status endpoint allows you to check the execution progress of a workflow using the correlation ID returned from the workflow execution endpoint.

Endpoint Details#

GET https://integrations.usestoryteller.com/api/{correlationId}/status

Headers#

Header Required Description
x-storyteller-api-key Yes Your API key for authentication

Path Parameters#

Parameter Type Required Description
correlationId string Yes The correlation ID returned from workflow execution

Response#

Success Response (200 OK)#

The response returns an array of workflow status objects, one for each workflow that was executed:

[
  {
    "code": "add-clip",
    "correlationId": "09a560ba-dfa2-4865-bf95-4b3ce773c0fd",
    "status": "Running",
    "message": "Workflow steps initiated, processing started",
    "timestamp": "2024-05-30T17:00:25.751751",
    "steps": [
      {
        "name": "Create Clip",
        "status": "Finished",
        "message": "Workflow successfully finished, 1 resource(s) were created",
        "timestamp": "2024-05-30T17:00:25.7727889",
        "locations": [
          "https://yourtenant.usestoryteller.com/clips/98226576-21a4-a1c9-efd6-3a12dc9eef9b/form"
        ]
      }
    ]
  }
]

Response Fields#

Workflow Object#

Field Type Description
code string The workflow identifier code
correlationId string The correlation ID for this execution
status string Overall workflow status: Running, Finished, Failed
message string Human-readable status message
timestamp string ISO timestamp when status was last updated
steps array Array of individual workflow step statuses

Step Object#

Field Type Description
name string The name of the workflow step
status string Step status: Running, Finished, Failed
message string Detailed step status message
timestamp string ISO timestamp when step status was last updated
locations array URLs to resources created by this step (optional)

Status Values#

Workflow Status#

  • Running - Workflow is currently executing
  • Finished - All workflow steps completed successfully
  • Failed - One or more workflow steps failed

Step Status#

  • Running - Step is currently executing
  • Finished - Step completed successfully
  • Failed - Step encountered an error and failed

Locations Array#

Each step that creates resources in Storyteller will include a locations array containing URLs to the created resources. This can be used to:

  • Provide direct links to content in your UI
  • Access the Storyteller admin interface for created content
  • Verify that resources were created successfully

Code Examples#

curl -X GET "https://integrations.usestoryteller.com/api/09a560ba-dfa2-4865-bf95-4b3ce773c0fd/status" \
  -H "x-storyteller-api-key: your-api-key-here"
const fetch = require('node-fetch');

async function getWorkflowStatus(correlationId) {
  try {
    const response = await fetch(`https://integrations.usestoryteller.com/api/${correlationId}/status`, {
      method: 'GET',
      headers: {
        'x-storyteller-api-key': process.env.STORYTELLER_API_KEY
      }
    });

    if (!response.ok) {
      const errorData = await response.json();
      throw new Error(`HTTP ${response.status}: ${errorData.message}`);
    }

    const workflows = await response.json();
    return workflows;
  } catch (error) {
    console.error('Error getting workflow status:', error);
    throw error;
  }
}

// Usage
getWorkflowStatus('09a560ba-dfa2-4865-bf95-4b3ce773c0fd')
  .then(workflows => {
    workflows.forEach(workflow => {
      console.log(`Workflow ${workflow.code}: ${workflow.status}`);
      console.log(`Message: ${workflow.message}`);

      workflow.steps.forEach(step => {
        console.log(`  Step "${step.name}": ${step.status}`);
        if (step.locations) {
          console.log(`  Created resources:`, step.locations);
        }
      });
    });
  })
  .catch(error => console.error('Failed to get workflow status:', error));
import requests
import os

def get_workflow_status(correlation_id):
    url = f'https://integrations.usestoryteller.com/api/{correlation_id}/status'
    headers = {
        'x-storyteller-api-key': os.environ.get('STORYTELLER_API_KEY')
    }

    try:
        response = requests.get(url, headers=headers)
        response.raise_for_status()

        workflows = response.json()
        return workflows
    except requests.exceptions.RequestException as e:
        print(f'Error getting workflow status: {e}')
        if hasattr(e.response, 'json'):
            print(f'Error details: {e.response.json()}')
        raise

# Usage
try:
    workflows = get_workflow_status('09a560ba-dfa2-4865-bf95-4b3ce773c0fd')

    for workflow in workflows:
        print(f'Workflow {workflow["code"]}: {workflow["status"]}')
        print(f'Message: {workflow["message"]}')

        for step in workflow['steps']:
            print(f'  Step "{step["name"]}": {step["status"]}')
            if 'locations' in step:
                print(f'  Created resources: {step["locations"]}')

except Exception as e:
    print(f'Failed to get workflow status: {e}')
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json;

public class WorkflowStatusChecker
{
    private readonly HttpClient _httpClient;
    private readonly string _baseUrl = "https://integrations.usestoryteller.com";

    public WorkflowStatusChecker(string apiKey)
    {
        _httpClient = new HttpClient();
        _httpClient.DefaultRequestHeaders.Add("x-storyteller-api-key", apiKey);
    }

    public async Task<WorkflowStatus[]> GetWorkflowStatusAsync(string correlationId)
    {
        try
        {
            var response = await _httpClient.GetAsync($"{_baseUrl}/api/{correlationId}/status");
            response.EnsureSuccessStatusCode();

            var responseContent = await response.Content.ReadAsStringAsync();
            var workflows = JsonConvert.DeserializeObject<WorkflowStatus[]>(responseContent);

            return workflows;
        }
        catch (HttpRequestException ex)
        {
            throw new Exception($"Error getting workflow status: {ex.Message}", ex);
        }
    }
}

public class WorkflowStatus
{
    public string Code { get; set; }
    public string CorrelationId { get; set; }
    public string Status { get; set; }
    public string Message { get; set; }
    public string Timestamp { get; set; }
    public WorkflowStep[] Steps { get; set; }
}

public class WorkflowStep
{
    public string Name { get; set; }
    public string Status { get; set; }
    public string Message { get; set; }
    public string Timestamp { get; set; }
    public string[] Locations { get; set; }
}

// Usage
var checker = new WorkflowStatusChecker(Environment.GetEnvironmentVariable("STORYTELLER_API_KEY"));

try
{
    var workflows = await checker.GetWorkflowStatusAsync("09a560ba-dfa2-4865-bf95-4b3ce773c0fd");

    foreach (var workflow in workflows)
    {
        Console.WriteLine($"Workflow {workflow.Code}: {workflow.Status}");
        Console.WriteLine($"Message: {workflow.Message}");

        foreach (var step in workflow.Steps)
        {
            Console.WriteLine($"  Step \"{step.Name}\": {step.Status}");
            if (step.Locations != null)
            {
                Console.WriteLine($"  Created resources: {string.Join(", ", step.Locations)}");
            }
        }
    }
}
catch (Exception ex)
{
    Console.WriteLine($"Error: {ex.Message}");
}

Error Responses#

Invalid Correlation ID#

{
  "error": "Not Found",
  "message": "Workflow execution not found for correlation ID: invalid-id",
  "statusCode": 404
}

Unauthorized Access#

{
  "error": "Unauthorized",
  "message": "Invalid or missing API key",
  "statusCode": 401
}

Failed Workflow Example#

When a workflow fails, the response will show the failure details:

[
  {
    "code": "add-to-story",
    "correlationId": "54ea4fa8-7b16-41cb-80cc-0ad2483433ab",
    "status": "Failed",
    "message": "One or more workflow steps failed",
    "timestamp": "2024-04-26T14:49:38.6656253",
    "steps": [
      {
        "name": "Create Story Page",
        "status": "Failed",
        "message": "Story not found for CreatePageFromWorkflowJob. TenantId: e96d2c5a-53c0-8dc9-8243-39f15dce7af1, StoryId: c16dbd3e-0138-86b0-711b-3a122b51b010",
        "timestamp": "2024-04-26T14:49:38.677777"
      }
    ]
  }
]

Polling Best Practices#

Polling Strategy#

async function pollWorkflowStatus(correlationId, maxAttempts = 30, intervalMs = 5000) {
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    try {
      const workflows = await getWorkflowStatus(correlationId);

      // Check if all workflows are complete
      const allComplete = workflows.every(workflow => 
        workflow.status === 'Finished' || workflow.status === 'Failed'
      );

      if (allComplete) {
        return workflows;
      }

      console.log(`Attempt ${attempt}: Still processing...`);

      // Wait before next poll
      if (attempt < maxAttempts) {
        await new Promise(resolve => setTimeout(resolve, intervalMs));
      }
    } catch (error) {
      console.error(`Polling attempt ${attempt} failed:`, error);
      throw error;
    }
  }

  throw new Error(`Workflow did not complete after ${maxAttempts} attempts`);
}

// Usage
pollWorkflowStatus('09a560ba-dfa2-4865-bf95-4b3ce773c0fd')
  .then(workflows => {
    console.log('Workflow completed:', workflows);
  })
  .catch(error => console.error('Polling failed:', error));

Exponential Backoff#

async function pollWithBackoff(correlationId, maxAttempts = 10) {
  let delay = 1000; // Start with 1 second

  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    try {
      const workflows = await getWorkflowStatus(correlationId);

      const allComplete = workflows.every(workflow => 
        workflow.status === 'Finished' || workflow.status === 'Failed'
      );

      if (allComplete) {
        return workflows;
      }

      // Exponential backoff with jitter
      const jitter = Math.random() * 0.1 * delay;
      const totalDelay = delay + jitter;

      console.log(`Waiting ${Math.round(totalDelay / 1000)}s before next check...`);
      await new Promise(resolve => setTimeout(resolve, totalDelay));

      delay = Math.min(delay * 2, 30000); // Max 30 seconds
    } catch (error) {
      console.error(`Attempt ${attempt} failed:`, error);
      if (attempt === maxAttempts) throw error;
    }
  }

  throw new Error('Maximum polling attempts reached');
}

Response Status Codes#

Status Code Description
200 OK Workflow status retrieved successfully
401 Unauthorized Invalid or missing API key
404 Not Found Correlation ID not found
500 Internal Server Error Server error occurred

Best Practices#

  1. Use Webhooks When Possible - Instead of polling, set up webhooks for real-time notifications
  2. Implement Exponential Backoff - Reduce server load with intelligent polling intervals
  3. Handle All Status Types - Check for Running, Finished, and Failed statuses
  4. Store Location URLs - Save the locations array for linking to created resources
  5. Set Polling Timeouts - Don't poll indefinitely; set reasonable limits
  6. Log Status Changes - Track workflow progress for debugging and analytics

Next Steps#

After checking workflow status: 1. Handle successful completions appropriately 2. Parse location URLs for created resources 3. Implement retry logic for failed workflows 4. Set up monitoring for long-running workflows