From camunda-skills
Browses, inspects, and applies pre-built Camunda connectors using element templates. Use for configuring connector templates on BPMN service tasks and events with c8ctl CLI.
How this skill is triggered — by the user, by Claude, or both
Slash command
/camunda-skills:camunda-connectorsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Browse and configure pre-built Camunda connectors using element templates. Apply connector configurations to BPMN service tasks and event elements for integrations with external systems (REST APIs, Slack, Kafka, AWS, email, databases, etc.).
Browse and configure pre-built Camunda connectors using element templates. Apply connector configurations to BPMN service tasks and event elements for integrations with external systems (REST APIs, Slack, Kafka, AWS, email, databases, etc.).
c8ctl add profile) — provides c8ctl element-template commandsc8ctl element-template sync once before using search, info, get-properties, get, or apply with an OOTB template ID. Re-run (optionally with --prune) to pick up upstream changes. Applying a template from a local file path or https:// URL bypasses the cache and does not require sync.--engine-version on discovery commands and --set FEEL auto-=. If a command or flag is unavailable, ask the user to upgrade: npm install -g @camunda8/cliElement templates (also called connector templates — the terms are used interchangeably in Camunda's docs and tooling) are JSON files that encapsulate connector configuration. Each template defines:
Read references/element-template-schema.md for the reader's guide to property fields and the binding → BPMN XML mapping. The full authoring schema lives in camunda-connectors-development.
Always discover the template ID via c8ctl element-template search rather than guessing or recalling an ID from memory. Template IDs and versions evolve — the search command reflects what's actually available in the local OOTB catalog.
c8ctl element-template search "REST" # find HTTP/REST connectors
c8ctl element-template search "slack" # find Slack connectors
c8ctl element-template search "kafka" # find Kafka connectors
c8ctl element-template search "connector" --limit 5 # cap results (default 20)
c8ctl element-template search "REST" --engine-version 8.8.0 # latest version compatible with 8.8.0
Each result shows the template name, ID (e.g. io.camunda.connectors.HttpJson.v2), version, appliesTo, engine constraint, and description. The header reads Showing N of M matches for '<query>' — if M > N, narrow the query or raise --limit. Pick the ID that matches your use case.
Inbound integrations typically ship as a family of templates — one per BPMN element type the inbound event can attach to (message-start event, intermediate-catch event, boundary event, receive task, …). search returns each variant; pick the one that matches the BPMN shape you're modelling.
Two commands cover the questions you'll ask before applying:
c8ctl element-template info <id> [--engine-version <x.y.z>] — metadata card (applies-to, engine constraint, description, docs link). Pass --engine-version to resolve the latest version compatible with that engine. Useful when the connector is unfamiliar.c8ctl element-template get-properties <id> [<name>...] [--engine-version <x.y.z>] — settable properties (condensed: name + description, grouped). Accepts positional names (shell-style globs work, quote them) and --group <id> to narrow. Pass --engine-version to resolve the latest version compatible with that engine. Add --detailed for per-property cards showing Required, FEEL, Active when, Pattern, Default, Choices — reach for --detailed when an apply --set call fails or when you need to know whether to prefix a value with =.c8ctl element-template get-properties io.camunda.connectors.HttpJson.v2 url method
c8ctl element-template get-properties io.camunda.connectors.HttpJson.v2 --group endpoint
c8ctl element-template get-properties io.camunda.connectors.HttpJson.v2 --detailed authentication.token
If a property's internal id differs from its binding name (the name --set matches), the condensed view annotates it as [id: <internal>] on a continuation line — always use the top-line name with --set.
Apply a template to a service task (or other supported element) — one call produces a fully-configured connector:
c8ctl element-template apply -i io.camunda.connectors.HttpJson.v2 Task_FetchUser process.bpmn
The <template> argument can be:
@<version>, e.g. io.camunda.connectors.HttpJson.v2@13). Without @<version>, the highest version compatible with the BPMN's executionPlatformVersion is auto-resolved. Requires c8ctl element-template sync to have run at least once../my-custom-template.json) — no sync requiredhttps:// URL (GitHub blob URLs are auto-rewritten to raw content) — no sync required-i modifies the BPMN file in place. Without -i, the modified XML is printed to stdout — useful for previews, redirected output, or composing with other tooling:
c8ctl element-template apply <id> <element> process.bpmn | diff process.bpmn - # preview the diff
c8ctl element-template apply <id> <element> process.bpmn > new-process.bpmn # write to a different file
c8ctl element-template apply <id> <element> process.bpmn | c8ctl bpmn lint # apply and lint in one pipeline
Apply writes zeebe:modelerTemplate, zeebe:modelerTemplateVersion, zeebe:modelerTemplateIcon, zeebe:taskDefinition, the entire zeebe:ioMapping block (inputs and outputs), and the zeebe:taskHeaders onto the element. All of those must stay consistent — apply owns them. In particular, custom <zeebe:output> mappings hand-added to a connector element will be wiped on the next apply — put downstream extraction on a separate activity, or on the next flow element's <zeebe:ioMapping> (end events accept it too).
apply auto-resolves the latest OOTB template version compatible with the BPMN's executionPlatformVersion. Pass --engine-version <x.y.z> to search, info, or get-properties to apply the same engine-compatibility filter during discovery — search returns the latest compatible version per template, and info / get-properties resolve via the same check. A pinned @<version> (e.g. io.camunda.connectors.HttpJson.v2@12) always takes precedence over --engine-version and produces a warning when the two differ.
Set every value via repeated --set key=value flags on the same apply call:
c8ctl element-template apply -i io.camunda.connectors.HttpJson.v2 Task_FetchUser process.bpmn \
--set method=GET \
--set url='="https://api.example.com/users/" + string(userId)' \
--set authentication.type=bearer \
--set authentication.token='{{secrets.API_TOKEN}}' \
--set resultExpression='={user: response.body}'
Note the string(userId) wrapper — userId is a number and FEEL does not auto-coerce in string concatenation. Without string(), the expression silently evaluates to null (the connector then issues a request to null). See camunda-feel for FEEL type coercion details.
key matches the template's property binding names — discover them with get-properties. When the same name appears on multiple binding types, prefix with input:, output:, header:, property:, or taskDefinition::
--set input:correlationKey='=order.id'
--set header:correlationKey=staticHeaderValue
apply errors with a helpful list of valid names if you pass an unknown property, and with the qualified-name list if a bare key is ambiguous.
FEEL value syntax. feel: required values must start with =. The canonical form is --set key='=value'; --set 'key==value' (compact) also works. For feel: required properties, c8ctl auto-prepends = when the value doesn't start with one, so --set key=expression stores =expression; value-side whitespace is trimmed. Check get-properties --detailed <name> when unsure about the feel setting for a property.
Defaults bake in. apply materializes every active property with a default into the BPMN — <zeebe:input>, <zeebe:output>, <zeebe:taskHeaders>, and <zeebe:property> entries — not just the keys you --set. The defaults are captured at apply time — if the template later ships a new default, this BPMN keeps the old value.
Re-apply. Omitted --set keys keep their current XML value, so single-property re-applies don't disturb the rest. Exception: dropdowns reset to the template default on every re-apply.
resultVariable and resultExpressionConnectors expose two properties under the Output mapping group that control what gets written back into the process scope when the connector completes:
resultVariable — name of a single process variable that receives the raw response. Plain string, no = prefix. Use when downstream tasks just need the whole response under one name.resultExpression — FEEL expression evaluated against the response, with its result merged into the process scope. Requires the = prefix. Use to extract specific fields, rename them, or compute derived values.Both can be set together — resultVariable captures the raw response, resultExpression shapes named variables alongside it. If neither is set, the response is discarded and downstream tasks see no new variables from this connector.
--set resultVariable=apiResponse \
--set resultExpression='={user: response.body.user, status: response.statusCode}'
The same mechanism applies to inbound connectors — e.g. the Slack inbound connector surfaces resultVariable + resultExpression under the same Output mapping group. The engine writes the incoming event payload into the process scope when the trigger fires, identically to how outbound writes the response when the service task completes.
When a connector is used as an AI-Agent tool, its output must surface under a toolCallResult variable (see camunda-ai-agents for the concept). REST connectors typically use resultExpression='={toolCallResult: response.body}'; other connectors apply the same resultExpression/resultVariable mechanics shaped to their own response.
# 1. Discover the template
c8ctl element-template search "REST"
# → io.camunda.connectors.HttpJson.v2 (REST Outbound Connector)
# 2. Apply with all values in one call
c8ctl element-template apply -i io.camunda.connectors.HttpJson.v2 Task_FetchUser process.bpmn \
--set authentication.type=bearer \
--set authentication.token='{{secrets.API_TOKEN}}' \
--set method=GET \
--set url='="https://api.example.com/users/" + string(userId)' \
--set resultVariable=apiResponse \
--set resultExpression='={user: response.body}' \
--set errorExpression='=if response.statusCode >= 400 then bpmnError("HTTP_ERROR", string(response.statusCode)) else null'
Resulting BPMN (the data:image/svg+xml;base64,... icon blob is elided here for readability — leave it in place in the real file):
<bpmn:serviceTask id="Task_FetchUser" name="Fetch user data"
zeebe:modelerTemplate="io.camunda.connectors.HttpJson.v2"
zeebe:modelerTemplateVersion="13"
zeebe:modelerTemplateIcon="data:image/svg+xml;base64,...">
<bpmn:extensionElements>
<zeebe:taskDefinition type="io.camunda:http-json:1" retries="3" />
<zeebe:ioMapping>
<zeebe:input source="bearer" target="authentication.type" />
<zeebe:input source="{{secrets.API_TOKEN}}" target="authentication.token" />
<zeebe:input source="GET" target="method" />
<zeebe:input source="="https://api.example.com/users/" + string(userId)" target="url" />
</zeebe:ioMapping>
<zeebe:taskHeaders>
<zeebe:header key="resultVariable" value="apiResponse" />
<zeebe:header key="resultExpression" value="={user: response.body}" />
<zeebe:header key="errorExpression" value="=if response.statusCode >= 400 then bpmnError("HTTP_ERROR", string(response.statusCode)) else null" />
</zeebe:taskHeaders>
</bpmn:extensionElements>
</bpmn:serviceTask>
After applying, validate with c8ctl bpmn lint process.bpmn.
<bpmn:documentation> is not settable via --set. It's a separate BPMN child element, not a template property — hand-edit it in after apply. Matters most when a connector is used as a camunda-ai-agents tool.authentication.token only applies when authentication.type=bearer) are silently skipped if their gating property isn't set in the same call. Decide the parent value first, then set the children.resultVariable and/or resultExpression. Omitting both means the connector's response is discarded.{{secrets.NAME}} for credentials. Never hardcode tokens, API keys, or webhook URLs in --set. See camunda-c8ctl for the secrets bootstrap on local clusters.TODO_REPLACE_WITH_API_URL or PLACEHOLDER_SLACK_CHANNEL. Avoid "", "test", or "xxx" — those can be mistaken for intended values.For detailed reference material, read from references/:
apply --set: property-reading checklist, binding → BPMN XML mapping table, HTTP worked example. For the full authoring schema, see camunda-connectors-developmentnpx claudepluginhub camunda/skills --plugin camunda-skillsGuides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.