2

We are trying to post data from SFMC data extension to some other cloud using custom activity(REST) in journey builder. We have tried the same steps as mentioned on https://developer.salesforce.com/docs/atlas.en-us.mc-app-development.meta/mc-app-development/creating-activities.htm and hosted web app on Heroku. We are getting an error on journey activation which has this custom activity.

"A custom activity or entry source failed validation. Check to ensure that the activity or entry source publishes to a valid endpoint. "

config.json contains firebase endpoints which are publicly accessible as mentioned in execute, save, publish, validate and stop.

 {
    "workflowApiVersion": "1.1",
    "metaData": {
        "icon": "images/icon.png"
    },
    "type": "REST",
    "lang": {
        "en-US": {
            "name": "Custom Activity (Workflow API v1.1)",
            "description": "A custom Journey Builder activity using workflow API v1.1 format."
        }
    },
    "arguments": {
        "execute": {
            "inArguments": [
                {
                    "name": "Test Name"
                },
                {
                    "myInArgument": "inArgument coming from iframe"
                }
            ],
            "outArguments": [
                {
                    "name": ""
                }],
            "verb": "POST", 
            "url": "https://<firebase_project_id>.firebaseio.com/User.json"
        }
    },
    "configurationArguments": {
        "save": {
            "url": "https://<firebase_project_id>.firebaseio.com/User.json",
            "verb": "POST",
            "body": "save"
        },
        "publish": {
            "url": "https://<firebase_project_id>.firebaseio.com/User.json",
            "verb": "POST",
            "body": "publish"
        },
        "validate": {
            "url": "https://<firebase_project_id>.firebaseio.com/User.json",
            "verb": "POST",
            "body": "validate"
        },
        "stop": {
            "url": "https://<firebase_project_id>.firebaseio.com/User.json",
            "verb": "POST",
            "body": "save"
        }
    },
    "wizardSteps": [{
        "label": "Step 1",
        "key": "step1"
    },
    {
        "label": "Step 2",
        "key": "step2"
    },
    {
        "label": "Step 3",
        "key": "step3"
    },
    {
        "label": "Step 4",
        "key": "step4"
    }
    ],
    "userInterfaces": {
        "configModal": {
            "height": 200,
            "width": 300,
            "fullscreen": true
        }
    },
    "schema": {
        "arguments": {
            "execute": {
                "inArguments": [
                    {
                    "myInArgument": {
                        "dataType": "Text",
                        "isNullable": false,
                        "direction": "in"
                    }
                }, 
                {
                    "name": {
                        "dataType": "Text",
                        "isNullable": false,
                        "direction": "in"
                    }
                }
            ],
                "outArguments": [
                    {
                        "name": {
                            "dataType": "Text",
                            "direction": "out",
                            "access": "visible"
                        }
                    }
                ]
            }
        }
    }
}

customActivity.js

define([
    'postmonger'
], function (
    Postmonger
) {
        'use strict';

        var connection = new Postmonger.Session();
        var payload = {};
        var lastStepEnabled = false;
        var steps = [ // initialize to the same value as what's set in config.json for consistency
            { "label": "Step 1", "key": "step1" },
            { "label": "Step 2", "key": "step2" },
            { "label": "Step 3", "key": "step3" },
            { "label": "Step 4", "key": "step4", "active": false }
        ];
        var currentStep = steps[0].key;

        $(window).ready(onRender);

        connection.on('initActivity', initialize);
        connection.on('requestedTokens', onGetTokens);
        connection.on('requestedEndpoints', onGetEndpoints);

        connection.on('clickedNext', onClickedNext);
        connection.on('clickedBack', onClickedBack);
        connection.on('gotoStep', onGotoStep);

        function onRender() {
            // JB will respond the first time 'ready' is called with 'initActivity'
            connection.trigger('ready');

            connection.trigger('requestTokens');
            connection.trigger('requestEndpoints');

            // Disable the next button if a value isn't selected
            $('#select1').change(function () {
                var message = getMessage();
                connection.trigger('updateButton', { button: 'next', enabled: Boolean(message) });

                $('#message').html(message);
            });

            // Toggle step 4 active/inactive
            // If inactive, wizard hides it and skips over it during navigation
            $('#toggleLastStep').click(function () {
                lastStepEnabled = !lastStepEnabled; // toggle status
                steps[3].active = !steps[3].active; // toggle active

                connection.trigger('updateSteps', steps);
            })
        }

        function initialize(data) {
            if (data) {
                payload = data;
            }

            var message;
            var hasInArguments = Boolean(
                payload['arguments'] &&
                payload['arguments'].execute &&
                payload['arguments'].execute.inArguments &&
                payload['arguments'].execute.inArguments.length > 0
            );

            var inArguments = hasInArguments ? payload['arguments'].execute.inArguments : {};

            $.each(inArguments, function (index, inArgument) {
                $.each(inArgument, function (key, val) {
                    if (key === 'message') {
                        message = val;
                    }
                });
            });

            // If there is no message selected, disable the next button
            if (!message) {
                showStep(null, 1);
                connection.trigger('updateButton', { button: 'next', enabled: false });
                // If there is a message, skip to the summary step
            } else {
                $('#select1').find('option[value=' + message + ']').attr('selected', 'selected');
                $('#message').html(message);
                showStep(null, 3);
            }
        }

        function onGetTokens(tokens) {
            // Response: tokens = { token: <legacy token>, fuel2token: <fuel api token> }
            // console.log(tokens);
        }

        function onGetEndpoints(endpoints) {
            // Response: endpoints = { restHost: <url> } i.e. "rest.s1.qa1.exacttarget.com"
            // console.log(endpoints);
        }

        function onClickedNext() {
            if (
                (currentStep.key === 'step3' && steps[3].active === false) ||
                currentStep.key === 'step4'
            ) {
                save();
            } else {
                connection.trigger('nextStep');
            }
        }

        function onClickedBack() {
            connection.trigger('prevStep');
        }

        function onGotoStep(step) {
            showStep(step);
            connection.trigger('ready');
        }

        function showStep(step, stepIndex) {
            if (stepIndex && !step) {
                step = steps[stepIndex - 1];
            }

            currentStep = step;

            $('.step').hide();

            switch (currentStep.key) {
                case 'step1':
                    $('#step1').show();
                    connection.trigger('updateButton', {
                        button: 'next',
                        enabled: Boolean(getMessage())
                    });
                    connection.trigger('updateButton', {
                        button: 'back',
                        visible: false
                    });
                    break;
                case 'step2':
                    $('#step2').show();
                    connection.trigger('updateButton', {
                        button: 'back',
                        visible: true
                    });
                    connection.trigger('updateButton', {
                        button: 'next',
                        text: 'next',
                        visible: true
                    });
                    break;
                case 'step3':
                    $('#step3').show();
                    connection.trigger('updateButton', {
                        button: 'back',
                        visible: true
                    });
                    if (lastStepEnabled) {
                        connection.trigger('updateButton', {
                            button: 'next',
                            text: 'next',
                            visible: true
                        });
                    } else {
                        connection.trigger('updateButton', {
                            button: 'next',
                            text: 'done',
                            visible: true
                        });
                    }
                    break;
                case 'step4':
                    $('#step4').show();
                    break;
            }
        }

        function save() {
            var name = $('#select1').find('option:selected').html();
            var value = getMessage();

            // 'payload' is initialized on 'initActivity' above.
            // Journey Builder sends an initial payload with defaults
            // set by this activity's config.json file.  Any property
            // may be overridden as desired.
            payload.name = name;

            payload['arguments'].execute.inArguments = [{ "message": value }];

            payload['metaData'].isConfigured = true;

            connection.trigger('updateActivity', payload);
        }

        function getMessage() {
            return $('#select1').find('option:selected').attr('value').trim();
        }

    });

error screenshot

enter image description here

5

Your endpoints for execute as well as save, publish, validate, and stop do not appear to be valid endpoints in your example.

The endpoint you have specified in for all of these in your example is:

https://<firebase_project_id>.firebaseio.com/User.json

This endpoint should be a url to a REST API endpoint that accepts a POST request, NOT an endpoint to a static json file as it appears in your example. Your application will need to accept POST requests from execute, save, publish, validate, and stop requests coming from Marketing Cloud and return a 200 to Marketing Cloud indicating success.

3

You need to make sure, that your /validate-route returns status code 200 and the following json response body:

{"success": true}

Another problem could be, that you need to specify the Application Extension Key, which with the new "Installed Packages" screen in Setup should now be the "Package Id" in configurationArguments. applicationExtensionKey and key in your config.json.

Setup > Installed Package > Package Id

An example config.json (although for a REST-decision activity) can be found here: example config.json for REST activity.

An excerpt of the example config.json:

{
    "key": "<YOUR APPLICATION EXTENSION KEY HERE>",
    "metaData": {
        "icon": "images/icon.png",
        "iconSmall": "images/icon_small.png"
    },
    "type": "RESTDECISION",
    "lang": {
        "en-US": {
            "name": "custom activity",
            "description": "custom activity description"
        }
    },
    "workflowApiVersion": "1.1",
    "configurationArguments": {
        "applicationExtensionKey": "<YOUR APPLICATION EXTENSION KEY HERE>",

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.