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 executingFinished- All workflow steps completed successfullyFailed- One or more workflow steps failed
Step Status#
Running- Step is currently executingFinished- Step completed successfullyFailed- 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#
- Use Webhooks When Possible - Instead of polling, set up webhooks for real-time notifications
- Implement Exponential Backoff - Reduce server load with intelligent polling intervals
- Handle All Status Types - Check for Running, Finished, and Failed statuses
- Store Location URLs - Save the locations array for linking to created resources
- Set Polling Timeouts - Don't poll indefinitely; set reasonable limits
- 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
Related Documentation#
- Executing Workflows - Start workflow execution
- Getting Workflows - Get available workflows
- Webhooks - Alternative to polling for status updates
- Troubleshooting - Handle common issues