Example workflows
Note: This article details three self-service workflow examples. See the overview article to explore execution types, parameters, variables, and the workflow events API.
- Running CI — Event-driven workflow that triggers a CI pipeline and receives progress updates.
- Software templates — Event-driven workflow that creates a GitHub repository from a template.
- Freeze deployments — Simple workflow that freezes deployments with a single HTTP request.
Running CI
Use an event-driven workflow to trigger a run in an external CI or pipeline (GitHub Actions, GitLab CI, Argo Workflows, etc.) and report progress and final status back to DX. The workflow run stays in an “In Progress” state until the pipeline calls the DX API to change its status.
| Aspect | Recommendation |
|---|---|
| Execution type | Event-driven |
| Scope | Global or entity-specific (e.g. pass {{entity.identifier}} to the pipeline) |
| Parameters | Whatever the pipeline needs: branch, environment, ref, custom inputs |
How it works
- The user triggers the DX workflow (from Self-Service or from an entity).
- DX sends the configured HTTP request to your CI/pipeline (e.g. GitHub Actions workflow_dispatch).
- The request includes {{run.id}} so the pipeline can call back to DX.
- The pipeline runs and calls workflow events API endpoints, including: workflowRuns.postMessage, workflowRuns.addLink, and workflowRuns.changeStatus.
- Messages, links, and status appear on the Workflow Run Detail page. When the pipeline calls
workflowRuns.changeStatus, the DX run completes.
Prerequisites
- A web API token with
workflows:writescope, stored as a secret in your CI system (e.g.DX_WORKFLOW_API_KEY). - Your CI workflow or job must accept the DX workflow run ID (and any other DX parameters) as inputs and use them in
curlcalls to the DX API.
Example: GitHub Actions
1. Repository secret
In the GitHub repo, navigate to Settings > Security > Actions > Repository secrets and add:
- Name:
DX_WORKFLOW_API_KEY - Secret: your DX API token with the
workflows:writescope
2. Workflow file (e.g. .github/workflows/dx_workflow_example.yml)
The workflow must accept dx_workflow_run_id and pass it to the DX API base URL. Example pattern:
YAML file contents
name: DX Workflow Example
on:
workflow_dispatch:
inputs:
dx_workflow_run_id:
type: string
required: true
description: "The ID of the DX Workflow run that triggered this workflow."
# Add other inputs that DX will pass (e.g. branch, environment).
favorite_number:
type: number
required: true
description: "Example parameter from DX"
env:
DX_API_BASE_URL: https://api.getdx.com
DX_WORKFLOW_API_KEY: ${{ secrets.DX_WORKFLOW_API_KEY }}
DX_WORKFLOW_RUN_ID: ${{ github.event.inputs.dx_workflow_run_id }}
jobs:
run-and-report:
runs-on: ubuntu-latest
steps:
- name: Add link to DX Workflow
run: |
WORKFLOW_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer $DX_WORKFLOW_API_KEY" \
-d "{\"workflow_run_id\": \"$DX_WORKFLOW_RUN_ID\", \"link\": { \"url\": \"$WORKFLOW_URL\", \"label\": \"GitHub Actions Workflow\", \"icon\": \"github\" }}" \
"${DX_API_BASE_URL}/workflowRuns.addLink"
- name: Post start message
run: |
curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer $DX_WORKFLOW_API_KEY" \
-d "{\"workflow_run_id\": \"$DX_WORKFLOW_RUN_ID\", \"message\": \"Starting the GHA workflow...\"}" \
"${DX_API_BASE_URL}/workflowRuns.postMessage"
- name: Run your steps
run: |
echo "Do your CI work here..."
- name: Mark DX Workflow as complete
if: success()
run: |
curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer $DX_WORKFLOW_API_KEY" \
-d "{\"workflow_run_id\": \"$DX_WORKFLOW_RUN_ID\", \"status\": \"SUCCEEDED\"}" \
"${DX_API_BASE_URL}/workflowRuns.changeStatus"
- name: Mark DX Workflow as failed
if: failure()
run: |
curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer $DX_WORKFLOW_API_KEY" \
-d "{\"workflow_run_id\": \"$DX_WORKFLOW_RUN_ID\", \"status\": \"FAILED\"}" \
"${DX_API_BASE_URL}/workflowRuns.changeStatus"
3. DX workflow configuration
- Execution type: Event driven
- Parameters: Define any inputs you want to pass (e.g. Favorite number, identifier
favorite_number, type integer, required). - HTTP request
- Method:
POST - URL:
https://api.github.com/repos/<your-org>/<your-repo>/actions/workflows/dx_workflow_example.yml/dispatches - Headers:
Content-Type: application/json,Accept: application/json,Authorization: Bearer <github-pat> - Body (use DX variables so the run ID and parameters are passed):
- Method:
{
"ref": "master",
"inputs": {
"dx_workflow_run_id": "{{run.id}}",
"favorite_number": "{{data.favorite_number}}"
}
}
Use a GitHub Personal Access Token that has Read and Write permissions on repository actions and Read-Only permissions on metadata. When the DX workflow is triggered, it dispatches the GitHub Actions workflow. As the job runs, it posts messages, adds a link, and sets the DX run status.
Software templates
Use an event-driven workflow to create a new GitHub repository from a template (e.g. cookiecutter). An external template service generates the code, creates the repo, and reports progress back to DX.
| Aspect | Recommendation |
|---|---|
| Execution type | Event-driven |
| Scope | Global or entity-specific |
| Parameters | Template type (select), GitHub organization (string), repository name (string), project name (string, optional), description (string, optional) |
How it works
- The user triggers the DX workflow and provides template type, org/repo name, and optional project details.
- DX sends the configured HTTP request to your template service.
- The template service generates code from the template, creates the GitHub repo, and pushes the initial commit.
- The service calls the workflow events API to post progress messages, add a link to the new repo, and set the final status.
- Messages, links, and status appear on the Workflow Run Detail page.
Prerequisites
- Template service — A service that exposes an HTTP endpoint (e.g.
POST /api/service), generates code from a template, creates the GitHub repo, and pushes the initial commit. It must call the DX web API with a token withworkflows:writescope. - DX API key — A web API token with
workflows:writescope, accessible to the template service so it can post messages, add links, and change workflow run status. - GitHub token — Used by the template service to create the repo and push; not used by DX.
DX provides an example template service you can use as a starting point. It includes a working implementation of the HTTP endpoint, DX API integration, and GitHub repo creation described above.
DX configuration
In Self-service, click Create workflow.
- Execution type: Event-driven
- Parameters: Define inputs for the template type, GitHub organization, repository name, and any optional fields (project name, description).
- HTTP request
- Method:
POST - URL: Your template service endpoint (e.g.
http://YOUR_SERVICE_HOST:8000/api/service) - Headers:
Content-Type: application/json - Body (use DX variables so the run ID and user inputs are sent to the service):
- Method:
{
"dx_workflow_run_id": "{{run.id}}",
"template_type": "{{data.template_type}}",
"github_organization": "{{data.github_organization}}",
"github_repository": "{{data.github_repository}}",
"project_name": "{{data.project_name}}",
"description": "{{data.description}}"
}
Including {{run.id}} is critical: the template service must receive this ID to send status updates to the correct workflow run.
As an alternative to one workflow with a template selector, you can create one workflow per template (e.g. “Create Python Package”) with only the parameters that template needs, hardcoding the template_type in the HTTP body.
Troubleshooting
| Problem | What to check |
|---|---|
| DX shows “Status code: null” | DX cannot reach the template service. Verify the service is running, use the correct URL (IP, host.docker.internal, or tunnel), and check firewalls. |
| No status updates in DX | Template service cannot reach DX. Verify the DX API key is set in the service environment with workflows:write scope and check service logs for API errors. |
| Repository created but empty | GitHub push failed. Verify the GitHub token used by the service has repo and workflow scopes; check service logs. |
| “Repository already exists” | The repo name is already taken on GitHub. Use a different name or delete the existing repo. |
Freeze deployments
Use a simple workflow to freeze (lock) deployments for a service during an incident or release. A single HTTP request to your deployment or Git provider does the work; DX marks the run as Success or Failed based on the response status code.
| Aspect | Recommendation |
|---|---|
| Execution type | Simple |
| Scope | Entity-specific (e.g. Service) so you can pass {{entity.identifier}} or {{entity.name}} to the provider |
| Parameters | Optional: reason (string), duration (string or select) |
How it works
- The user triggers the workflow from the Self-Service page or from a service’s Entity Detail page.
- DX sends one HTTP request (e.g. POST) to your provider’s freeze/lock endpoint.
- The request includes the entity identifier (or name) so the provider knows which service to freeze.
- If the provider returns a 2XX response, DX marks the workflow run as Success; otherwise Failed. The run completes as soon as the response is received.
Configuration
Parameters (optional) — You can add a “Reason” (string) or “Duration” (string/select) and pass them in the body so the provider or your team can see why deployments were frozen.
HTTP request
- Method: Usually
POST(or whatever your provider’s API uses for “freeze” or “lock deployment”). - URL: The provider’s API endpoint (e.g. GitLab project freeze, or your own API that wraps the provider).
- Headers:
Content-Type: application/json, plus anAuthorizationheader with a token that has permission to freeze deployments. - Body: Include the entity and any optional parameters. Example (GitLab-style):
{
"project_id": "{{entity.identifier}}",
"reason": "{{data.reason}}"
}
If your provider uses path parameters, put the entity identifier in the URL (e.g. /projects/{{entity.identifier}}/freeze).
Example: entity-specific freeze
- Scope: Entity-specific, applicable to entity type Service.
- Who can run: For a freeze workflow you may want Entity owners only so only users or teams who own the service can trigger it. See Who can run this workflow in the overview.
- Parameters: Reason (identifier
reason, type string, optional). - HTTP: POST to your provider’s freeze endpoint with
Authorization: Bearer <token>, body{ "project_id": "{{entity.identifier}}", "reason": "{{data.reason}}" }.
Only one request is sent; no callback to DX is needed. For an event-driven “unfreeze after N minutes” flow, you can use a separate workflow or an external scheduler that calls the provider’s “unfreeze” API.