Quick Start (Zero-Config — Recommended)
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 key | Maps to env var |
|---|---|
RestAddress | CAMUNDA_REST_ADDRESS |
TokenAudience | CAMUNDA_TOKEN_AUDIENCE |
DefaultTenantId | CAMUNDA_DEFAULT_TENANT_ID |
LogLevel | CAMUNDA_SDK_LOG_LEVEL |
Validation | CAMUNDA_SDK_VALIDATION |
Auth:Strategy | CAMUNDA_AUTH_STRATEGY |
Auth:ClientId | CAMUNDA_CLIENT_ID |
Auth:ClientSecret | CAMUNDA_CLIENT_SECRET |
Auth:BasicUsername | CAMUNDA_BASIC_AUTH_USERNAME |
Auth:BasicPassword | CAMUNDA_BASIC_AUTH_PASSWORD |
OAuth:Url | CAMUNDA_OAUTH_URL |
OAuth:ClientId | CAMUNDA_CLIENT_ID |
OAuth:ClientSecret | CAMUNDA_CLIENT_SECRET |
OAuth:GrantType | CAMUNDA_OAUTH_GRANT_TYPE |
OAuth:Scope | CAMUNDA_OAUTH_SCOPE |
OAuth:TimeoutMs | CAMUNDA_OAUTH_TIMEOUT_MS |
OAuth:RetryMax | CAMUNDA_OAUTH_RETRY_MAX |
OAuth:RetryBaseDelayMs | CAMUNDA_OAUTH_RETRY_BASE_DELAY_MS |
HttpRetry:MaxAttempts | CAMUNDA_SDK_HTTP_RETRY_MAX_ATTEMPTS |
HttpRetry:BaseDelayMs | CAMUNDA_SDK_HTTP_RETRY_BASE_DELAY_MS |
HttpRetry:MaxDelayMs | CAMUNDA_SDK_HTTP_RETRY_MAX_DELAY_MS |
Backpressure:Profile | CAMUNDA_SDK_BACKPRESSURE_PROFILE |
Backpressure:InitialMax | CAMUNDA_SDK_BACKPRESSURE_INITIAL_MAX |
Backpressure:SoftFactor | CAMUNDA_SDK_BACKPRESSURE_SOFT_FACTOR |
Backpressure:SevereFactor | CAMUNDA_SDK_BACKPRESSURE_SEVERE_FACTOR |
Backpressure:RecoveryIntervalMs | CAMUNDA_SDK_BACKPRESSURE_RECOVERY_INTERVAL_MS |
Backpressure:RecoveryStep | CAMUNDA_SDK_BACKPRESSURE_RECOVERY_STEP |
Backpressure:DecayQuietMs | CAMUNDA_SDK_BACKPRESSURE_DECAY_QUIET_MS |
Backpressure:Floor | CAMUNDA_SDK_BACKPRESSURE_FLOOR |
Backpressure:SevereThreshold | CAMUNDA_SDK_BACKPRESSURE_SEVERE_THRESHOLD |
Eventual:PollDefaultMs | CAMUNDA_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,
});