{ "kind": "open-flow-workflow", "version": 1, "name": "Monitor Competitor Pricing Changes", "content": { "modelVersion": 14, "document": { "bindings": {}, "graph": { "nodes": { "n_a12caf93ded7100a": { "name": "Run manually", "kind": "start", "inputDefs": [] }, "n_03c55dde06973cfb": { "inputs": { "spreadsheetId": { "kind": "value", "value": "YOUR_SPREADSHEET_ID" }, "range": { "kind": "value", "value": "'Sheet1'!A:ZZZ" }, "majorDimension": { "kind": "value", "value": "ROWS" } }, "name": "Read pricing pages", "kind": "task", "task": { "inputs": [ { "description": "The spreadsheet ID.", "jsonSchema": { "type": "string", "minLength": 1, "description": "The spreadsheet ID." }, "nullable": true, "handle": "spreadsheetId", "value": null }, { "description": "The A1 notation of the range to retrieve.", "jsonSchema": { "type": "string", "minLength": 1, "description": "The A1 notation of the range to retrieve." }, "nullable": false, "handle": "range" }, { "description": "The major dimension for the returned values.", "jsonSchema": { "type": "string", "enum": [ "DIMENSION_UNSPECIFIED", "ROWS", "COLUMNS" ], "description": "The major dimension for the returned values." }, "nullable": true, "handle": "majorDimension", "value": null }, { "description": "How values should be rendered in the output.", "jsonSchema": { "type": "string", "enum": [ "FORMATTED_VALUE", "UNFORMATTED_VALUE", "FORMULA" ], "description": "How values should be rendered in the output." }, "nullable": true, "handle": "valueRenderOption", "value": null }, { "description": "How dates and times should be rendered in the output.", "jsonSchema": { "type": "string", "enum": [ "SERIAL_NUMBER", "FORMATTED_STRING" ], "description": "How dates and times should be rendered in the output." }, "nullable": true, "handle": "dateTimeRenderOption", "value": null } ], "outputs": [ { "description": "The A1 notation of the range.", "jsonSchema": { "type": "string", "description": "The A1 notation of the range." }, "nullable": false, "handle": "range" }, { "description": "The major dimension of the values (ROWS or COLUMNS).", "jsonSchema": { "type": "string", "description": "The major dimension of the values (ROWS or COLUMNS)." }, "nullable": false, "handle": "majorDimension" }, { "description": "The data values in the range.", "jsonSchema": { "type": "array", "items": { "type": "array", "items": { "anyOf": [ { "type": "string", "description": "A union variant." }, { "type": "number", "description": "A union variant." }, { "type": "boolean", "description": "A union variant." }, { "const": null, "description": "A union variant." } ], "description": "The cell value schema." }, "description": "An array item." }, "description": "The data values in the range." }, "nullable": false, "handle": "values" } ], "name": "Read pricing pages", "executor": { "kind": "connector", "action": "googlesheets.values_get" } } }, "n_9967f56716c3a221": { "inputs": { "values": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_03c55dde06973cfb", "output": "values" } ] }, "sheet": { "kind": "value", "value": "Sheet1" } }, "name": "Identify pricing rows", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "array", "items": { "type": "array", "items": { "anyOf": [ { "type": "string", "description": "A union variant." }, { "type": "number", "description": "A union variant." }, { "type": "boolean", "description": "A union variant." }, { "const": null, "description": "A union variant." } ], "description": "The cell value schema." }, "description": "An array item." }, "description": "The data values in the range." }, "nullable": false, "handle": "values" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "sheet" } ], "outputs": [ { "jsonSchema": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "nullable": false, "handle": "rows" } ], "name": "Identify pricing rows", "moduleId": "n_67ef8329c1a12926", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_968fb406bdff860d": { "inputs": { "rows": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_9967f56716c3a221", "output": "rows" } ] }, "previous": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_968fb406bdff860d", "output": "state" } ] } }, "name": "Select the next page", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "nullable": false, "handle": "rows" }, { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": true, "handle": "previous" } ], "outputs": [ { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "state" }, { "jsonSchema": { "type": "boolean" }, "nullable": false, "handle": "more" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "person" }, { "jsonSchema": { "type": "string", "minLength": 1 }, "nullable": false, "handle": "range" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "url" } ], "name": "Select the next page", "moduleId": "n_2c79b14be09d3b13", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_b60beffd7ff26b6b": { "inputs": {}, "name": "More pricing pages?", "kind": "condition", "matchMode": "first", "cases": [ { "output": "yes", "groups": [ { "expressions": [ { "left": { "kind": "source", "source": { "kind": "node", "nodeId": "n_968fb406bdff860d", "output": "more" } }, "operator": "isTrue" } ] } ] } ] }, "n_951e76807d899672": { "inputs": { "url": { "kind": "value", "value": "https://api.airtop.ai/api/v1/sessions" }, "body": { "kind": "value", "value": {} }, "auth.token": { "kind": "unset" } }, "name": "Create an Airtop session", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "url" }, { "jsonSchema": {}, "nullable": true, "handle": "body" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "auth.token" } ], "outputs": [ { "jsonSchema": {}, "nullable": true, "handle": "body" }, { "jsonSchema": { "type": "integer" }, "nullable": false, "handle": "statusCode" }, { "jsonSchema": { "type": "object", "additionalProperties": { "type": "string" } }, "nullable": false, "handle": "headers" } ], "name": "Create an Airtop session", "executor": { "method": "POST", "query": { "mode": "fields", "names": [] }, "headers": { "mode": "fields", "names": [] }, "bodyFormat": "json", "authentication": { "type": "bearer" }, "responseFormat": "json", "statusPolicy": "success", "kind": "http-request" } } }, "n_4d2ed30a1677e1da": { "inputs": { "body": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_951e76807d899672", "output": "body" } ] } }, "name": "Check the session", "kind": "task", "task": { "inputs": [ { "jsonSchema": {}, "nullable": true, "handle": "body" } ], "outputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "windowUrl" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "terminateUrl" }, { "jsonSchema": { "type": "boolean" }, "nullable": false, "handle": "ready" } ], "name": "Check the session", "moduleId": "n_e47cb75dd1ab2b6b", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_72fdc943a8f73fab": { "inputs": {}, "name": "Session ready?", "kind": "condition", "matchMode": "first", "cases": [ { "output": "yes", "groups": [ { "expressions": [ { "left": { "kind": "source", "source": { "kind": "node", "nodeId": "n_4d2ed30a1677e1da", "output": "ready" } }, "operator": "isTrue" } ] } ] } ] }, "n_fb89f9af54873928": { "inputs": {}, "name": "Wait for the browser", "kind": "wait", "inputDefinitions": [], "prompt": "Wait for the browser", "autoContinue": { "kind": "after", "durationMs": 5000 } }, "n_eb7746e2036b5178": { "inputs": { "url": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_4d2ed30a1677e1da", "output": "terminateUrl" } ] }, "auth.token": { "kind": "unset" } }, "name": "Check browser readiness", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "url" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "auth.token" } ], "outputs": [ { "jsonSchema": {}, "nullable": true, "handle": "body" }, { "jsonSchema": { "type": "integer" }, "nullable": false, "handle": "statusCode" }, { "jsonSchema": { "type": "object", "additionalProperties": { "type": "string" } }, "nullable": false, "handle": "headers" } ], "name": "Check browser readiness", "executor": { "method": "GET", "query": { "mode": "fields", "names": [] }, "headers": { "mode": "fields", "names": [] }, "bodyFormat": "none", "authentication": { "type": "bearer" }, "responseFormat": "json", "statusPolicy": "success", "kind": "http-request" } } }, "n_f7b8daab380c57be": { "inputs": { "body": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_eb7746e2036b5178", "output": "body" } ] }, "previous": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_f7b8daab380c57be", "output": "state" } ] }, "sessionUrl": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_4d2ed30a1677e1da", "output": "terminateUrl" } ] } }, "name": "Evaluate browser readiness", "kind": "task", "task": { "inputs": [ { "jsonSchema": {}, "nullable": true, "handle": "body" }, { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": true, "handle": "previous" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "sessionUrl" } ], "outputs": [ { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "state" }, { "jsonSchema": { "type": "boolean" }, "nullable": false, "handle": "ready" } ], "name": "Evaluate browser readiness", "moduleId": "n_bf9055edecae4f17", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_d8ca2f0e4ca3ac15": { "inputs": {}, "name": "Browser ready?", "kind": "condition", "matchMode": "first", "cases": [ { "output": "yes", "groups": [ { "expressions": [ { "left": { "kind": "source", "source": { "kind": "node", "nodeId": "n_f7b8daab380c57be", "output": "ready" } }, "operator": "isTrue" } ] } ] } ] }, "n_90c6a5875c4768ef": { "inputs": { "url": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_968fb406bdff860d", "output": "url" } ] } }, "name": "Prepare the pricing URL", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "url" } ], "outputs": [ { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "body" } ], "name": "Prepare the pricing URL", "moduleId": "n_b3977d5d1b87829a", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_92ca173214c7a782": { "inputs": { "url": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_4d2ed30a1677e1da", "output": "windowUrl" } ] }, "body": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_90c6a5875c4768ef", "output": "body" } ] }, "auth.token": { "kind": "unset" } }, "name": "Open the pricing page", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "url" }, { "jsonSchema": {}, "nullable": true, "handle": "body" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "auth.token" } ], "outputs": [ { "jsonSchema": {}, "nullable": true, "handle": "body" }, { "jsonSchema": { "type": "integer" }, "nullable": false, "handle": "statusCode" }, { "jsonSchema": { "type": "object", "additionalProperties": { "type": "string" } }, "nullable": false, "handle": "headers" } ], "name": "Open the pricing page", "executor": { "method": "POST", "query": { "mode": "fields", "names": [] }, "headers": { "mode": "fields", "names": [] }, "bodyFormat": "json", "authentication": { "type": "bearer" }, "responseFormat": "json", "statusPolicy": "success", "kind": "http-request" } } }, "n_97eebf2acb264756": { "inputs": { "body": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_92ca173214c7a782", "output": "body" } ] }, "terminateUrl": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_4d2ed30a1677e1da", "output": "terminateUrl" } ] }, "person": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_968fb406bdff860d", "output": "person" } ] } }, "name": "Prepare the pricing comparison", "kind": "task", "task": { "inputs": [ { "jsonSchema": {}, "nullable": true, "handle": "body" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "terminateUrl" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "person" } ], "outputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "url" }, { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "query" } ], "name": "Prepare the pricing comparison", "moduleId": "n_1e7bdec10c264854", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_9a0aa9fe6ecaf7c0": { "inputs": { "url": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_97eebf2acb264756", "output": "url" } ] }, "body": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_97eebf2acb264756", "output": "query" } ] }, "auth.token": { "kind": "unset" } }, "name": "Compare the pricing", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "url" }, { "jsonSchema": {}, "nullable": true, "handle": "body" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "auth.token" } ], "outputs": [ { "jsonSchema": {}, "nullable": true, "handle": "body" }, { "jsonSchema": { "type": "integer" }, "nullable": false, "handle": "statusCode" }, { "jsonSchema": { "type": "object", "additionalProperties": { "type": "string" } }, "nullable": false, "handle": "headers" } ], "name": "Compare the pricing", "executor": { "method": "POST", "query": { "mode": "fields", "names": [] }, "headers": { "mode": "fields", "names": [] }, "bodyFormat": "json", "authentication": { "type": "bearer" }, "responseFormat": "json", "statusPolicy": "success", "kind": "http-request" } } }, "n_9dbb22b8e9fc213d": { "inputs": { "body": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_9a0aa9fe6ecaf7c0", "output": "body" } ] }, "range": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_968fb406bdff860d", "output": "range" } ] } }, "name": "Check the comparison", "kind": "task", "task": { "inputs": [ { "jsonSchema": {}, "nullable": true, "handle": "body" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "range" } ], "outputs": [ { "jsonSchema": { "type": "boolean" }, "nullable": false, "handle": "changed" }, { "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "range": { "type": "string", "minLength": 1, "description": "The A1 notation of the range to write to." }, "values": { "type": "array", "items": { "type": "array", "items": { "anyOf": [ { "type": "string", "description": "A union variant." }, { "type": "number", "description": "A union variant." }, { "type": "boolean", "description": "A union variant." }, { "const": null, "description": "A union variant." } ], "description": "The cell value schema." }, "description": "An array item." }, "description": "The data to write into the range." }, "majorDimension": { "type": "string", "enum": [ "ROWS", "COLUMNS" ], "description": "The major dimension of the values array." } }, "required": [ "range", "values" ], "additionalProperties": false, "description": "A batch values update item." }, "minItems": 1, "description": "The list of value ranges to update." }, "nullable": false, "handle": "data" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "message" } ], "name": "Check the comparison", "moduleId": "n_c15cea1b279ead07", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_1030b5c9b7e7bd7f": { "inputs": { "url": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_4d2ed30a1677e1da", "output": "terminateUrl" } ] }, "auth.token": { "kind": "unset" } }, "name": "Close the Airtop session", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "url" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "auth.token" } ], "outputs": [ { "jsonSchema": { "type": "string" }, "nullable": true, "handle": "body" }, { "jsonSchema": { "type": "integer" }, "nullable": false, "handle": "statusCode" }, { "jsonSchema": { "type": "object", "additionalProperties": { "type": "string" } }, "nullable": false, "handle": "headers" } ], "name": "Close the Airtop session", "executor": { "method": "DELETE", "query": { "mode": "fields", "names": [] }, "headers": { "mode": "fields", "names": [] }, "bodyFormat": "none", "authentication": { "type": "bearer" }, "responseFormat": "text", "statusPolicy": "success", "kind": "http-request" } } }, "n_c589b1db5b4ca6bf": { "inputs": { "spreadsheetId": { "kind": "value", "value": "YOUR_SPREADSHEET_ID" }, "data": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_9dbb22b8e9fc213d", "output": "data" } ] }, "valueInputOption": { "kind": "value", "value": "RAW" } }, "name": "Update pricing and time", "kind": "task", "task": { "inputs": [ { "description": "The spreadsheet ID.", "jsonSchema": { "type": "string", "minLength": 1, "description": "The spreadsheet ID." }, "nullable": true, "handle": "spreadsheetId", "value": null }, { "description": "The list of value ranges to update.", "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "range": { "type": "string", "minLength": 1, "description": "The A1 notation of the range to write to." }, "values": { "type": "array", "items": { "type": "array", "items": { "anyOf": [ { "type": "string", "description": "A union variant." }, { "type": "number", "description": "A union variant." }, { "type": "boolean", "description": "A union variant." }, { "const": null, "description": "A union variant." } ], "description": "The cell value schema." }, "description": "An array item." }, "description": "The data to write into the range." }, "majorDimension": { "type": "string", "enum": [ "ROWS", "COLUMNS" ], "description": "The major dimension of the values array." } }, "required": [ "range", "values" ], "additionalProperties": false, "description": "A batch values update item." }, "minItems": 1, "description": "The list of value ranges to update." }, "nullable": false, "handle": "data" }, { "description": "How the input data should be interpreted.", "jsonSchema": { "type": "string", "enum": [ "INPUT_VALUE_OPTION_UNSPECIFIED", "RAW", "USER_ENTERED" ], "description": "How the input data should be interpreted." }, "nullable": true, "handle": "valueInputOption", "value": null }, { "description": "Whether to include the written values in the response.", "jsonSchema": { "type": "boolean", "description": "Whether to include the written values in the response." }, "nullable": true, "handle": "includeValuesInResponse", "value": null }, { "description": "How values in the response should be rendered.", "jsonSchema": { "type": "string", "enum": [ "FORMATTED_VALUE", "UNFORMATTED_VALUE", "FORMULA" ], "description": "How values in the response should be rendered." }, "nullable": true, "handle": "responseValueRenderOption", "value": null }, { "description": "How dates in the response should be rendered.", "jsonSchema": { "type": "string", "enum": [ "SERIAL_NUMBER", "FORMATTED_STRING" ], "description": "How dates in the response should be rendered." }, "nullable": true, "handle": "responseDateTimeRenderOption", "value": null } ], "outputs": [ { "description": "The unique ID of the spreadsheet.", "jsonSchema": { "type": "string", "description": "The unique ID of the spreadsheet." }, "nullable": false, "handle": "spreadsheetId" }, { "description": "The total number of rows updated across all ranges.", "jsonSchema": { "type": "integer", "description": "The total number of rows updated across all ranges." }, "nullable": false, "handle": "totalUpdatedRows" }, { "description": "The total number of columns updated across all ranges.", "jsonSchema": { "type": "integer", "description": "The total number of columns updated across all ranges." }, "nullable": false, "handle": "totalUpdatedColumns" }, { "description": "The total number of cells updated across all ranges.", "jsonSchema": { "type": "integer", "description": "The total number of cells updated across all ranges." }, "nullable": false, "handle": "totalUpdatedCells" }, { "description": "The per-range update responses.", "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "updatedRange": { "type": "string", "description": "The A1 notation of the range that was updated." }, "updatedRows": { "type": "integer", "description": "The number of rows that were updated." }, "updatedColumns": { "type": "integer", "description": "The number of columns that were updated." }, "updatedCells": { "type": "integer", "description": "The number of cells that were updated." }, "updatedData": { "type": "object", "properties": { "range": { "type": "string", "description": "The A1 notation of the range." }, "majorDimension": { "type": "string", "description": "The major dimension of the values (ROWS or COLUMNS)." }, "values": { "type": "array", "items": { "type": "array", "items": { "anyOf": [ { "type": "string", "description": "A union variant." }, { "type": "number", "description": "A union variant." }, { "type": "boolean", "description": "A union variant." }, { "const": null, "description": "A union variant." } ], "description": "The cell value schema." }, "description": "An array item." }, "description": "The data values in the range." } }, "required": [ "range", "majorDimension", "values" ], "additionalProperties": false, "description": "The values of the cells after the update." } }, "required": [ "updatedRange", "updatedRows", "updatedColumns", "updatedCells" ], "additionalProperties": false, "description": "The batch update item schema." }, "description": "The per-range update responses." }, "nullable": false, "handle": "responses" } ], "name": "Update pricing and time", "executor": { "kind": "connector", "action": "googlesheets.update_values_batch" } } }, "n_9a20d8ca705cd86d": { "inputs": {}, "name": "Pricing changed?", "kind": "condition", "matchMode": "first", "cases": [ { "output": "yes", "groups": [ { "expressions": [ { "left": { "kind": "source", "source": { "kind": "node", "nodeId": "n_9dbb22b8e9fc213d", "output": "changed" } }, "operator": "isTrue" } ] } ] } ] }, "n_af20886394147d1e": { "inputs": { "channelId": { "kind": "value", "value": "YOUR_SLACK_CHANNEL_ID" }, "text": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_9dbb22b8e9fc213d", "output": "message" } ] } }, "name": "Notify pricing change", "kind": "task", "task": { "inputs": [ { "description": "The Slack conversation or channel ID.", "jsonSchema": { "type": "string", "minLength": 1, "description": "The Slack conversation or channel ID." }, "nullable": false, "handle": "channelId" }, { "description": "Plain text message content. When blocks are provided, Slack uses this as notification and accessibility fallback text.", "jsonSchema": { "type": "string", "description": "Plain text message content. When blocks are provided, Slack uses this as notification and accessibility fallback text." }, "nullable": true, "handle": "text", "value": null }, { "description": "Slack Block Kit blocks to render in the message.", "jsonSchema": { "type": "array", "items": { "type": "object", "properties": {}, "additionalProperties": true, "description": "A Slack Block Kit block object. Pass the block exactly as Slack documents it." }, "minItems": 1, "description": "Slack Block Kit blocks to render in the message." }, "nullable": true, "handle": "blocks", "value": null }, { "description": "Slack legacy attachments to include in the message.", "jsonSchema": { "type": "array", "items": { "type": "object", "properties": {}, "additionalProperties": true, "description": "A Slack legacy attachment object. Prefer blocks for new messages when possible." }, "minItems": 1, "description": "Slack legacy attachments to include in the message." }, "nullable": true, "handle": "attachments", "value": null }, { "description": "Whether Slack should unfurl links in the message.", "jsonSchema": { "type": "boolean", "description": "Whether Slack should unfurl links in the message." }, "nullable": true, "handle": "unfurlLinks", "value": null }, { "description": "Whether Slack should unfurl media in the message.", "jsonSchema": { "type": "boolean", "description": "Whether Slack should unfurl media in the message." }, "nullable": true, "handle": "unfurlMedia", "value": null }, { "description": "Slack message metadata to attach to the message.", "jsonSchema": { "type": "object", "properties": {}, "additionalProperties": true, "description": "Slack message metadata to attach to the message." }, "nullable": true, "handle": "metadata", "value": null } ], "outputs": [ { "description": "The timestamp identifier of the posted message.", "jsonSchema": { "type": "string", "description": "The timestamp identifier of the posted message." }, "nullable": false, "handle": "ts" }, { "description": "The channel ID where the message was posted.", "jsonSchema": { "type": "string", "description": "The channel ID where the message was posted." }, "nullable": false, "handle": "channelId" } ], "name": "Notify pricing change", "executor": { "kind": "connector", "action": "slack.post_message" } } } }, "edges": [ { "source": "n_a12caf93ded7100a", "target": "n_03c55dde06973cfb" }, { "source": "n_03c55dde06973cfb", "target": "n_9967f56716c3a221" }, { "source": "n_9967f56716c3a221", "target": "n_968fb406bdff860d" }, { "source": "n_968fb406bdff860d", "target": "n_b60beffd7ff26b6b" }, { "source": "n_b60beffd7ff26b6b", "target": "n_951e76807d899672", "sourceHandle": "yes" }, { "source": "n_951e76807d899672", "target": "n_4d2ed30a1677e1da" }, { "source": "n_4d2ed30a1677e1da", "target": "n_72fdc943a8f73fab" }, { "source": "n_72fdc943a8f73fab", "target": "n_90c6a5875c4768ef", "sourceHandle": "yes" }, { "source": "n_72fdc943a8f73fab", "target": "n_fb89f9af54873928", "sourceHandle": "otherwise" }, { "source": "n_fb89f9af54873928", "target": "n_eb7746e2036b5178", "sourceHandle": "continue" }, { "source": "n_eb7746e2036b5178", "target": "n_f7b8daab380c57be" }, { "source": "n_f7b8daab380c57be", "target": "n_d8ca2f0e4ca3ac15" }, { "source": "n_d8ca2f0e4ca3ac15", "target": "n_90c6a5875c4768ef", "sourceHandle": "yes" }, { "source": "n_d8ca2f0e4ca3ac15", "target": "n_fb89f9af54873928", "sourceHandle": "otherwise" }, { "source": "n_90c6a5875c4768ef", "target": "n_92ca173214c7a782" }, { "source": "n_92ca173214c7a782", "target": "n_97eebf2acb264756" }, { "source": "n_97eebf2acb264756", "target": "n_9a0aa9fe6ecaf7c0" }, { "source": "n_9a0aa9fe6ecaf7c0", "target": "n_9dbb22b8e9fc213d" }, { "source": "n_9dbb22b8e9fc213d", "target": "n_1030b5c9b7e7bd7f" }, { "source": "n_1030b5c9b7e7bd7f", "target": "n_9a20d8ca705cd86d" }, { "source": "n_c589b1db5b4ca6bf", "target": "n_af20886394147d1e" }, { "source": "n_af20886394147d1e", "target": "n_968fb406bdff860d" }, { "source": "n_9a20d8ca705cd86d", "target": "n_c589b1db5b4ca6bf", "sourceHandle": "yes" }, { "source": "n_9a20d8ca705cd86d", "target": "n_968fb406bdff860d", "sourceHandle": "otherwise" } ] } }, "modules": { "n_67ef8329c1a12926": { "name": "Identify pricing rows", "imports": [], "source": "export default function plan({values,sheet}){if(!Array.isArray(values)||!values.length)return{rows:[]};const h=values[0],names=['Pricing URL','Pricing','Time'],idx=names.map(x=>h.indexOf(x));if(idx.some((n,i)=>n<0||h.lastIndexOf(names[i])!==n))throw Error('Sheet requires unique Pricing URL, Pricing and Time headers');function col(n){let s='';for(n++;n;n=Math.floor((n-1)/26))s=String.fromCharCode(65+(n-1)%26)+s;return s}const tab=\"'\"+sheet.replaceAll(\"'\",\"''\")+\"'\";return{rows:values.slice(1).map((r,i)=>({url:String(r[idx[0]]??'').trim(),previous:String(r[idx[1]]??''),priceRange:`${tab}!${col(idx[1])}${i+2}`,timeRange:`${tab}!${col(idx[2])}${i+2}`})).filter(x=>x.url)}}\n" }, "n_2c79b14be09d3b13": { "name": "Select the next page", "imports": [], "source": "export default function next({rows,previous}){const index=(previous?.index??-1)+1;if(index>=rows.length)return{state:{index},more:false,person:'',range:'{}',url:'https://example.com/'};const r=rows[index];let u;try{u=new URL(r.url)}catch{throw Error('Invalid pricing URL')}if(!['http:','https:'].includes(u.protocol))throw Error('Expected HTTP pricing URL');return{state:{index},more:true,person:r.previous,range:JSON.stringify({price:r.priceRange,time:r.timeRange,url:r.url}),url:r.url}}\n" }, "n_e47cb75dd1ab2b6b": { "name": "Check the session", "imports": [], "source": "export default function session({body}){const x=body?.data;if(!x||typeof x.id!=='string'||!/^[-a-z0-9]+$/i.test(x.id)||body.errors?.length)throw Error('Invalid Airtop session');const base='https://api.airtop.ai/api/v1/sessions/'+encodeURIComponent(x.id);if(!['initializing','running','active'].includes(x.status))throw Error('Invalid Airtop session state');return {windowUrl:base+'/windows',terminateUrl:base,ready:x.status==='running'||x.status==='active'};}\n" }, "n_bf9055edecae4f17": { "name": "Evaluate browser readiness", "imports": [], "source": "export default function poll({body,previous,sessionUrl}){const count=(previous?.sessionUrl===sessionUrl?previous.count:0)+1;if(body?.errors?.length||!['initializing','running','active'].includes(body?.data?.status))throw Error('Invalid Airtop session status');if(count>=60&&body.data.status==='initializing')throw Error('Airtop session did not become ready');return{state:{count,sessionUrl},ready:body.data.status!=='initializing'};}\n" }, "n_b3977d5d1b87829a": { "name": "Prepare the pricing URL", "imports": [], "source": "export default function run({url}) { return {body:{url}}; }" }, "n_1e7bdec10c264854": { "name": "Prepare the pricing comparison", "imports": [], "source": "export default function query({body,terminateUrl,person}){const id=body?.data?.windowId;if(typeof id!=='string'||!/^[-a-z0-9]+$/i.test(id)||body.errors?.length)throw Error('Invalid Airtop window');const schema={type:'object',properties:{pricing_summary:{type:'string'},differences_summary:{type:'string'},status:{type:'string'}},required:['pricing_summary','differences_summary','status'],additionalProperties:false};return{url:terminateUrl+'/windows/'+encodeURIComponent(id)+'/page-query',query:{prompt:`This is a pricing page. Summarize every plan with price and top 3 features. Compare prices to the previous summary below. Return pricing_summary, differences_summary and status: [DIFF] for significant price differences, [SIMILAR] for similar prices, [NEW] when no previous summary. Do not guess. Previous summary: ${person}`,configuration:{outputSchema:JSON.stringify(schema)}}}}\n" }, "n_c15cea1b279ead07": { "name": "Check the comparison", "imports": [], "source": "export default function result({body,range}){if(body?.errors?.length||typeof body?.data?.modelResponse!=='string')throw Error('Invalid Airtop response');let x,r;try{x=JSON.parse(body.data.modelResponse);r=JSON.parse(range)}catch{throw Error('Invalid pricing response')}if(typeof x.pricing_summary!=='string'||typeof x.differences_summary!=='string'||typeof x.status!=='string'||!r.price||!r.time||!r.url)throw Error('Incomplete pricing response');return{changed:!x.status.includes('SIMILAR'),data:[{range:r.price,values:[[x.pricing_summary]]},{range:r.time,values:[[new Date().toISOString()]]}],message:r.url+' - '+x.differences_summary}}\n" } } }, "presentation": { "designer": { "version": 1, "flow": { "direction": "vertical" } } } }