{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "38ca63e6",
   "metadata": {},
   "source": [
    "# Creating Calculation Transforms\n",
    "\n",
    "This notebook provides a step-by-step guide to set up, test, and deploy Calculation models using Falkonry APIs. Follow each section to create a workspace, define calculation, evaluate them, set up assessments, and monitor live outputs.\n",
    "\n",
    "### 9 Steps to go live with your custom Calculations\n",
    "1. Set Up Falkonry API Access\n",
    "2. Create Workspace\n",
    "3. Test the calculation function with sample data before creating the transform\n",
    "4. Convert the calculate function in to string\n",
    "5. Create a calculated model\n",
    "6. Run CALCEVAL for Testing\n",
    "7. Create Assessment\n",
    "8. Get Assessment Info and Extract Output Signals\n",
    "9. Run CALCEVAL for Live Assessment Output\n",
    "10. Stop monitoring an assessment\n",
    "11. Restart monitoring an assessment"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2f8ccf4d",
   "metadata": {},
   "source": [
    "COPYRIGHT (c) 2026 FALKONRY, INC. ALL RIGHTS RESERVED.\n",
    "\n",
    "FOR FALKONRY's CUSTOMER USE ONLY.\n",
    "\n",
    "THIS SAMPLE CODE FROM FALKONRY IS PROVIDED \"AS IS\" AND WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL FALKONRY INC. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) SUSTAINED BY YOU OR A THIRD PARTY, HOWEVER CAUSED AND UNDER ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ARISING IN ANY WAY OUT OF THE USE OF OR INABILITY TO USE THIS SAMPLE CODE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "29b89e3a",
   "metadata": {},
   "source": [
    "## 1. Set Up Falkonry API Access\n",
    "\n",
    "Configure authentication and base URL for Falkonry API requests. Set your API key, account_id, and other required variables."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a6a8c728",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Set up Falkonry API access\n",
    "import requests\n",
    "from asyncio import sleep\n",
    "\n",
    "# Set your API key and account ID here\n",
    "BASE_SERVER = \"\" # app3.falkonry.ai\n",
    "API_TOKEN = \"\" #<YOUR_API_TOKEN>\n",
    "ACCOUNT_ID = \"\" #<YOUR_ACCOUNT_ID>\n",
    "BASE_URL = f\"https://{BASE_SERVER}/api/1.3\"\n",
    "\n",
    "HEADERS = {\n",
    "    \"Authorization\": f\"Bearer {API_TOKEN}\",\n",
    "    \"Content-Type\": \"application/json\"\n",
    "}\n",
    "\n",
    "# Set your workspace, anomaly model and assessment parameters here\n",
    "WORKSPACE_ID = \"\" # e.g., \"1356886815950516129\"\n",
    "WORKSPACE_NAME = \"\" # e.g., \"Machine 2 Model Development\"\n",
    "TREE_NAME = \"\" # e.g., Assets\n",
    "NODE_NAME = \"\" # e.g., 1356886129815950516\n",
    "\n",
    "# Naming convention: <calculated_signal_name>/calculated\n",
    "MODEL_NAME = f\"\" # e.g., M1_Temp_Torque_Ratio/calculated\n",
    "\n",
    "MODEL_NAME_SUFFIX = \"01\" # e.g., \"01\"\n",
    "LEARN_TIME_RANGE = [\n",
    "    {\n",
    "        \"startTime\": \"\", # e.g., \"2024-07-22T00:00:00.00Z\",\n",
    "        \"endTime\": \"\" # e.g., \"2024-10-10T23:59:59.00Z\"\n",
    "    }\n",
    "]\n",
    "MODEL_PARAMETERS_STATISTIC = \"\" # e.g., \"mean\", \"min\", \"max\"\n",
    "MODEL_PARAMETERS_VALUETYPE = \"\" # e.g., Numeric, Categorical\n",
    "MODEL_PARAMETERS_EVALWINDOW= \"\" # e.g., \"PT1M\"\n",
    "\n",
    "EVAL_TIME_RANGE = {\n",
    "        \"startTime\": \"\", # e.g., \"2024-07-22T23:01:09.000Z\", \n",
    "        \"endTime\": \"\" # e.g., \"2024-08-01T23:01:09.000Z\"\n",
    "    }\n",
    "\n",
    "INPUT_SIGNALS = [\n",
    "      { \"signal\": \"\", \"name\": \"\" }, # e.g., { \"signal\": \"189245342354643574\", \"name\": \"temperature\" },\n",
    "      { \"signal\": \"\", \"name\": \"\" }  # e.g., { \"signal\": \"189876234785236753\", \"name\": \"torque\" },\n",
    "    ]\n",
    "OUTPUT_PREFIX = \"test01/\" # e.g., \"test01/\"\n",
    "\n",
    "# Test the API connection before proceeding with the rest of the notebook\n",
    "print(\"Testing API connection...\")\n",
    "try:\n",
    "    test_url = f\"{BASE_URL}/accounts/{ACCOUNT_ID}\"\n",
    "    print (test_url)\n",
    "    response = requests.get(test_url, headers=HEADERS, timeout=10)\n",
    "    print(f\"Status code: {response.status_code}\")\n",
    "    if response.status_code == 200:\n",
    "        print(\"API connection successful!\")\n",
    "        print(\"Proceed with the rest of the notebook...\")\n",
    "    else:\n",
    "        print(f\"API error: {response.text[:100]}\")\n",
    "        print(\"STOP! Check your API connection parameters and try again.\")\n",
    "except Exception as e:\n",
    "    print(f\"Connection error: {str(e)}\")\n",
    "    print(\"STOP! Check your API connection parameters and try again.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d2865181",
   "metadata": {},
   "source": [
    "## 2. Create Workspace\n",
    "\n",
    "A workspace in Falkonry is a dedicated environment where users can create, organize, and manage different types of analytical models. Create a workspace for an asset to create and test different models for that asset.\n",
    "\n",
    "Send a POST request to `/api/1.3/accounts/{{account_id}}/workspace` to create a new workspace for development. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a6e2edf2",
   "metadata": {},
   "outputs": [],
   "source": [
    "if WORKSPACE_ID:\n",
    "    workspace_id = WORKSPACE_ID\n",
    "    print(\"Using the Existing Workspace ID:\", workspace_id)\n",
    "else:\n",
    "    # Create a new workspace\n",
    "    workspace_payload = {\n",
    "        \"name\": WORKSPACE_NAME,\n",
    "        \"description\": \"Workspaces for \" + WORKSPACE_NAME\n",
    "    }\n",
    "\n",
    "    response = requests.post(\n",
    "        f\"{BASE_URL}/accounts/{ACCOUNT_ID}/workspace\",\n",
    "        headers=HEADERS,\n",
    "        json=workspace_payload\n",
    "    )\n",
    "\n",
    "    print(\"Status:\", response.status_code)\n",
    "    print(\"Response:\", response.json())\n",
    "\n",
    "    workspace_id = response.json().get(\"id\")\n",
    "    print(\"Created Workspace ID:\", workspace_id)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "649a6135",
   "metadata": {},
   "source": [
    "## 3. Test the calculation function with sample data before creating the transform\n",
    "Prepare the function to setup the calculation model. Function should include the inputschema and outputschema for the model. \n",
    "\n",
    "Import the python libraries such as numpy within the function itself. Do not use aliases for the libraries\n",
    "\n",
    "Models can now be reused with different set of input and output signals. Each model has a fixed schema defined i.e, a model will have an input schema and an output schema. A schema is nothing but a name and valueType list. To use a model for evaluations, the user has to make sure the model's schema is validated against input and output signal sets.\n",
    "\n",
    "The name that you provide in the output schema will be the name of the calculated signal. We recommend following the below naming convention for calculated signals:\n",
    "\n",
    "Naming convention: `<calculated_signal_name>/calculated`\n",
    "\n",
    "In the next cell, we will prepare the function to setup the calculation model. The function should include the inputschema and outputschema for the model. Import the python libraries such as numpy within the function itself. Do not use aliases for the libraries."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e5156121",
   "metadata": {},
   "outputs": [],
   "source": [
    "#Test the calculation function with sample data before creating the transform\n",
    "input_schema = [\n",
    "    {\"name\": \"temperature\", \"valueType\": \"Numeric\"}\n",
    "]\n",
    "\n",
    "output_schema = [\n",
    "    {\"name\": \"temp_roc/calculated\", \"valueType\": \"Numeric\"}\n",
    "]\n",
    "\n",
    "def calculate(signal_data):\n",
    "    import numpy\n",
    "    \n",
    "    temp = numpy.array(signal_data.get(\"temperature\", []))\n",
    "    if temp.size == 0:\n",
    "        return 0.0\n",
    "\n",
    "    start_temp = temp[0]\n",
    "    end_temp = temp[-1]\n",
    "    \n",
    "    if start_temp == 0:\n",
    "        return 0.0 \n",
    "     \n",
    "    temp_roc = ((end_temp - start_temp) / start_temp) * 100\n",
    "    \n",
    "    return float(temp_roc)\n",
    "\n",
    "# --- Example Usage ---\n",
    "# The API sends a 5-minute chunk of data:\n",
    "api_window_data = {\"temperature\": [70.0, 71.2, 70.8, 71.5, 73.0]}\n",
    "\n",
    "roc_result = calculate(api_window_data)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7c52c879",
   "metadata": {},
   "source": [
    "## 4. Convert the calculate function in to string\n",
    "Now that the `calculate ()` function is tested OK, convert the function to a string for API submission"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3b61b728",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Convert the calculation function to a string for API submission\n",
    "\n",
    "calc_script = \"\"\"input_schema = [\n",
    "    {\"name\": \"temperature\", \"valueType\": \"Numeric\"}\n",
    "]\n",
    "\n",
    "output_schema = [\n",
    "    {\"name\": \"temp_roc/calculated\", \"valueType\": \"Numeric\"}\n",
    "]\n",
    "\n",
    "def calculate(signal_data):\n",
    "    import numpy\n",
    "    \n",
    "    temp = numpy.array(signal_data.get(\"temperature\", []))\n",
    "    if temp.size == 0:\n",
    "        return 0.0\n",
    "\n",
    "    start_temp = temp[0]\n",
    "    end_temp = temp[-1]\n",
    "    \n",
    "    if start_temp == 0:\n",
    "        return 0.0 \n",
    "     \n",
    "    temp_roc = ((end_temp - start_temp) / start_temp) * 100\n",
    "    \n",
    "    return float(temp_roc)\"\"\".strip()\n",
    "\n",
    "calc_script"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c10747d9",
   "metadata": {},
   "source": [
    "## 5. Create a calculated model\n",
    "\n",
    "Send a POST request to `/api/1.3/accounts/{{account_id}}/flows` to create a new calculated model in the development workspace. Use the payload specifying python script, input schema, and model configuration.\n",
    "\n",
    "Naming convention for the model: <signal_name>-CM[n] where CM stands for \"Calculated model\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1fe21503",
   "metadata": {},
   "outputs": [],
   "source": [
    "calc_payload = {\n",
    "  \"name\": \"Calc Transform - ROC\",\n",
    "  \"flowType\": \"MODELSETUP\",\n",
    "  \"spec\": {\n",
    "    \"workspace\": workspace_id,\n",
    "    \"modelName\": MODEL_NAME,      #update the model name for each new transform\n",
    "    \"modelType\": \"CALCULATED\",\n",
    "    \"modelDetails\": {\n",
    "      \"statistic\": MODEL_PARAMETERS_STATISTIC,\n",
    "      \"script\": calc_script,\n",
    "      \"valueType\": MODEL_PARAMETERS_VALUETYPE,\n",
    "      \"evaluationWindow\": MODEL_PARAMETERS_EVALWINDOW\n",
    "    }\n",
    "  }\n",
    "}\n",
    "\n",
    "response = requests.post(\n",
    "    f\"{BASE_URL}/accounts/{ACCOUNT_ID}/flows\",\n",
    "    headers=HEADERS,\n",
    "    json=calc_payload\n",
    ")\n",
    "\n",
    "print(\"Status:\", response.status_code)\n",
    "flow_id = response.json().get(\"id\")\n",
    "print(\"MODELSETUP Flow ID:\", flow_id)\n",
    "\n",
    "# Wait for the Flow to be readyand then get the model ID from the created flow\n",
    "await sleep (10)\n",
    "#get the model ID from the created flow\n",
    "response = requests.get(\n",
    "    f\"{BASE_URL}/accounts/{ACCOUNT_ID}/flows/{flow_id}\",\n",
    "    headers=HEADERS)\n",
    "\n",
    "print(response.json())\n",
    "model_id = response.json()[\"outputs\"][0][\"model\"]\n",
    "print(\"Model ID:\", model_id)\n",
    "\n",
    "await sleep (10)\n",
    "# Get the model ID from the flow created above\n",
    "#\n",
    "# Send a GET request to `/models/{model_id}?denorm=inputschema&denorm=outputschema` \n",
    "# to get info on the input and output schema for the model. This is useful in debugging \n",
    "# failed CALCEVAL flows due to mismatch in the input schema and output schema.\n",
    "response = requests.get(\n",
    "    f\"{BASE_URL}/accounts/{ACCOUNT_ID}/models/{model_id}?denorm=inputschema&denorm=outputschema\",\n",
    "    headers=HEADERS)\n",
    "\n",
    "links = response.json()[\"links\"]\n",
    "input_schema = links[0][\"object\"][\"schema\"]\n",
    "\n",
    "print(\"Input Schema:\", input_schema)\n",
    "\n",
    "output_schema = links[1][\"object\"][\"schema\"]\n",
    "print(\"Output Schema:\", output_schema)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5827fff7",
   "metadata": {},
   "source": [
    "## 6. Run CALCEVAL for Testing\n",
    "\n",
    "Send a POST request to `/api/1.3/accounts/{{account_id}}/flows` with `flowType` 'CALCEVAL' and an `outputsignalPrefix` to test the rule on historical data without affecting assessment outputs."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c75ee2d7",
   "metadata": {},
   "outputs": [],
   "source": [
    "calceval_payload = {\n",
    "  \"name\": \"eval for Calc ROC\",\n",
    "  \"description\": \"Evaluating the ROC for signal: <ID> from May 1 to May 20 2026\",\n",
    "  \"flowType\": \"CALCEVAL\",\n",
    "  \"spec\": {\n",
    "    \"model\": model_id,\n",
    "    \"workspace\": workspace_id,\n",
    "    \"timeRange\": EVAL_TIME_RANGE,\n",
    "    \"inputsignals\": INPUT_SIGNALS,\n",
    "    \"outputsignalPrefix\": OUTPUT_PREFIX     #ensure to increment this prefix for each new CALCEVAL to avoid signal name conflicts\n",
    "  }\n",
    "}\n",
    "\n",
    "response = requests.post(\n",
    "    f\"{BASE_URL}/accounts/{ACCOUNT_ID}/flows\",\n",
    "    headers=HEADERS,\n",
    "    json=calceval_payload\n",
    ")\n",
    "\n",
    "print(\"Status:\", response.status_code)\n",
    "flow_id = response.json().get(\"id\")\n",
    "print(\"CALCEVAL Flow ID:\", flow_id)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e96a4964",
   "metadata": {},
   "source": [
    "## 7. Create Assessment\n",
    "\n",
    "Assessments are models that are deployed for monitoring live data streams. They can be enabled or disabled as needed.\n",
    "\n",
    "Send a POST request to `/api/1.3/accounts/{{account_id}}/flows` with `flowType` 'ASSESSMENTSETUP' to create a live assessment for the calculation. Provide the model, assessment name, and input signals.\n",
    "\n",
    "Naming convention: <signal_name> or <calculated_signal_name>\n",
    "\n",
    "The output signal i.e. the calculated signal will have the following name: <assessment_name>/<output_signal_name_defined_in_outputschema>\n",
    "\n",
    "Eg: TE_991_80/temp_roc/calculated"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "852c541b",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Create a live assessment\n",
    "assessment_payload = {\n",
    "    \"description\": \"ROC for ___\",\n",
    "    \"flowType\": \"ASSESSMENTSETUP\",\n",
    "    \"name\": \"create assessment\",\n",
    "    \"spec\": {\n",
    "        \"assessmentName\": MODEL_NAME,\n",
    "        \"assessmentState\": \"MONITORING\",\n",
    "        \"inputsignals\": INPUT_SIGNALS,\n",
    "        \"model\": model_id \n",
    "    }\n",
    "}\n",
    "\n",
    "response = requests.post(\n",
    "    f\"{BASE_URL}/accounts/{ACCOUNT_ID}/flows\",\n",
    "    headers=HEADERS,\n",
    "    json=assessment_payload\n",
    ")\n",
    "\n",
    "await sleep (10)\n",
    "print(\"Status:\", response.status_code)\n",
    "print(\"Response:\", response.json())\n",
    "assessment_name = response.json()[\"spec\"][\"assessmentName\"]\n",
    "print(\"Created Assessment:\", assessment_name)\n",
    "\n",
    "response = requests.get(\n",
    "    f\"{BASE_URL}/accounts/{ACCOUNT_ID}/assessments\",\n",
    "    headers=HEADERS)\n",
    "\n",
    "count = response.json()[0][\"count\"]\n",
    "\n",
    "response = requests.get(\n",
    "    f\"{BASE_URL}/accounts/{ACCOUNT_ID}/assessments?limit={count}\",\n",
    "    headers=HEADERS)\n",
    "\n",
    "response = response.json()\n",
    "for assessment in response:\n",
    "    if assessment[\"name\"] == assessment_name:\n",
    "        assessment_id = assessment[\"id\"]\n",
    "        print(\"Assessment ID:\", assessment_id)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "37960a11",
   "metadata": {},
   "source": [
    "## 8. Get Assessment Info and Extract Output Signals\n",
    "\n",
    "Send a GET request to `/api/1.3/accounts/{{account_id}}/assessments/{{assessment_id}}?denorm=inputSignalset&denorm=outputSignalset` to retrieve assessment info. Extract the `outputsignals` array for use in live calculation evaluation.\n",
    "\n",
    "Wait for the above flow to complete before running the next cell."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0043fde5",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Get assessment info and extract output signals\n",
    "response = requests.get(\n",
    "    f\"{BASE_URL}/accounts/{ACCOUNT_ID}/assessments/{assessment_id}?denorm=inputSignalset&denorm=outputSignalset\",\n",
    "    headers=HEADERS\n",
    ")\n",
    "\n",
    "links = response.json()[\"links\"]\n",
    "for link in links:\n",
    "    if link[\"name\"] == \"outputSignalset\":\n",
    "        outputsignalset = link[\"object\"][\"signals\"]\n",
    "        outputsignals = [\n",
    "            {\"name\": sig[\"name\"], \"signal\": sig[\"signal\"]}\n",
    "            for sig in outputsignalset\n",
    "        ]\n",
    "\n",
    "print(\"Extracted output signals:\")\n",
    "for sig in outputsignals:\n",
    "    print(sig)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "40da46c4",
   "metadata": {},
   "source": [
    "## 9. Run CALCEVAL for Live Assessment Output\n",
    "\n",
    "Send a POST request to `/api/1.3/accounts/{{account_id}}/flows` with `flowType` 'CALCEVAL', providing the extracted `outputsignals` to route rule evaluation results to assessment output signals."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "eaeefbe4",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Run CALCEVAL for live assessment output\n",
    "calceval_live_payload = {\n",
    "    \"description\": \"Evaluating the ROC for machine1/temperature from May 20 to May 21 2026\",\n",
    "    \"flowType\": \"CALCEVAL\",\n",
    "    \"name\": \"Live Calc Eval ROC for machine1/temperature from May 20 to May 21 2026\",\n",
    "    \"spec\": {\n",
    "        \"inputsignals\": INPUT_SIGNALS,\n",
    "        \"model\": model_id,\n",
    "        \"outputsignals\": outputsignals,  # Use extracted outputsignals\n",
    "        \"timeRange\": EVAL_TIME_RANGE,\n",
    "        \"workspace\": workspace_id\n",
    "    }\n",
    "}\n",
    "\n",
    "response = requests.post(\n",
    "    f\"{BASE_URL}/accounts/{ACCOUNT_ID}/flows\",\n",
    "    headers=HEADERS,\n",
    "    json=calceval_live_payload\n",
    ")\n",
    "\n",
    "print(\"Status:\", response.status_code)\n",
    "print(\"Response:\", response.json())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f69bffa9",
   "metadata": {},
   "source": [
    "## 10. Stop monitoring an assessment"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1018094f",
   "metadata": {},
   "outputs": [],
   "source": [
    "live_payload = {\n",
    "    \"name\": \"stop live monitoring for calc assessments\",\n",
    "    \"flowType\": \"STOPMONITORASSESSMENT\",\n",
    "    \"spec\":{\n",
    "        \"query\":{\n",
    "            \"id\":[\"\"]   #array assessment IDs to stop live monitoring\n",
    "        }\n",
    "    }\n",
    "\n",
    "}\n",
    "\n",
    "response = requests.post(\n",
    "    f\"{BASE_URL}/accounts/{ACCOUNT_ID}/flows\",\n",
    "    headers=HEADERS,\n",
    "    json=live_payload\n",
    ")\n",
    "\n",
    "print(\"Status:\", response.status_code)\n",
    "print(\"Response:\", response.json())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "74f30cf4",
   "metadata": {},
   "source": [
    "## 11. Restart monitoring an assessment"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3fd24154",
   "metadata": {},
   "outputs": [],
   "source": [
    "live_payload = {\n",
    "    \"name\": \"start live monitoring for calc assessments\",\n",
    "    \"flowType\": \"STARTMONITORASSESSMENT\",\n",
    "    \"spec\":{\n",
    "        \"query\":{\n",
    "            \"id\":[\"\"]   #array assessment IDs to stop live monitoring\n",
    "        }\n",
    "    }\n",
    "\n",
    "}\n",
    "\n",
    "response = requests.post(\n",
    "    f\"{BASE_URL}/accounts/{ACCOUNT_ID}/flows\",\n",
    "    headers=HEADERS,\n",
    "    json=live_payload\n",
    ")\n",
    "\n",
    "print(\"Status:\", response.status_code)\n",
    "print(\"Response:\", response.json())"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv (3.13.7)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
