API returning 404 on some requests but not others

Solved
jake07
New here

API returning 404 on some requests but not others

Hello im new to the meraki API but i am trying to export all firewall rules to a csv. The code is written in python and successfully exports both L3 and L7 data but for some reason port forwarding comes back as 404. I have full admin privileges with my API key and i know the key is working because it is able to pull L3 and L7. If i go directly to the url https://api.meraki.com/api/v1/networks/{network_id}/appliance/firewall/portForwardingRules on a web browser, i can see the data it should be exporting so i know its valid. This result is consistent across multiple networks. Im not sure where else to trouble . Here is the code in python and results. Thanks.

 

 

 

 

import requests
import os
import csv

# Constants
API_KEY = 'redacted'
NETWORK_ID = 'redacted'
BASE_URL = 'https://api.meraki.com/api/v1'
OUTPUT_CSV_FILE = 'export_all_firewall_rules.csv'

# Headers for authentication
headers = {
    'X-Cisco-Meraki-API-Key': API_KEY,
    'Content-Type': 'application/json'
}

# Function to get the Layer 3 firewall rules for the network
def get_l3_firewall_rules(network_id):
    url = f'{BASE_URL}/networks/{network_id}/appliance/firewall/l3FirewallRules'
    response = requests.get(url, headers=headers)

    print(f"Status Code (L3): {response.status_code}")  # Debugging line
    print(f"Response Body (L3): {response.text}")  # Debugging line

    if response.status_code == 200:
        return response.json().get('rules', [])
    else:
        print(f"Error retrieving Layer 3 rules: {response.status_code} - {response.text}")
        return []

# Function to get the Layer 7 firewall rules for the network
def get_l7_firewall_rules(network_id):
    url = f'{BASE_URL}/networks/{network_id}/appliance/firewall/l7FirewallRules'
    response = requests.get(url, headers=headers)

    print(f"Status Code (L7): {response.status_code}")  # Debugging line
    print(f"Response Body (L7): {response.text}")  # Debugging line

    if response.status_code == 200:
        return response.json().get('rules', [])
    else:
        print(f"Error retrieving Layer 7 rules: {response.status_code} - {response.text}")
        return []

# Function to get the port forwarding rules for the network
def get_port_forwarding_rules(network_id):
    url = f'{BASE_URL}/networks/{network_id}/appliance/portForwardingRules'
    response = requests.get(url, headers=headers)

    print(f"Status Code (Port Forwarding): {response.status_code}")  # Debugging line
    print(f"Response Body (Port Forwarding): {response.text}")  # Debugging line

    if response.status_code == 200:
        return response.json()
    else:
        print(f"Error retrieving port forwarding rules: {response.status_code} - {response.text}")
        return []

# Function to export firewall rules to CSV
def export_to_csv(l3_rules, l7_rules, pf_rules, filename):
    if not l3_rules and not l7_rules and not pf_rules:
        print("No rules to export.")
        return

    # Open the file in write mode
    with open(filename, mode='w', newline='') as file:
        fieldnames = [
            'Rule Type', 'Policy', 'Protocol', 'Src Port', 'Dst Port', 'Src CIDR', 'Dst CIDR', 'Comment', 'Private IP', 'Public Port'
        ]
        writer = csv.DictWriter(file, fieldnames=fieldnames)

        writer.writeheader()  # Write the header row

        # Write the Layer 3 firewall rules to the CSV file
        for rule in l3_rules:
            print(rule)  # Debugging line to inspect each rule
           
            if isinstance(rule, dict):
                writer.writerow({
                    'Rule Type': 'Layer 3 Firewall',
                    'Policy': rule.get('policy', 'N/A'),
                    'Protocol': rule.get('protocol', 'N/A'),
                    'Src Port': rule.get('srcPort', 'N/A'),
                    'Dst Port': rule.get('destPort', 'N/A'),
                    'Src CIDR': rule.get('srcCidr', 'N/A'),
                    'Dst CIDR': rule.get('destCidr', 'N/A'),
                    'Comment': rule.get('comment', 'N/A'),
                    'Private IP': 'N/A',
                    'Public Port': 'N/A'
                })

        # Write the Layer 7 firewall rules to the CSV file
        for rule in l7_rules:
            print(rule)  # Debugging line to inspect each rule

            if isinstance(rule, dict):
                writer.writerow({
                    'Rule Type': 'Layer 7 Firewall',
                    'Policy': rule.get('policy', 'N/A'),
                    'Protocol': rule.get('protocol', 'N/A'),
                    'Src Port': 'N/A',
                    'Dst Port': rule.get('destPort', 'N/A'),
                    'Src CIDR': 'N/A',
                    'Dst CIDR': 'N/A',
                    'Comment': rule.get('comment', 'N/A'),
                    'Private IP': 'N/A',
                    'Public Port': 'N/A'
                })

        # Write the port forwarding rules to the CSV file
        for rule in pf_rules:
            print(rule)  # Debugging line to inspect each rule

            if isinstance(rule, dict):
                writer.writerow({
                    'Rule Type': 'Port Forwarding',
                    'Policy': 'Allow',  # Port forwarding rules are typically "Allow"
                    'Protocol': rule.get('protocol', 'N/A'),
                    'Src Port': 'N/A',
                    'Dst Port': rule.get('privatePort', 'N/A'),
                    'Src CIDR': 'N/A',
                    'Dst CIDR': 'N/A',
                    'Comment': rule.get('name', 'N/A'),
                    'Private IP': rule.get('localIp', 'N/A'),
                    'Public Port': rule.get('publicPort', 'N/A')
                })

    print(f"Rules exported to {filename}")

# Main execution
l3_rules = get_l3_firewall_rules(NETWORK_ID)
l7_rules = get_l7_firewall_rules(NETWORK_ID)
pf_rules = get_port_forwarding_rules(NETWORK_ID)

if not l3_rules and not l7_rules and not pf_rules:
    print("No firewall or port forwarding rules found.")
else:
    export_to_csv(l3_rules, l7_rules, pf_rules, OUTPUT_CSV_FILE)

 

 

 

Status Code (L3): 200
Response Body (L3): {"rules":[{"comment":"test api","policy":"deny","protocol":"tcp","srcPort":"Any","srcCidr":"192.168.128.0/24","destPort":"Any","destCidr":"192.168.127.0/24","syslogEnabled":false},{"comment":"Default rule","policy":"allow","protocol":"Any","srcPort":"Any","srcCidr":"Any","destPort":"Any","destCidr":"Any","syslogEnabled":false}]}
Status Code (L7): 200
Response Body (L7): {"rules":[]}
Status Code (Port Forwarding): 404
Response Body (Port Forwarding): <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <title>Page not found - Cisco Meraki</title>
  <style type="text/css">
    body {
      display: flex;
      flex-direction: column;
      justify-content: flex-start;
      align-items: center;
      margin: 0 2em;
      font-family: Helvetica, Arial, sans-serif;
      line-height: 1.45;
      color: #222325; /* same as $gray-10 in mkiColorVariables.json */
    }
    .header__container,
    .content__container,
    .footer__container {
      max-width: 800px;
      width: 100%;
    }
    .header__container {
      padding: 2em 0;
      border-bottom: 1px solid #D7D7D9; /* same as $gray-80 in mkiColorVariables.json */
    }
    .header__merakiLogo {
      height: 2.125em;
    }
    .header__merakiLogo--gray {
      fill: #898b8e;
    }
    .header__merakiLogo--green {
      fill: #67b346;
    }
    h1.content__title {
      font-size: 1.728em; /* from typographyBase.scss */
      font-weight: 300;
      margin-bottom: 1em;
    }
    .content__container {
      margin-bottom: 1em;
    }
    .content__container a {
      color: #1D770B; /* same as $linkColor in variables.scss */
    }
    .footer__container {
      padding: 1em 0;
      text-align: right;
      border-top: 1px solid #D7D7D9; /* same as $gray-80 in mkiColorVariables.json */
    }
    .footer__text {
      font-size: 0.833em;
      color: #898A8C; /* same as $gray-50 in mkiColorVariables.json */
    }
  </style>
</head>
<body>
  <div class="header__container">
    <svg class="header__merakiLogo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 130 25"><title>Cisco Meraki</title><rect class="header__merakiLogo--gray" x="13.29" y="16.46" width="2.06" height="8.17"/><path class="header__merakiLogo--gray" d="M32,18.8a3.64,3.64,0,0,0-1.73-.44,2.18,2.18,0,1,0,0,4.36A3.63,3.63,0,0,0,32,22.29v2.19a6.53,6.53,0,0,1-1.88.29,4.23,4.23,0,1,1,0-8.46,6.29,6.29,0,0,1,1.88.29Z"/><path class="header__merakiLogo--gray" d="M10.46,18.8a3.59,3.59,0,0,0-1.73-.44,2.18,2.18,0,1,0,0,4.36,3.59,3.59,0,0,0,1.73-.43v2.19a6.49,6.49,0,0,1-1.88.29,4.23,4.23,0,1,1,0-8.46,6.23,6.23,0,0,1,1.88.29Z"/><path class="header__merakiLogo--gray" d="M38.45,18.4a2.15,2.15,0,1,0,2.13,2.15,2.11,2.11,0,0,0-2.13-2.15m4.31,2.15a4.31,4.31,0,1,1-4.31-4.23,4.2,4.2,0,0,1,4.31,4.23"/><path class="header__merakiLogo--gray" d="M23.17,18.32a7.05,7.05,0,0,0-1.61-.25c-.83,0-1.27.27-1.27.67s.6.67.94.78l.57.18A2.46,2.46,0,0,1,23.74,22c0,2.05-1.81,2.74-3.38,2.74a12.56,12.56,0,0,1-2.22-.22V22.67a7.73,7.73,0,0,0,1.95.31c1,0,1.5-.3,1.5-.77s-.41-.65-.92-.81l-.44-.14c-1.15-.36-2.1-1-2.1-2.39,0-1.53,1.14-2.55,3-2.55a8.91,8.91,0,0,1,2,.26Z"/><path class="header__merakiLogo--gray" d="M2,7.68a1,1,0,0,0-2,0V9.83a1,1,0,1,0,2,0Z"/><path class="header__merakiLogo--gray" d="M7.66,4.87a1,1,0,0,0-2,0v5a1,1,0,0,0,2,0Z"/><path class="header__merakiLogo--gray" d="M13.28,1a1,1,0,0,0-2,0V11.87a1,1,0,1,0,2,0Z"/><path class="header__merakiLogo--gray" d="M18.9,4.87a1,1,0,0,0-2,0v5a1,1,0,1,0,2,0Z"/><path class="header__merakiLogo--gray" d="M24.52,7.68a1,1,0,0,0-2,0V9.83a1,1,0,1,0,2,0Z"/><path class="header__merakiLogo--gray" d="M30.14,4.87a1,1,0,0,0-2,0v5a1,1,0,1,0,2,0Z"/><path class="header__merakiLogo--gray" d="M35.77,1a1,1,0,1,0-2,0V11.87a1,1,0,1,0,2,0Z"/><path class="header__merakiLogo--gray" d="M41.39,4.87a1,1,0,0,0-2.06,0v5a1,1,0,0,0,2.06,0Z"/><path class="header__merakiLogo--gray" d="M47,7.68a1,1,0,0,0-2,0V9.83a1,1,0,1,0,2,0Z"/><path class="header__merakiLogo--green" d="M68.43,24.64,62.06,8.9V24.64H60.73V7.13h2l6.44,16,6.08-16h1.95V24.64H75.9V9l-6,15.61Z"/><path class="header__merakiLogo--green" d="M91.28,21.18A5.11,5.11,0,0,1,86,25c-3.43,0-6-2.36-6-6.69s2.5-6.69,5.76-6.69,5.71,2.19,5.71,7H81.36c.12,3.6,2.16,5.25,4.69,5.25a3.77,3.77,0,0,0,3.84-2.7Zm-9.9-3.65h8.75c-.17-3.24-2-4.84-4.35-4.84S81.63,14.37,81.38,17.54Z"/><path class="header__merakiLogo--green" d="M94.57,24.64V12h1.07l.19,2.43a3.67,3.67,0,0,1,3.55-2.8,4.51,4.51,0,0,1,1.31.2v1.29a4.93,4.93,0,0,0-1.39-.22c-1.85,0-3.43,1.8-3.43,4.84v6.91Z"/><path class="header__merakiLogo--green" d="M102.35,15.28c.19-2.16,2.12-3.65,4.91-3.65S112,13.21,112,15.79v8.85h-1.07l-.19-2.09A5,5,0,0,1,106.22,25c-2.46,0-4.23-1.33-4.23-3.57s1.31-3.48,4.86-4.06l3.79-.63v-1.1c0-1.82-1.29-2.94-3.45-2.94s-3.31,1-3.48,2.58Zm8.29,4.86V17.78l-3.4.58c-3,.51-3.89,1.46-3.89,3,0,1.7,1.31,2.55,3.21,2.55A4,4,0,0,0,110.64,20.14Z"/><path class="header__merakiLogo--green" d="M115.32,24.64V7.13h1.31v10L122.69,12h1.78L118,17.51l7.3,7.12h-1.77L116.63,18v6.69Z"/><path class="header__merakiLogo--green" d="M126.92,8.93V7.13h1.58v1.8ZM127,24.64V12h1.31V24.64Z"/></svg>
  </div>
  <div class="content__container">
    <h1 class="content__title">Page not found</h1>
    <p class="content__primaryText">The page you are looking for may have been moved or does not exist.</p> 
    <p class="content__secondaryText">To log in to the Cisco Meraki Dashboard, go to <a href="https://dashboard.meraki.com">https://dashboard.meraki.com</a>.</p>
  </div>
  <div class="footer__container">
    <span id="footer" class="footer__text">&copy; Cisco Systems, Inc.</span>
  </div>
  <script type="text/javascript" charset="utf-8">
  //<![CDATA[
  (function () {
    var year = new Date().getFullYear();
    document.getElementById("footer").innerHTML = '&copy; ' + year + ' Cisco Systems, Inc.';
  })()
  //]]>
  </script>
</body>
</html>


Error retrieving port forwarding rules: 404 - <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <title>Page not found - Cisco Meraki</title>
  <style type="text/css">
    body {
      display: flex;
      flex-direction: column;
      justify-content: flex-start;
      align-items: center;
      margin: 0 2em;
      font-family: Helvetica, Arial, sans-serif;
      line-height: 1.45;
      color: #222325; /* same as $gray-10 in mkiColorVariables.json */
    }
    .header__container,
    .content__container,
    .footer__container {
      max-width: 800px;
      width: 100%;
    }
    .header__container {
      padding: 2em 0;
      border-bottom: 1px solid #D7D7D9; /* same as $gray-80 in mkiColorVariables.json */
    }
    .header__merakiLogo {
      height: 2.125em;
    }
    .header__merakiLogo--gray {
      fill: #898b8e;
    }
    .header__merakiLogo--green {
      fill: #67b346;
    }
    h1.content__title {
      font-size: 1.728em; /* from typographyBase.scss */
      font-weight: 300;
      margin-bottom: 1em;
    }
    .content__container {
      margin-bottom: 1em;
    }
    .content__container a {
      color: #1D770B; /* same as $linkColor in variables.scss */
    }
    .footer__container {
      padding: 1em 0;
      text-align: right;
      border-top: 1px solid #D7D7D9; /* same as $gray-80 in mkiColorVariables.json */
    }
    .footer__text {
      font-size: 0.833em;
      color: #898A8C; /* same as $gray-50 in mkiColorVariables.json */
    }
  </style>
</head>
<body>
  <div class="header__container">
    <svg class="header__merakiLogo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 130 25"><title>Cisco Meraki</title><rect class="header__merakiLogo--gray" x="13.29" y="16.46" width="2.06" height="8.17"/><path class="header__merakiLogo--gray" d="M32,18.8a3.64,3.64,0,0,0-1.73-.44,2.18,2.18,0,1,0,0,4.36A3.63,3.63,0,0,0,32,22.29v2.19a6.53,6.53,0,0,1-1.88.29,4.23,4.23,0,1,1,0-8.46,6.29,6.29,0,0,1,1.88.29Z"/><path class="header__merakiLogo--gray" d="M10.46,18.8a3.59,3.59,0,0,0-1.73-.44,2.18,2.18,0,1,0,0,4.36,3.59,3.59,0,0,0,1.73-.43v2.19a6.49,6.49,0,0,1-1.88.29,4.23,4.23,0,1,1,0-8.46,6.23,6.23,0,0,1,1.88.29Z"/><path class="header__merakiLogo--gray" d="M38.45,18.4a2.15,2.15,0,1,0,2.13,2.15,2.11,2.11,0,0,0-2.13-2.15m4.31,2.15a4.31,4.31,0,1,1-4.31-4.23,4.2,4.2,0,0,1,4.31,4.23"/><path class="header__merakiLogo--gray" d="M23.17,18.32a7.05,7.05,0,0,0-1.61-.25c-.83,0-1.27.27-1.27.67s.6.67.94.78l.57.18A2.46,2.46,0,0,1,23.74,22c0,2.05-1.81,2.74-3.38,2.74a12.56,12.56,0,0,1-2.22-.22V22.67a7.73,7.73,0,0,0,1.95.31c1,0,1.5-.3,1.5-.77s-.41-.65-.92-.81l-.44-.14c-1.15-.36-2.1-1-2.1-2.39,0-1.53,1.14-2.55,3-2.55a8.91,8.91,0,0,1,2,.26Z"/><path class="header__merakiLogo--gray" d="M2,7.68a1,1,0,0,0-2,0V9.83a1,1,0,1,0,2,0Z"/><path class="header__merakiLogo--gray" d="M7.66,4.87a1,1,0,0,0-2,0v5a1,1,0,0,0,2,0Z"/><path class="header__merakiLogo--gray" d="M13.28,1a1,1,0,0,0-2,0V11.87a1,1,0,1,0,2,0Z"/><path class="header__merakiLogo--gray" d="M18.9,4.87a1,1,0,0,0-2,0v5a1,1,0,1,0,2,0Z"/><path class="header__merakiLogo--gray" d="M24.52,7.68a1,1,0,0,0-2,0V9.83a1,1,0,1,0,2,0Z"/><path class="header__merakiLogo--gray" d="M30.14,4.87a1,1,0,0,0-2,0v5a1,1,0,1,0,2,0Z"/><path class="header__merakiLogo--gray" d="M35.77,1a1,1,0,1,0-2,0V11.87a1,1,0,1,0,2,0Z"/><path class="header__merakiLogo--gray" d="M41.39,4.87a1,1,0,0,0-2.06,0v5a1,1,0,0,0,2.06,0Z"/><path class="header__merakiLogo--gray" d="M47,7.68a1,1,0,0,0-2,0V9.83a1,1,0,1,0,2,0Z"/><path class="header__merakiLogo--green" d="M68.43,24.64,62.06,8.9V24.64H60.73V7.13h2l6.44,16,6.08-16h1.95V24.64H75.9V9l-6,15.61Z"/><path class="header__merakiLogo--green" d="M91.28,21.18A5.11,5.11,0,0,1,86,25c-3.43,0-6-2.36-6-6.69s2.5-6.69,5.76-6.69,5.71,2.19,5.71,7H81.36c.12,3.6,2.16,5.25,4.69,5.25a3.77,3.77,0,0,0,3.84-2.7Zm-9.9-3.65h8.75c-.17-3.24-2-4.84-4.35-4.84S81.63,14.37,81.38,17.54Z"/><path class="header__merakiLogo--green" d="M94.57,24.64V12h1.07l.19,2.43a3.67,3.67,0,0,1,3.55-2.8,4.51,4.51,0,0,1,1.31.2v1.29a4.93,4.93,0,0,0-1.39-.22c-1.85,0-3.43,1.8-3.43,4.84v6.91Z"/><path class="header__merakiLogo--green" d="M102.35,15.28c.19-2.16,2.12-3.65,4.91-3.65S112,13.21,112,15.79v8.85h-1.07l-.19-2.09A5,5,0,0,1,106.22,25c-2.46,0-4.23-1.33-4.23-3.57s1.31-3.48,4.86-4.06l3.79-.63v-1.1c0-1.82-1.29-2.94-3.45-2.94s-3.31,1-3.48,2.58Zm8.29,4.86V17.78l-3.4.58c-3,.51-3.89,1.46-3.89,3,0,1.7,1.31,2.55,3.21,2.55A4,4,0,0,0,110.64,20.14Z"/><path class="header__merakiLogo--green" d="M115.32,24.64V7.13h1.31v10L122.69,12h1.78L118,17.51l7.3,7.12h-1.77L116.63,18v6.69Z"/><path class="header__merakiLogo--green" d="M126.92,8.93V7.13h1.58v1.8ZM127,24.64V12h1.31V24.64Z"/></svg>
  </div>
  <div class="content__container">
    <h1 class="content__title">Page not found</h1>
    <p class="content__primaryText">The page you are looking for may have been moved or does not exist.</p> 
    <p class="content__secondaryText">To log in to the Cisco Meraki Dashboard, go to <a href="https://dashboard.meraki.com">https://dashboard.meraki.com</a>.</p>
  </div>
  <div class="footer__container">
    <span id="footer" class="footer__text">&copy; Cisco Systems, Inc.</span>
  </div>
  <script type="text/javascript" charset="utf-8">
  //<![CDATA[
  (function () {
    var year = new Date().getFullYear();
    document.getElementById("footer").innerHTML = '&copy; ' + year + ' Cisco Systems, Inc.';
  })()
  //]]>
  </script>
</body>
</html>


{'comment': 'test api', 'policy': 'deny', 'protocol': 'tcp', 'srcPort': 'Any', 'srcCidr': '192.168.128.0/24', 'destPort': 'Any', 'destCidr': '192.168.127.0/24', 'syslogEnabled': False}
{'comment': 'Default rule', 'policy': 'allow', 'protocol': 'Any', 'srcPort': 'Any', 'srcCidr': 'Any', 'destPort': 'Any', 'destCidr': 'Any', 'syslogEnabled': False}
Rules exported to export_all_firewall_rules.csv

 

1 Accepted Solution
Ryan_Miles
Meraki Employee
Meraki Employee

The word "firewall" is missing from path in your script.

View solution in original post

4 Replies 4
Ryan_Miles
Meraki Employee
Meraki Employee

The word "firewall" is missing from path in your script.

jake07
New here

Wow your right, that was simple. Thank you for the quick response.

CarolineS
Community Manager
Community Manager

Huzzah! I’m going to mark this thread as “resolved” since it seems Ryan’s response is the answer!

Caroline S | Community Manager, Cisco Meraki
New to the community? Get started here
PhilipDAth
Kind of a big deal
Kind of a big deal

You deserve double kudos for that.  I can only see a wall of text.

Get notified when there are additional replies to this discussion.