Skip to main content

I’m a bit new to this and working with an API that requires a separate username/password login process in order to establish a session ID as a keytoken for use in authentication with all other API calls. Each session only lasts 60 minutes after the last API call.

 

I know I could use a scheduled trigger to automate the login process first, but my preference would be to only run the zap when a new record is found in the data I would like to poll.

 

Is this a common issue or something that is easily handled within the trigger fields that I’m not seeing?  Thanks!

 

 

What app API are you using?

Does the app offer Webhooks? (This would trigger the Zap each time there is a new record, rather than having to poll the app API.)

 

Here’s a help article about Webhooks Retrieve Poll: https://zapier.com/help/doc/how-get-started-webhooks-zapier#using-the-retrieve-poll-trigger-option


Hey @Troy Tessalone - I was attempting to use the Zapier Webhooks app to Retrieve Poll from a URL I don’t have the option to get the data sent to a Zapier webhook for use with “Catch hook” triggers.

 

Thanks for the article link - found the limitation here:

This trigger is one that only supports basic authentication - should you need to create your own polling triggers for APIs that offer advanced forms of authentication, you should create your own private application on the Zapier platform.

 

I guess it makes sense to dive into that and see what I can do. Thanks so much!


SO I got pretty far into the “session authentication” portion of building my own private app except for the returning of the session token.

 

Here is the code that Zapier provides:

return z.request(options)
.then((response) => {
response.throwForStatus();
const results = response.json;

// You can do any parsing you need for results here before returning them

return {
'sessionKey': results.sessionKey
};
});

Here’s the response from the logs - you’ll see that the login is successful and the ‘SessionID’ is provided in the output but I have no clue how to parse the sessionID and get it into the ‘SessionKey’ using the default code above.

 

{"Columns":-{"Name":"Success","Type":"Int16"},{"Name":"SessionID","Type":"String"},{"Name":"Permission","Type":"String"},{"Name":"Canadian","Type":"Int16"},{"Name":"Internal","Type":"Int16"},{"Name":"International","Type":"Int16"},{"Name":"Account","Type":"String"},{"Name":"Store","Type":"String"},{"Name":"Email","Type":"String"},{"Name":"FirstName","Type":"String"},{"Name":"LastName","Type":"String"},{"Name":"Email","Type":"String"}],"Rows":"S1,"57EE00E41FA808B56E567B28BFD38EA515C3E0AF47E2D687AD611366CF7703B2","30",0,0,0,":censored:6:fbf1d817b6:","","myemail@sample.com","Jack","Ryan","myemail@sample.com"]]}

 


@dstepchew - You can extract the session ID using the following code snippet:

return z.request(options).then((response) => {
response.throwForStatus();
const results = response.json;

const sessionIdIndex = results.Columns.findIndex(
(column) => column.Name === "SessionID"
);
const sessionId = results.Rowss0]]sessionIdIndex];

return {
sessionKey: sessionId,
};
});

 


@ikbelkirasan - That worked great! Got the authentication piece set up and successfully tested.

Now onto the trigger - On step 1 “Configure API Request” I have the necessary headers, params, and body - also figured out how to parse the response content from another article:

const options = {
url: bundle.inputData.url,
method: 'POST',
headers: {
'Content-Type': 'text/plain'
},
params: {
'content-type': 'text'
},
body:

{"Columns":n{"Name":"SessionID","Type":"String"},
{"Name":"Account","Type":"String"},
{"Name":"OrderStatus","Type":"String"}],
"Rows":wsbundle.authData.SessionID,bundle.authData.Account,bundle.inputData.OrderStatus]]
}

}

return z.request(options)
.then((response) => {
response.throwForStatus();
const results = z.JSON.parse(response.content);

// You can do any parsing you need for results here before returning them

return results.Rows;
});

Then I go to the next step - Test your API request, and I’m getting a response that the SessionID is missing.

Oddly, looking at the ‘HTTP’ logs, I see a successful authentication step and another step showing a successful response with the array I’m looking for. Why would I be getting this missing session ID error if I’m seeing a valid response in the logs? 

 


@dstepchew That’s because bundle.authData.SessionID doesn’t exist. The session ID is actually stored in bundle.authData.sessionKey.

 


@ikbelkirasan OK that worked. Now I’m up against the “Got a result missing the ‘id’ property” error. Looking at this response I noticed that the user was able to establish the id for result using the values provided in each result, but my issue is that the column definitions are sent in a separate array. I tried to repurpose the same method used in the login help provided above but to no avail - getting error ‘cannot ready property of ‘number’ of undefined.’

 

Here is a sample of the results:

{
"Columns": r
{
"Name": "SalesOrder",
"Type": "Int64"
},
{
"Name": "SalesOrderPrefix",
"Type": "String"
},
{
"Name": "CustPurchaseOrder",
"Type": "String"
},
{
"Name": "Store",
"Type": "String"
},
{
"Name": "UnitsOrder",
"Type": "Int32"
},
{
"Name": "UnitsShip",
"Type": "Int32"
},
{
"Name": "UnitsCancel",
"Type": "Int32"
},
{
"Name": "UnitsPacked",
"Type": "Int32"
},
{
"Name": "UnitsOpen",
"Type": "Int32"
},
{
"Name": "ShipComplete",
"Type": "String"
},
{
"Name": "CancelBackOrder",
"Type": "String"
},
{
"Name": "Total",
"Type": "Decimal"
},
{
"Name": "Terms",
"Type": "String"
},
{
"Name": "OrderDate",
"Type": "String"
},
{
"Name": "CancelDate",
"Type": "String"
},
{
"Name": "Status",
"Type": "String"
},
{
"Name": "TrackingCode",
"Type": "String"
},
{
"Name": "ShipVia",
"Type": "String"
},
{
"Name": "TrackingLink",
"Type": "String"
},
{
"Name": "IntTrackingLink",
"Type": "String"
},
{
"Name": "PktCtrlNbr",
"Type": "String"
},
{
"Name": "MinShipDate",
"Type": "String"
},
{
"Name": "Address1",
"Type": "String"
},
{
"Name": "Address2",
"Type": "String"
},
{
"Name": "City",
"Type": "String"
},
{
"Name": "State",
"Type": "String"
},
{
"Name": "Zip",
"Type": "String"
},
{
"Name": "Country",
"Type": "String"
},
{
"Name": "FeeType",
"Type": "String"
},
{
"Name": "FeeTotal",
"Type": "Decimal"
},
{
"Name": "OrderLevelNote",
"Type": "String"
},
{
"Name": "Page",
"Type": "String"
}
],
"Rows": ,
s
17924398,
"SO",
"SO1153678",
"",
1,
0,
0,
1,
0,
"0",
"0",
237.73,
"N30",
"12/14/2020",
"12/14/2021",
"In Packing",
"",
"UP10",
"",
"",
"",
"12/14/2020",
"Test Test",
"1Test parkway",
"New York",
"NY",
"11111",
"US",
"DROP2",
2.50,
"",
"1-1"
]
]
}

 

Here is my code right now:

const options = {
url: bundle.inputData.url,
method: 'POST',
headers: {
'Content-Type': 'text/plain'
},
params: {
'content-type': 'text'
},
body:

{"Columns":>{"Name":"SessionID","Type":"String"},
{"Name":"Account","Type":"String"},
{"Name":"OrderStatus","Type":"String"}],
"Rows":inbundle.authData.sessionKey,bundle.authData.Account,bundle.inputData.OrderStatus]]
}

}

return z.request(options)
.then((response) => {
response.throwForStatus();
//const results = response.json;
const results = z.JSON.parse(response.content);

const SalesOrderIndex = results.Columns.findIndex(
(column) => column.Name === "SalesOrder"
);
number = results.Rowsu0]eSalesOrderIndex];
// const number = results.Rowsu0];
const Rows = results.Rows.map((obj) => {
const p = obj.Row;
p.id = p.number;
return p;
});

// You can do any parsing you need for results here before returning them

return Rows;
});

I’m so close! So appreciative of your support here.


@dstepchew - You’re welcome! Ok, in that case, you would do it like so:

const options = {
url: bundle.inputData.url,
method: "POST",
headers: {
"Content-Type": "text/plain",
},
params: {
"content-type": "text",
},
body: {
Columns: n
{ Name: "SessionID", Type: "String" },
{ Name: "Account", Type: "String" },
{ Name: "OrderStatus", Type: "String" },
],
Rows: w

bundle.authData.sessionKey,
bundle.authData.Account,
bundle.inputData.OrderStatus,
],
],
},
};

return z.request(options).then((response) => {
response.throwForStatus();
const results = z.JSON.parse(response.content);

// Convert to an object
const item = results.Columns.reduce((prev, current, index) => {
prevpcurrent.Name] = results.RowsR0]sindex];
return prev;
}, {});
item.id = item.SalesOrder;

return uitem];
});

 


@ikbelkirasan - Result was exactly what I needed. Setting this up now as a new Zap. Initial test looks great. Thanks so much.


@dstepchew - That’s great news!

One last thing, can you update the best answer selection because it seems that you chose the wrong one :)