Jenkins integration
How to integrate Codemagic into your Jenkins workflows using the Codemagic REST API
Trigger Codemagic builds from Jenkins pipeline stages using the REST API. Poll build status from Jenkins, or report results back from codemagic.yaml publishing scripts.
Create a Codemagic API key
You need a Codemagic API key to authenticate REST API requests from Jenkins. Every Codemagic account has an API key available in the Account settings.
Find your Application ID
The Application ID uniquely identifies your app in Codemagic API calls.
- Navigate to your app in Codemagic
- Look at the app URL: https://codemagic.io/app/xxxxxxxxxxxxxxxxxxxxxxxx
- Copy the UUID at the end - this is your
AppID.
Find your workflow key
The workflow key identifies which workflow to trigger. Pass it as workflowId in API requests.
- Navigate to your
codemagic.yamlfile (in Codemagic or in your repository) - Copy the workflow key under
workflows:(e.g.,sample-workflow). This is the value forworkflowIdin API calls—not the optional displayname:field.
workflows:
sample-workflow:
name: Codemagic Sample WorkflowConfiguring access to Codemagic in Jenkins
Store your Codemagic API key as a Jenkins Secret text credential with ID codemagic-api-key.
- Go to Manage Jenkins → Credentials → System → Global credentials.
- Click Add Credentials.
- Set Kind to Secret text
- Set Scope to Global
- Set Secret to
your-codemagic-api-key - Set ID to codemagic-api-key.
- Click OK.
Trigger a Codemagic build
A Pipeline job can send a request to Codemagic with the app, workflow, and branch or tag to build.
Learn more about required parameters: Builds API documentation
appId, workflowId, and branch or tag in the request determine what runs. Trigger and branch filters in codemagic.yaml are not applied to API-started builds.The following example triggers a Codemagic build, passes Jenkins metadata as environment variables, and stores the returned buildId. JSON is parsed with Groovy’s built-in JsonSlurper (no extra Jenkins plugin required). If you already use Pipeline Utility Steps, readJSON text: body is equivalent. For API-only pipelines that do not use the repository on the agent, add options { skipDefaultCheckout(true) } to skip an unnecessary SCM checkout.
pipeline {
agent any
options {
skipDefaultCheckout(true)
}
environment {
CODEMAGIC_APP_ID = 'YOUR_APP_ID' // change to your AppID
CODEMAGIC_WORKFLOW = 'YOUR_WORKFLOW_KEY' // workflow key from codemagic.yaml
CODEMAGIC_BRANCH = 'YOUR_BRANCH_NAME' // change to your branch name
}
stages {
stage('Trigger Codemagic build') {
steps {
withCredentials([string(credentialsId: 'codemagic-api-key', variable: 'CODEMAGIC_API_KEY')]) {
script {
def result = sh(
script: """
curl -s -w "\\nHTTP_CODE:%{http_code}" \
-X POST \
-H "Content-Type: application/json" \
-H "x-auth-token: \$CODEMAGIC_API_KEY" \
-d '{
\"appId\": \"${CODEMAGIC_APP_ID}\",
\"branch\": \"${CODEMAGIC_BRANCH}\",
\"workflowId\": \"${CODEMAGIC_WORKFLOW}\",
\"environment\": {
\"variables\": {
\"BUILD_NUMBER\": \"${env.BUILD_NUMBER}\",
\"TRIGGERED_BY\": \"jenkins\"
},
\"groups\": [
\"YOUR_VARIABLE_GROUP\"
]
}
}' \
https://api.codemagic.io/builds
""",
returnStdout: true
).trim()
def parts = result.split('HTTP_CODE:')
def body = parts[0].trim()
def httpCode = parts[1].trim()
if (httpCode == '200') {
def build = new groovy.json.JsonSlurper().parseText(body)
env.CODEMAGIC_BUILD_ID = build.buildId as String
echo "Codemagic build triggered: https://codemagic.io/app/${CODEMAGIC_APP_ID}/build/${build.buildId}"
} else {
error "Codemagic API returned HTTP ${httpCode}: ${body}"
}
}
}
}
}
}
}For release pipelines that build from a Git tag, send tag instead of branch in the JSON body.
You can pass software version overrides in the environment object, and instanceType at the top level of the request body (not inside environment). See Pass custom build parameters. Variables you pass from Jenkins are available in Codemagic build scripts alongside built-in environment variables (CM_TRIGGER_SOURCE is api for API-started builds). That includes Jenkins callback variables for the publishing script when you want per-build URLs without editing Codemagic settings:
"environment": {
"variables": {
"BUILD_NUMBER": "42",
"JENKINS_CALLBACK_URL": "https://jenkins.example.com/job/codemagic-callback",
"JENKINS_USER": "ci-bot",
"JENKINS_API_TOKEN": "…",
"JENKINS_TRIGGER_BUILD": "42"
}
}Store secrets in a Codemagic environment variable group when the values are fixed across builds.
If a Jenkins run is aborted while a Codemagic build is in flight, call Cancel build with the stored buildId.
Poll build status
Poll GET https://codemagic.io/api/v3/builds/{buildId} until the build reaches a terminal status. The v3 response wraps the build under data; read data.status, not a top-level status field.
| Status | Meaning |
|---|---|
initializing, queued, preparing, fetching, testing, building, publishing, finishing | In progress — keep polling |
finished | Build completed successfully |
failed, canceled, timeout, skipped | Build did not complete successfully |
There is no separate success status — treat finished as success.
The example below adds a wait stage after the trigger. codemagicBuildStatus is marked @NonCPS and returns a plain String so Jenkins can safely call sleep() between polls (parsed JSON objects cannot be held across sleep() in Declarative Pipelines).
@NonCPS
String codemagicBuildStatus(String jsonBody) {
def parsed = new groovy.json.JsonSlurper().parseText(jsonBody)
return parsed.data.status as String
}
pipeline {
agent any
environment {
CODEMAGIC_APP_ID = 'YOUR_APP_ID'
CODEMAGIC_WORKFLOW = 'YOUR_WORKFLOW_KEY' // workflow key from codemagic.yaml
CODEMAGIC_BRANCH = 'YOUR_BRANCH_NAME'
}
stages {
stage('Trigger Codemagic build') {
steps {
withCredentials([string(credentialsId: 'codemagic-api-key', variable: 'CODEMAGIC_API_KEY')]) {
script {
// ... same trigger script as above ...
}
}
}
}
stage('Wait for Codemagic build') {
steps {
withCredentials([string(credentialsId: 'codemagic-api-key', variable: 'CODEMAGIC_API_KEY')]) {
script {
def terminalStatuses = ['finished', 'failed', 'canceled', 'timeout', 'skipped']
def status = ''
while (!terminalStatuses.contains(status)) {
def body = sh(
script: """
curl -s \
-H "x-auth-token: \$CODEMAGIC_API_KEY" \
https://codemagic.io/api/v3/builds/${env.CODEMAGIC_BUILD_ID}
""",
returnStdout: true
).trim()
status = codemagicBuildStatus(body)
echo "Codemagic build status: ${status}"
if (!terminalStatuses.contains(status)) {
sleep(time: 30, unit: 'SECONDS')
}
}
if (status != 'finished') {
error "Codemagic build ${env.CODEMAGIC_BUILD_ID} ended with status: ${status}"
}
}
}
}
}
}
}Report results back to Jenkins
Codemagic runs builds in the cloud. The publishing script sends a POST request to Jenkins when the build finishes, so Jenkins must be reachable at a public HTTPS URL (reverse proxy, ingress, and so on). A localhost Jenkins URL will not work.
Create the callback job
Create a parameterized Pipeline job that receives the Codemagic result—for example, codemagic-callback at https://jenkins.example.com/job/codemagic-callback. Define these string parameters:
| Parameter | Description |
|---|---|
CM_BUILD_ID | Codemagic build ID |
CM_BUILD_STATUS | success or failure |
CM_ARTIFACT_LINKS | JSON list of artifact names and URLs (built-in variable) |
JENKINS_TRIGGER_BUILD | Optional. Jenkins build number that triggered the Codemagic build |
pipeline {
agent any
parameters {
string(name: 'CM_BUILD_ID', defaultValue: '')
string(name: 'CM_BUILD_STATUS', defaultValue: '')
string(name: 'CM_ARTIFACT_LINKS', defaultValue: '')
string(name: 'JENKINS_TRIGGER_BUILD', defaultValue: '')
}
stages {
stage('Handle Codemagic result') {
steps {
echo "Codemagic build ${params.CM_BUILD_ID}: ${params.CM_BUILD_STATUS}"
if (params.CM_BUILD_STATUS != 'success') {
error "Codemagic build failed"
}
}
}
}
}Configure callback credentials
Store JENKINS_CALLBACK_URL, JENKINS_USER, and JENKINS_API_TOKEN in a Codemagic environment variable group, or pass them in the start-build request environment.variables object.
JENKINS_CALLBACK_URL— Job URL without/buildWithParameters. Example:https://jenkins.example.com/job/codemagic-callback. The publishing script appends/buildWithParameters.JENKINS_USER— Jenkins username for API access.JENKINS_API_TOKEN— A Jenkins API token for that user (not the account password). Generate one under the user’s profile (for example, click the username → Security → API Token → Add new Token). API token authentication bypasses CSRF protection onbuildWithParameters; using a password often returns403unless CSRF is disabled (not recommended for production).
Notify Jenkins from codemagic.yaml
Add a publishing script that runs when the Codemagic build finishes. Publishing scripts run regardless of build status unless you add conditions.
The example below runs build steps first, then creates ~/SUCCESS only if they all pass. If a script step fails, ~/SUCCESS is not created and the publishing script reports failure to Jenkins.
workflows:
sample-workflow:
scripts:
- name: Build app
script: |
# ... your build steps ...
- name: Mark build successful
script: touch ~/SUCCESS
publishing:
scripts:
- name: Notify Jenkins
script: |
if [ -f "$HOME/SUCCESS" ]; then
STATUS=success
else
STATUS=failure
fi
HTTP_CODE=$(curl -s -o /tmp/jenkins-response.txt -w "%{http_code}" \
-X POST "$JENKINS_CALLBACK_URL/buildWithParameters" \
--user "$JENKINS_USER:$JENKINS_API_TOKEN" \
--data-urlencode "CM_BUILD_ID=$CM_BUILD_ID" \
--data-urlencode "CM_BUILD_STATUS=$STATUS" \
--data-urlencode "CM_ARTIFACT_LINKS=$CM_ARTIFACT_LINKS" \
--data-urlencode "JENKINS_TRIGGER_BUILD=$JENKINS_TRIGGER_BUILD")
if [ "$HTTP_CODE" -lt 200 ] || [ "$HTTP_CODE" -ge 300 ]; then
cat /tmp/jenkins-response.txt
exit 1
fi CM_BUILD_ID and CM_ARTIFACT_LINKS are built-in Codemagic environment variables. CM_ARTIFACT_LINKS is a JSON-encoded list of artifact names and download URLs.
If pull request gating runs on GitHub rather than Jenkins, you can report build status with GitHub Checks instead of—or in addition to—a Jenkins callback.
Configuring Fastlane
Codemagic has Fastlane preinstalled, you can define lanes in codemagic.yaml and trigger that workflow from Jenkins with the API steps above.
For Match, App Store Connect API keys, and sample codemagic.yaml snippets, see Fastlane integration.