Calling webhook listener in postSubmit using exports.run

Hey everyone, I hope this is an easy question. I set up a real-time flow with a Celigo listener that posts errors to Slack. The real-time flow itself was tested using Postman to post data to the listener’s secret URL, it works great. Following this documentation, https://docs.celigo.com/hc/en-us/articles/26902372908827-Send-errors-to-an-integrator-io-listener-in-a-postSubmit-hook#send-errors-to-an-integrator-io-listener-in-a-postsubmit-hook-0, I added code to a postSubmit hook in a separate integration flow step:

import { exports } from 'integrator-api';

function postResponseMap (options) {
  let e = {
    integrationId: options._integrationId,
    flowId: options._flowId,
    exportId: options._exportId,
    channel: options.postResponseMapData[0].channel,
    source: options.postResponseMapData[0].source,
    errors: options.postResponseMapData[0].errors
  };
  try {
    console.log('postResponseMap: running export with data', JSON.stringify(e));
    let res = exports.run({
      _id: '6954................d15c',
      listenerData: e
    });
    console.log('postResponseMap: res', JSON.stringify(res));
  } catch (ex) {
    throw new Error(JSON.stringify(ex));
  }

  return options.postResponseMapData
}

Forgetting for a moment that I should be iterating over options.postResponseMapData (I’m just trying to get it to work), the listener is never executed. Both of the log statements are recorded so I know that it’s hitting the code, but the export is never run and the response is always null. I also attempted this with a test flow in the same integration as the listener flow thinking that maybe you can’t run an export that exists in a different integration (which would be baffling), but I still can’t get the flow with the listener to be executed. I’ve double-checked the ID of the listener export way too many times, I’ve reread the document to the point it’s almost memorized. I have no idea. Is there something in my code that I’m completely missing?

Thanks!

The listenerData function input is required to be an object array :slight_smile:
https://docs.celigo.com/hc/en-us/articles/20239758683035-integrator-io-API-and-JavaScript-runtime-objects#export-runtime-objects-1

Thanks @tylerlamparter ! It’s always the details :wink: Ok, so I update the code to this:

import { exports } from 'integrator-api';

function postResponseMap (options) {
  let e = [{
    integrationId: options._integrationId,
    flowId: options._flowId,
    exportId: options._exportId,
    channel: options.postResponseMapData[0].channel,
    source: options.postResponseMapData[0].source,
    errors: options.postResponseMapData[0].errors
  }];
  try {
    console.log('postResponseMap: running export with data', JSON.stringify(e));
    let res = exports.run({
      _id: '6954................d15c',
      listenerData: e
    });
    console.log('postResponseMap: res', JSON.stringify(res));
  } catch (ex) {
    throw new Error(JSON.stringify(ex));
  }

  return options.postResponseMapData
}

and I get {"message":"Error response from API."}, this is what’s trapped in the catch block. Again, no activity from the real-time flow and no more information other than this error. I really feel like I’m missing something basic here… as is evident by my inability to read API documentation :upside_down_face:

I don't really see anything wrong with that. I used the same script and just removed the references to channel, source, and errors and it's working for me. I've attached an integration that you can try and to see if this works for you?
69703217cd1641509c2978c1.zip (5.4 KB)

Thanks again, @tylerlamparter . That’s weird. I removed channel, source, and errors from my code and ran the flow again but still getting the error and no sign of activity from the listener. Thanks for the test flow, I’ll take a look and report back what I’ve figured out.

Hey @tylerlamparter, I figured it out. In my flow I was using a webhook listener and not a Celigo listener. Once I converted it over to a Celigo listener the flow picked up the data it was sent and pushed it over to Slack. And the reason the flow worked when initialized from a Postman call is because was configured with a secret URL. Have to say, though, that I’m not grooving on the Celigo listener being publicly available, but security by obscurity… so long as I don’t publish the export id anywhere. Right now it’s working and that’s good enough.

I’m a bit confused, however. I read in multiple spots that a webhook listener can’t be used in an exports.run call, but the document I referenced has a link to setting up and using a webhook listener. This confuses me; to confirm, directly invoking a webhook listener is not supported in an exports.run call, correct? Using a Celigo listener works great, though.

The Celigo listener is secured behind Celigo API tokens if you're calling it externally, but when it's called internally, we use internal authentication for that Celigo listener. So publishing your export ID isn't a concern because no one would be able to post to it unless they also have your API token.

Calling exports.run to run a Celigo listener is supported, but calling exports.run for a generic webhook is not supported.

Great, thanks again, @tylerlamparter

Hi @tylerlamparter, sorry to keep bugging you about this. Is it possible to call a real-time listener from a different integration via exports.run? To test, I took your sample integration and broke out Flow 1 (the sender) into a separate integration. Making sure that the real-time listener export id was correct I ran the “sender” flow but I get an ‘access_restricted’ error. If I open the script and preview the code I get an ‘API call is not allowed(_integrationId)’ error. Is it possible to execute a flow via api from a separate integration? Basically, what I’m trying to achieve is to have an error handling integration flow that my other integrations can send data to post to Slack without having to create a separate instance in each integration.

From hooks, that's not possible because hooks are scoped to the integration they’re running in at runtime. You could have one flow in each integration that is a “gatherer” flow, where it has one export listener and one import to send data to an export living in another integration. When using an import step on the flow, you have a Celigo connection with an API token, which we then use to determine access, whereas a hook’s access is predetermined by where it is.

Ok, I’ll have to go that approach then. Thanks for all your help with this, @tylerlamparter , truly appreciate it!