Pause Automation in SFMC Using SOAP API

Sometimes you need to stop a running Automation from outside Automation Studio. A monitoring system might detect bad data upstream and need to halt a send before it goes out, an internal tool might want a “kill switch” button, or another system in your stack might need to react to something and pause a dependent automation. SFMC doesn’t expose a simple REST endpoint for this: pausing an Automation actually goes through the older SOAP Schedule API, using the pause action against the Automation’s Object ID.

This post walks through a Cloud Page endpoint that does exactly that: authenticates and sends the SOAP pause request with a given objectId.

Example Script

<script runat="server">
Platform.Load("core", "1.1.5");

try {
    var objectId = "07d18e12-077d-359a-746d-bcb683b2d05c";

    if (!objectId) {
        Write(Stringify({ success: false, message: "Missing required field 'objectId' in request body." }));
    } else {

        // 2. Get credentials and an access token
        var authUrl = "https://YOUR_SUBDOMAIN.auth.marketingcloudapis.com/";
        var clientId = "your client id";
        var clientSecret = "your client secret";

        // The MID of the Business Unit where the automation actually lives.
        // SSJS has no built-in "et_mid" variable (that's an AMPscript personalization
        // string, unavailable inside <script runat="server">) — this needs to be set
        // explicitly, or pulled from your own config source.
        var targetMid = "0000000"; // TODO: replace with your target Business Unit's MID

        if (!authUrl || !clientId || !clientSecret ) {
            Write(Stringify({ success: false, message: "Credentials not found." }));
        } else {
            if (authUrl .charAt(authUrl .length - 1) != "/") {
                authUrl += "/";
            }

            var gettoken = HTTP.Post(authUrl + "v2/token", "application/json", Stringify({
                grant_type: "client_credentials",
                client_id: clientId,
                client_secret: clientSecret ,
                account_id: targetMid
            }));

            if (gettoken.StatusCode != 200) {
                Write(Stringify({ success: false, message: "Error fetching access token.", detail: gettoken.Response }));
            } else {
                var tokenresponseJSON = Platform.Function.ParseJSON(gettoken.Response[0]);

                if (!tokenresponseJSON || !tokenresponseJSON.access_token) {
                    Write(Stringify({ success: false, message: "Access token missing from token response.", detail: tokenresponseJSON }));
                } else {
                    var accessToken = tokenresponseJSON.access_token;
                    var soap_instance_url = tokenresponseJSON.soap_instance_url;

                    // 3. Issue the pause via the SOAP Schedule API
                    var soapEndpoint = soap_instance_url + "Service.asmx";
                    var soapPayload =
                        '<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' +
                        '<soap:Header><fueloauth>' + accessToken + '</fueloauth></soap:Header>' +
                        '<soap:Body>' +
                        '<ScheduleRequestMsg xmlns="http://exacttarget.com/wsdl/partnerAPI">' +
                        '<Action>pause</Action>' +
                        '<Schedule></Schedule>' +
                        '<Interactions><Interaction xsi:type="Automation"><ObjectID>' + objectId + '</ObjectID></Interaction></Interactions>' +
                        '</ScheduleRequestMsg>' +
                        '</soap:Body></soap:Envelope>';

                    var soapResp = HTTP.Post(soapEndpoint, "text/xml; charset=UTF-8", soapPayload, ["SOAPAction"], ["Schedule"]);

                    if (soapResp.StatusCode != 200) {
                        Write(Stringify({
                            success: false,
                            message: "Pause request failed.",
                            statusCode: soapResp.StatusCode,
                            detail: soapResp.Response
                        }));
                    } else {
                        Write(Stringify({
                            success: true,
                            message: "Pause request accepted for automation " + objectId + "."
                        }));
                    }
                }
            }
        }
    }
} catch (e) {
    Write(Stringify({ success: false, message: "Unexpected error.", error: Stringify(e) }));
}
</script>Code language: PHP (php)

A few things worth knowing if you build on this

  • If you need a hard confirmation that the automation reached Paused status (not just that the request was accepted), you’ll need a separate step — a scheduled Automation Studio script that re-checks status a minute or two later, or a webhook callback pattern — rather than trying to poll synchronously inside this request. SSJS doesn’t have a reliable sleep/delay function, and Cloud Pages have execution time limits that make busy-wait polling both unreliable and poor practice.
  • pause only works on a currently running automation. If the automation is idle, already paused, or has already completed its current run, the SOAP call may still return 200 while doing nothing meaningful — worth checking the automation’s actual state via the REST API separately if your calling system needs to distinguish “successfully paused” from “was already stopped.”
  • This endpoint has no authentication of its own. Since it accepts a POST body and triggers a real action against your SFMC account, make sure the Cloud Page itself is protected — an API key/shared secret check on the incoming request, IP allowlisting, or routing it through an authenticated internal system — so it can’t be triggered by anyone who finds the URL.

Summary

Pausing an automation externally is a small, high-leverage capability. It’s the kind of endpoint you build once and then rely on during an actual incident, which is exactly when you don’t want it silently failing or leaving you guessing whether the request went through. Making every failure path explicit is worth the extra lines of code the first time this genuinely needs to stop something in production.

Similar Posts