Skip to main content
Version: 8.9 (unreleased)

Quick Start (Zero-Config — Recommended)

Technical Preview

The C# SDK is a technical preview available from Camunda 8.9. It will become fully supported in Camunda 8.10. Its API surface may change in future releases without following semver.

Keep configuration out of application code. Let the factory read CAMUNDA_* variables from the environment (12-factor style). This makes rotation, secret management, and environment promotion safer and simpler.

using Camunda.Orchestration.Sdk;

// Zero-config construction: reads CAMUNDA_* from environment variables.
// If no configuration is present, defaults to Camunda 8 Run on localhost.
using var client = CamundaClient.Create();

var topology = await client.GetTopologyAsync();
Console.WriteLine($"Brokers: {topology.Brokers?.Count ?? 0}");

Typical environment (example):

CAMUNDA_REST_ADDRESS=https://cluster.example   # SDK appends /v2 automatically
CAMUNDA_AUTH_STRATEGY=OAUTH
CAMUNDA_CLIENT_ID=***
CAMUNDA_CLIENT_SECRET=***
CAMUNDA_OAUTH_URL=https://login.cloud.camunda.io/oauth/token
CAMUNDA_DEFAULT_TENANT_ID=<default> # optional: override default tenant

Why zero-config?

  • Separation of concerns: business code depends on an interface, not on secrets/constants wiring.
  • 12-Factor alignment: config lives in the environment → simpler promotion (dev → staging → prod).
  • Secret rotation: rotate credentials without a code change or redeploy.
  • Immutable start: single hydration pass prevents drift / mid-request mutations.
  • Test ergonomics: swap env vars per test without touching source; create multiple clients for multi-tenant tests.
  • Security review: fewer code paths handling secrets; scanners & vault tooling work at the boundary.
  • Deploy portability: same artifact runs everywhere; only the environment differs.
  • Cross-SDK consistency: identical variable names across JavaScript, C#, and Python SDKs.

Programmatic Overrides (Advanced)

Use only when you must supply or mutate configuration dynamically (e.g. multi-tenant routing, tests, ephemeral preview environments). Keys mirror their CAMUNDA_* env names:

using Camunda.Orchestration.Sdk;

using var client = CamundaClient.Create(new CamundaOptions
{
Config = new Dictionary<string, string>
{
["CAMUNDA_REST_ADDRESS"] = "https://my-cluster.camunda.io",
["CAMUNDA_AUTH_STRATEGY"] = "OAUTH",
["CAMUNDA_CLIENT_ID"] = "my-client-id",
["CAMUNDA_CLIENT_SECRET"] = "my-secret",
["CAMUNDA_OAUTH_URL"] = "https://login.cloud.camunda.io/oauth/token",
["CAMUNDA_TOKEN_AUDIENCE"] = "zeebe.camunda.io",
},
});

Configuration via appsettings.json

The SDK can read configuration from any IConfiguration source (appsettings.json, user secrets, Azure Key Vault, etc.) using idiomatic .NET PascalCase section keys:

{
"Camunda": {
"RestAddress": "https://cluster.example.com",
"Auth": {
"Strategy": "OAUTH",
"ClientId": "my-client-id",
"ClientSecret": "my-secret"
},
"OAuth": {
"Url": "https://login.cloud.camunda.io/oauth/token"
},
"Backpressure": {
"Profile": "CONSERVATIVE"
}
}
}

Pass the section to the client:

using Camunda.Orchestration.Sdk;

var builder = WebApplication.CreateBuilder(args);

using var client = CamundaClient.Create(new CamundaOptions
{
Configuration = builder.Configuration.GetSection("Camunda"),
});

Precedence (highest wins): Config dictionary > IConfiguration section > environment variables > defaults.

This means you can set secrets via environment variables (or a vault) and non-sensitive settings via appsettings.json — they layer naturally:

// appsettings.json — non-sensitive, checked into source control
{
"Camunda": {
"RestAddress": "https://cluster.example.com",
"Backpressure": { "Profile": "CONSERVATIVE" }
}
}
# Secrets injected via environment (vault, CI, container orchestrator)
CAMUNDA_CLIENT_ID=***
CAMUNDA_CLIENT_SECRET=***
CAMUNDA_OAUTH_URL=https://login.cloud.camunda.io/oauth/token
appsettings.json key reference
appsettings.json keyMaps to env var
RestAddressCAMUNDA_REST_ADDRESS
TokenAudienceCAMUNDA_TOKEN_AUDIENCE
DefaultTenantIdCAMUNDA_DEFAULT_TENANT_ID
LogLevelCAMUNDA_SDK_LOG_LEVEL
ValidationCAMUNDA_SDK_VALIDATION
Auth:StrategyCAMUNDA_AUTH_STRATEGY
Auth:ClientIdCAMUNDA_CLIENT_ID
Auth:ClientSecretCAMUNDA_CLIENT_SECRET
Auth:BasicUsernameCAMUNDA_BASIC_AUTH_USERNAME
Auth:BasicPasswordCAMUNDA_BASIC_AUTH_PASSWORD
OAuth:UrlCAMUNDA_OAUTH_URL
OAuth:ClientIdCAMUNDA_CLIENT_ID
OAuth:ClientSecretCAMUNDA_CLIENT_SECRET
OAuth:GrantTypeCAMUNDA_OAUTH_GRANT_TYPE
OAuth:ScopeCAMUNDA_OAUTH_SCOPE
OAuth:TimeoutMsCAMUNDA_OAUTH_TIMEOUT_MS
OAuth:RetryMaxCAMUNDA_OAUTH_RETRY_MAX
OAuth:RetryBaseDelayMsCAMUNDA_OAUTH_RETRY_BASE_DELAY_MS
HttpRetry:MaxAttemptsCAMUNDA_SDK_HTTP_RETRY_MAX_ATTEMPTS
HttpRetry:BaseDelayMsCAMUNDA_SDK_HTTP_RETRY_BASE_DELAY_MS
HttpRetry:MaxDelayMsCAMUNDA_SDK_HTTP_RETRY_MAX_DELAY_MS
Backpressure:ProfileCAMUNDA_SDK_BACKPRESSURE_PROFILE
Backpressure:InitialMaxCAMUNDA_SDK_BACKPRESSURE_INITIAL_MAX
Backpressure:SoftFactorCAMUNDA_SDK_BACKPRESSURE_SOFT_FACTOR
Backpressure:SevereFactorCAMUNDA_SDK_BACKPRESSURE_SEVERE_FACTOR
Backpressure:RecoveryIntervalMsCAMUNDA_SDK_BACKPRESSURE_RECOVERY_INTERVAL_MS
Backpressure:RecoveryStepCAMUNDA_SDK_BACKPRESSURE_RECOVERY_STEP
Backpressure:DecayQuietMsCAMUNDA_SDK_BACKPRESSURE_DECAY_QUIET_MS
Backpressure:FloorCAMUNDA_SDK_BACKPRESSURE_FLOOR
Backpressure:SevereThresholdCAMUNDA_SDK_BACKPRESSURE_SEVERE_THRESHOLD
Eventual:PollDefaultMsCAMUNDA_SDK_EVENTUAL_POLL_DEFAULT_MS

Dependency Injection (AddCamundaClient)

For ASP.NET Core and other DI-based applications, use the AddCamundaClient() extension method on IServiceCollection. The client is registered as a singleton and automatically picks up ILoggerFactory from the container.

Zero-config (environment variables only):

using Camunda.Orchestration.Sdk;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCamundaClient();

With appsettings.json:

using Camunda.Orchestration.Sdk;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCamundaClient(builder.Configuration.GetSection("Camunda"));

With options callback (full control):

using Camunda.Orchestration.Sdk;

builder.Services.AddCamundaClient(options =>
{
options.Configuration = builder.Configuration.GetSection("Camunda");
// or: options.Config = new Dictionary<string, string> { ... };
});

Inject the client anywhere via constructor injection:

public class OrderController(CamundaClient camunda) : ControllerBase
{
[HttpPost]
public async Task<IActionResult> StartProcess()
{
var result = await camunda.CreateProcessInstanceAsync(
new ProcessInstanceCreationInstructionById
{
ProcessDefinitionId = ProcessDefinitionId.AssumeExists("order-process"),
});
return Ok(result);
}
}

Custom HttpClient

using Camunda.Orchestration.Sdk;

var httpClient = new HttpClient { BaseAddress = new Uri("https://my-cluster/v2/") };
using var client = CamundaClient.Create(new CamundaOptions
{
HttpClient = httpClient,
});