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.

  1. Navigate to your app in Codemagic
  2. Look at the app URL: https://codemagic.io/app/xxxxxxxxxxxxxxxxxxxxxxxx
  3. 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.

  1. Navigate to your codemagic.yaml file (in Codemagic or in your repository)
  2. Copy the workflow key under workflows: (e.g., sample-workflow). This is the value for workflowId in API calls—not the optional display name: field.
workflows:
  sample-workflow:
    name: Codemagic Sample Workflow

Configuring access to Codemagic in Jenkins

Store your Codemagic API key as a Jenkins Secret text credential with ID codemagic-api-key.

  1. Go to Manage Jenkins → Credentials → System → Global credentials.
  2. Click Add Credentials.
  3. Set Kind to Secret text
  4. Set Scope to Global
  5. Set Secret to your-codemagic-api-key
  6. Set ID to codemagic-api-key.
  7. 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

Note: When you start a build through the API, 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.

StatusMeaning
initializing, queued, preparing, fetching, testing, building, publishing, finishingIn progress — keep polling
finishedBuild completed successfully
failed, canceled, timeout, skippedBuild 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:

ParameterDescription
CM_BUILD_IDCodemagic build ID
CM_BUILD_STATUSsuccess or failure
CM_ARTIFACT_LINKSJSON list of artifact names and URLs (built-in variable)
JENKINS_TRIGGER_BUILDOptional. 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 → SecurityAPI TokenAdd new Token). API token authentication bypasses CSRF protection on buildWithParameters; using a password often returns 403 unless 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.