1

While this appears to be a straightforward, descriptive error message, I think there may be more to it...

The context: I am attempting to fire an entry event for a journey using the interaction/v1/events REST endpoint and am receiving a 401  Unauthorized response, which the documentation indicates is due to "Empty or Incorrect Authorization Token" even though the access token is supplied.

The full error message is as follows:

"An error occurred when attempting to evaluate a HTTPPost2 function call. See inner exception for details."
"ExactTarget.OMM.FunctionExecutionException: An error occurred when attempting to evaluate a HTTPPost2 function call. See inner exception for details.\r\n Error Code: OMM_FUNC_EXEC_ERROR\r\n - from Jint --> \r\n\r\n --- inner exception 1---\r\n\r\nSystem.Net.WebException: The remote server returned an error: (401) Unauthorized. - from System\r\n\r\n\r\n\r\n"

I have checked:

  • the auth call returns a token
  • the installed package has the permissions required by the documentation (list_and_subscribers_read),  to execute the second method

I've included the code below - having stripped out anything superfluous. Note I'm using a combination of AMPScript and SSJS  because elsewhere I'll be using methods only available in AMPScript, but AMPSCript doesn't have a built in method for parsing JSON or handling errors - my understanding is this is relatively common practice.

The code:

<script runat="server">
Platform.Load("Core","1.1.1");
try{
</script>
%%[
  set @url = "https://XXXXXXXXXXXX.auth.marketingcloudapis.com/v2/token"
  set @content = "application/json"
  set @payload = '{
    "grant_type":"client_credentials",
    "client_id":"XXXXXXXXXXXX",
    "client_secret":"XXXXXXXXXXXXX",
    "scope": "list_and_subscribers_read",
    "account_id": "1111111111"
    }';
  var @response1
  set @HTTP1 = HTTPPost2(@url, @content, @payload, true, @response1)
]%%
<script runat="server">
  Platform.Load("Core", "1.1.1");
  var str = Variable.GetValue("@response1");
  var obj = Platform.Function.ParseJSON(str);
  Variable.SetValue("@access_token",obj.access_token);
  Variable.SetValue("@token_type",obj.token_type);
  Variable.SetValue("@expires_in",obj.expires_in);
  Variable.SetValue("@scope",obj.scope);
  Variable.SetValue("@rest_instance_url",obj.rest_instance_url);
</script>
%%[
  var @response2
  set @content = "application/json"
  set @headerNames = "Authorization"
  set @headerValues = "Bearer " + @access_token
  set @url = "https://XXXXXXXXXXXX.rest.marketingcloudapis.com/interaction/v1/events"
  set @payload = '{
    "Contactkey":"XXXXXXXXXX",
    "EventDefinitionKey":"APIEvent-XXXXXXXXXXXXX",
    "Data": {
      "MobileNumber":"8888888888",
      "VerifyCode":"888888",
      "Locale":"en-nz"
    }
  }';
  /*THE NEXT LINE RETURNS THE ERROR*/
  set @HTTP2 = HTTPPost2(@url, @content, @payload, true, @response2)
]%%
<script runat="server">
}catch(e){
  Write(Stringify(e.message)+"
");
  Write(Stringify(e.description)+"
");
}
</script>

<!-- THEN, IN THE HTML BODY -->
Access Token: %%=V(@access_token)=%%<br/>
Token Type: %%=V(@token_type)=%%<br/>
Expires in: %%=V(@expires_in)=%%<br/>
Scope: %%=V(@scope)=%%<br/>
Instance URL: %%=V(@rest_instance_url)=%%<br/>

The output of the Auth response are all as expected:

Please advise whether there are any obvious errors in my approach - or should this be a support case? Any other observations warmly welcomed!

3
  • Did you try your REST API calls in Postman first? If not, you should, because Postman will generate much of the necessary JS code for you. Apr 19, 2022 at 12:53
  • Why are you specifying the scope in your auth call? Apr 19, 2022 at 12:57
  • Thanks Adam. No I didn't try in Postman. I also tried without explicitly setting the scope here, instead relying on scope specified in the installed package. Neither worked. I figured I'd leave it in so nobody would need to ask whether the scope was correctly set - which I think it is per the docs linked above. Apr 19, 2022 at 23:21

2 Answers 2

1

I'd definitely stick with SSJS for all of the REST API part -- you don't need to bounce around between them to troubleshoot it. I use a debug flag to conditional output the debugging statements.

<script runat="server" language="JavaScript">

  Platform.Load("Core","1");

  var debug = true;

  var url = 'https://xxxx.auth.marketingcloudapis.com/v2/token';
  var contentType = 'application/json';
  var mid = 111111;
  var payload = '{"grant_type":"client_credentials","client_id":"xxxx","client_secret":"xxxx","account_id":"'+mid+'"}';

  try {
  
    var result = HTTP.Post(url, contentType, payload);

    if (debug) {
      Write("<br>result (token): " + Stringify(result))
    }

    var statusCode = result["StatusCode"];
    var accessToken = Platform.Function.ParseJSON(result["Response"][0]).access_token;

  } catch (e) {

    if (debug) {
      Write("<br>e: " + Stringify(e))
    }
    
  }

  var url = "https://xxxx.rest.marketingcloudapis.com/interaction/v1/events";
  var contentType = 'application/json';
  var headerNames = ["Authorization"];
  var headerValues = ["Bearer " + accessToken];
  var payload = '{"Contactkey":"XXXXXXXXXX","EventDefinitionKey":"APIEvent-XXXXXXXXXXXXX","Data": {"MobileNumber":"8888888888","VerifyCode":"888888","Locale":"en-nz"}}';

  try {

    var result = HTTP.Post(url, contentType, payload, headerNames, headerValues);

    if (debug) {
      Write("<br>result (journey): " + Stringify(result))
    }

    // parse results and set AMPscript vars here

  } catch (e) {

    if (debug) {
      Write("<br>e: " + Stringify(e))
    }

  }

</script>

1
  • Thanks Adam, I've followed your advice and rewritten in SSJS. I don't have any issue with the auth call or passing the access token into a subsequent call e.g. /contacts/v1/addresses/email/search. For the method I want to use (interaction/v1/events) I am now receiving (403) Forbidden instead - so that's progress! I think that relates to incorrect values in my payload. Anyway, thanks for your help! Apr 19, 2022 at 23:55
0

You shouldn't combine 2 languages in your code then it can make you confused (except some special use cases), in my opinion the whole process can be done by SSJS.

I've taken a look at it and the issue is at your AMPscript @headerValues
It supposes to be this

set @headerValues = Concat("Bearer ", @access_token)
3
  • Thanks, but that returns the same result. I also rewrote the AMPScript bits in SSJS... same result. I don't disagree about the confusion of 2 languages, but there are some things AMPScript can do better than SSJS e.g. creating Salesforce objects. Apr 19, 2022 at 11:58
  • How could it return the same result? The set @headerValues = "Bearer " + @access_token is not valid. Apr 19, 2022 at 12:56
  • I rewrote in SSJS so that line is now... var headerValues = ["Bearer " + accessToken]; ...and that works fine for other API methods, but my interaction/v1/events call is still returning the same "401 Unauthorized" message. Apr 19, 2022 at 23:23

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .