API & Client
Comprehensive guide to interacting with Elsa Server programmatically via HTTP APIs and the elsa-api-client library, covering workflow publishing, instance management, bookmarks, and resilience pattern
Executive Summary
This guide covers how to interact with Elsa Workflows programmatically using:
HTTP APIs — Direct REST calls to Elsa Server endpoints
elsa-api-client — Official .NET client library for type-safe API interactions
When to Choose Direct HTTP vs Client Library
Direct HTTP
Polyglot teams, non-.NET clients, simple integrations
Language-agnostic, minimal dependencies
Manual serialization, no type safety
elsa-api-client
.NET applications, complex workflows, production systems
Type-safe, automatic serialization, resilience patterns
.NET-only, additional dependency
Recommendation: For .NET applications, prefer elsa-api-client for type safety and built-in conveniences. For non-.NET clients or simple webhook integrations, use direct HTTP calls.
Code Reference: src/clients/Elsa.Api.Client/ — Official API client implementation.
Architecture Overview
Core Concepts
Elsa's API is organized around three primary entities:
Workflow Definitions
Blueprint templates for workflows
/api/workflow-definitions
Workflow Instances
Running or completed executions
/api/workflow-instances
Bookmarks
Suspension points for workflow resume
/api/bookmarks
High-Level Workflow Lifecycle
┌────────────────────────────────────────────────────────────────────────────┐
│ │
│ Design ──► Publish ──► Instantiate ──► Execute ──► Suspend ──► Resume │
│ │ (bookmark) │ │
│ │ │ │ │
│ └──────────────────────────────┴─────────┘ │
│ │ │
│ ▼ │
│ Complete │
│ │
└────────────────────────────────────────────────────────────────────────────┘Design — Create workflow definition (via Studio or programmatically)
Publish — Activate the definition for execution
Instantiate — Create a new workflow instance
Execute — Run activities until completion or suspension
Suspend (Bookmark) — Workflow pauses at blocking activity, creates bookmark
Resume — External event triggers bookmark, execution continues
Complete — Workflow finishes with success or fault status
Code Reference: src/modules/Elsa.Workflows.Core/Contexts/ActivityExecutionContext.cs — Contains CreateBookmark() for suspending workflows.
Authentication & Identity
Elsa Server supports multiple authentication mechanisms. For comprehensive security guidance, see the Security & Authentication Guide (DOC-020).
Quick Reference
Bearer Token (curl)
curl -X GET "https://your-elsa-server.com/elsa/api/workflow-definitions" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json"API Key (curl)
curl -X GET "https://your-elsa-server.com/elsa/api/workflow-definitions" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json"elsa-api-client Configuration
using Elsa.Api.Client;
services.AddElsaClient(client =>
{
client.BaseUrl = new Uri("https://your-elsa-server.com");
client.ApiKey = "YOUR_API_KEY";
// Or use ConfigureHttpClient for JWT bearer tokens
});Code Reference: src/clients/Elsa.Api.Client/Extensions/ServiceCollectionExtensions.cs — Client registration extensions.
Publishing Workflow Definitions
Using elsa-api-client (C#)
The client library provides a type-safe way to create and publish workflow definitions.
using Elsa.Api.Client.Resources.WorkflowDefinitions.Contracts;
using Elsa.Api.Client.Resources.WorkflowDefinitions.Models;
using Elsa.Api.Client.Resources.WorkflowDefinitions.Requests;
public class WorkflowPublisher
{
private readonly IWorkflowDefinitionsApi _api;
public WorkflowPublisher(IWorkflowDefinitionsApi api)
{
_api = api;
}
public async Task<WorkflowDefinition> PublishWorkflowAsync()
{
var request = new SaveWorkflowDefinitionRequest
{
Model = new WorkflowDefinitionModel
{
DefinitionId = "my-workflow",
Name = "My Workflow",
Description = "A sample workflow",
Version = 1,
IsPublished = true,
Root = new Activity
{
Type = "Elsa.WriteLine",
Id = "write-line-1"
// Configure activity properties as needed
},
Options = new WorkflowOptions
{
CommitStrategyName = "WorkflowExecuted",
ActivationStrategyType = "Singleton",
AutoUpdateConsumingWorkflows = true
}
},
Publish = true
};
var response = await _api.SaveAsync(request);
return response;
}
}Key Properties:
DefinitionId
Unique identifier for the workflow definition
Version
Version number (increments with each publish)
Root
The root activity of the workflow
Options.CommitStrategyName
How often workflow state is persisted (see DOC-021)
Options.ActivationStrategyType
Controls how new instances are created (e.g., Singleton, Default)
Options.AutoUpdateConsumingWorkflows
Whether to update workflows that reference this one
Code Reference: src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Models/WorkflowOptions.cs
See publish-workflow.cs for a complete example.
HTTP Variant (POST)
curl -X POST "https://your-elsa-server.com/elsa/api/workflow-definitions" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"definitionId": "my-workflow",
"name": "My Workflow",
"description": "A sample workflow",
"version": 1,
"isPublished": true,
"root": {
"type": "Elsa.WriteLine",
"id": "write-line-1",
"text": "Hello, World!"
},
"options": {
"commitStrategyName": "WorkflowExecuted",
"activationStrategyType": "Default",
"autoUpdateConsumingWorkflows": true
}
}'Response (Success - 201 Created):
{
"id": "abc123",
"definitionId": "my-workflow",
"name": "My Workflow",
"version": 1,
"isPublished": true,
"createdAt": "2025-01-01T00:00:00Z"
}Versioning & Publishing Semantics
Draft vs Published
Workflow definitions have two states:
Draft
Work-in-progress definition
No
Published
Active, executable version
Yes
Multiple versions can exist, but only one version is the "latest published" version at any time.
Publishing Options
When saving a workflow definition, set Publish = true to immediately publish:
var request = new SaveWorkflowDefinitionRequest
{
Model = new WorkflowDefinitionModel { /* ... */ },
Publish = true // Immediately publish this version
};AutoUpdateConsumingWorkflows
When set to true, workflows that reference this definition (via Dispatch Workflow activity) will automatically use the new version:
Options = new WorkflowOptions
{
AutoUpdateConsumingWorkflows = true
}Code Reference: src/modules/Elsa.Workflows.Core/Models/WorkflowOptions.cs
Activation Strategies
Control how new workflow instances are created:
Default
Each trigger creates a new instance
Singleton
Only one running instance per definition
See the documentation on Activation Strategies in the main Elsa docs for detailed guidance.
Code Reference: src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Models/WorkflowOptions.cs — ActivationStrategyType property.
Starting / Instantiating Workflows
Using elsa-api-client (C#)
using Elsa.Api.Client.Resources.WorkflowInstances.Contracts;
using Elsa.Api.Client.Resources.WorkflowInstances.Requests;
public class WorkflowStarter
{
private readonly IWorkflowInstancesApi _api;
public WorkflowStarter(IWorkflowInstancesApi api)
{
_api = api;
}
public async Task<string> StartWorkflowAsync(
string definitionId,
string? correlationId = null,
Dictionary<string, object>? input = null)
{
var request = new StartWorkflowRequest
{
DefinitionId = definitionId,
CorrelationId = correlationId,
Input = input
};
var response = await _api.StartAsync(request);
return response.WorkflowInstanceId;
}
}See start-workflow.cs for a complete example.
HTTP Variant (POST)
curl -X POST "https://your-elsa-server.com/elsa/api/workflow-instances/start" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"definitionId": "my-workflow",
"correlationId": "order-12345",
"input": {
"orderId": "12345",
"customerEmail": "[email protected]"
}
}'Response (Success - 200 OK):
{
"workflowInstanceId": "inst-abc123",
"status": "Running"
}Key Parameters
definitionId
ID of the workflow definition to start
Yes
correlationId
External identifier for correlation
No
input
Dictionary of input values
No
versionOptions
Which version to run (Latest, Published, Specific)
No
Note:
TriggerWorkflowsOptionsis obsolete. Use theStartWorkflowRequestpattern shown above for creating new workflow instances.
Code Reference: src/clients/Elsa.Api.Client/Resources/WorkflowInstances/ — Instance management models.
Querying Workflow Definitions & Instances
Filtering Workflow Instances
The API supports filtering by status, correlationId, definitionId, and version with pagination.
Using elsa-api-client (C#)
using Elsa.Api.Client.Resources.WorkflowInstances.Contracts;
using Elsa.Api.Client.Resources.WorkflowInstances.Requests;
using Elsa.Api.Client.Resources.WorkflowInstances.Enums;
public class WorkflowQuerier
{
private readonly IWorkflowInstancesApi _api;
public WorkflowQuerier(IWorkflowInstancesApi api)
{
_api = api;
}
public async Task<PagedListResponse<WorkflowInstanceSummary>> QueryByCorrelationAsync(
string correlationId,
WorkflowStatus? status = null,
int page = 0,
int pageSize = 25)
{
var request = new ListWorkflowInstancesRequest
{
CorrelationId = correlationId,
Status = status,
Page = page,
PageSize = pageSize
};
return await _api.ListAsync(request);
}
}See query-workflows.cs for a complete example.
HTTP Variant (curl)
# Query by correlationId
curl -X GET "https://your-elsa-server.com/elsa/api/workflow-instances?correlationId=order-12345&page=0&pageSize=25" \
-H "Authorization: Bearer YOUR_TOKEN"
# Query by status
curl -X GET "https://your-elsa-server.com/elsa/api/workflow-instances?status=Running&page=0&pageSize=25" \
-H "Authorization: Bearer YOUR_TOKEN"
# Query by definitionId and version
curl -X GET "https://your-elsa-server.com/elsa/api/workflow-instances?definitionId=my-workflow&version=2" \
-H "Authorization: Bearer YOUR_TOKEN"Query Parameters
status
Filter by workflow status (Running, Suspended, Finished, Faulted)
Enum
correlationId
Filter by correlation ID
String
definitionId
Filter by workflow definition ID
String
version
Filter by specific version
Integer
page
Page number (0-indexed)
Integer
pageSize
Number of results per page (default: 25, max: 100)
Integer
Bookmarks & Resuming
How Bookmarks Work
Bookmarks are created when a workflow reaches a blocking activity (e.g., waiting for HTTP callback, human approval, or external event). The workflow suspends until resumed via the bookmark.
Code Reference: src/modules/Elsa.Workflows.Core/Contexts/ActivityExecutionContext.cs — CreateBookmark() method.
Bookmark Creation
Activities create bookmarks using ActivityExecutionContext.CreateBookmark():
// Internal to activity implementation
var bookmark = context.CreateBookmark(
callback: ResumeAsync,
payload: new MyBookmarkPayload { Data = "value" },
options: new CreateBookmarkArgs { AutoBurn = true }
);Stimulus Hashing
Bookmarks are matched using a deterministic hash based on:
Activity type name
Stimulus payload data
This allows the runtime to efficiently find matching bookmarks without knowing the instance ID.
Code Reference: src/modules/Elsa.Workflows.Core/Bookmarks/ — Stimulus hashing implementation (e.g., StimulusHasher).
Resuming Workflows
Token-Based Resume (URL)
HTTP triggers generate tokenized URLs for easy resumption:
# Token-based resume (generated URL)
curl -X POST "https://your-elsa-server.com/elsa/api/bookmarks/resume?t=ENCRYPTED_TOKEN" \
-H "Content-Type: application/json" \
-d '{"status": "approved"}'Code Reference: src/modules/Elsa.Http/Extensions/BookmarkExecutionContextExtensions.cs — GenerateBookmarkTriggerUrl method.
Stimulus-Based Resume
Resume by providing the stimulus payload directly:
# Stimulus-based resume
curl -X POST "https://your-elsa-server.com/elsa/api/bookmarks/resume" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"activityTypeName": "Elsa.HttpEndpoint",
"stimulus": {
"path": "/webhook/order-approved",
"method": "POST"
},
"input": {
"status": "approved",
"approvedBy": "[email protected]"
}
}'See resume-bookmark.curl.md for complete examples.
elsa-api-client Resume
using Elsa.Api.Client.Resources.WorkflowInstances.Contracts;
// Resume via workflow instance ID and bookmark ID
await _instancesApi.ResumeAsync(new ResumeWorkflowRequest
{
WorkflowInstanceId = instanceId,
BookmarkId = bookmarkId,
Input = new Dictionary<string, object>
{
["status"] = "approved"
}
});Resume Flow & Locking
The WorkflowResumer service:
Acquires a distributed lock on the workflow instance
Loads the workflow state from the database
Finds the matching bookmark
Resumes execution from the bookmarked activity
Burns (deletes) the bookmark if
AutoBurn = true
Code Reference: src/modules/Elsa.Workflows.Runtime/Services/WorkflowResumer.cs — Resume logic and locking.
Security Note
Tokenized resume URLs should be treated as secrets:
Use HTTPS to prevent interception
Tokens expire when the bookmark is burned or workflow is cancelled
See Security & Authentication Guide (DOC-020) for token security best practices
Incidents & Retry / Resilience
Resilience Strategies
Elsa supports configuring resilience strategies for activities to handle transient failures. The exact API for configuring resilience may vary by version.
Setting a Resilience Strategy (Conceptual Pattern)
The following example demonstrates a conceptual pattern for configuring resilience. Consult the current Elsa documentation and source code for the actual API in your version:
using Elsa.Api.Client.Resources.WorkflowDefinitions.Models;
var activity = new Activity
{
Type = "Elsa.HttpEndpoint",
Id = "http-call-1"
};
// Conceptual pattern: Configure resilience via activity properties
// The actual API may differ - check Elsa documentation for your version
activity.CustomProperties["resilience"] = new Dictionary<string, object>
{
["retryCount"] = 3,
["backoffDelay"] = TimeSpan.FromSeconds(5).TotalMilliseconds,
["backoffType"] = "Exponential"
};See resilience-strategy.cs for additional patterns and considerations.
Note: The resilience configuration API is evolving. Check the
src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Models/directory in elsa-core for current extension methods and models.
Handling Incidents
When activities fail, Elsa creates incidents. Query instance state to check for faults:
var instance = await _instancesApi.GetAsync(instanceId);
if (instance.Status == WorkflowStatus.Faulted)
{
// Check faults and incidents
var faults = instance.Faults;
foreach (var fault in faults)
{
Console.WriteLine($"Activity {fault.ActivityId} failed: {fault.Message}");
}
}For incident configuration and strategies, see the main documentation on incidents in the Operate Guide.
Commit Strategies
Commit strategies control when workflow state is persisted to the database. This affects durability and performance.
Selecting a Strategy
When creating a workflow definition, specify the commit strategy:
Options = new WorkflowOptions
{
CommitStrategyName = "WorkflowExecuted" // Minimal commits, highest throughput
}Available Strategies
WorkflowExecuted
Commits after workflow completes
High throughput, short workflows
ActivityExecuted
Commits after each activity
Maximum durability
Periodic
Commits at regular intervals
Long-running workflows
For detailed guidance on commit strategies and performance tuning, see Performance & Scaling Guide (DOC-021).
Code Reference: src/modules/Elsa.Workflows.Core/CommitStates/CommitStrategiesFeature.cs — Strategy registration.
Pagination & Performance
Pagination Parameters
All list endpoints support pagination:
page
Zero-indexed page number
0
-
pageSize
Results per page
25
100
Example with Pagination
# First page
curl "https://your-elsa-server.com/elsa/api/workflow-instances?page=0&pageSize=50"
# Second page
curl "https://your-elsa-server.com/elsa/api/workflow-instances?page=1&pageSize=50"Performance Recommendations
Use Server-Side Filtering: Always filter on the server rather than fetching all results and filtering client-side.
# Good: Server-side filtering curl "https://your-elsa-server.com/elsa/api/workflow-instances?status=Running&correlationId=order-123" # Avoid: Fetching all and filtering client-sideLimit Page Size: Use the smallest page size that meets your needs to reduce response time and memory usage.
Avoid Large Instance Graphs: When querying instances, request only summary data unless you need the full execution history.
Consider Field Selection (Future): Future versions may support field selection to reduce payload size. Check release notes for updates.
Error Handling & Troubleshooting
Common HTTP Status Codes
200 OK
Success
-
201 Created
Resource created
-
400 Bad Request
Validation error
Missing required field (e.g., root activity), malformed JSON
401 Unauthorized
Authentication failed
Invalid or expired token
404 Not Found
Resource not found
Definition ID doesn't exist
409 Conflict
Publish conflict
Version conflict during concurrent publish
410 Gone
Resource expired
Bookmark already consumed or expired
Validation Errors (400)
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"errors": {
"root": ["The Root field is required."],
"definitionId": ["The DefinitionId field is required."]
}
}Bookmark Not Found (404/410)
Common causes:
Bookmark already burned (consumed)
Workflow instance was cancelled
Token expired or invalid
Resolution:
Verify the workflow instance still exists and is suspended
Check if the bookmark was already consumed
Verify the stimulus payload matches exactly what the bookmark expects
Troubleshooting Checklist
Check logs for detailed error messages
Verify authentication with a simple GET request
Validate JSON syntax before sending
Check workflow state via instance query
Review bookmark existence in database
For comprehensive troubleshooting, see Troubleshooting Guide (DOC-017).
Best Practices Summary
Correlation IDs
Use correlation IDs for multi-event workflows to track related activities
Choose meaningful, unique identifiers (e.g., order ID, customer ID)
Query by correlation ID for efficient instance lookup
var request = new StartWorkflowRequest
{
DefinitionId = "order-processing",
CorrelationId = $"order-{orderId}" // Use meaningful ID
};Idempotent Resume Handlers
Design resume handlers to be idempotent (safe to call multiple times):
// Check if action already performed
if (await HasAlreadyProcessedAsync(bookmarkId))
{
return; // Skip duplicate processing
}
await ProcessAsync(input);
await MarkAsProcessedAsync(bookmarkId);Commit Strategy Selection
Choose commit strategy based on your durability vs throughput requirements:
High throughput, short workflows
WorkflowExecuted
Long-running, must not lose progress
ActivityExecuted
Balanced for most use cases
Periodic
Client Instrumentation
For custom metrics and monitoring:
User-defined metrics for throughput, latency, error rates
Built-in tracing via Elsa.OpenTelemetry for workflow execution visibility
See Performance & Scaling Guide (DOC-021) for observability patterns.
General Recommendations
Prefer elsa-api-client for .NET applications
Handle transient failures with retry policies
Use HTTPS for all API calls
Paginate results to avoid memory issues
Monitor workflow health via status queries
Clean up completed instances via retention policies
Example Files
publish-workflow.cs — Create and publish a workflow definition
start-workflow.cs — Start a workflow instance with correlation and input
query-workflows.cs — Query instances with filtering and pagination
resume-bookmark.curl.md — Resume workflow via token or stimulus
resilience-strategy.cs — Configure resilience for activities
Source File References — elsa-core source paths for grounding
Related Documentation
Security & Authentication Guide (DOC-020) — Authentication, tokenized URLs, security
Performance & Scaling Guide (DOC-021) — Commit strategies, observability
Persistence Guide (DOC-022) — Database configuration
Troubleshooting Guide (DOC-017) — Diagnosing common issues
Clustering Guide (DOC-015) — Distributed deployment
Last Updated: 2025-11-28
Acceptance Criteria (DOC-023):
✅ Covers HTTP APIs and elsa-api-client library usage
✅ Documents workflow lifecycle: publish, start, suspend, resume
✅ Provides actionable C# and curl examples
✅ Explains bookmark creation, stimulus hashing, and resume patterns
✅ References grounded in elsa-core
mainbranch✅ Notes obsolete TriggerWorkflowsOptions, recommends new patterns
✅ Links to DOC-020 (security), DOC-021 (performance), DOC-017 (troubleshooting)
✅ Differentiates built-in tracing vs user-defined metrics
Last updated