Use a snippet to call a downstream system or API, or to turn a repeated part of your journey into one reusable definition. You can apply the same template to many steps while giving each use its own endpoint, identity context, selector, text or other arguments.
For example, one account-risk integration can serve both login and payment steps. One HTML template can add a notice to several pages. One header template can label requests differently for each origin route. The Marketplace packages demonstrate these same patterns: Ekata provides API operations, Dynamic Messaging expands into several HTML injections, and tag-only profiling creates an entire step.
Start with Making your own integrations for a complete API example. This reference explains how scopes, arguments, placement and shared updates work, then shows a reusable header and HTML example.
File, template and operation names
These names have different purposes:
| Name | Example | Purpose |
|---|---|---|
| File path | customer_account_risk.snippet |
Loads the snippet file through the journey's snippets list |
| Template name | customer_account_risk |
Selects the definition inside that file |
| Operation name | account_risk_lookup |
Identifies this use within the step's model operations |
snippets:
- customer_account_risk.snippet
# Inside the selected step:
models:
- name: account_risk_lookup
apply_template:
name: customer_account_risk
arguments:
- name: api_base
value: https://risk.example.invalid
- name: auth_secret
value: internal_risk_token
- name: identity_context
value: ACCOUNT
The models block above belongs inside a step, not at the journey root. The complete example journey in Making your own integrations shows its placement.
Keep template names unique across imported files and paths relative to the journey. Removing an import breaks references to its templates.
Two stages of substitution
In {{api_base}}, api_base is a snippet argument. It is replaced while the journey is built. In {{ identity['ACCOUNT'].customer_token.customer_token }}, the identity value comes from the event at runtime.
The custom example deliberately nests the argument {{identity_context}} inside the runtime attribute expression. After expansion, it becomes an ordinary runtime reference to the selected context. Likewise, {{ secret({{auth_secret}}) }} becomes {{ secret(internal_risk_token) }}.
An attribute path passed as an argument is just text unless the template places it in an attribute-aware field or runtime expression. This distinction matters when adapting requests: a literal card.bin_number in a URL does not read the event's BIN.
Encode for the outgoing request
Call URL percent-encodes runtime substitutions in its URL. Pass original attribute values rather than pre-encoded strings. The runtime request-body template uses the declared content type: with Content-Type: application/json, interpolated string values are JSON-escaped. Form bodies use field rules with application/x-www-form-urlencoded.
This runtime handling does not make arbitrary build-time text substitutions safe. If a snippet argument is inserted directly into JSON or JavaScript source, it becomes part of that source before runtime escaping. Prefer runtime attribute expressions for event data and use typed template parameters for reusable assets. Test quotes, ampersands, plus signs and empty values against the actual request format.
Choose a scope
A scope describes the kind of journey position the template can fill. It does not select a step or automatically make the operation run on every event.
| Scope | Template shape | Snippets → Add behavior |
|---|---|---|
model/operation |
List of model/action operations | Choose an API or proxy step; opens Workflows → Models. This is the usual scope for a downstream API call. |
html/operation |
List of HTML mapping rules | Choose a compatible proxy step; adds to its response HTML mappings and opens Data Mappings. |
header/operation |
List of header mapping rules | Choose a proxy step; adds to its request header mappings and opens Data Mappings. |
step |
One complete step object | Creates a new step immediately; opens Customizations for its arguments. |
url_query/operation |
List of query mapping rules | The schema recognizes the scope, but the Add control does not place it automatically. Use manual YAML and validate it. |
For HTML placement, the picker excludes responses already parsed as JSON, XML, protobuf, JWT and other incompatible formats. A missing response mapping can be created as HTML. An API step does not provide an HTML response to rewrite.
The mapping editor can also offer imported snippets at an existing HTML or header mapping. In that case, the mapping's location determines request versus response. This differs from the defaults chosen by Snippets → Add.
Additional loader scopes
Advanced YAML authoring can target the following scopes accepted by the journey loader. They are not all represented in the visual editor's scope type or automatic placement controls. Validate the exact position and template shape before using them.
| Scope family | Expected template shape |
|---|---|
xml/operation, json/operation, multipart_body/operation, split_by_token/operation |
List of path or field mapping rules |
body/operation, url_scheme/operation, url_host/operation, url_path/operation, url_fragment/operation |
One parsing-rule object |
proxy_action/operation, decision_strategy/operation |
One model/action configuration object |
Declare scope before template in the YAML file. The loader uses it to parse the template. A scope mismatch at the reference is an error. A whole-step template is one object; it is not a list of several steps.
Design the arguments
Declare what varies between uses. Keep the common request, mapping or injection logic in the template.
| Argument type | Editor control / purpose |
|---|---|
string |
Text input; endpoint, text or another scalar setting |
xpath |
Text input for a path; it is not an automatic element picker |
attribute |
Attribute selector; the template must use the selected path in an attribute-aware field or expression |
context |
Context selector; also specify the context family, such as IdentityContext or AddressContext |
boolean |
Switch; use YAML true / false |
integer |
Integer input |
list |
Single selection from the declared options |
string_or_string_array |
A string or comma-separated values represented as a string list |
url_glob_regex |
URL glob input, converted to a regular expression during expansion |
Use display_name for the label and documentation for helper text. Supply a default where appropriate. Every declared argument without a default needs a value. An explicitly supplied empty value does not mean “use the default”.
The editor commonly writes defaults into each reference when you add a template. Changing a default later does not override values already saved in those references. Review each use when changing defaults or adding required arguments.
Some fields are typed before expansion. For example, use timeout: 1000 in a call_url; a quoted {{timeout_ms}} in that field is rejected even when the declared argument type is integer.
Journey variables can supply arguments using {{var.api_base}}. An exact variable reference can retain a number, boolean or list type; embedding it in a longer string produces text. Undefined variables fail validation.
Reuse a header across steps
This complete file sets a request header for your origin service. The route label varies at each use:
api_version: darwinium.com/api/snippet/v1
snippets:
- name: customer_route_header
display_name: Set customer route header
scope: header/operation
mode: Merge
arguments:
- name: route
display_name: Route name
type: string
default: account
validation: |
return item !== undefined && item.name === 'X-Customer-Route';
template:
- name: X-Customer-Route
inject:
mode: OverwriteOrInsertContent
content: "{{route}}"
Save it as customer_shared.snippet, import it, then add Set customer route header to your login and payment steps. Set route to sign-in on one and payment on the other. Both steps reference the same definition; their argument values remain independent.
The literal header name gives the placement helper a suitable destination. The validation function further restricts where the editor offers the snippet. It receives stepDef, path and item; it is an editor eligibility check, not a runtime condition or security boundary. Put event conditions in the generated journey operations.
Reuse HTML and supporting files
Append an HTML definition to the same file's snippets list:
- name: customer_notice
display_name: Add customer notice
scope: html/operation
mode: Merge
arguments:
- name: message
display_name: Notice text
type: string
default: Check the details before continuing.
validation: |
return true;
template:
- name: "{{name}}"
inject:
mode: AfterContent
template_from_file: customer-notice.html
template_parameters:
- key: message
value: "{{message}}"
data_type: String
Create customer-notice.html beside the snippet:
<p class="customer-notice" role="note">{{ message }}</p>
Import the file once, then add Add customer notice to each HTML page step. Set a different message at each use. {{name}} receives the surrounding mapping rule's name, such as /html/body; do not declare it as a separate selector argument. In this example, AfterContent places the notice after the selected element's existing content.
Supporting-file paths in the snippet resolve relative to the snippet file's directory. Keep the HTML, JavaScript, WebAssembly or other referenced assets with the definition when moving it. template_parameters passes typed values to a templated asset; the profiling packages use this pattern extensively for boolean flags, numeric limits and script settings.
The Dynamic Messaging package demonstrates a larger version: one reference expands into a script-loader injection in the document head and a message injection in the body. A template can generate several compatible operations at one reference.
Reuse a complete step
For scope: step, the template describes a complete configurable step. The tag-only profiling package uses this to create a serving endpoint with a host, listen URL, assets and arguments. Add it from the Snippets tab, then configure it under Customizations.
Adding the template again creates another step with its own name and arguments. It does not modify every existing step or provide a way to replace an existing step in place. Review URL matching so the new endpoint does not overlap unintentionally with another step.
Basic authentication with named secrets
The supplied Jira and Twilio headers build Basic authentication from a quoted user:password string. Inserting a nested secret expression into that string is not equivalent to evaluating the secret.
For an adapted local template, use a runtime expression that concatenates the account value and the secret before encoding. For example:
Basic {{ ('service@customer.com:' ~ secret(jira_api_token)) | b64encode }}
Use your Jira API account email, or the Twilio Account SID for the corresponding integration. Validate the expanded header without exposing the credential in logs. Base64 encoding is the HTTP authentication format; it does not protect a credential stored in source.
Change and validate a shared snippet
Changes to an imported file affect its references when their journeys are rebuilt and deployed. Review affected arguments, dependencies, assets and output attributes. Update every intended deployment; saving a workspace file does not change an already deployed journey.
The file's mode: Merge / Create metadata does not provide a Marketplace upgrade or a customization merge. Preserve custom copies before reinstalling. Removing a file from the journey's Snippets list removes the import, not the workspace file; references still using it will fail to load.
Give each template a unique name across all imports. Prefer a customer-specific prefix for your own library. Before deployment, check a reference using defaults, one with overridden arguments, missing input, and every step or target affected by a shared change.