Deployments (DORA)
Push a deployment event from your CI/CD when you ship. Milestone uses it to compute your DORA deployment frequency, lead time, and change-failure rate.
Step 1 — Get your ingest token
In your Milestone account, navigate to App Settings → Integrations → Deployments (DORA) and click Setup.
Copy the ingest token and save it as a CI/CD secret named MILESTONE_INGEST_TOKEN.
The token is shown only once and is not stored by Milestone. Regenerating a token issues a new one; the old one stays valid until it expires. If a token is exposed, contact Milestone support to rotate it.
Step 2 — Add a step to your pipeline
Recipes require curl ≥ 7.76 and jq on the runner. Replace "your-service" in the snippets with the name of the service being deployed.
- GitHub Actions
- GitLab CI
- Jenkins
- Datadog format
Add this as the last step of your deploy job in .github/workflows/deploy.yml:
- name: Report deployment to Milestone
if: success()
env:
MILESTONE_INGEST_TOKEN: ${{ secrets.MILESTONE_INGEST_TOKEN }}
REPOSITORY: ${{ github.repository }}
RUN_ID: ${{ github.run_id }}
RUN_ATTEMPT: ${{ github.run_attempt }}
REF_NAME: ${{ github.ref_name }}
COMMIT_SHA: ${{ github.sha }}
REPO_URL: ${{ github.server_url }}/${{ github.repository }}
run: |
curl -sS --fail-with-body -X POST "https://events.mstone.ai/deployments" \
-H "x-shared-secret: $MILESTONE_INGEST_TOKEN" \
-H "content-type: application/json" \
-d "$(jq -n \
--arg id "$REPOSITORY-$RUN_ID-$RUN_ATTEMPT-$GITHUB_JOB" --arg at "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
--arg st "success" --arg ref "$REF_NAME" --arg sha "$COMMIT_SHA" --arg repo "$REPO_URL" \
'{external_id:$id, triggered_at:$at, status:$st, service_names:["your-service"], repo_url:$repo, ref_name:$ref, commit_sha:$sha}')"
Add this job to your .gitlab-ci.yml. Set MILESTONE_INGEST_TOKEN as a masked CI/CD variable (mark it Protected only if your deploy pipelines run exclusively on protected refs).
report-deployment:
stage: .post
# Fires after a fully-green default-branch pipeline. Align this rule with
# where your deploys actually run (or tie it to your deploy job via needs:).
rules:
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
# A failed report stays visible but never blocks your pipeline.
allow_failure: true
image: alpine:latest
script:
- apk add --no-cache curl jq
- |
curl -sS --fail-with-body -X POST "https://events.mstone.ai/deployments" \
-H "x-shared-secret: $MILESTONE_INGEST_TOKEN" \
-H "content-type: application/json" \
-d "$(jq -n \
--arg id "$CI_PROJECT_PATH-$CI_PIPELINE_ID-$CI_JOB_ID" --arg at "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
--arg st "success" --arg ref "$CI_COMMIT_REF_NAME" \
--arg sha "$CI_COMMIT_SHA" --arg repo "$CI_PROJECT_URL" \
'{external_id:$id, triggered_at:$at, status:$st, service_names:["your-service"], repo_url:$repo, ref_name:$ref, commit_sha:$sha}')"
Add the success{} block to your deploy stage's post section:
// Add the success{} block to your deploy stage's post section (or paste the
// whole block if it has none). Needs an agent: with a top-level 'agent none',
// put it on the deploy stage, not the pipeline.
post {
success {
withCredentials([string(credentialsId: 'milestone-ingest-token', variable: 'MILESTONE_INGEST_TOKEN')]) {
sh '''
curl -sS --fail-with-body -X POST "https://events.mstone.ai/deployments" \
-H "x-shared-secret: $MILESTONE_INGEST_TOKEN" \
-H "content-type: application/json" \
-d "$(jq -n \
--arg id "$BUILD_TAG" --arg at "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
--arg st "success" --arg ref "${GIT_BRANCH#origin/}" --arg sha "$GIT_COMMIT" --arg repo "$GIT_URL" \
'{external_id:$id, triggered_at:$at, status:$st, service_names:["your-service"], repo_url:$repo, ref_name:$ref, commit_sha:$sha}')"
'''
}
}
}
Already emit Datadog DORA deployments? Repoint the host and add ?format=datadog:
curl -sS --fail-with-body -X POST "https://events.mstone.ai/deployments?format=datadog" \
-H "x-shared-secret: $MILESTONE_INGEST_TOKEN" \
-H "content-type: application/json" \
-d '{"data":{"id":"deploy-1234","attributes":{"service":"your-service","started_at":1784478720000000000,"env":"production","git":{"commit_sha":"...","repository_url":"..."}}}}'
Step 3 — Test it
Run this command to verify the connection. A {"accepted":1} response means Milestone received it. Set MILESTONE_INGEST_TOKEN in your shell first.
- macOS / Linux
- Windows (PowerShell)
curl -sS --fail-with-body -X POST "https://events.mstone.ai/deployments" \
-H "x-shared-secret: $MILESTONE_INGEST_TOKEN" \
-H "content-type: application/json" \
-d '{"external_id":"test-1","triggered_at":"2026-07-19T14:32:00Z","status":"success","service_names":["your-service"]}'
Invoke-RestMethod -Method Post -Uri "https://events.mstone.ai/deployments" `
-Headers @{ "x-shared-secret" = $env:MILESTONE_INGEST_TOKEN } `
-ContentType "application/json" `
-Body '{"external_id":"test-1","triggered_at":"2026-07-19T14:32:00Z","status":"success","service_names":["your-service"]}'