Esri Webhooks for ArcGIS Online - Payload schema for tracking changes in a Hosted Feature Service?

5488
20
10-15-2020 07:24 AM
Henry_PeleshBW
Occasional Contributor

Hello all,

I am working to create a Webhook for a Hosted Feature Service in ArcGIS Online that will use Microsoft Power Automate to send emails when a HTTP request is received. I want to receive emails when a feature service is edited, but I am having trouble with my payload schema for the HTTP request (receiving a "BadRequest" error). I am wondering if anyone has done this and can share what their JSON payload schema consisted of.

Thanks,

Henry

0 Kudos
20 Replies
PhilLarkin1
Occasional Contributor III

Instead of using the payload option, just copy/paste directly into the Request Body JSON Schema window. 

An Example:

PhilLarkin1_0-1614107444308.png

 

0 Kudos
Danielle_Journey
Occasional Contributor

@PhilLarkin1  That's what I did.  Still nothing when I test it:

Danielle_Journey_1-1614108934383.png

 

0 Kudos
PhilLarkin1
Occasional Contributor III

You might want to edit your Change Types to call out the subscriptions directly. I'd also double check that the HookUrl is the same on AGOL as in your flow. 

PhilLarkin1_1-1614116209855.png

 

 

0 Kudos
Danielle_Journey
Occasional Contributor

I made the update to the Change Types and re-copy/pasted the Hook Url.  Still no test results after making a change to the feature service.  I am so stumped on what I am doing wrong!

Danielle_Journey_0-1614118379626.png

 

0 Kudos
by Anonymous User
Not applicable

I wanted to add to the great information already provided here.

To avoid Bad Requests, try removing any actions that sends alerts or messages or otherwise connects to Microsoft Office or teams, mail etc.

Due to a bug (wrong content-type) I have found that these actions can cause Bad Requests when getting requests from a live Feature service WebHook trigger. This can be deceiving as it  usually works well in test mode (when using a previous successful test request). 

If you have a need to have alerts as par of your workflows, maybe a workaround would be to have another flow handling only the alert/message piece.

I was able to create a working Flow package (with no alerts) that completes the following workflow:

-   handles request with Payload

-   gets token

-   query URL returning final JSON with feature changes.

The actions json are below. Just export/change/import into new Flow and change credentials within. 

Hopefully it will help those interested handling feature service changes with Power Automate.

{         "actions": {
            "Parse_JSON": {
               "runAfter": {
                  "Initialize_variable_-_STATUS": [
                     "Succeeded"
                  ]
               },
               "type": "ParseJson",
               "inputs": {
                  "content": "@triggerBody()?['$formdata']",
                  "schema": {
                     "type": "array",
                     "items": {
                        "type": "object",
                        "properties": {
                           "key": {
                              "type": "string"
                           },
                           "value": {
                              "type": "string"
                           }
                        },
                        "required": [
                           "key",
                           "value"
                        ]
                     }
                  }
               }
            },
            "Apply_to_each": {
               "foreach": "@body('Parse_JSON')",
               "actions": {
                  "Parse_JSON_2": {
                     "runAfter": {},
                     "type": "ParseJson",
                     "inputs": {
                        "content": "@items('Apply_to_each')['value']",
                        "schema": {
                           "type": "array",
                           "items": {
                              "type": "object",
                              "properties": {
                                 "name": {
                                    "type": "string"
                                 },
                                 "layerId": {
                                    "type": "integer"
                                 },
                                 "orgId": {
                                    "type": "string"
                                 },
                                 "serviceName": {
                                    "type": "string"
                                 },
                                 "lastUpdatedTime": {
                                    "type": "integer"
                                 },
                                 "changesUrl": {
                                    "type": "string"
                                 },
                                 "events": {
                                    "type": "array",
                                    "items": {
                                       "type": "string"
                                    }
                                 }
                              },
                              "required": [
                                 "name",
                                 "layerId",
                                 "orgId",
                                 "serviceName",
                                 "lastUpdatedTime",
                                 "changesUrl",
                                 "events"
                              ]
                           }
                        }
                     }
                  },
                  "HTTP": {
                     "runAfter": {
                        "Parse_JSON_2": [
                           "Succeeded"
                        ]
                     },
                     "type": "Http",
                     "inputs": {
                        "method": "POST",
                        "uri": "https://www.arcgis.com/sharing/rest/generateToken",
                        "headers": {
                           "Content-Type": "application/x-www-form-urlencoded"
                        },
                        "body": "username=@{variables('Username')}&password=@{variables('Password')}&f=json&referer=http://arcgis.com"
                     }
                  },
                  "Parse_JSON_3": {
                     "runAfter": {
                        "HTTP": [
                           "Succeeded"
                        ]
                     },
                     "type": "ParseJson",
                     "inputs": {
                        "content": "@body('HTTP')",
                        "schema": {
                           "properties": {
                              "expires": {
                                 "type": "integer"
                              },
                              "ssl": {
                                 "type": "boolean"
                              },
                              "token": {
                                 "type": "string"
                              }
                           },
                           "type": "object"
                        }
                     }
                  },
                  "Apply_to_each_2": {
                     "foreach": "@body('Parse_JSON_2')",
                     "actions": {
                        "HTTP_2": {
                           "runAfter": {},
                           "type": "Http",
                           "inputs": {
                              "method": "POST",
                              "uri": "@{items('Apply_to_each_2')['changesUrl']}&token=@{body('Parse_JSON_3')?['token']}&f=json",
                              "headers": {
                                 "Content-Type": "application/x-www-form-urlencoded"
                              }
                           }
                        },
                        "Parse_JSON_4": {
                           "runAfter": {
                              "HTTP_2": [
                                 "Succeeded"
                              ]
                           },
                           "type": "ParseJson",
                           "inputs": {
                              "content": "@body('HTTP_2')",
                              "schema": {
                                 "type": "object",
                                 "properties": {
                                    "statusUrl": {
                                       "type": "string"
                                    }
                                 }
                              }
                           }
                        },
                        "Do_until": {
                           "actions": {
                              "HTTP_3": {
                                 "runAfter": {},
                                 "type": "Http",
                                 "inputs": {
                                    "method": "POST",
                                    "uri": "@{body('Parse_JSON_4')?['statusUrl']}?token=@{body('Parse_JSON_3')?['token']}&f=json",
                                    "headers": {
                                       "Content-Type": "application/x-www-form-urlencoded"
                                    }
                                 }
                              },
                              "Parse_JSON_5": {
                                 "runAfter": {
                                    "HTTP_3": [
                                       "Succeeded"
                                    ]
                                 },
                                 "type": "ParseJson",
                                 "inputs": {
                                    "content": "@body('HTTP_3')",
                                    "schema": {
                                       "type": "object",
                                       "properties": {
                                          "submissionTime": {
                                             "type": "integer"
                                          },
                                          "lastUpdatedTime": {
                                             "type": "integer"
                                          },
                                          "status": {
                                             "type": "string"
                                          },
                                          "responseType": {
                                             "type": "string"
                                          },
                                          "resultUrl": {
                                             "type": "string"
                                          }
                                       }
                                    }
                                 }
                              },
                              "Set_variable": {
                                 "runAfter": {
                                    "Parse_JSON_5": [
                                       "Succeeded"
                                    ]
                                 },
                                 "type": "SetVariable",
                                 "inputs": {
                                    "name": "Status",
                                    "value": "@body('Parse_JSON_5')?['status']"
                                 }
                              },
                              "Condition": {
                                 "actions": {
                                    "HTTP_4": {
                                       "runAfter": {},
                                       "type": "Http",
                                       "inputs": {
                                          "method": "POST",
                                          "uri": "@{body('Parse_JSON_5')?['resultUrl']}?token=@{body('Parse_JSON_3')?['token']}&f=json",
                                          "headers": {
                                             "Content-Type": "application/x-www-form-urlencoded"
                                          }
                                       }
                                    },
                                    "Parse_JSON_6": {
                                       "runAfter": {
                                          "HTTP_4": [
                                             "Succeeded",
                                             "Failed"
                                          ]
                                       },
                                       "type": "ParseJson",
                                       "inputs": {
                                          "content": "@outputs('HTTP_4')['headers']",
                                          "schema": {
                                             "type": "object",
                                             "properties": {
                                                "location": {
                                                   "type": "string"
                                                }
                                             }
                                          }
                                       }
                                    },
                                    "HTTP_5": {
                                       "runAfter": {
                                          "Parse_JSON_6": [
                                             "Succeeded"
                                          ]
                                       },
                                       "type": "Http",
                                       "inputs": {
                                          "method": "GET",
                                          "uri": "@body('Parse_JSON_6')?['location']"
                                       }
                                    },
                                    "Compose": {
                                       "runAfter": {
                                          "HTTP_5": [
                                             "Succeeded"
                                          ]
                                       },
                                       "type": "Compose",
                                       "inputs": "@base64ToString(body('HTTP_5')?['$content'])"
                                    },
                                    "Parse_JSON_7": {
                                       "runAfter": {
                                          "Compose": [
                                             "Succeeded"
                                          ]
                                       },
                                       "type": "ParseJson",
                                       "inputs": {
                                          "content": "@outputs('Compose')",
                                          "schema": {
                                             "type": "object",
                                             "properties": {
                                                "layerServerGens": {
                                                   "type": "array",
                                                   "items": {
                                                      "type": "object",
                                                      "properties": {
                                                         "id": {
                                                            "type": "integer"
                                                         },
                                                         "serverGen": {
                                                            "type": "integer"
                                                         }
                                                      },
                                                      "required": [
                                                         "id",
                                                         "serverGen"
                                                      ]
                                                   }
                                                },
                                                "transportType": {
                                                   "type": "string"
                                                },
                                                "responseType": {
                                                   "type": "string"
                                                },
                                                "edits": {
                                                   "type": "array",
                                                   "items": {
                                                      "type": "object",
                                                      "properties": {
                                                         "id": {
                                                            "type": "integer"
                                                         },
                                                         "features": {
                                                            "type": "object",
                                                            "properties": {
                                                               "adds": {
                                                                  "type": "array",
                                                                  "items": {
                                                                     "type": "object",
                                                                     "properties": {
                                                                        "geometry": {
                                                                           "type": "object",
                                                                           "properties": {
                                                                              "x": {
                                                                                 "type": "number"
                                                                              },
                                                                              "y": {
                                                                                 "type": "number"
                                                                              }
                                                                           }
                                                                        },
                                                                        "attributes": {
                                                                           "type": "object",
                                                                           "properties": {
                                                                              "OBJECTID": {
                                                                                 "type": "integer"
                                                                              },
                                                                              "GlobalID": {
                                                                                 "type": "string"
                                                                              },
                                                                              "REQUESTID": {},
                                                                              "PROBLEM": {},
                                                                              "COMMENTS": {},
                                                                              "NAME": {},
                                                                              "PHONE": {},
                                                                              "EMAIL": {},
                                                                              "REQUESTDATE": {},
                                                                              "STATUS": {},
                                                                              "FACILITYKEY": {},
                                                                              "CreationDate": {
                                                                                 "type": "integer"
                                                                              },
                                                                              "Creator": {
                                                                                 "type": "string"
                                                                              },
                                                                              "EditDate": {
                                                                                 "type": "integer"
                                                                              },
                                                                              "Editor": {
                                                                                 "type": "string"
                                                                              }
                                                                           }
                                                                        }
                                                                     },
                                                                     "required": [
                                                                        "geometry",
                                                                        "attributes"
                                                                     ]
                                                                  }
                                                               },
                                                               "updates": {
                                                                  "type": "array"
                                                               },
                                                               "deleteIds": {
                                                                  "type": "array"
                                                               }
                                                            }
                                                         },
                                                         "attachments": {
                                                            "type": "object",
                                                            "properties": {
                                                               "adds": {
                                                                  "type": "array"
                                                               },
                                                               "updates": {
                                                                  "type": "array"
                                                               },
                                                               "deleteIds": {
                                                                  "type": "array"
                                                               }
                                                            }
                                                         }
                                                      },
                                                      "required": [
                                                         "id",
                                                         "features",
                                                         "attachments"
                                                      ]
                                                   }
                                                }
                                             }
                                          }
                                       }
                                    },
                                    "Set_variable_2": {
                                       "runAfter": {
                                          "Parse_JSON_7": [
                                             "Succeeded"
                                          ]
                                       },
                                       "type": "SetVariable",
                                       "inputs": {
                                          "name": "Status",
                                          "value": "\"Completed\""
                                       }
                                    }
                                 },
                                 "runAfter": {
                                    "Set_variable": [
                                       "Succeeded"
                                    ]
                                 },
                                 "expression": {
                                    "not": {
                                       "equals": [
                                          "@body('Parse_JSON_5')?['resultUrl']",
                                          ""
                                       ]
                                    }
                                 },
                                 "type": "If"
                              }
                           },
                           "runAfter": {
                              "Parse_JSON_4": [
                                 "Succeeded"
                              ]
                           },
                           "expression": "@equals(variables('Status'), '\"Completed\"')",
                           "limit": {
                              "count": 60,
                              "timeout": "PT1H"
                           },
                           "type": "Until"
                        }
                     },
                     "runAfter": {
                        "Parse_JSON_3": [
                           "Succeeded"
                        ]
                     },
                     "type": "Foreach"
                  }
               },
               "runAfter": {
                  "Parse_JSON": [
                     "Succeeded"
                  ]
               },
               "type": "Foreach"
            },
            "Initialize_variable_-_STATUS": {
               "runAfter": {
                  "Password": [
                     "Succeeded"
                  ]
               },
               "type": "InitializeVariable",
               "inputs": {
                  "variables": [
                     {
                        "name": "Status",
                        "type": "string",
                        "value": "Pending"
                     }
                  ]
               }
            },
            "Password": {
               "runAfter": {
                  "Username": [
                     "Succeeded"
                  ]
               },
               "type": "InitializeVariable",
               "inputs": {
                  "variables": [
                     {
                        "name": "Password",
                        "type": "string",
                        "value": "Password_Goes_Here!"
                     }
                  ]
               }
            },
            "Username": {
               "runAfter": {},
               "type": "InitializeVariable",
               "inputs": {
                  "variables": [
                     {
                        "name": "Username",
                        "type": "string",
                        "value": "Username_Goes_Here!"
                     }
                  ]
               }
            }
         }
}
Henry_PeleshBW
Occasional Contributor

Juliano Kersting

Thank you very much for this information and the detailed response. This was very helpful and I appreciate you taking the time to provide this information. 

I am hoping you can expand a bit on how to "have another flow handling only the alert/message piece"? Sending alerts as a part of our flow is ultimately the goal for our WebHook work flow. I am wondering how a separate flow that handles the alerts will be able to communicate with the other flow that handles the HTTP request and parsing the json? 

Thank you again,

-Henry

0 Kudos
hgaignard
Esri Contributor

For the past few days, I have encountered an error on the first module When a HTTP request is received : BadRequest.

2021-03-01_10-57-11.png

This issue seems to come from the JSON schema of the request body predefined during my configuration. @Anonymous User, would Esri have recently modified the request sent by the webhook (e.g Content-Type header)?

I solved this issue by removing the JSON schema of the request body (leave blank) in my first module.

2021-03-01_10-39-46.png

by Anonymous User
Not applicable

Hi @hgaignard I was not able to repro this with JSON schema in the HTTP module:

{
  "type": "object",
  "properties": {
    "$content-type": {
      "type": "string"
    },
    "$content": {
      "type": "string"
    },
    "$formdata": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string"
          },
          "value": {
            "type": "string"
          }
        },
        "required": [
          "key",
          "value"
        ]
      }
    }
  }
}

 

I tried a couple of different change types with no issues. Are you still seeing the issue? 

Thanks,

-Peter 

0 Kudos
PhilLarkin1
Occasional Contributor III

I just reproduced the error with the schema you provided. 

The issue stems from flows which also include connectors like Teams, Outlook, etc. 

hgaignard
Esri Contributor

@PhilLarkin1, I confirm, if I delete my last Outlook module, I no longer have the "BadRequest" error for the first HTTP module with a predefined JSON schema.

To keep the Outlook module, I need to remove the JSON schema from the first HTTP module.

But it worked before...

0 Kudos