diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 00000000..87fdf720
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,12 @@
+# See GitHub's documentation for more information on this file:
+# https://docs.github.com/en/code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/configuration-options-for-dependency-updates
+version: 2
+updates:
+  - package-ecosystem: "github-actions"
+    directory: "/"
+    schedule:
+      interval: "daily"
+  - package-ecosystem: "gomod"
+    directory: "/"
+    schedule:
+      interval: "daily"
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 00000000..d2bd6834
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,42 @@
+# Terraform Provider release workflow.
+name: Release
+
+# This GitHub action creates a release when a tag that matches the pattern
+# "v*" (e.g. v0.1.0) is created.
+on:
+  push:
+    tags:
+      - 'v*'
+
+# Releases need permissions to read and write the repository contents.
+# GitHub considers creating releases and uploading assets as writing contents.
+permissions:
+  contents: write
+
+jobs:
+  goreleaser:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v4
+        with:
+          # Allow goreleaser to access older tag information.
+          fetch-depth: 0
+      - uses: actions/setup-go@v5
+        with:
+          go-version-file: 'go.mod'
+          cache: true
+      - name: Import GPG key
+        id: import_gpg
+        uses: crazy-max/ghaction-import-gpg@v6.1.0
+        with:
+          # These secrets will need to be configured for the repository:
+          gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
+          passphrase: ${{ secrets.PASSPHRASE }}
+      - name: Run GoReleaser
+        uses: goreleaser/goreleaser-action@v6.0.0
+        with:
+          args: release --rm-dist
+        env:
+          # GitHub sets the GITHUB_TOKEN secret automatically.
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }}
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
new file mode 100644
index 00000000..99310a1d
--- /dev/null
+++ b/.github/workflows/test.yml
@@ -0,0 +1,70 @@
+# Terraform Provider testing workflow.
+name: Tests
+
+# This GitHub action runs your tests for each pull request and push.
+# Optionally, you can turn it on using a schedule for regular testing.
+on:
+  workflow_dispatch:
+  pull_request:
+    paths-ignore:
+      - "README.md"
+  push:
+    paths-ignore:
+      - "README.md"
+
+# Testing only needs permissions to read the repository contents.
+permissions:
+  contents: read
+
+jobs:
+  # Ensure project builds before running testing matrix
+  build:
+    name: Build
+    runs-on: ubuntu-latest
+    timeout-minutes: 5
+    steps:
+      - uses: actions/checkout@v4
+      - uses: actions/setup-python@v5
+        with:
+          python-version: "3.10"
+      - uses: actions/setup-go@v5
+        with:
+          go-version-file: "go.mod"
+          cache: true
+      - run: pip install yamale
+      - run: yamale -s gen/schema/schema.yaml gen/definitions/
+      - run: go mod download
+      - run: go generate
+      - run: git diff --exit-code
+      - run: go build -v .
+
+  # Run acceptance tests in a matrix with Terraform CLI versions
+  test:
+    name: Terraform Provider Acceptance Tests
+    needs: [build] # [consecutiveness, build]
+    runs-on: ubuntu-latest
+    timeout-minutes: 90
+    strategy:
+      fail-fast: true
+      max-parallel: 1
+      matrix:
+        # list whatever Terraform versions here you would like to support
+        terraform:
+          - "1.0.*"
+          - "1.9.*"
+    steps:
+      - uses: actions/checkout@v4
+      - uses: actions/setup-go@v5
+        with:
+          go-version-file: "go.mod"
+          cache: true
+      - uses: hashicorp/setup-terraform@v3
+        with:
+          terraform_version: ${{ matrix.terraform }}
+          terraform_wrapper: false
+      - run: go mod download
+      - env:
+          TF_ACC: "1"
+          MERAKI_API_KEY: ${{ secrets.MERAKI_API_KEY }}
+        run: go test -v -cover -timeout 45m ./internal/provider/
+        timeout-minutes: 45
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..fd3ad8e1
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,35 @@
+*.dll
+*.exe
+.DS_Store
+example.tf
+terraform.tfplan
+terraform.tfstate
+bin/
+dist/
+modules-dev/
+/pkg/
+website/.vagrant
+website/.bundle
+website/build
+website/node_modules
+.vagrant/
+*.backup
+./*.tfstate
+.terraform/
+*.log
+*.bak
+*~
+.*.swp
+.idea
+*.iml
+*.test
+*.iml
+
+website/vendor
+
+# Test exclusions
+!command/test-fixtures/**/*.tfstate
+!command/test-fixtures/**/.terraform/
+
+# Keep windows files with windows line endings
+*.winfile eol=crlf
diff --git a/.goreleaser.yml b/.goreleaser.yml
new file mode 100644
index 00000000..9bb0aa71
--- /dev/null
+++ b/.goreleaser.yml
@@ -0,0 +1,60 @@
+# Visit https://goreleaser.com for documentation on how to customize this
+# behavior.
+before:
+  hooks:
+    # this is just an example and not a requirement for provider building/publishing
+    - go mod tidy
+builds:
+- env:
+    # goreleaser does not work with CGO, it could also complicate
+    # usage by users in CI/CD systems like Terraform Cloud where
+    # they are unable to install libraries.
+    - CGO_ENABLED=0
+  mod_timestamp: '{{ .CommitTimestamp }}'
+  flags:
+    - -trimpath
+  ldflags:
+    - '-s -w -X main.version={{.Version}} -X main.commit={{.Commit}}'
+  goos:
+    - freebsd
+    - windows
+    - linux
+    - darwin
+  goarch:
+    - amd64
+    - '386'
+    - arm
+    - arm64
+  ignore:
+    - goos: darwin
+      goarch: '386'
+  binary: '{{ .ProjectName }}_v{{ .Version }}'
+archives:
+- format: zip
+  name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}'
+checksum:
+  extra_files:
+    - glob: 'terraform-registry-manifest.json'
+      name_template: '{{ .ProjectName }}_{{ .Version }}_manifest.json'
+  name_template: '{{ .ProjectName }}_{{ .Version }}_SHA256SUMS'
+  algorithm: sha256
+signs:
+  - artifacts: checksum
+    args:
+      # if you are using this in a GitHub action or some other automated pipeline, you 
+      # need to pass the batch flag to indicate its not interactive.
+      - "--batch"
+      - "--local-user"
+      - "{{ .Env.GPG_FINGERPRINT }}" # set this environment variable for your signing key
+      - "--output"
+      - "${signature}"
+      - "--detach-sign"
+      - "${artifact}"
+release:
+  extra_files:
+    - glob: 'terraform-registry-manifest.json'
+      name_template: '{{ .ProjectName }}_{{ .Version }}_manifest.json'
+  # If you want to manually examine the release before its live, uncomment this line:
+  # draft: true
+changelog:
+  skip: true
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 00000000..d2e326d8
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,16 @@
+{
+    // Use IntelliSense to learn about possible attributes.
+    // Hover to view descriptions of existing attributes.
+    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+    "version": "0.2.0",
+    "configurations": [
+        {
+            "name": "Launch generator",
+            "type": "go",
+            "request": "launch",
+            "mode": "auto",
+            "program": "gen/generator.go",
+            "cwd": "./"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 00000000..190a5173
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,3 @@
+## 0.1.0 (unreleased)
+
+- Initial release
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 00000000..f5fd27c7
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,76 @@
+# Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and maintainers pledge to making participation in our project and
+our community a harassment-free experience for everyone, regardless of age, body
+size, disability, ethnicity, sex characteristics, gender identity and expression,
+level of experience, education, socio-economic status, nationality, personal
+appearance, race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or
+ advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic
+ address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or
+reject comments, commits, code, wiki edits, issues, and other contributions
+that are not aligned to this Code of Conduct, or to ban temporarily or
+permanently any contributor for other behaviors that they deem inappropriate,
+threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. Examples of
+representing a project or community include using an official project e-mail
+address, posting via an official social media account, or acting as an appointed
+representative at an online or offline event. Representation of a project may be
+further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported by sending an email to devnet-github-owners@cisco.com. All
+complaints will be reviewed and investigated and will result in a response that
+is deemed necessary and appropriate to the circumstances. The project team is
+obligated to maintain confidentiality with regard to the reporter of an incident.
+Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good
+faith may face temporary or permanent repercussions as determined by other
+members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
+available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
+
+[homepage]: https://www.contributor-covenant.org
+
+For answers to common questions about this code of conduct, see
+https://www.contributor-covenant.org/faq
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 00000000..ae8b62db
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,76 @@
+# How to Contribute
+
+Thanks for your interest in contributing to this Terraform provider! Here are a few general guidelines on contributing and
+reporting bugs that we ask you to review. Following these guidelines helps to communicate that you respect the time of
+the contributors managing and developing this open source project. In return, they should reciprocate that respect in
+addressing your issue, assessing changes, and helping you finalize your pull requests. In that spirit of mutual respect,
+we endeavor to review incoming issues and pull requests within 10 days, and will close any lingering issues or pull
+requests after 60 days of inactivity.
+
+Please note that all of your interactions in the project are subject to our [Code of Conduct](/CODE_OF_CONDUCT.md). This
+includes creation of issues or pull requests, commenting on issues or pull requests, and extends to all interactions in
+any real-time space e.g., Slack, Discord, etc.
+
+## Table Of Contents
+
+- [Reporting Issues](#reporting-issues)
+- [Development](#development)
+    - [Building the Provider](#building-the-provider)
+    - [Acceptance Tests](#acceptance-tests)
+- [Sending Pull Requests](#sending-pull-requests)
+- [Other Ways to Contribute](#other-ways-to-contribute)
+
+## Reporting Issues
+
+Before reporting a new issue, please ensure that the issue was not already reported or fixed by searching through our
+[issues list](https://github.com/netascode/terraform-provider-meraki/issues).
+
+When creating a new issue, please be sure to include a **title and clear description**, as much relevant information as
+possible, and, if possible, a test case.
+
+**If you discover a security bug, please do not report it through GitHub. Instead, please see security procedures in
+[SECURITY.md](/SECURITY.md).**
+
+## Development
+
+### Building the Provider
+
+1. Clone the repository
+2. Enter the repository directory
+3. Build the provider using the Go `install` command:
+
+```shell
+go install
+```
+
+### Acceptance Tests
+
+In order to run the full suite of Acceptance tests, run `make testacc`. Make sure the respective environment variables are set (e.g., `MERAKI_DASHBOARD_API_KEY`).
+
+Note: Acceptance tests create real resources.
+
+```shell
+make testacc
+```
+
+## Sending Pull Requests
+
+Before sending a new pull request, take a look at existing pull requests and issues to see if the proposed change or fix
+has been discussed in the past, or if the change was already implemented but not yet released.
+
+We expect new pull requests to include tests for any affected behavior, and, as we follow semantic versioning, we may
+reserve breaking changes until the next major version release.
+
+## Other Ways to Contribute
+
+We welcome anyone that wants to contribute to this Terraform provider to triage and reply to open issues to help troubleshoot
+and fix existing bugs. Here is what you can do:
+
+- Help ensure that existing issues follows the recommendations from the _[Reporting Issues](#reporting-issues)_ section,
+  providing feedback to the issue's author on what might be missing.
+- Review existing pull requests, and testing patches against real infrastructure.
+- Write a test, or add a missing test case to an existing test.
+
+Thanks again for your interest on contributing to this Terraform provider!
+
+:heart:
diff --git a/GNUmakefile b/GNUmakefile
new file mode 100644
index 00000000..7771cd69
--- /dev/null
+++ b/GNUmakefile
@@ -0,0 +1,6 @@
+default: testacc
+
+# Run acceptance tests
+.PHONY: testacc
+testacc:
+	TF_ACC=1 go test ./... -v $(TESTARGS) -timeout 120m
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 00000000..a612ad98
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,373 @@
+Mozilla Public License Version 2.0
+==================================
+
+1. Definitions
+--------------
+
+1.1. "Contributor"
+    means each individual or legal entity that creates, contributes to
+    the creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+    means the combination of the Contributions of others (if any) used
+    by a Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+    means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+    means Source Code Form to which the initial Contributor has attached
+    the notice in Exhibit A, the Executable Form of such Source Code
+    Form, and Modifications of such Source Code Form, in each case
+    including portions thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+    means
+
+    (a) that the initial Contributor has attached the notice described
+        in Exhibit B to the Covered Software; or
+
+    (b) that the Covered Software was made available under the terms of
+        version 1.1 or earlier of the License, but not also under the
+        terms of a Secondary License.
+
+1.6. "Executable Form"
+    means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+    means a work that combines Covered Software with other material, in
+    a separate file or files, that is not Covered Software.
+
+1.8. "License"
+    means this document.
+
+1.9. "Licensable"
+    means having the right to grant, to the maximum extent possible,
+    whether at the time of the initial grant or subsequently, any and
+    all of the rights conveyed by this License.
+
+1.10. "Modifications"
+    means any of the following:
+
+    (a) any file in Source Code Form that results from an addition to,
+        deletion from, or modification of the contents of Covered
+        Software; or
+
+    (b) any new file in Source Code Form that contains any Covered
+        Software.
+
+1.11. "Patent Claims" of a Contributor
+    means any patent claim(s), including without limitation, method,
+    process, and apparatus claims, in any patent Licensable by such
+    Contributor that would be infringed, but for the grant of the
+    License, by the making, using, selling, offering for sale, having
+    made, import, or transfer of either its Contributions or its
+    Contributor Version.
+
+1.12. "Secondary License"
+    means either the GNU General Public License, Version 2.0, the GNU
+    Lesser General Public License, Version 2.1, the GNU Affero General
+    Public License, Version 3.0, or any later versions of those
+    licenses.
+
+1.13. "Source Code Form"
+    means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+    means an individual or a legal entity exercising rights under this
+    License. For legal entities, "You" includes any entity that
+    controls, is controlled by, or is under common control with You. For
+    purposes of this definition, "control" means (a) the power, direct
+    or indirect, to cause the direction or management of such entity,
+    whether by contract or otherwise, or (b) ownership of more than
+    fifty percent (50%) of the outstanding shares or beneficial
+    ownership of such entity.
+
+2. License Grants and Conditions
+--------------------------------
+
+2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark)
+    Licensable by such Contributor to use, reproduce, make available,
+    modify, display, perform, distribute, and otherwise exploit its
+    Contributions, either on an unmodified basis, with Modifications, or
+    as part of a Larger Work; and
+
+(b) under Patent Claims of such Contributor to make, use, sell, offer
+    for sale, have made, import, and otherwise transfer either its
+    Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+(a) for any code that a Contributor has removed from Covered Software;
+    or
+
+(b) for infringements caused by: (i) Your and any other third party's
+    modifications of Covered Software, or (ii) the combination of its
+    Contributions with other software (except as part of its Contributor
+    Version); or
+
+(c) under Patent Claims infringed by Covered Software in the absence of
+    its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+3. Responsibilities
+-------------------
+
+3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+(a) such Covered Software must also be made available in Source Code
+    Form, as described in Section 3.1, and You must inform recipients of
+    the Executable Form how they can obtain a copy of such Source Code
+    Form by reasonable means in a timely manner, at a charge no more
+    than the cost of distribution to the recipient; and
+
+(b) You may distribute such Executable Form under the terms of this
+    License, or sublicense it under different terms, provided that the
+    license for the Executable Form does not attempt to limit or alter
+    the recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+---------------------------------------------------
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: (a) comply with
+the terms of this License to the maximum extent possible; and (b)
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+5. Termination
+--------------
+
+5.1. The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated (a) provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and (b) on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+************************************************************************
+*                                                                      *
+*  6. Disclaimer of Warranty                                           *
+*  -------------------------                                           *
+*                                                                      *
+*  Covered Software is provided under this License on an "as is"       *
+*  basis, without warranty of any kind, either expressed, implied, or  *
+*  statutory, including, without limitation, warranties that the       *
+*  Covered Software is free of defects, merchantable, fit for a        *
+*  particular purpose or non-infringing. The entire risk as to the     *
+*  quality and performance of the Covered Software is with You.        *
+*  Should any Covered Software prove defective in any respect, You     *
+*  (not any Contributor) assume the cost of any necessary servicing,   *
+*  repair, or correction. This disclaimer of warranty constitutes an   *
+*  essential part of this License. No use of any Covered Software is   *
+*  authorized under this License except under this disclaimer.         *
+*                                                                      *
+************************************************************************
+
+************************************************************************
+*                                                                      *
+*  7. Limitation of Liability                                          *
+*  --------------------------                                          *
+*                                                                      *
+*  Under no circumstances and under no legal theory, whether tort      *
+*  (including negligence), contract, or otherwise, shall any           *
+*  Contributor, or anyone who distributes Covered Software as          *
+*  permitted above, be liable to You for any direct, indirect,         *
+*  special, incidental, or consequential damages of any character      *
+*  including, without limitation, damages for lost profits, loss of    *
+*  goodwill, work stoppage, computer failure or malfunction, or any    *
+*  and all other commercial damages or losses, even if such party      *
+*  shall have been informed of the possibility of such damages. This   *
+*  limitation of liability shall not apply to liability for death or   *
+*  personal injury resulting from such party's negligence to the       *
+*  extent applicable law prohibits such limitation. Some               *
+*  jurisdictions do not allow the exclusion or limitation of           *
+*  incidental or consequential damages, so this exclusion and          *
+*  limitation may not apply to You.                                    *
+*                                                                      *
+************************************************************************
+
+8. Litigation
+-------------
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+9. Miscellaneous
+----------------
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+10. Versions of the License
+---------------------------
+
+10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+-------------------------------------------
+
+  This Source Code Form is subject to the terms of the Mozilla Public
+  License, v. 2.0. If a copy of the MPL was not distributed with this
+  file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+---------------------------------------------------------
+
+  This Source Code Form is "Incompatible With Secondary Licenses", as
+  defined by the Mozilla Public License, v. 2.0.
diff --git a/README.md b/README.md
new file mode 100644
index 00000000..eedab971
--- /dev/null
+++ b/README.md
@@ -0,0 +1,68 @@
+[![Tests](https://github.com/netascode/terraform-provider-meraki/actions/workflows/test.yml/badge.svg)](https://github.com/netascode/terraform-provider-meraki/actions/workflows/test.yml)
+
+# Terraform Provider Meraki
+
+The Meraki provider provides resources to interact with a Cisco Meraki Dashboard. It communicates with Meraki Dashboard via the REST API.
+
+All resources and data sources have been tested with the following API releases.
+
+| API | Version |
+| ---------------- | ------- |
+| Meraki Dashboard | 1.49    |
+
+Documentation: <https://registry.terraform.io/providers/netascode/meraki/latest>
+
+## Requirements
+
+- [Terraform](https://www.terraform.io/downloads.html) >= 1.0
+- [Go](https://golang.org/doc/install) >= 1.22
+
+## Building The Provider
+
+1. Clone the repository
+2. Enter the repository directory
+3. Build the provider using the Go `install` command:
+
+```shell
+go install
+```
+
+## Adding Dependencies
+
+This provider uses [Go modules](https://github.com/golang/go/wiki/Modules).
+Please see the Go documentation for the most up to date information about using Go modules.
+
+To add a new dependency `github.com/author/dependency` to your Terraform provider:
+
+```shell
+go get github.com/author/dependency
+go mod tidy
+```
+
+Then commit the changes to `go.mod` and `go.sum`.
+
+## Using the provider
+
+This Terraform Provider is available to install automatically via `terraform init`. If you're building the provider, follow the instructions to
+[install it as a plugin.](https://www.terraform.io/docs/plugins/basics.html#installing-a-plugin)
+After placing it into your plugins directory,  run `terraform init` to initialize it.
+
+Additional documentation, including available resources and their arguments/attributes can be found on the [Terraform documentation website](https://registry.terraform.io/providers/netascode/meraki/latest/docs).
+
+## Developing the Provider
+
+If you wish to work on the provider, you'll first need [Go](http://www.golang.org) installed on your machine (see [Requirements](#requirements) above).
+
+To compile the provider, run `go install`. This will build the provider and put the provider binary in the `$GOPATH/bin` directory.
+
+To generate or update documentation, run `go generate`.
+
+## Acceptance tests
+
+In order to run the full suite of Acceptance tests, run `make testacc`. Make sure the respective environment variables are set (e.g., `MERAKI_DASHBOARD_API_KEY`).
+
+Note: Acceptance tests create real resources.
+
+```shell
+make testacc
+```
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 00000000..16e7837f
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,38 @@
+# Security Policies and Procedures
+
+This document outlines security procedures and general policies for this project.
+
+- [Reporting a Bug](#reporting-a-bug)
+- [Disclosure Policy](#disclosure-policy)
+- [Comments on this Policy](#comments-on-this-policy)
+
+## Reporting a Bug
+
+The team and community take all security bugs in this project seriously. Thank
+you for improving the security of this project. We appreciate your efforts and
+responsible disclosure and will make every effort to acknowledge your
+contributions.
+
+Report security bugs by emailing `oss-security@cisco.com`.
+
+The lead maintainer will acknowledge your email within 48 hours, and will send a
+more detailed response within 48 hours indicating the next steps in handling
+your report. After the initial reply to your report, the security team will
+endeavor to keep you informed of the progress towards a fix and full
+announcement, and may ask for additional information or guidance.
+
+## Disclosure Policy
+
+When the security team receives a security bug report, they will assign it to a
+primary handler. This person will coordinate the fix and release process,
+involving the following steps:
+
+- Confirm the problem and determine the affected versions.
+- Audit code to find any potential similar problems.
+- Prepare fixes for all releases still under maintenance. These fixes will be
+  released as quickly as possible.
+
+## Comments on this Policy
+
+If you have suggestions on how this process could be improved please submit a
+pull request.
diff --git a/docs/data-sources/admin.md b/docs/data-sources/admin.md
new file mode 100644
index 00000000..172532ea
--- /dev/null
+++ b/docs/data-sources/admin.md
@@ -0,0 +1,56 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "meraki_admin Data Source - terraform-provider-meraki"
+subcategory: "Organizations"
+description: |-
+  This data source can read the Admin configuration.
+---
+
+# meraki_admin (Data Source)
+
+This data source can read the `Admin` configuration.
+
+## Example Usage
+
+```terraform
+data "meraki_admin" "example" {
+  id              = "12345678"
+  organization_id = "123456"
+}
+```
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Required
+
+- `organization_id` (String) Organization ID
+
+### Optional
+
+- `id` (String) The id of the object
+- `name` (String) The name of the dashboard administrator
+
+### Read-Only
+
+- `email` (String) The email of the dashboard administrator. This attribute can not be updated.
+- `networks` (Attributes List) The list of networks that the dashboard administrator has privileges on (see [below for nested schema](#nestedatt--networks))
+- `org_access` (String) The privilege of the dashboard administrator on the organization. Can be one of `full`, `read-only`, `enterprise` or `none`
+- `tags` (Attributes List) The list of tags that the dashboard administrator has privileges on (see [below for nested schema](#nestedatt--tags))
+
+<a id="nestedatt--networks"></a>
+### Nested Schema for `networks`
+
+Read-Only:
+
+- `access` (String) The privilege of the dashboard administrator on the network. Can be one of `full`, `read-only`, `guest-ambassador` or `monitor-only`
+- `id` (String) The network ID
+
+
+<a id="nestedatt--tags"></a>
+### Nested Schema for `tags`
+
+Read-Only:
+
+- `access` (String) The privilege of the dashboard administrator on the tag. Can be one of `full`, `read-only`, `guest-ambassador` or `monitor-only`
+- `tag` (String) The name of the tag
diff --git a/docs/data-sources/network.md b/docs/data-sources/network.md
new file mode 100644
index 00000000..cb60937e
--- /dev/null
+++ b/docs/data-sources/network.md
@@ -0,0 +1,39 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "meraki_network Data Source - terraform-provider-meraki"
+subcategory: "Networks"
+description: |-
+  This data source can read the Network configuration.
+---
+
+# meraki_network (Data Source)
+
+This data source can read the `Network` configuration.
+
+## Example Usage
+
+```terraform
+data "meraki_network" "example" {
+  id              = "12345678"
+  organization_id = "123456"
+}
+```
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Required
+
+- `organization_id` (String) Organization ID
+
+### Optional
+
+- `id` (String) The id of the object
+- `name` (String) The name of the new network
+
+### Read-Only
+
+- `notes` (String) Add any notes or additional information about this network here.
+- `product_types` (List of String) The product type(s) of the new network. If more than one type is included, the network will be a combined network.
+- `tags` (List of String) A list of tags to be applied to the network
+- `time_zone` (String) The timezone of the network. For a list of allowed timezones, please see the 'TZ' column in the table in this article.
diff --git a/docs/data-sources/organization.md b/docs/data-sources/organization.md
new file mode 100644
index 00000000..9766e634
--- /dev/null
+++ b/docs/data-sources/organization.md
@@ -0,0 +1,39 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "meraki_organization Data Source - terraform-provider-meraki"
+subcategory: "Organizations"
+description: |-
+  This data source can read the Organization configuration.
+---
+
+# meraki_organization (Data Source)
+
+This data source can read the `Organization` configuration.
+
+## Example Usage
+
+```terraform
+data "meraki_organization" "example" {
+  id = "12345678"
+}
+```
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Optional
+
+- `id` (String) The id of the object
+- `name` (String) The name of the organization
+
+### Read-Only
+
+- `management_details` (Attributes List) Details related to organization management, possibly empty (see [below for nested schema](#nestedatt--management_details))
+
+<a id="nestedatt--management_details"></a>
+### Nested Schema for `management_details`
+
+Read-Only:
+
+- `name` (String) Name of management data
+- `value` (String) Value of management data
diff --git a/docs/guides/changelog.md b/docs/guides/changelog.md
new file mode 100644
index 00000000..19ba619f
--- /dev/null
+++ b/docs/guides/changelog.md
@@ -0,0 +1,13 @@
+---
+subcategory: "Guides"
+page_title: "Changelog"
+description: |-
+    Changelog
+---
+
+# Changelog
+
+## 0.1.0 (unreleased)
+
+- Initial release
+
diff --git a/docs/index.md b/docs/index.md
new file mode 100644
index 00000000..08569e57
--- /dev/null
+++ b/docs/index.md
@@ -0,0 +1,36 @@
+
+---
+layout: ""
+page_title: "Provider: Meraki"
+description: |-
+  The Meraki provider provides resources to interact with Cisco Meraki Dashboard.
+
+---
+
+# Meraki Provider
+
+The Meraki provider provides resources to interact with a Cisco Meraki Dashboard. It communicates with Meraki Dashboard via the REST API.
+
+All resources and data sources have been tested with the following API releases.
+
+| API | Version |
+| ---------------- | ------- |
+| Meraki Dashboard | 1.49    |
+
+## Example Usage
+
+```terraform
+provider "meraki" {
+  api_key = "abc123"
+}
+```
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Optional
+
+- `api_key` (String, Sensitive) Meraki Dashboard API key. This can also be set as the MERAKI_API_KEY environment variable.
+- `base_url` (String) Base URL to be used. The default value is `https://api.meraki.com/api/v1`. This can also be set as the MERAKI_BASE_URL environment variable.
+- `req_timeout` (String) Timeout for a single HTTPS request made to REST API before it is retried. This can also be set as the MERAKI_REQTIMEOUT environment variable. A string like `"1s"` means one second. Defaults to `"5s"`.
+- `retries` (Number) Number of retries for REST API calls. This can also be set as the MERAKI_RETRIES environment variable. Defaults to `3`.
diff --git a/docs/resources/admin.md b/docs/resources/admin.md
new file mode 100644
index 00000000..8f810a74
--- /dev/null
+++ b/docs/resources/admin.md
@@ -0,0 +1,81 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "meraki_admin Resource - terraform-provider-meraki"
+subcategory: "Organizations"
+description: |-
+  This resource can manage the Admin configuration.
+---
+
+# meraki_admin (Resource)
+
+This resource can manage the `Admin` configuration.
+
+## Example Usage
+
+```terraform
+resource "meraki_admin" "example" {
+  organization_id = "123456"
+  email           = "miles@meraki.com"
+  name            = "Miles Meraki"
+  org_access      = "none"
+  networks = [
+    {
+      access = "full"
+      id     = "N_24329156"
+    }
+  ]
+  tags = [
+    {
+      access = "read-only"
+      tag    = "west"
+    }
+  ]
+}
+```
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Required
+
+- `email` (String) The email of the dashboard administrator. This attribute can not be updated.
+- `name` (String) The name of the dashboard administrator
+- `org_access` (String) The privilege of the dashboard administrator on the organization. Can be one of `full`, `read-only`, `enterprise` or `none`
+  - Choices: `full`, `read-only`, `enterprise`, `none`
+- `organization_id` (String) Organization ID
+
+### Optional
+
+- `networks` (Attributes List) The list of networks that the dashboard administrator has privileges on (see [below for nested schema](#nestedatt--networks))
+- `tags` (Attributes List) The list of tags that the dashboard administrator has privileges on (see [below for nested schema](#nestedatt--tags))
+
+### Read-Only
+
+- `id` (String) The id of the object
+
+<a id="nestedatt--networks"></a>
+### Nested Schema for `networks`
+
+Required:
+
+- `access` (String) The privilege of the dashboard administrator on the network. Can be one of `full`, `read-only`, `guest-ambassador` or `monitor-only`
+  - Choices: `full`, `read-only`, `guest-ambassador`, `monitor-only`
+- `id` (String) The network ID
+
+
+<a id="nestedatt--tags"></a>
+### Nested Schema for `tags`
+
+Required:
+
+- `access` (String) The privilege of the dashboard administrator on the tag. Can be one of `full`, `read-only`, `guest-ambassador` or `monitor-only`
+  - Choices: `full`, `read-only`, `guest-ambassador`, `monitor-only`
+- `tag` (String) The name of the tag
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+terraform import meraki_admin.example "<organization_id>,<id>"
+```
diff --git a/docs/resources/network.md b/docs/resources/network.md
new file mode 100644
index 00000000..9fedce76
--- /dev/null
+++ b/docs/resources/network.md
@@ -0,0 +1,51 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "meraki_network Resource - terraform-provider-meraki"
+subcategory: "Networks"
+description: |-
+  This resource can manage the Network configuration.
+---
+
+# meraki_network (Resource)
+
+This resource can manage the `Network` configuration.
+
+## Example Usage
+
+```terraform
+resource "meraki_network" "example" {
+  organization_id = "123456"
+  name            = "Main Office"
+  notes           = "Additional description of the network"
+  time_zone       = "America/Los_Angeles"
+  product_types   = ["switch"]
+  tags            = ["tag1"]
+}
+```
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Required
+
+- `name` (String) The name of the new network
+- `organization_id` (String) Organization ID
+- `product_types` (List of String) The product type(s) of the new network. If more than one type is included, the network will be a combined network.
+
+### Optional
+
+- `notes` (String) Add any notes or additional information about this network here.
+- `tags` (List of String) A list of tags to be applied to the network
+- `time_zone` (String) The timezone of the network. For a list of allowed timezones, please see the 'TZ' column in the table in this article.
+
+### Read-Only
+
+- `id` (String) The id of the object
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+terraform import meraki_network.example "<organization_id>,<id>"
+```
diff --git a/docs/resources/organization.md b/docs/resources/organization.md
new file mode 100644
index 00000000..226abdcb
--- /dev/null
+++ b/docs/resources/organization.md
@@ -0,0 +1,56 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "meraki_organization Resource - terraform-provider-meraki"
+subcategory: "Organizations"
+description: |-
+  This resource can manage the Organization configuration.
+---
+
+# meraki_organization (Resource)
+
+This resource can manage the `Organization` configuration.
+
+## Example Usage
+
+```terraform
+resource "meraki_organization" "example" {
+  name = "My organization"
+  management_details = [
+    {
+      name  = "MSP ID"
+      value = "123456"
+    }
+  ]
+}
+```
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Required
+
+- `name` (String) The name of the organization
+
+### Optional
+
+- `management_details` (Attributes List) Details related to organization management, possibly empty (see [below for nested schema](#nestedatt--management_details))
+
+### Read-Only
+
+- `id` (String) The id of the object
+
+<a id="nestedatt--management_details"></a>
+### Nested Schema for `management_details`
+
+Required:
+
+- `name` (String) Name of management data
+- `value` (String) Value of management data
+
+## Import
+
+Import is supported using the following syntax:
+
+```shell
+terraform import meraki_organization.example "<id>"
+```
diff --git a/examples/README.md b/examples/README.md
new file mode 100644
index 00000000..026c42c7
--- /dev/null
+++ b/examples/README.md
@@ -0,0 +1,9 @@
+# Examples
+
+This directory contains examples that are mostly used for documentation, but can also be run/tested manually via the Terraform CLI.
+
+The document generation tool looks for files in the following locations by default. All other *.tf files besides the ones mentioned below are ignored by the documentation tool. This is useful for creating examples that can run and/or ar testable even if some parts are not relevant for the documentation.
+
+* **provider/provider.tf** example file for the provider index page
+* **data-sources/`full data source name`/data-source.tf** example file for the named data source page
+* **resources/`full resource name`/resource.tf** example file for the named data source page
diff --git a/examples/data-sources/meraki_admin/data-source.tf b/examples/data-sources/meraki_admin/data-source.tf
new file mode 100644
index 00000000..986cc7c9
--- /dev/null
+++ b/examples/data-sources/meraki_admin/data-source.tf
@@ -0,0 +1,4 @@
+data "meraki_admin" "example" {
+  id              = "12345678"
+  organization_id = "123456"
+}
diff --git a/examples/data-sources/meraki_network/data-source.tf b/examples/data-sources/meraki_network/data-source.tf
new file mode 100644
index 00000000..e85b616c
--- /dev/null
+++ b/examples/data-sources/meraki_network/data-source.tf
@@ -0,0 +1,4 @@
+data "meraki_network" "example" {
+  id              = "12345678"
+  organization_id = "123456"
+}
diff --git a/examples/data-sources/meraki_organization/data-source.tf b/examples/data-sources/meraki_organization/data-source.tf
new file mode 100644
index 00000000..2a6280b8
--- /dev/null
+++ b/examples/data-sources/meraki_organization/data-source.tf
@@ -0,0 +1,3 @@
+data "meraki_organization" "example" {
+  id = "12345678"
+}
diff --git a/examples/provider/provider.tf b/examples/provider/provider.tf
new file mode 100644
index 00000000..57ec0121
--- /dev/null
+++ b/examples/provider/provider.tf
@@ -0,0 +1,3 @@
+provider "meraki" {
+  api_key = "abc123"
+}
diff --git a/examples/resources/meraki_admin/import.sh b/examples/resources/meraki_admin/import.sh
new file mode 100644
index 00000000..d885b116
--- /dev/null
+++ b/examples/resources/meraki_admin/import.sh
@@ -0,0 +1 @@
+terraform import meraki_admin.example "<organization_id>,<id>"
diff --git a/examples/resources/meraki_admin/resource.tf b/examples/resources/meraki_admin/resource.tf
new file mode 100644
index 00000000..d34bed07
--- /dev/null
+++ b/examples/resources/meraki_admin/resource.tf
@@ -0,0 +1,18 @@
+resource "meraki_admin" "example" {
+  organization_id = "123456"
+  email           = "miles@meraki.com"
+  name            = "Miles Meraki"
+  org_access      = "none"
+  networks = [
+    {
+      access = "full"
+      id     = "N_24329156"
+    }
+  ]
+  tags = [
+    {
+      access = "read-only"
+      tag    = "west"
+    }
+  ]
+}
diff --git a/examples/resources/meraki_network/import.sh b/examples/resources/meraki_network/import.sh
new file mode 100644
index 00000000..44bacf8e
--- /dev/null
+++ b/examples/resources/meraki_network/import.sh
@@ -0,0 +1 @@
+terraform import meraki_network.example "<organization_id>,<id>"
diff --git a/examples/resources/meraki_network/resource.tf b/examples/resources/meraki_network/resource.tf
new file mode 100644
index 00000000..2881df6a
--- /dev/null
+++ b/examples/resources/meraki_network/resource.tf
@@ -0,0 +1,8 @@
+resource "meraki_network" "example" {
+  organization_id = "123456"
+  name            = "Main Office"
+  notes           = "Additional description of the network"
+  time_zone       = "America/Los_Angeles"
+  product_types   = ["switch"]
+  tags            = ["tag1"]
+}
diff --git a/examples/resources/meraki_organization/import.sh b/examples/resources/meraki_organization/import.sh
new file mode 100644
index 00000000..748e862f
--- /dev/null
+++ b/examples/resources/meraki_organization/import.sh
@@ -0,0 +1 @@
+terraform import meraki_organization.example "<id>"
diff --git a/examples/resources/meraki_organization/resource.tf b/examples/resources/meraki_organization/resource.tf
new file mode 100644
index 00000000..586604b6
--- /dev/null
+++ b/examples/resources/meraki_organization/resource.tf
@@ -0,0 +1,9 @@
+resource "meraki_organization" "example" {
+  name = "My organization"
+  management_details = [
+    {
+      name  = "MSP ID"
+      value = "123456"
+    }
+  ]
+}
diff --git a/gen/definitions/admin.yaml b/gen/definitions/admin.yaml
new file mode 100644
index 00000000..9ac54480
--- /dev/null
+++ b/gen/definitions/admin.yaml
@@ -0,0 +1,70 @@
+---
+name: Admin
+rest_endpoint: /organizations/%v/admins
+get_from_all: true
+data_source_name_query: true
+doc_category: Organizations
+attributes:
+  - tf_name: organization_id
+    type: String
+    reference: true
+    description: Organization ID
+    example: 123456
+    test_value: data.meraki_organization.test.id
+  - model_name: email
+    type: String
+    mandatory: true
+    description: The email of the dashboard administrator. This attribute can not be updated.
+    example: miles@meraki.com
+  - model_name: name
+    type: String
+    mandatory: true
+    description: The name of the dashboard administrator
+    example: Miles Meraki
+  - model_name: orgAccess
+    type: String
+    mandatory: true
+    description: The privilege of the dashboard administrator on the organization. Can be one of `full`, `read-only`, `enterprise` or `none`
+    enum_values: [full, read-only, enterprise, none]
+    example: none
+    minimum_test_value: '"full"'
+  - model_name: networks
+    type: List
+    description: The list of networks that the dashboard administrator has privileges on
+    attributes:
+      - model_name: access
+        type: String
+        mandatory: true
+        description: The privilege of the dashboard administrator on the network. Can be one of `full`, `read-only`, `guest-ambassador` or `monitor-only`
+        enum_values: [full, read-only, guest-ambassador, monitor-only]
+        example: full
+      - model_name: id
+        type: String
+        mandatory: true
+        description: The network ID
+        example: N_24329156
+        test_value: meraki_network.test.id
+  - model_name: tags
+    type: List
+    description: The list of tags that the dashboard administrator has privileges on
+    attributes:
+      - model_name: access
+        type: String
+        mandatory: true
+        description: The privilege of the dashboard administrator on the tag. Can be one of `full`, `read-only`, `guest-ambassador` or `monitor-only`
+        enum_values: [full, read-only, guest-ambassador, monitor-only]
+        example: read-only
+      - model_name: tag
+        type: String
+        mandatory: true
+        description: The name of the tag
+        example: west
+test_prerequisites: |
+  data "meraki_organization" "test" {
+    name = "TF Test"
+  }
+  resource "meraki_network" "test" {
+    organization_id = data.meraki_organization.test.id
+    name            = "Network1"
+    product_types   = ["switch"]
+  }
diff --git a/gen/definitions/network.yaml b/gen/definitions/network.yaml
new file mode 100644
index 00000000..74130f81
--- /dev/null
+++ b/gen/definitions/network.yaml
@@ -0,0 +1,40 @@
+---
+name: Network
+rest_endpoint: /organizations/%v/networks
+data_source_name_query: true
+doc_category: Networks
+attributes:
+  - tf_name: organization_id
+    type: String
+    reference: true
+    description: Organization ID
+    example: 123456
+    test_value: data.meraki_organization.test.id
+  - model_name: name
+    type: String
+    mandatory: true
+    description: The name of the new network
+    example: Main Office
+  - model_name: notes
+    type: String
+    description: Add any notes or additional information about this network here.
+    example: Additional description of the network
+  - model_name: timeZone
+    type: String
+    description: The timezone of the network. For a list of allowed timezones, please see the 'TZ' column in the table in this article.
+    example: America/Los_Angeles
+  - model_name: productTypes
+    type: List
+    element_type: String
+    mandatory: true
+    description: The product type(s) of the new network. If more than one type is included, the network will be a combined network.
+    example: switch
+  - model_name: tags
+    type: List
+    element_type: String
+    description: A list of tags to be applied to the network
+    example: tag1
+test_prerequisites: |
+  data "meraki_organization" "test" {
+    name = "TF Test"
+  }
diff --git a/gen/definitions/organization.yaml b/gen/definitions/organization.yaml
new file mode 100644
index 00000000..88186605
--- /dev/null
+++ b/gen/definitions/organization.yaml
@@ -0,0 +1,27 @@
+---
+name: Organization
+rest_endpoint: /organizations
+data_source_name_query: true
+doc_category: Organizations
+attributes:
+  - model_name: name
+    type: String
+    mandatory: true
+    description: The name of the organization
+    example: My organization
+  - model_name: details
+    data_path: [management]
+    description: Details related to organization management, possibly empty
+    type: List
+    attributes:
+      - model_name: name
+        type: String
+        mandatory: true
+        id: true
+        description: Name of management data
+        example: MSP ID
+      - model_name: value
+        type: String
+        mandatory: true
+        description: Value of management data
+        example: 123456
diff --git a/gen/doc_category.go b/gen/doc_category.go
new file mode 100644
index 00000000..9adc48c9
--- /dev/null
+++ b/gen/doc_category.go
@@ -0,0 +1,104 @@
+// Copyright © 2024 Cisco Systems, Inc. and its affiliates.
+// All rights reserved.
+//
+// Licensed under the Mozilla Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://mozilla.org/MPL/2.0/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+//go:build ignore
+
+package main
+
+import (
+	"log"
+	"os"
+	"path/filepath"
+	"strings"
+
+	"gopkg.in/yaml.v3"
+)
+
+const (
+	definitionsPath = "./gen/definitions/"
+)
+
+type YamlConfig struct {
+	Name        string `yaml:"name"`
+	DocCategory string `yaml:"doc_category"`
+}
+
+var docPaths = []string{"./docs/data-sources/", "./docs/resources/"}
+
+var extraDocs = map[string]string{}
+
+func SnakeCase(s string) string {
+	var g []string
+
+	p := strings.Fields(s)
+
+	for _, value := range p {
+		g = append(g, strings.ToLower(value))
+	}
+	return strings.Join(g, "_")
+}
+
+func main() {
+	files, _ := os.ReadDir(definitionsPath)
+	configs := make([]YamlConfig, len(files))
+
+	// Load configs
+	for i, filename := range files {
+		yamlFile, err := os.ReadFile(filepath.Join(definitionsPath, filename.Name()))
+		if err != nil {
+			log.Fatalf("Error reading file: %v", err)
+		}
+
+		config := YamlConfig{}
+		err = yaml.Unmarshal(yamlFile, &config)
+		if err != nil {
+			log.Fatalf("Error parsing yaml: %v", err)
+		}
+		configs[i] = config
+	}
+
+	// Update doc category
+	for i := range configs {
+		for _, path := range docPaths {
+			filename := path + SnakeCase(configs[i].Name) + ".md"
+			content, err := os.ReadFile(filename)
+			if err != nil {
+				log.Fatalf("Error opening documentation: %v", err)
+			}
+
+			cat := configs[i].DocCategory
+			s := string(content)
+			s = strings.ReplaceAll(s, `subcategory: ""`, `subcategory: "`+cat+`"`)
+
+			os.WriteFile(filename, []byte(s), 0644)
+		}
+	}
+
+	// Update extra doc categories
+	for doc, cat := range extraDocs {
+		for _, path := range docPaths {
+			filename := path + doc + ".md"
+			content, err := os.ReadFile(filename)
+			if err == nil {
+				s := string(content)
+				s = strings.ReplaceAll(s, `subcategory: ""`, `subcategory: "`+cat+`"`)
+
+				os.WriteFile(filename, []byte(s), 0644)
+			}
+		}
+	}
+}
diff --git a/gen/generator.go b/gen/generator.go
new file mode 100644
index 00000000..72c071b9
--- /dev/null
+++ b/gen/generator.go
@@ -0,0 +1,585 @@
+// Copyright © 2024 Cisco Systems, Inc. and its affiliates.
+// All rights reserved.
+//
+// Licensed under the Mozilla Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://mozilla.org/MPL/2.0/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+//go:build ignore
+
+package main
+
+import (
+	"bufio"
+	"bytes"
+	"fmt"
+	"log"
+	"os"
+	"path"
+	"path/filepath"
+	"regexp"
+	"strings"
+	"text/template"
+	"unicode"
+
+	"gopkg.in/yaml.v3"
+)
+
+const (
+	definitionsPath   = "./gen/definitions/"
+	providerTemplate  = "./gen/templates/provider.go"
+	providerLocation  = "./internal/provider/provider.go"
+	changelogTemplate = "./gen/templates/changelog.md.tmpl"
+	changelogLocation = "./templates/guides/changelog.md.tmpl"
+	changelogOriginal = "./CHANGELOG.md"
+)
+
+type t struct {
+	path   string
+	prefix string
+	suffix string
+}
+
+var templates = []t{
+	{
+		path:   "./gen/templates/model.go",
+		prefix: "./internal/provider/model_meraki_",
+		suffix: ".go",
+	},
+	{
+		path:   "./gen/templates/data_source.go",
+		prefix: "./internal/provider/data_source_meraki_",
+		suffix: ".go",
+	},
+	{
+		path:   "./gen/templates/data_source_test.go",
+		prefix: "./internal/provider/data_source_meraki_",
+		suffix: "_test.go",
+	},
+	{
+		path:   "./gen/templates/resource.go",
+		prefix: "./internal/provider/resource_meraki_",
+		suffix: ".go",
+	},
+	{
+		path:   "./gen/templates/resource_test.go",
+		prefix: "./internal/provider/resource_meraki_",
+		suffix: "_test.go",
+	},
+	{
+		path:   "./gen/templates/data-source.tf",
+		prefix: "./examples/data-sources/meraki_",
+		suffix: "/data-source.tf",
+	},
+	{
+		path:   "./gen/templates/resource.tf",
+		prefix: "./examples/resources/meraki_",
+		suffix: "/resource.tf",
+	},
+	{
+		path:   "./gen/templates/import.sh",
+		prefix: "./examples/resources/meraki_",
+		suffix: "/import.sh",
+	},
+}
+
+type YamlConfig struct {
+	Name                string                `yaml:"name"`
+	TfName              string                `yaml:"tf_name"`
+	RestEndpoint        string                `yaml:"rest_endpoint"`
+	PutCreate           bool                  `yaml:"put_create"`
+	GetFromAll          bool                  `yaml:"get_from_all"`
+	NoUpdate            bool                  `yaml:"no_update"`
+	NoDelete            bool                  `yaml:"no_delete"`
+	DataSourceNameQuery bool                  `yaml:"data_source_name_query"`
+	MinimumVersion      string                `yaml:"minimum_version"`
+	DsDescription       string                `yaml:"ds_description"`
+	ResDescription      string                `yaml:"res_description"`
+	DocCategory         string                `yaml:"doc_category"`
+	ExcludeTest         bool                  `yaml:"exclude_test"`
+	SkipMinimumTest     bool                  `yaml:"skip_minimum_test"`
+	Attributes          []YamlConfigAttribute `yaml:"attributes"`
+	TestTags            []string              `yaml:"test_tags"`
+	TestPrerequisites   string                `yaml:"test_prerequisites"`
+}
+
+type YamlConfigAttribute struct {
+	ModelName        string                `yaml:"model_name"`
+	TfName           string                `yaml:"tf_name"`
+	Type             string                `yaml:"type"`
+	ElementType      string                `yaml:"element_type"`
+	DataPath         []string              `yaml:"data_path"`
+	Id               bool                  `yaml:"id"`
+	ResourceId       bool                  `yaml:"resource_id"`
+	Reference        bool                  `yaml:"reference"`
+	RequiresReplace  bool                  `yaml:"requires_replace"`
+	Mandatory        bool                  `yaml:"mandatory"`
+	WriteOnly        bool                  `yaml:"write_only"`
+	WriteChangesOnly bool                  `yaml:"write_changes_only"`
+	ExcludeTest      bool                  `yaml:"exclude_test"`
+	ExcludeExample   bool                  `yaml:"exclude_example"`
+	Description      string                `yaml:"description"`
+	Example          string                `yaml:"example"`
+	EnumValues       []string              `yaml:"enum_values"`
+	MinList          int64                 `yaml:"min_list"`
+	MaxList          int64                 `yaml:"max_list"`
+	MinInt           int64                 `yaml:"min_int"`
+	MaxInt           int64                 `yaml:"max_int"`
+	MinFloat         float64               `yaml:"min_float"`
+	MaxFloat         float64               `yaml:"max_float"`
+	MapKeyExample    string                `yaml:"map_key_example"`
+	OrderedList      bool                  `yaml:"ordered_list"`
+	StringPatterns   []string              `yaml:"string_patterns"`
+	StringMinLength  int64                 `yaml:"string_min_length"`
+	StringMaxLength  int64                 `yaml:"string_max_length"`
+	DefaultValue     string                `yaml:"default_value"`
+	Value            string                `yaml:"value"`
+	TestValue        string                `yaml:"test_value"`
+	MinimumTestValue string                `yaml:"minimum_test_value"`
+	TestTags         []string              `yaml:"test_tags"`
+	Attributes       []YamlConfigAttribute `yaml:"attributes"`
+	GoTypeName       string
+}
+
+// Templating helper function to convert TF name to GO name
+func ToGoName(s string) string {
+	var g []string
+
+	p := strings.Split(s, "_")
+
+	for _, value := range p {
+		g = append(g, strings.Title(value))
+	}
+	s = strings.Join(g, "")
+	return s
+}
+
+// Templating helper function to convert string to camel case
+func CamelCase(s string) string {
+	var g []string
+
+	s = strings.ReplaceAll(s, "-", " ")
+	p := strings.Fields(s)
+
+	for _, value := range p {
+		g = append(g, strings.Title(value))
+	}
+	return strings.Join(g, "")
+}
+
+// Templating helper function to convert string to snake case
+func SnakeCase(s string) string {
+	var g []string
+
+	s = strings.ReplaceAll(s, "-", " ")
+	p := strings.Fields(s)
+
+	for _, value := range p {
+		g = append(g, strings.ToLower(value))
+	}
+	return strings.Join(g, "_")
+}
+
+// Templating helper function to fail a template mid-way
+func Errorf(s string, args ...any) (struct{}, error) {
+	return struct{}{}, fmt.Errorf(s, args...)
+}
+
+// Templating helper function to build a SJSON path
+func BuildPath(s []string) string {
+	return strings.Join(s, ".")
+}
+
+func contains(s []string, str string) bool {
+	for _, v := range s {
+		if v == str {
+			return true
+		}
+	}
+	return false
+}
+
+// Templating helper function to return true if id included in attributes
+func HasId(attributes []YamlConfigAttribute) bool {
+	for _, attr := range attributes {
+		if attr.Id {
+			return true
+		}
+	}
+	return false
+}
+
+// Templating helper function to return true if reference included in attributes
+func HasReference(attributes []YamlConfigAttribute) bool {
+	for _, attr := range attributes {
+		if attr.Reference {
+			return true
+		}
+	}
+	return false
+}
+
+// Templating helper function to return true if reference included in attributes
+func HasResourceId(attributes []YamlConfigAttribute) bool {
+	for _, attr := range attributes {
+		if attr.ResourceId {
+			return true
+		}
+		if len(attr.Attributes) > 0 {
+			if HasResourceId(attr.Attributes) {
+				return true
+			}
+		}
+	}
+	return false
+}
+
+// Templating helper function to return true if type is a list or set without nested elements
+func IsListSet(attribute YamlConfigAttribute) bool {
+	if (attribute.Type == "List" || attribute.Type == "Set") && attribute.ElementType != "" {
+		return true
+	}
+	return false
+}
+
+// Templating helper function to return true if type is a list without nested elements
+func IsList(attribute YamlConfigAttribute) bool {
+	if attribute.Type == "List" && attribute.ElementType != "" {
+		return true
+	}
+	return false
+}
+
+// Templating helper function to return true if type is a set without nested elements
+func IsSet(attribute YamlConfigAttribute) bool {
+	if attribute.Type == "Set" && attribute.ElementType != "" {
+		return true
+	}
+	return false
+}
+
+// Templating helper function to return true if type is a list or set of strings without nested elements
+func IsStringListSet(attribute YamlConfigAttribute) bool {
+	if (attribute.Type == "List" || attribute.Type == "Set") && attribute.ElementType == "String" {
+		return true
+	}
+	return false
+}
+
+// Templating helper function to return true if type is a list or set of integers without nested elements
+func IsInt64ListSet(attribute YamlConfigAttribute) bool {
+	if (attribute.Type == "List" || attribute.Type == "Set") && attribute.ElementType == "Int64" {
+		return true
+	}
+	return false
+}
+
+// Templating helper function to return true if type is a list or a map or a set, anyway with nested elements
+func IsNestedListMapSet(attribute YamlConfigAttribute) bool {
+	if (attribute.Type == "List" || attribute.Type == "Map" || attribute.Type == "Set") && attribute.ElementType == "" {
+		return true
+	}
+	return false
+}
+
+// Templating helper function to return true if type is a list or set with nested elements
+func IsNestedListSet(attribute YamlConfigAttribute) bool {
+	if (attribute.Type == "List" || attribute.Type == "Set") && attribute.ElementType == "" {
+		return true
+	}
+	return false
+}
+
+// Templating helper function to return true if type is a list with nested elements
+func IsNestedList(attribute YamlConfigAttribute) bool {
+	if attribute.Type == "List" && attribute.ElementType == "" {
+		return true
+	}
+	return false
+}
+
+// Templating helper function to return true if type is a map with nested elements
+func IsNestedMap(attribute YamlConfigAttribute) bool {
+	if attribute.Type == "Map" && attribute.ElementType == "" {
+		return true
+	}
+	return false
+}
+
+// Templating helper function to return true if type is a set with nested elements
+func IsNestedSet(attribute YamlConfigAttribute) bool {
+	if attribute.Type == "Set" && attribute.ElementType == "" {
+		return true
+	}
+	return false
+}
+
+// Templating helper function to return number of import parts
+func ImportParts(attributes []YamlConfigAttribute) int {
+	parts := 1
+	for _, attr := range attributes {
+		if attr.Reference {
+			parts += 1
+		} else if attr.Id {
+			parts += 1
+		}
+	}
+	return parts
+}
+
+// Templating helper function to subtract one number from another
+func Subtract(a, b int) int {
+	return a - b
+}
+
+// Map of templating functions
+var functions = template.FuncMap{
+	"toGoName":           ToGoName,
+	"camelCase":          CamelCase,
+	"snakeCase":          SnakeCase,
+	"sprintf":            fmt.Sprintf,
+	"errorf":             Errorf,
+	"toLower":            strings.ToLower,
+	"path":               BuildPath,
+	"hasId":              HasId,
+	"hasReference":       HasReference,
+	"hasResourceId":      HasResourceId,
+	"isListSet":          IsListSet,
+	"isList":             IsList,
+	"isSet":              IsSet,
+	"isStringListSet":    IsStringListSet,
+	"isInt64ListSet":     IsInt64ListSet,
+	"isNestedListMapSet": IsNestedListMapSet,
+	"isNestedListSet":    IsNestedListSet,
+	"isNestedList":       IsNestedList,
+	"isNestedMap":        IsNestedMap,
+	"isNestedSet":        IsNestedSet,
+	"importParts":        ImportParts,
+	"subtract":           Subtract,
+}
+
+func (attr *YamlConfigAttribute) init(parentGoTypeName string) error {
+	// Augument
+	if attr.TfName == "" {
+		var words []string
+		fullString := ""
+		for _, s := range attr.DataPath {
+			fullString += strings.ToUpper(string(s[0])) + s[1:]
+		}
+		fullString += strings.ToUpper(string(attr.ModelName[0])) + attr.ModelName[1:]
+		l := 0
+		for s := fullString; s != ""; s = s[l:] {
+			l = strings.IndexFunc(s[1:], unicode.IsUpper) + 1
+			if l <= 0 {
+				l = len(s)
+			}
+			words = append(words, strings.ToLower(s[:l]))
+		}
+		attr.TfName = strings.Join(words, "_")
+	}
+
+	attr.GoTypeName = parentGoTypeName + ToGoName(attr.TfName)
+
+	// Validate
+	if len(attr.Attributes) > 0 && attr.Type != "List" && attr.Type != "Map" && attr.Type != "Set" {
+		return fmt.Errorf("%q has type %q which cannot have `attributes`: instead use type List, Map, Set",
+			attr.TfName, attr.Type)
+	}
+
+	if len(attr.Attributes) > 0 && attr.ElementType != "" {
+		return fmt.Errorf("%q: either `attributes` or `element_type` can be specified, but not both", attr.TfName)
+	}
+
+	if attr.Type == "Map" && attr.ElementType != "" {
+		return fmt.Errorf("%q: the `element_type` is not yet implemented for type Map", attr.TfName)
+	}
+
+	if attr.OrderedList {
+		if attr.Type != "List" {
+			return fmt.Errorf("%q has type %q which cannot use `ordered_list`: instead use type List",
+				attr.TfName, attr.Type)
+		}
+		if HasId(attr.Attributes) {
+			return fmt.Errorf("%q: the `ordered_list: true` conflicts with sub-attributes having `id: true`, as it treats list index ([i]) as the only unique id",
+				attr.TfName)
+		}
+	}
+
+	if attr.Type == "Map" && HasId(attr.Attributes) {
+		return fmt.Errorf("Map %q cannot contain sub-attributes with `id: true`, as it treats map key ([k]) as the only unique id",
+			attr.TfName)
+	}
+
+	// Recurse
+	for i := range attr.Attributes {
+		if err := attr.Attributes[i].init(attr.GoTypeName); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func NewYamlConfig(bytes []byte) (YamlConfig, error) {
+	var config YamlConfig
+
+	if err := yaml.Unmarshal(bytes, &config); err != nil {
+		return config, err
+	}
+
+	for i := range config.Attributes {
+		if err := config.Attributes[i].init(CamelCase(config.Name)); err != nil {
+			return YamlConfig{}, err
+		}
+	}
+	if config.DsDescription == "" {
+		config.DsDescription = fmt.Sprintf("This data source can read the `%s` configuration.", config.Name)
+	}
+	if config.ResDescription == "" {
+		config.ResDescription = fmt.Sprintf("This resource can manage the `%s` configuration.", config.Name)
+	}
+	if config.TfName == "" {
+		config.TfName = strings.Replace(config.Name, " ", "_", -1)
+	}
+
+	return config, nil
+}
+
+func getTemplateSection(content, name string) string {
+	scanner := bufio.NewScanner(strings.NewReader(content))
+	result := ""
+	foundSection := false
+	beginRegex := regexp.MustCompile(`\/\/template:begin\s` + name + `$`)
+	endRegex := regexp.MustCompile(`\/\/template:end\s` + name + `$`)
+	for scanner.Scan() {
+		line := scanner.Text()
+		if !foundSection {
+			match := beginRegex.MatchString(line)
+			if match {
+				foundSection = true
+				result += line + "\n"
+			}
+		} else {
+			result += line + "\n"
+			match := endRegex.MatchString(line)
+			if match {
+				foundSection = false
+			}
+		}
+	}
+	return result
+}
+
+func renderTemplate(templatePath, outputPath string, config interface{}) {
+	file, err := os.Open(templatePath)
+	if err != nil {
+		log.Fatalf("Error opening template: %v", err)
+	}
+	defer file.Close()
+
+	// skip first line with 'build-ignore' directive for go files
+	scanner := bufio.NewScanner(file)
+	if strings.HasSuffix(templatePath, ".go") {
+		scanner.Scan()
+	}
+	var temp string
+	for scanner.Scan() {
+		temp = temp + scanner.Text() + "\n"
+	}
+
+	template, err := template.New(path.Base(templatePath)).Funcs(functions).Parse(temp)
+	if err != nil {
+		log.Fatalf("Error parsing template: %v", err)
+	}
+
+	output := new(bytes.Buffer)
+	err = template.Execute(output, config)
+	if err != nil {
+		log.Fatalf("Error executing template for %s: %v", outputPath, err)
+	}
+
+	outputFile := filepath.Join(outputPath)
+	existingFile, err := os.Open(outputPath)
+	if err != nil {
+		os.MkdirAll(filepath.Dir(outputFile), 0755)
+	} else if strings.HasSuffix(templatePath, ".go") {
+		existingScanner := bufio.NewScanner(existingFile)
+		var newContent string
+		currentSectionName := ""
+		beginRegex := regexp.MustCompile(`\/\/template:begin\s(.*?)$`)
+		endRegex := regexp.MustCompile(`\/\/template:end\s(.*?)$`)
+		for existingScanner.Scan() {
+			line := existingScanner.Text()
+			if currentSectionName == "" {
+				matches := beginRegex.FindStringSubmatch(line)
+				if len(matches) > 1 && matches[1] != "" {
+					currentSectionName = matches[1]
+				} else {
+					newContent += line + "\n"
+				}
+			} else {
+				matches := endRegex.FindStringSubmatch(line)
+				if len(matches) > 1 && matches[1] == currentSectionName {
+					currentSectionName = ""
+					newSection := getTemplateSection(string(output.Bytes()), matches[1])
+					newContent += newSection
+				}
+			}
+		}
+		output = bytes.NewBufferString(newContent)
+	}
+	// write to output file
+	f, err := os.Create(outputFile)
+	if err != nil {
+		log.Fatalf("Error creating output file: %v", err)
+	}
+	f.Write(output.Bytes())
+}
+
+func main() {
+	// Load configs
+	var configs []YamlConfig
+	files, _ := os.ReadDir(definitionsPath)
+
+	for _, filename := range files {
+		path := filepath.Join(definitionsPath, filename.Name())
+		bytes, err := os.ReadFile(path)
+		if err != nil {
+			log.Fatalf("Error reading file %q: %v", path, err)
+		}
+
+		config, err := NewYamlConfig(bytes)
+		if err != nil {
+			log.Fatalf("Error parsing %q: %v", path, err)
+		}
+		configs = append(configs, config)
+	}
+
+	var providerConfig []string
+	for i := range configs {
+		// Iterate over templates and render files
+		for _, t := range templates {
+			renderTemplate(t.path, t.prefix+SnakeCase(configs[i].Name)+t.suffix, configs[i])
+		}
+		providerConfig = append(providerConfig, configs[i].Name)
+	}
+
+	// render provider.go
+	renderTemplate(providerTemplate, providerLocation, providerConfig)
+
+	changelog, err := os.ReadFile(changelogOriginal)
+	if err != nil {
+		log.Fatalf("Error reading %q: %v", changelogOriginal, err)
+	}
+	renderTemplate(changelogTemplate, changelogLocation, string(changelog))
+}
diff --git a/gen/schema/schema.yaml b/gen/schema/schema.yaml
new file mode 100644
index 00000000..95a654cb
--- /dev/null
+++ b/gen/schema/schema.yaml
@@ -0,0 +1,52 @@
+---
+name: str() # Name of the resource
+rest_endpoint: str(required=False) # REST endpoint path
+put_create: bool(required=False) # Set to true if the PUT request is used for create
+get_from_all: bool(required=False) # Set to true if GET does not support querying individual objects
+no_update: bool(required=False) # Set to true if the PUT request is not supported
+no_delete: bool(required=False) # Set to true if the DELETE request is not supported
+data_source_name_query: bool(required=False) # Set to true if the data source supports name queries
+minimum_version: str(required=False) # Define a minimum supported version
+ds_description: str(required=False) # Define a data source description
+res_description: str(required=False) # Define a resource description
+doc_category: str(required=False) # Define a documentation category
+skip_minimum_test: bool(required=False) # Do not perform a "minimum" (only mandatory attributes) test
+attributes: list(include('attribute'), required=False) # List of attributes
+test_tags: list(str(), required=False) # List of test tags, tests are only executed if an environment variable with one of these tags is configured
+test_prerequisites: str(required=False) # HCL code that is included in the acceptance tests to define prerequisites
+---
+attribute:
+  model_name: str(required=False) # Name of the attribute in the model (payload)
+  tf_name: str(required=False) # Name of the attribute in the Terraform resource, by default derived from model_name
+  type: enum('String', 'Int64', 'Float', 'Bool', 'List', 'Map', 'Set', required=False) # Type of the attribute
+  element_type: enum('String', 'Int64', required=False) # only relevant if type is either 'List' or 'Set'
+  data_path: list(str(), required=False) # Path to the attribute in the model structure
+  id: bool(required=False) # Set to true if the attribute is part of the ID
+  resource_id: bool(required=False) # Set to true if the attribute is a resource ID (and needs to be included in PUT payload)
+  reference: bool(required=False) # Set to true if the attribute is a reference being used in the path (URL) of the REST endpoint
+  requires_replace: bool(required=False) # Set to true if the attribute update forces Terraform to destroy/recreate the entire resource
+  mandatory: bool(required=False) # Set to true if the attribute is mandatory
+  write_only: bool(required=False) # Set to true if the attribute is write-only, meaning we cannot read the value
+  write_changes_only: bool(required=False) # Set to true if the attribute should only be written (included in PUT payload) if it has changed
+  exclude_test: bool(required=False) # Exclude attribute from example (documentation) and acceptance test
+  exclude_example: bool(required=False) # Exclude attribute from acceptance test only (example/documentation is still generated)
+  description: str(required=False) # Attribute description
+  example: any(str(), int(), bool(), required=False) # Example value for documentation, also used for acceptance test
+  enum_values: list(str(), required=False) # List of enum values, only relevant if type is "String". Null value is instead governed by `mandatory`, never include null here
+  min_list: int(required=False) # Minimum number of elements in a list, only relevant if type is "List"
+  max_list: int(required=False) # Maximum number of elements in a list, only relevant if type is "List"
+  min_int: int(required=False) # Minimum value of an integer, only relevant if type is "Int64"
+  max_int: int(required=False) # Maximum value of an integer, only relevant if type is "Int64"
+  min_float: num(required=False) # Minimum value of a float, only relevant if type is "Float"
+  max_float: num(required=False) # Maximum value of a float, only relevant if type is "Float"
+  map_key_example: str(required=False) # Example value of the map key, only relevant if type is "Map"
+  ordered_list: bool(required=False) # Treat `type: List` as strictly ordered. If API ever returns different order, destroy and re-create elements.
+  string_patterns: list(str(), required=False) # List of regular expressions that the string must match, only relevant if type is "String"
+  string_min_length: int(required=False) # Minimum length of a string, only relevant if type is "String"
+  string_max_length: int(required=False) # Maximum length of a string, only relevant if type is "String"
+  default_value: any(str(), int(), bool(), required=False) # Default value for the attribute
+  value: any(str(), int(), bool(), required=False) # Hardcoded value for the attribute
+  test_value: str(required=False) # Value used for acceptance test
+  minimum_test_value: str(required=False) # Value used for "minimum" resource acceptance test
+  test_tags: list(str(), required=False) # List of test tags, attribute is only included in acceptance tests if an environment variable with one of these tags is configured
+  attributes: list(include('attribute'), required=False) # List of attributes, only relevant if type is "List" or "Set"
diff --git a/gen/templates/changelog.md.tmpl b/gen/templates/changelog.md.tmpl
new file mode 100644
index 00000000..dc53abff
--- /dev/null
+++ b/gen/templates/changelog.md.tmpl
@@ -0,0 +1,10 @@
+---
+subcategory: "Guides"
+page_title: "Changelog"
+description: |-
+    Changelog
+---
+
+# Changelog
+
+{{.}}
diff --git a/gen/templates/data-source.tf b/gen/templates/data-source.tf
new file mode 100644
index 00000000..7b11f802
--- /dev/null
+++ b/gen/templates/data-source.tf
@@ -0,0 +1,21 @@
+{{- $name := .Name -}}
+data "meraki_{{snakeCase .Name}}" "example" {
+  id = "{{$id := false}}{{range .Attributes}}{{if .Id}}{{$id = true}}{{.Example}}{{end}}{{end}}{{if not $id}}12345678{{end}}"
+  {{- range  .Attributes}}
+  {{- if .Reference}}
+  {{.TfName}} = {{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}
+  {{- else if isNestedMap .}}
+  {{- $map := .TfName}}
+  {{- $mapkey := .MapKeyExample}}
+  {{.TfName}} = {
+  "{{.MapKeyExample}}" = {
+    {{- range  .Attributes}}
+    {{- if .ResourceId}}
+    {{.TfName}} = meraki_{{snakeCase $name}}.test.{{$map}}["{{$mapkey}}"].{{.TfName}}
+    {{- end}}
+    {{- end}}
+  }
+  }
+  {{- end}}
+  {{- end}}
+}
diff --git a/gen/templates/data_source.go b/gen/templates/data_source.go
new file mode 100644
index 00000000..f5403b87
--- /dev/null
+++ b/gen/templates/data_source.go
@@ -0,0 +1,242 @@
+//go:build ignore
+// Copyright © 2024 Cisco Systems, Inc. and its affiliates.
+// All rights reserved.
+//
+// Licensed under the Mozilla Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://mozilla.org/MPL/2.0/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+// Section below is generated&owned by "gen/generator.go". //template:begin imports
+import (
+	"context"
+	"fmt"
+	"net/url"
+
+	"github.com/hashicorp/terraform-plugin-framework/diag"
+	"github.com/hashicorp/terraform-plugin-framework/tfsdk"
+	"github.com/hashicorp/terraform-plugin-framework/datasource"
+	"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+	"github.com/hashicorp/terraform-plugin-log/tflog"
+	"github.com/netascode/go-meraki"
+	"github.com/netascode/terraform-provider-meraki/internal/provider/helpers"
+)
+
+// End of section. //template:end imports
+
+// Section below is generated&owned by "gen/generator.go". //template:begin model
+
+// Ensure the implementation satisfies the expected interfaces.
+var (
+	_ datasource.DataSource              = &{{camelCase .Name}}DataSource{}
+	_ datasource.DataSourceWithConfigure = &{{camelCase .Name}}DataSource{}
+)
+
+func New{{camelCase .Name}}DataSource() datasource.DataSource {
+	return &{{camelCase .Name}}DataSource{}
+}
+
+type {{camelCase .Name}}DataSource struct {
+	client *meraki.Client
+}
+
+func (d *{{camelCase .Name}}DataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
+	resp.TypeName = req.ProviderTypeName + "_{{snakeCase .Name}}"
+}
+
+{{- $nameQuery := .DataSourceNameQuery}}
+
+func (d *{{camelCase .Name}}DataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
+	resp.Schema = schema.Schema{
+		// This description is used by the documentation generator and the language server.
+		MarkdownDescription: "{{.DsDescription}}",
+
+		Attributes: map[string]schema.Attribute{
+			"id": schema.StringAttribute{
+				MarkdownDescription: "The id of the object",
+				{{- if not .DataSourceNameQuery}}
+				Required:            true,
+				{{- else}}
+				Optional:            true,
+				Computed:            true,
+				{{- end}}
+			},
+			{{- range  .Attributes}}
+			{{- if not .Value}}
+			"{{.TfName}}": schema.{{if isNestedListMapSet .}}{{.Type}}Nested{{else if isList .}}List{{else if isSet .}}Set{{else if eq .Type "Versions"}}List{{else if eq .Type "Version"}}Int64{{else}}{{.Type}}{{end}}Attribute{
+				MarkdownDescription: "{{.Description}}",
+				{{- if isListSet .}}
+				ElementType:         types.{{.ElementType}}Type,
+				{{- end}}
+				{{- if .Reference}}
+				Required:            true,
+				{{- else}}
+				{{- if and (eq .ModelName "name") ($nameQuery)}}
+				Optional:            true,
+				{{- end}}
+				Computed:            true,
+				{{- end}}
+				{{- if isNestedListMapSet .}}
+				NestedObject: schema.NestedAttributeObject{
+					Attributes: map[string]schema.Attribute{
+						{{- range  .Attributes}}
+						{{- if not .Value}}
+						"{{.TfName}}": schema.{{if isNestedListMapSet .}}{{.Type}}Nested{{else if isList .}}List{{else if isSet .}}Set{{else if eq .Type "Versions"}}List{{else if eq .Type "Version"}}Int64{{else}}{{.Type}}{{end}}Attribute{
+							MarkdownDescription: "{{.Description}}",
+							{{- if isListSet .}}
+							ElementType:         types.{{.ElementType}}Type,
+							{{- end}}
+							Computed:            true,
+							{{- if isNestedListMapSet .}}
+							NestedObject: schema.NestedAttributeObject{
+								Attributes: map[string]schema.Attribute{
+									{{- range  .Attributes}}
+									{{- if not .Value}}
+									"{{.TfName}}": schema.{{if isNestedListMapSet .}}{{.Type}}Nested{{else if isList .}}List{{else if isSet .}}Set{{else if eq .Type "Versions"}}List{{else if eq .Type "Version"}}Int64{{else}}{{.Type}}{{end}}Attribute{
+										MarkdownDescription: "{{.Description}}",
+										{{- if isListSet .}}
+										ElementType:         types.{{.ElementType}}Type,
+										{{- end}}
+										Computed:            true,
+										{{- if isNestedListMapSet .}}
+										NestedObject: schema.NestedAttributeObject{
+											Attributes: map[string]schema.Attribute{
+												{{- range  .Attributes}}
+												{{- if not .Value}}
+												"{{.TfName}}": schema.{{if isNestedListMapSet .}}{{.Type}}Nested{{else if isList .}}List{{else if isSet .}}Set{{else if eq .Type "Versions"}}List{{else if eq .Type "Version"}}Int64{{else}}{{.Type}}{{end}}Attribute{
+													MarkdownDescription: "{{.Description}}",
+													{{- if isListSet .}}
+													ElementType:         types.{{.ElementType}}Type,
+													{{- end}}
+													Computed:            true,
+												},
+												{{- end}}
+												{{- end}}
+											},
+										},
+										{{- end}}
+									},
+									{{- end}}
+									{{- end}}
+								},
+							},
+							{{- end}}
+						},
+						{{- end}}
+						{{- end}}
+					},
+				},
+				{{- end}}
+			},
+			{{- end}}
+			{{- end}}
+		},
+	}
+}
+
+{{- if .DataSourceNameQuery}}
+func (d *{{camelCase .Name}}DataSource) ConfigValidators(ctx context.Context) []datasource.ConfigValidator {
+    return []datasource.ConfigValidator{
+        datasourcevalidator.ExactlyOneOf(
+            path.MatchRoot("id"),
+            path.MatchRoot("name"),
+        ),
+    }
+}
+{{- end}}
+
+func (d *{{camelCase .Name}}DataSource) Configure(_ context.Context, req datasource.ConfigureRequest, _ *datasource.ConfigureResponse) {
+	if req.ProviderData == nil {
+		return
+	}
+
+	d.client = req.ProviderData.(*MerakiProviderData).Client
+}
+
+// End of section. //template:end model
+
+// Section below is generated&owned by "gen/generator.go". //template:begin read
+
+func (d *{{camelCase .Name}}DataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
+	var config {{camelCase .Name}}
+
+	// Read config
+	diags := req.Config.Get(ctx, &config)
+	resp.Diagnostics.Append(diags...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Read", config.Id.String()))
+
+	{{- if .DataSourceNameQuery}}
+	var res gjson.Result
+	var err error
+	if config.Id.IsNull() && !config.Name.IsNull() {
+			res, err = d.client.Get(config.getPath())
+			if err != nil {
+				resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err))
+				return
+			}
+			if len(res.Array()) > 0 {
+				res.ForEach(func(k, v gjson.Result) bool {
+					if config.Name.ValueString() == v.Get("name").String() {
+						config.Id = types.StringValue(v.Get("id").String())
+						tflog.Debug(ctx, fmt.Sprintf("%s: Found object with name '%v', id: %v", config.Id.String(), config.Name.ValueString(), config.Id.String()))
+						return false
+					}
+					return true
+				})
+			}
+
+		if config.Id.IsNull() {
+			resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to find object with name: %s", config.Name.ValueString()))
+			return
+		}
+	}
+	{{- end}}
+
+	if !res.Exists() {
+		{{- if .GetFromAll}}
+		res, err = d.client.Get(config.getPath())
+		{{- else}}
+		res, err = d.client.Get(config.getPath() + "/" + url.QueryEscape(config.Id.ValueString()))
+		{{- end}}
+		if err != nil {
+			resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve object, got error: %s", err))
+			return
+		}
+	}
+	{{- if .GetFromAll}}
+	if len(res.Array()) > 0 {
+		res.ForEach(func(k, v gjson.Result) bool {
+			if config.Id.ValueString() == v.Get("id").String() {
+				res = v
+				return false
+			}
+			return true
+		})
+	}
+	{{- end}}
+
+	config.fromBody(ctx, res)
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Read finished successfully", config.Id.ValueString()))
+
+	diags = resp.State.Set(ctx, &config)
+	resp.Diagnostics.Append(diags...)
+}
+
+// End of section. //template:end read
diff --git a/gen/templates/data_source_test.go b/gen/templates/data_source_test.go
new file mode 100644
index 00000000..3007e17f
--- /dev/null
+++ b/gen/templates/data_source_test.go
@@ -0,0 +1,356 @@
+//go:build ignore
+// Copyright © 2024 Cisco Systems, Inc. and its affiliates.
+// All rights reserved.
+//
+// Licensed under the Mozilla Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://mozilla.org/MPL/2.0/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+// Section below is generated&owned by "gen/generator.go". //template:begin imports
+import (
+	"testing"
+
+	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+// End of section. //template:end imports
+
+// Section below is generated&owned by "gen/generator.go". //template:begin testAccDataSource
+
+func TestAccDataSourceMeraki{{camelCase .Name}}(t *testing.T) {
+	{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} && {{end}}os.Getenv("{{$e}}") == ""{{end}} {
+        t.Skip("skipping test, set environment variable {{range $i, $e := .TestTags}}{{if $i}} or {{end}}{{$e}}{{end}}")
+	}
+	{{- end}}
+	var checks []resource.TestCheckFunc
+	{{- $name := .Name }}
+	{{- range  .Attributes}}
+	{{- if and (not .WriteOnly) (not .ExcludeTest) (not .Value) (not .TestValue) (not .ResourceId)}}
+	{{- if isNestedListSet .}}
+	{{- $list := .TfName }}
+	{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+	{{- end}}
+	{{- range  .Attributes}}
+	{{- if and (not .WriteOnly) (not .ExcludeTest) (not .Value) (not .TestValue)}}
+	{{- if isNestedListSet .}}
+	{{- $clist := .TfName }}
+	{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+	{{- end}}
+	{{- range  .Attributes}}
+	{{- if and (not .WriteOnly) (not .ExcludeTest) (not .Value) (not .TestValue)}}
+	{{- if isNestedListSet .}}
+	{{- $cclist := .TfName }}
+	{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+	{{- end}}
+	{{- range  .Attributes}}
+	{{- if and (not .WriteOnly) (not .ExcludeTest) (not .Value) (not .TestValue) (not (isSet .))}}
+	{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+		checks = append(checks, resource.TestCheckResourceAttr("data.meraki_{{snakeCase $name}}.test", "{{$list}}.0.{{$clist}}.0.{{$cclist}}.0.{{.TfName}}{{if isList .}}.0{{end}}", "{{.Example}}"))
+	}
+	{{- else}}
+	checks = append(checks, resource.TestCheckResourceAttr("data.meraki_{{snakeCase $name}}.test", "{{$list}}.0.{{$clist}}.0.{{$cclist}}.0.{{.TfName}}{{if isList .}}.0{{end}}", "{{.Example}}"))
+	{{- end}}
+	{{- end}}
+	{{- end}}
+	{{- if len .TestTags}}
+	}
+	{{- end}}
+	{{- else if not (or (isSet .) (isNestedMap .))}}
+	{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+		checks = append(checks, resource.TestCheckResourceAttr("data.meraki_{{snakeCase $name}}.test", "{{$list}}.0.{{$clist}}.0.{{.TfName}}{{if isList .}}.0{{end}}", "{{.Example}}"))
+	}
+	{{- else}}
+	checks = append(checks, resource.TestCheckResourceAttr("data.meraki_{{snakeCase $name}}.test", "{{$list}}.0.{{$clist}}.0.{{.TfName}}{{if isList .}}.0{{end}}", "{{.Example}}"))
+	{{- end}}
+	{{- end}}
+	{{- end}}
+	{{- end}}
+	{{- if len .TestTags}}
+	}
+	{{- end}}
+	{{- else if not (or (isSet .) (isNestedMap .))}}
+	{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+		checks = append(checks, resource.TestCheckResourceAttr("data.meraki_{{snakeCase $name}}.test", "{{$list}}.0.{{.TfName}}{{if isList .}}.0{{end}}", "{{.Example}}"))
+	}
+	{{- else}}
+	checks = append(checks, resource.TestCheckResourceAttr("data.meraki_{{snakeCase $name}}.test", "{{$list}}.0.{{.TfName}}{{if isList .}}.0{{end}}", "{{.Example}}"))
+	{{- end}}
+	{{- end}}
+	{{- end}}
+	{{- end}}
+	{{- if len .TestTags}}
+	}
+	{{- end}}
+	{{- else if not (or (isSet .) (isNestedMap .))}}
+	{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+		checks = append(checks, resource.TestCheckResourceAttr("data.meraki_{{snakeCase $name}}.test", "{{.TfName}}{{if isList .}}.0{{end}}", "{{.Example}}"))
+	}
+	{{- else}}
+	checks = append(checks, resource.TestCheckResourceAttr("data.meraki_{{snakeCase $name}}.test", "{{.TfName}}{{if isList .}}.0{{end}}", "{{.Example}}"))
+	{{- end}}
+	{{- end}}
+	{{- end}}
+	{{- end}}
+	resource.Test(t, resource.TestCase{
+		PreCheck:                 func() { testAccPreCheck(t) },
+		ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+		Steps: []resource.TestStep{
+			{
+				Config: {{if .TestPrerequisites}}testAccDataSourceMeraki{{camelCase .Name}}PrerequisitesConfig+{{end}}testAccDataSourceMeraki{{camelCase .Name}}Config(),
+				Check: resource.ComposeTestCheckFunc(checks...),
+			},
+			{{- if .DataSourceNameQuery}}
+			{
+				Config: {{if .TestPrerequisites}}testAccDataSourceMeraki{{camelCase .Name}}PrerequisitesConfig+{{end}}testAccNamedDataSourceMeraki{{camelCase .Name}}Config(),
+				Check: resource.ComposeTestCheckFunc(checks...),
+			},
+			{{- end}}
+		},
+	})
+}
+
+// End of section. //template:end testAccDataSource
+
+// Section below is generated&owned by "gen/generator.go". //template:begin testPrerequisites
+{{- if .TestPrerequisites}}
+
+const testAccDataSourceMeraki{{camelCase .Name}}PrerequisitesConfig = `
+{{.TestPrerequisites}}
+`
+
+{{- end}}
+// End of section. //template:end testPrerequisites
+
+// Section below is generated&owned by "gen/generator.go". //template:begin testAccDataSourceConfig
+
+func testAccDataSourceMeraki{{camelCase .Name}}Config() string {
+	config := `resource "meraki_{{snakeCase $name}}" "test" {` + "\n"
+	{{- range  .Attributes}}
+	{{- if and (not .ExcludeTest) (not .Value) (not .ResourceId)}}
+	{{- if isNestedListMapSet .}}
+	{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+	{{- end}}
+	{{- if isNestedListSet .}}
+	config += `	{{.TfName}} = [{` + "\n"
+	{{- else if isNestedMap .}}
+	config += `	{{.TfName}} = { "{{.MapKeyExample}}" = {` + "\n"
+	{{- end}}
+		{{- range  .Attributes}}
+		{{- if and (not .ExcludeTest) (not .Value)}}
+		{{- if isNestedListSet .}}
+		{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+		{{- end}}
+	config += `		{{.TfName}} = [{` + "\n"
+			{{- range  .Attributes}}
+			{{- if and (not .ExcludeTest) (not .Value)}}
+			{{- if isNestedListSet .}}
+			{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+			{{- end}}
+	config += `			{{.TfName}} = [{` + "\n"
+				{{- range  .Attributes}}
+				{{- if and (not .ExcludeTest) (not .Value)}}
+				{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+		config += `				{{.TfName}} = {{if .TestValue}}{{.TestValue}}{{else}}{{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}{{end}}` + "\n"
+	}
+				{{- else}}
+	config += `				{{.TfName}} = {{if .TestValue}}{{.TestValue}}{{else}}{{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}{{end}}` + "\n"
+				{{- end}}
+				{{- end}}
+				{{- end}}
+	config += `			}]` + "\n"
+			{{- if len .TestTags}}
+	}
+			{{- end}}
+			{{- else}}
+			{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+		config += `			{{.TfName}} = {{if .TestValue}}{{.TestValue}}{{else}}{{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}{{end}}` + "\n"
+	}
+			{{- else}}
+	config += `			{{.TfName}} = {{if .TestValue}}{{.TestValue}}{{else}}{{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}{{end}}` + "\n"
+			{{- end}}
+			{{- end}}
+			{{- end}}
+			{{- end}}
+	config += `		}]` + "\n"
+		{{- if len .TestTags}}
+	}
+		{{- end}}
+		{{- else}}
+		{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+		config += `		{{.TfName}} = {{if .TestValue}}{{.TestValue}}{{else}}{{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}{{end}}` + "\n"
+	}
+			{{- else}}
+	config += `		{{.TfName}} = {{if .TestValue}}{{.TestValue}}{{else}}{{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}{{end}}` + "\n"
+		{{- end}}
+		{{- end}}
+		{{- end}}
+		{{- end}}
+	{{- if isNestedListSet .}}
+	config += `	}]` + "\n"
+	{{- else if isNestedMap .}}
+	config += `	}}` + "\n"
+	{{- end}}
+		{{- if len .TestTags}}
+	}
+		{{- end}}
+	{{- else}}
+	{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+		config += `	{{.TfName}} = {{if .TestValue}}{{.TestValue}}{{else}}{{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}{{end}}` + "\n"
+	}
+	{{- else}}
+	config += `	{{.TfName}} = {{if .TestValue}}{{.TestValue}}{{else}}{{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}{{end}}` + "\n"
+	{{- end}}
+	{{- end}}
+	{{- end}}
+	{{- end}}
+	config += `}` + "\n"
+
+	config += `
+		data "meraki_{{snakeCase .Name}}" "test" {
+			id = meraki_{{snakeCase $name}}.test.id
+			{{- range  .Attributes}}
+			{{- if .Reference}}
+			{{.TfName}} = {{if .TestValue}}{{.TestValue}}{{else}}{{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}{{end}}
+			{{- else if isNestedMap .}}
+			{{- $map := .TfName}}
+			{{- $mapkey := .MapKeyExample}}
+			{{.TfName}} = {
+				"{{.MapKeyExample}}" = {
+					{{- range  .Attributes}}
+					{{- if .ResourceId}}
+					{{.TfName}} = meraki_{{snakeCase $name}}.test.{{$map}}["{{$mapkey}}"].{{.TfName}}
+					{{- end}}
+					{{- end}}
+				}
+			}
+			{{- end}}
+			{{- end}}
+		}
+	`
+	return config
+}
+
+{{if .DataSourceNameQuery -}}
+func testAccNamedDataSourceMeraki{{camelCase .Name}}Config() string {
+	config := `resource "meraki_{{snakeCase $name}}" "test" {` + "\n"
+	{{- range  .Attributes}}
+	{{- if and (not .ExcludeTest) (not .Value) (not .ResourceId)}}
+	{{- if isNestedListSet .}}
+	{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+	{{- end}}
+	config += `	{{.TfName}} = [{` + "\n"
+		{{- range  .Attributes}}
+		{{- if and (not .ExcludeTest) (not .Value)}}
+		{{- if isNestedListSet .}}
+		{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+		{{- end}}
+	config += `		{{.TfName}} = [{` + "\n"
+			{{- range  .Attributes}}
+			{{- if and (not .ExcludeTest) (not .Value)}}
+			{{- if isNestedListSet .}}
+			{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+			{{- end}}
+	config += `			{{.TfName}} = [{` + "\n"
+				{{- range  .Attributes}}
+				{{- if and (not .ExcludeTest) (not .Value)}}
+				{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+		config += `				{{.TfName}} = {{if .TestValue}}{{.TestValue}}{{else}}{{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}{{end}}` + "\n"
+	}
+				{{- else}}
+	config += `				{{.TfName}} = {{if .TestValue}}{{.TestValue}}{{else}}{{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}{{end}}` + "\n"
+				{{- end}}
+				{{- end}}
+				{{- end}}
+	config += `			}]` + "\n"
+			{{- if len .TestTags}}
+	}
+			{{- end}}
+			{{- else}}
+			{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+		config += `			{{.TfName}} = {{if .TestValue}}{{.TestValue}}{{else}}{{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}{{end}}` + "\n"
+	}
+			{{- else}}
+	config += `			{{.TfName}} = {{if .TestValue}}{{.TestValue}}{{else}}{{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}{{end}}` + "\n"
+			{{- end}}
+			{{- end}}
+			{{- end}}
+			{{- end}}
+	config += `		}]` + "\n"
+		{{- if len .TestTags}}
+	}
+		{{- end}}
+		{{- else}}
+		{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+		config += `		{{.TfName}} = {{if .TestValue}}{{.TestValue}}{{else}}{{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}{{end}}` + "\n"
+	}
+			{{- else}}
+	config += `		{{.TfName}} = {{if .TestValue}}{{.TestValue}}{{else}}{{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}{{end}}` + "\n"
+		{{- end}}
+		{{- end}}
+		{{- end}}
+		{{- end}}
+	config += `	}]` + "\n"
+		{{- if len .TestTags}}
+	}
+		{{- end}}
+	{{- else}}
+	{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+		config += `	{{.TfName}} = {{if .TestValue}}{{.TestValue}}{{else}}{{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}{{end}}` + "\n"
+	}
+	{{- else}}
+	config += `	{{.TfName}} = {{if .TestValue}}{{.TestValue}}{{else}}{{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}{{end}}` + "\n"
+	{{- end}}
+	{{- end}}
+	{{- end}}
+	{{- end}}
+	config += `}` + "\n"
+
+	config += `
+		data "meraki_{{snakeCase .Name}}" "test" {
+			name = meraki_{{snakeCase $name}}.test.name
+			{{- range  .Attributes}}
+			{{- if .Reference}}
+			{{.TfName}} = {{if .TestValue}}{{.TestValue}}{{else}}{{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}{{end}}
+			{{- end}}
+			{{- end}}
+		}
+	`
+	return config
+}
+{{- end}}
+
+// End of section. //template:end testAccDataSourceConfig
diff --git a/gen/templates/import.sh b/gen/templates/import.sh
new file mode 100644
index 00000000..4cd1ceda
--- /dev/null
+++ b/gen/templates/import.sh
@@ -0,0 +1 @@
+terraform import meraki_{{snakeCase .Name}}.example "{{$id := false}}{{range .Attributes}}{{if .Id}}{{$id = true}}<{{.TfName}}>{{end}}{{end}}{{if not $id}}{{range .Attributes}}{{if .Reference}}<{{.TfName}}>,{{end}}{{end}}<id>{{end}}"
diff --git a/gen/templates/model.go b/gen/templates/model.go
new file mode 100644
index 00000000..32a5eeac
--- /dev/null
+++ b/gen/templates/model.go
@@ -0,0 +1,567 @@
+//go:build ignore
+// Copyright © 2024 Cisco Systems, Inc. and its affiliates.
+// All rights reserved.
+//
+// Licensed under the Mozilla Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://mozilla.org/MPL/2.0/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+// Section below is generated&owned by "gen/generator.go". //template:begin imports
+import (
+	"context"
+	"fmt"
+	"net/url"
+	"strconv"
+
+	"github.com/hashicorp/terraform-plugin-framework/types"
+	"github.com/hashicorp/terraform-plugin-log/tflog"
+	"github.com/netascode/terraform-provider-meraki/internal/provider/helpers"
+	"github.com/tidwall/gjson"
+	"github.com/tidwall/sjson"
+)
+
+// End of section. //template:end imports
+
+// Section below is generated&owned by "gen/generator.go". //template:begin types
+
+type {{camelCase .Name}} struct {
+	Id types.String `tfsdk:"id"`
+{{- range .Attributes}}
+{{- if not .Value}}
+{{- if isNestedListSet .}}
+	{{toGoName .TfName}} []{{.GoTypeName}} `tfsdk:"{{.TfName}}"`
+{{- else if isNestedMap .}}
+	{{toGoName .TfName}} map[string]{{.GoTypeName}} `tfsdk:"{{.TfName}}"`
+{{- else}}
+	{{toGoName .TfName}} types.{{.Type}} `tfsdk:"{{.TfName}}"`
+{{- end}}
+{{- end}}
+{{- end}}
+}
+
+{{range .Attributes}}
+{{- if not .Value}}
+{{- if isNestedListMapSet .}}
+type {{.GoTypeName}} struct {
+{{- range .Attributes}}
+{{- if not .Value}}
+{{- if isNestedListSet .}}
+	{{toGoName .TfName}} []{{.GoTypeName}} `tfsdk:"{{.TfName}}"`
+{{- else if isNestedMap .}}
+	{{toGoName .TfName}} map[string]{{.GoTypeName}} `tfsdk:"{{.TfName}}"`
+{{- else}}
+	{{toGoName .TfName}} types.{{.Type}} `tfsdk:"{{.TfName}}"`
+{{- end}}
+{{- end}}
+{{- end}}
+}
+{{- end}}
+{{- end}}
+{{end}}
+
+{{range .Attributes}}
+{{- if not .Value}}
+{{- if isNestedListMapSet .}}
+{{range .Attributes}}
+{{- if not .Value}}
+{{- if isNestedListMapSet .}}
+type {{.GoTypeName}} struct {
+{{- range .Attributes}}
+{{- if not .Value}}
+{{- if isNestedListSet .}}
+	{{toGoName .TfName}} []{{.GoTypeName}} `tfsdk:"{{.TfName}}"`
+{{- else if isNestedMap .}}
+	{{toGoName .TfName}} map[string]{{.GoTypeName}} `tfsdk:"{{.TfName}}"`
+{{- else}}
+	{{toGoName .TfName}} types.{{.Type}} `tfsdk:"{{.TfName}}"`
+{{- end}}
+{{- end}}
+{{- end}}
+}
+{{- end}}
+{{- end}}
+{{- end}}
+{{- end}}
+{{- end}}
+{{end}}
+
+{{range .Attributes}}
+{{- if not .Value}}
+{{- if isNestedListMapSet .}}
+{{range .Attributes}}
+{{- if not .Value}}
+{{- if isNestedListMapSet .}}
+{{range .Attributes}}
+{{- if not .Value}}
+{{- if isNestedListMapSet .}}
+type {{.GoTypeName}} struct {
+{{- range .Attributes}}
+{{- if not .Value}}
+	{{toGoName .TfName}} types.{{.Type}} `tfsdk:"{{.TfName}}"`
+{{- end}}
+{{- end}}
+}
+{{- end}}
+{{- end}}
+{{- end}}
+{{- end}}
+{{- end}}
+{{- end}}
+{{- end}}
+{{- end}}
+{{end}}
+
+// End of section. //template:end types
+
+// Section below is generated&owned by "gen/generator.go". //template:begin getPath
+
+func (data {{camelCase .Name}}) getPath() string {
+	{{- if hasReference .Attributes}}
+		return fmt.Sprintf("{{.RestEndpoint}}"{{range .Attributes}}{{if .Reference}}, url.QueryEscape(data.{{toGoName .TfName}}.Value{{.Type}}()){{end}}{{end}})
+	{{- else}}
+		return "{{.RestEndpoint}}"
+	{{- end}}
+}
+
+// End of section. //template:end getPath
+
+// Section below is generated&owned by "gen/generator.go". //template:begin toBody
+
+func (data {{camelCase .Name}}) toBody(ctx context.Context, state {{camelCase .Name}}) string {
+	body := ""
+	if data.Id.ValueString() != "" {
+		body, _ = sjson.Set(body, "id", data.Id.ValueString())
+	}
+	{{- range .Attributes}}
+	{{- if .Value}}
+	body, _ = sjson.Set(body, "{{range .DataPath}}{{.}}.{{end}}{{.ModelName}}", {{if eq .Type "String"}}"{{end}}{{.Value}}{{if eq .Type "String"}}"{{end}})
+	{{- else if .ResourceId}}
+	if state.{{toGoName .TfName}}.ValueString() != "" {
+		body, _ = sjson.Set(body, "{{range .DataPath}}{{.}}.{{end}}{{.ModelName}}", state.{{toGoName .TfName}}.ValueString())
+	}
+	{{- else if not .Reference}}
+	{{- if or (eq .Type "String") (eq .Type "Int64") (eq .Type "Float64") (eq .Type "Bool")}}
+	if !data.{{toGoName .TfName}}.IsNull() {{if .WriteChangesOnly}}&& data.{{toGoName .TfName}} != state.{{toGoName .TfName}}{{end}} {
+		body, _ = sjson.Set(body, "{{range .DataPath}}{{.}}.{{end}}{{.ModelName}}", data.{{toGoName .TfName}}.Value{{.Type}}())
+	}
+	{{- else if isListSet .}}
+	if !data.{{toGoName .TfName}}.IsNull() {
+		var values []{{if isStringListSet .}}string{{else if isInt64ListSet .}}int64{{end}}
+		data.{{toGoName .TfName}}.ElementsAs(ctx, &values, false)
+		body, _ = sjson.Set(body, "{{range .DataPath}}{{.}}.{{end}}{{.ModelName}}", values)
+	}
+	{{- else if isNestedListMapSet .}}
+	if len(data.{{toGoName .TfName}}) > 0 {
+		body, _ = sjson.Set(body, "{{range .DataPath}}{{.}}.{{end}}{{.ModelName}}", []interface{}{})
+		{{- if isNestedMap .}}
+		for key, item := range data.{{toGoName .TfName}} {
+			itemBody, _ := sjson.Set("{}", "name", key)
+		{{- else}}
+		for _, item := range data.{{toGoName .TfName}} {
+			itemBody := ""
+		{{- end}}
+			{{- range .Attributes}}
+			{{- if .Value}}
+			itemBody, _ = sjson.Set(itemBody, "{{range .DataPath}}{{.}}.{{end}}{{.ModelName}}", {{if eq .Type "String"}}"{{end}}{{.Value}}{{if eq .Type "String"}}"{{end}})
+			{{- else if not .Reference}}
+			{{- if or (eq .Type "String") (eq .Type "Int64") (eq .Type "Float64") (eq .Type "Bool")}}
+			if !item.{{toGoName .TfName}}.IsNull() {{ if .ResourceId -}} && !item.{{toGoName .TfName}}.IsUnknown() {{- end}} {
+				itemBody, _ = sjson.Set(itemBody, "{{range .DataPath}}{{.}}.{{end}}{{.ModelName}}", item.{{toGoName .TfName}}.Value{{.Type}}())
+			}
+			{{- else if isListSet .}}
+			if !item.{{toGoName .TfName}}.IsNull() {
+				var values []{{if isStringListSet .}}string{{else if isInt64ListSet .}}int64{{end}}
+				item.{{toGoName .TfName}}.ElementsAs(ctx, &values, false)
+				itemBody, _ = sjson.Set(itemBody, "{{range .DataPath}}{{.}}.{{end}}{{.ModelName}}", values)
+			}
+			{{- else if isNestedListSet .}}
+			if len(item.{{toGoName .TfName}}) > 0 {
+				itemBody, _ = sjson.Set(itemBody, "{{range .DataPath}}{{.}}.{{end}}{{.ModelName}}", []interface{}{})
+				for _, childItem := range item.{{toGoName .TfName}} {
+					itemChildBody := ""
+					{{- range .Attributes}}
+					{{- if .Value}}
+					itemChildBody, _ = sjson.Set(itemChildBody, "{{range .DataPath}}{{.}}.{{end}}{{.ModelName}}", {{if eq .Type "String"}}"{{end}}{{.Value}}{{if eq .Type "String"}}"{{end}})
+					{{- else if not .Reference}}
+					{{- if or (eq .Type "String") (eq .Type "Int64") (eq .Type "Float64") (eq .Type "Bool")}}
+					if !childItem.{{toGoName .TfName}}.IsNull() {
+						itemChildBody, _ = sjson.Set(itemChildBody, "{{range .DataPath}}{{.}}.{{end}}{{.ModelName}}", childItem.{{toGoName .TfName}}.Value{{.Type}}())
+					}
+					{{- else if isListSet .}}
+					if !childItem.{{toGoName .TfName}}.IsNull() {
+						var values []{{if isStringListSet .}}string{{else if isInt64ListSet .}}int64{{end}}
+						childItem.{{toGoName .TfName}}.ElementsAs(ctx, &values, false)
+						itemChildBody, _ = sjson.Set(itemChildBody, "{{range .DataPath}}{{.}}.{{end}}{{.ModelName}}", values)
+					}
+					{{- else if isNestedListSet .}}
+					if len(childItem.{{toGoName .TfName}}) > 0 {
+						itemChildBody, _ = sjson.Set(itemChildBody, "{{range .DataPath}}{{.}}.{{end}}{{.ModelName}}", []interface{}{})
+						for _, childChildItem := range childItem.{{toGoName .TfName}} {
+							itemChildChildBody := ""
+							{{- range .Attributes}}
+							{{- if .Value}}
+							itemChildChildBody, _ = sjson.Set(itemChildChildBody, "{{range .DataPath}}{{.}}.{{end}}{{.ModelName}}", {{if eq .Type "String"}}"{{end}}{{.Value}}{{if eq .Type "String"}}"{{end}})
+							{{- else if not .Reference}}
+							{{- if or (eq .Type "String") (eq .Type "Int64") (eq .Type "Float64") (eq .Type "Bool")}}
+							if !childChildItem.{{toGoName .TfName}}.IsNull() {
+								itemChildChildBody, _ = sjson.Set(itemChildChildBody, "{{range .DataPath}}{{.}}.{{end}}{{.ModelName}}", childChildItem.{{toGoName .TfName}}.Value{{.Type}}())
+							}
+							{{- else if isListSet .}}
+							if !childChildItem.{{toGoName .TfName}}.IsNull() {
+								var values []{{if isStringListSet .}}string{{else if isInt64ListSet .}}int64{{end}}
+								childChildItem.{{toGoName .TfName}}.ElementsAs(ctx, &values, false)
+								itemChildChildBody, _ = sjson.Set(itemChildChildBody, "{{range .DataPath}}{{.}}.{{end}}{{.ModelName}}", values)
+							}
+							{{- end}}
+							{{- end}}
+							{{- end}}
+							itemChildBody, _ = sjson.SetRaw(itemChildBody, "{{range .DataPath}}{{.}}.{{end}}{{.ModelName}}.-1", itemChildChildBody)
+						}
+					}
+					{{- end}}
+					{{- end}}
+					{{- end}}
+					itemBody, _ = sjson.SetRaw(itemBody, "{{range .DataPath}}{{.}}.{{end}}{{.ModelName}}.-1", itemChildBody)
+				}
+			}
+			{{- end}}
+			{{- end}}
+			{{- end}}
+			body, _ = sjson.SetRaw(body, "{{range .DataPath}}{{.}}.{{end}}{{if .ModelName}}{{.ModelName}}.{{end}}-1", itemBody)
+		}
+	}
+	{{- end}}
+	{{- end}}
+	{{- end}}
+	return body
+}
+
+// End of section. //template:end toBody
+
+// Section below is generated&owned by "gen/generator.go". //template:begin fromBody
+
+func (data *{{camelCase .Name}}) fromBody(ctx context.Context, res gjson.Result) {
+{{- define "fromBodyTemplate"}}
+	{{- range .Attributes}}
+	{{- if and (not .Value) (not .WriteOnly) (not .Reference)}}
+	{{- if or (eq .Type "String") (eq .Type "Int64") (eq .Type "Float64") (eq .Type "Bool")}}
+	if value := res.Get("{{range .DataPath}}{{.}}.{{end}}{{.ModelName}}"); value.Exists() {
+		data.{{toGoName .TfName}} = types.{{.Type}}Value(value.{{if eq .Type "Int64"}}Int{{else if eq .Type "Float64"}}Float{{else}}{{.Type}}{{end}}())
+	} else {
+		{{- if .DefaultValue}}
+		data.{{toGoName .TfName}} = types.{{.Type}}Value({{if eq .Type "String"}}"{{end}}{{.DefaultValue}}{{if eq .Type "String"}}"{{end}})
+		{{- else}}
+		data.{{toGoName .TfName}} = types.{{.Type}}Null()
+		{{- end}}
+	}
+	{{- else if isListSet .}}
+	if value := res.Get("{{range .DataPath}}{{.}}.{{end}}{{.ModelName}}"); value.Exists() {
+		data.{{toGoName .TfName}} = helpers.Get{{.ElementType}}{{.Type}}(value.Array())
+	} else {
+		data.{{toGoName .TfName}} = types.{{.Type}}Null(types.{{.ElementType}}Type)
+	}
+	{{- else if isNestedListSet .}}
+	if value := res{{if .ModelName}}.Get("{{range .DataPath}}{{.}}.{{end}}{{.ModelName}}"){{end}}; value.Exists() {
+		data.{{toGoName .TfName}} = make([]{{.GoTypeName}}, 0)
+		value.ForEach(func(k, res gjson.Result) bool {
+			parent := &data
+			data := {{.GoTypeName}}{}
+			{{- template "fromBodyTemplate" .}}
+			(*parent).{{toGoName .TfName}} = append((*parent).{{toGoName .TfName}}, data)
+			return true
+		})
+	}
+	{{- else if isNestedMap .}}
+	for k := range data.{{toGoName .TfName}} {
+		parent := &data
+		data := (*parent).{{toGoName .TfName}}[k]
+		parentRes := &res
+		var res gjson.Result
+
+		parentRes.{{if .ModelName}}Get("{{range .DataPath}}{{.}}.{{end}}{{.ModelName}}").{{end}}ForEach(
+			func(_, v gjson.Result) bool {
+				if v.Get("id").String() == data.Id.ValueString() && data.Id.ValueString() != "" {
+					res = v
+					return false // break ForEach
+				}
+				return true
+			},
+		)
+		if !res.Exists() {
+			tflog.Debug(ctx, fmt.Sprintf("subresource not found, removing: uuid=%s, key=%v", data.Id, k))
+			delete((*parent).{{toGoName .TfName}}, k)
+		}
+		{{- template "fromBodyTemplate" .}}
+		(*parent).{{toGoName .TfName}}[k] = data
+	}
+	{{- end}}
+	{{- end}}
+	{{- end}}
+{{- end}}
+{{- template "fromBodyTemplate" .}}
+}
+
+// End of section. //template:end fromBody
+
+// Section below is generated&owned by "gen/generator.go". //template:begin fromBodyPartial
+
+// fromBodyPartial reads values from a gjson.Result into a tfstate model. It ignores null attributes in order to
+// uncouple the provider from the exact values that the backend API might summon to replace nulls. (Such behavior might
+// easily change across versions of the backend API.) For List/Set/Map attributes, the func only updates the
+// "managed" elements, instead of all elements.
+func (data *{{camelCase .Name}}) fromBodyPartial(ctx context.Context, res gjson.Result) {
+{{- define "fromBodyPartialTemplate"}}
+	{{- range .Attributes}}
+	{{- if and (not .Value) (not .WriteOnly) (not .Reference)}}
+	{{- if or (eq .Type "String") (eq .Type "Int64") (eq .Type "Float64") (eq .Type "Bool")}}
+	if value := res.Get("{{range .DataPath}}{{.}}.{{end}}{{.ModelName}}"); value.Exists(){{if not .ResourceId}} && !data.{{toGoName .TfName}}.IsNull(){{end}} {
+		data.{{toGoName .TfName}} = types.{{.Type}}Value(value.{{if eq .Type "Int64"}}Int{{else if eq .Type "Float64"}}Float{{else}}{{.Type}}{{end}}())
+	} else {{if .DefaultValue}}if data.{{toGoName .TfName}}.Value{{.Type}}() != {{if eq .Type "String"}}"{{end}}{{.DefaultValue}}{{if eq .Type "String"}}"{{end}} {{end}}{
+		data.{{toGoName .TfName}} = types.{{.Type}}Null()
+	}
+	{{- else if isListSet .}}
+	if value := res.Get("{{range .DataPath}}{{.}}.{{end}}{{.ModelName}}"); value.Exists() && !data.{{toGoName .TfName}}.IsNull() {
+		data.{{toGoName .TfName}} = helpers.Get{{.ElementType}}{{.Type}}(value.Array())
+	} else {
+		data.{{toGoName .TfName}} = types.{{.Type}}Null(types.{{.ElementType}}Type)
+	}
+	{{- else if isNestedListMapSet .}}
+	{{- $list := (toGoName .TfName)}}
+	{{- if isNestedMap .}}
+	for i := range data.{{toGoName .TfName}} {
+		parent := &data
+		data := (*parent).{{toGoName .TfName}}[i]
+		parentRes := &res
+		var res gjson.Result
+
+		parentRes.{{if .ModelName}}Get("{{range .DataPath}}{{.}}.{{end}}{{.ModelName}}").{{end}}ForEach(
+			func(_, v gjson.Result) bool {
+				if v.Get("id").String() == data.Id.ValueString() && data.Id.ValueString() != "" {
+					res = v
+					return false // break ForEach
+				}
+				return true
+			},
+		)
+	{{- else if .OrderedList }}
+	{
+		l := len(res.Get("{{range .DataPath}}{{.}}.{{end}}{{.ModelName}}").Array())
+		tflog.Debug(ctx, fmt.Sprintf("{{range .DataPath}}{{.}}.{{end}}{{.ModelName}} array resizing from %d to %d", len(data.{{toGoName .TfName}}), l))
+		for i := len(data.{{toGoName .TfName}}); i < l; i++ {
+			data.{{toGoName .TfName}} = append(data.{{toGoName .TfName}}, {{.GoTypeName}}{})
+		}
+		if len(data.{{toGoName .TfName}}) > l {
+			data.{{toGoName .TfName}} = data.{{toGoName .TfName}}[:l]
+		}
+	}
+	for i := range data.{{toGoName .TfName}} {
+		parent := &data
+		data := (*parent).{{toGoName .TfName}}[i]
+		parentRes := &res
+		res := parentRes.Get(fmt.Sprintf("{{range .DataPath}}{{.}}.{{end}}{{.ModelName}}.%d", i))
+	{{- else }}
+	for i := 0; i < len(data.{{toGoName .TfName}}); i++ {
+		keys := [...]string{ {{$noId := not (hasId .Attributes)}}{{range .Attributes}}{{if or .Id (and $noId (not .Value))}}{{if or (eq .Type "Int64") (eq .Type "Bool") (eq .Type "String")}}"{{range .DataPath}}{{.}}.{{end}}{{.ModelName}}", {{end}}{{end}}{{end}} }
+		keyValues := [...]string{ {{$noId := not (hasId .Attributes)}}{{range .Attributes}}{{if or .Id (and $noId (not .Value))}}{{if eq .Type "Int64"}}strconv.FormatInt(data.{{$list}}[i].{{toGoName .TfName}}.ValueInt64(), 10), {{else if eq .Type "Bool"}}strconv.FormatBool(data.{{$list}}[i].{{toGoName .TfName}}.ValueBool()), {{else if eq .Type "String"}}data.{{$list}}[i].{{toGoName .TfName}}.Value{{.Type}}(), {{end}}{{end}}{{end}} }
+
+		parent := &data
+		data := (*parent).{{toGoName .TfName}}[i]
+		parentRes := &res
+		var res gjson.Result
+
+		parentRes.{{if .ModelName}}Get("{{range .DataPath}}{{.}}.{{end}}{{.ModelName}}").{{end}}ForEach(
+			func(_, v gjson.Result) bool {
+				found := false
+				for ik := range keys {
+					if v.Get(keys[ik]).String() != keyValues[ik] {
+						found = false
+						break
+					}
+					found = true
+				}
+				if found {
+					res = v
+					return false
+				}
+				return true
+			},
+		)
+		if !res.Exists() {
+			tflog.Debug(ctx, fmt.Sprintf("removing {{toGoName .TfName}}[%d] = %+v",
+				i,
+				(*parent).{{toGoName .TfName}}[i],
+			))
+			(*parent).{{toGoName .TfName}} = slices.Delete((*parent).{{toGoName .TfName}}, i, i+1)
+			i--
+
+			continue
+		}
+	{{- end}}
+
+		{{- template "fromBodyPartialTemplate" .}}
+		(*parent).{{toGoName .TfName}}[i] = data
+	}
+	{{- end}}
+	{{- end}}
+	{{- end}}
+{{- end}}
+{{- template "fromBodyPartialTemplate" .}}
+}
+
+// End of section. //template:end fromBodyPartial
+
+// Section below is generated&owned by "gen/generator.go". //template:begin fromBodyUnknowns
+
+// fromBodyUnknowns updates the Unknown Computed tfstate values from a JSON.
+// Known values are not changed (usual for Computed attributes with UseStateForUnknown or with Default).
+func (data *{{camelCase .Name}}) fromBodyUnknowns(ctx context.Context, res gjson.Result) {
+	{{- range .Attributes}}
+	{{- if and .ResourceId (not .Reference)}}
+	{{- if or (eq .Type "String") (eq .Type "Int64") (eq .Type "Float64") (eq .Type "Bool")}}
+	if data.{{toGoName .TfName}}.IsUnknown() {
+		if value := res.Get("{{range .DataPath}}{{.}}.{{end}}{{.ModelName}}"); value.Exists() {
+			data.{{toGoName .TfName}} = types.{{.Type}}Value(value.{{if eq .Type "Int64"}}Int{{else if eq .Type "Float64"}}Float{{else}}{{.Type}}{{end}}())
+		} else {
+			data.{{toGoName .TfName}} = types.{{.Type}}Null()
+		}
+	}
+	{{- else}}
+	{{- errorf "resource_id is not yet implemented for type %v" .Type}}
+	{{- end}}
+	{{- else if isNestedListMapSet .}}
+	{{- if hasResourceId .Attributes}}
+	{{- $list := (toGoName .TfName)}}
+	{{- if .OrderedList }}
+	for i := range data.{{toGoName .TfName}} {
+		r := res.Get(fmt.Sprintf("{{range .DataPath}}{{.}}.{{end}}{{.ModelName}}.%d", i))
+	{{- else if isNestedListSet .}}
+	for i := range data.{{toGoName .TfName}} {
+		keys := [...]string{ {{$noId := not (hasId .Attributes)}}{{range .Attributes}}{{if or .Id (and $noId (not .Value))}}{{if or (eq .Type "Int64") (eq .Type "Bool") (eq .Type "String")}}"{{range .DataPath}}{{.}}.{{end}}{{.ModelName}}", {{end}}{{end}}{{end}} }
+		keyValues := [...]string{ {{$noId := not (hasId .Attributes)}}{{range .Attributes}}{{if or .Id (and $noId (not .Value))}}{{if eq .Type "Int64"}}strconv.FormatInt(data.{{$list}}[i].{{toGoName .TfName}}.ValueInt64(), 10), {{else if eq .Type "Bool"}}strconv.FormatBool(data.{{$list}}[i].{{toGoName .TfName}}.ValueBool()), {{else if eq .Type "String"}}data.{{$list}}[i].{{toGoName .TfName}}.Value{{.Type}}(), {{end}}{{end}}{{end}} }
+
+		var r gjson.Result
+		res.{{if .ModelName}}Get("{{range .DataPath}}{{.}}.{{end}}{{.ModelName}}").{{end}}ForEach(
+			func(_, v gjson.Result) bool {
+				found := false
+				for ik := range keys {
+					if v.Get(keys[ik]).String() != keyValues[ik] {
+						found = false
+						break
+					}
+					found = true
+				}
+				if found {
+					r = v
+					return false
+				}
+				return true
+			},
+		)
+	{{- else if isNestedMap .}}
+	for i, val := range data.{{toGoName .TfName}} {
+		var r gjson.Result
+		res.{{if .ModelName}}Get("{{range .DataPath}}{{.}}.{{end}}{{.ModelName}}").{{end}}ForEach(
+			func(_, v gjson.Result) bool {
+				if val.Id.IsUnknown() {
+					if v.Get("name").String() == i {
+						r = v
+						return false // break ForEach
+					}
+				} else {
+					if v.Get("id").String() == val.Id.ValueString() && val.Id.ValueString() != "" {
+						r = v
+						return false // break ForEach
+					}
+				}
+
+				return true
+			},
+		)
+	{{- end}}
+
+		{{- range .Attributes}}
+		{{- if and .ResourceId (not .Reference)}}
+		{{- if or (eq .Type "String") (eq .Type "Int64") (eq .Type "Float64") (eq .Type "Bool")}}
+		if v := data.{{$list}}[i]; v.{{toGoName .TfName}}.IsUnknown() {
+			if value := r.Get("{{range .DataPath}}{{.}}.{{end}}{{.ModelName}}"); value.Exists() {
+				v.{{toGoName .TfName}} = types.{{.Type}}Value(value.{{if eq .Type "Int64"}}Int{{else if eq .Type "Float64"}}Float{{else}}{{.Type}}{{end}}())
+			} else {
+				v.{{toGoName .TfName}} = types.{{.Type}}Null()
+			}
+			data.{{$list}}[i] = v
+		}
+		{{- else}}
+		{{- errorf "resource_id is not yet implemented for type %v" .Type}}
+		{{- end}}
+		{{- end}}
+		{{- end}}
+	}
+	{{- end}}
+	{{- end}}
+	{{- end}}
+}
+
+// End of section. //template:end fromBodyUnknowns
+{{- range .Attributes}}
+	{{- if isNestedMap .}}
+		{{- $found := false }}
+		{{- range .Attributes }}
+			{{- if and (eq .ModelName "id") (eq .TfName "id") .ResourceId}}
+				{{- $found = true }}
+			{{- end}}
+		{{- end}}
+		{{- if not $found }}
+			{{- errorf "type Map with attributes has a limitation for now: it must always contain attribute with `model_name: id` and `tf_name: id` and `resource_id: true`, because it must always be used to track subresources."}}
+		{{- end}}
+	{{- end}}
+	{{- range .Attributes}}
+		{{- if isNestedMap .}}
+			{{- errorf "Map not yet implemented at this depth"}}
+		{{- end}}
+		{{- if .OrderedList }}
+			{{- errorf "ordered_list not yet implemented at this depth"}}
+		{{- end}}
+		{{- if hasResourceId .Attributes}}
+			{{- errorf "resource_id not yet implemented at this depth"}}
+		{{- end}}
+
+		{{- range .Attributes}}
+			{{- if isNestedMap .}}
+				{{- errorf "Map not yet implemented at this depth"}}
+			{{- end}}
+			{{- if .OrderedList }}
+				{{- errorf "ordered_list not yet implemented at this depth"}}
+			{{- end}}
+			{{- if hasResourceId .Attributes}}
+				{{- errorf "resource_id not yet implemented at this depth"}}
+			{{- end}}
+
+			{{- range .Attributes}}
+				{{- if isNestedMap .}}
+					{{- errorf "Map not yet implemented at this depth"}}
+				{{- end}}
+				{{- if .OrderedList }}
+					{{- errorf "ordered_list not yet implemented at this depth"}}
+				{{- end}}
+				{{- if hasResourceId .Attributes}}
+					{{- errorf "resource_id not yet implemented at this depth"}}
+				{{- end}}
+				{{- range .Attributes}}
+					{{- errorf "attributes not yet implemented at this depth"}}
+				{{- end}}
+			{{- end}}
+		{{- end}}
+	{{- end}}
+{{- end}}
diff --git a/gen/templates/provider.go b/gen/templates/provider.go
new file mode 100644
index 00000000..98073468
--- /dev/null
+++ b/gen/templates/provider.go
@@ -0,0 +1,243 @@
+//go:build ignore
+
+// Copyright © 2024 Cisco Systems, Inc. and its affiliates.
+// All rights reserved.
+//
+// Licensed under the Mozilla Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://mozilla.org/MPL/2.0/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+// Section below is generated&owned by "gen/generator.go". //template:begin provider
+import (
+	"context"
+	"fmt"
+	"os"
+	"strconv"
+	"sync"
+	"time"
+
+	"github.com/hashicorp/terraform-plugin-framework-validators/int64validator"
+	"github.com/hashicorp/terraform-plugin-framework/provider"
+	"github.com/hashicorp/terraform-plugin-framework/provider/schema"
+	"github.com/hashicorp/terraform-plugin-framework/schema/validator"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+	"github.com/hashicorp/terraform-plugin-log/tflog"
+	"github.com/netascode/go-meraki"
+)
+
+// MerakiProvider defines the provider implementation.
+type MerakiProvider struct {
+	// version is set to the provider version on release, "dev" when the
+	// provider is built and ran locally, and "test" when running acceptance
+	// testing.
+	version string
+}
+
+// MerakiProviderModel describes the provider data model.
+type MerakiProviderModel struct {
+	ApiKey   types.String `tfsdk:"api_key"`
+	BaseUrl   types.String `tfsdk:"base_url"`
+	ReqTimeout types.String `tfsdk:"req_timeout"`
+	Retries    types.Int64  `tfsdk:"retries"`
+}
+
+// MerakiProviderData describes the data maintained by the provider.
+type MerakiProviderData struct {
+	Client      *meraki.Client
+}
+
+// Metadata returns the provider type name.
+func (p *MerakiProvider) Metadata(_ context.Context, _ provider.MetadataRequest, resp *provider.MetadataResponse) {
+	resp.TypeName = "meraki"
+	resp.Version = p.version
+}
+
+func (p *MerakiProvider) Schema(ctx context.Context, req provider.SchemaRequest, resp *provider.SchemaResponse) {
+	resp.Schema = schema.Schema{
+		Attributes: map[string]schema.Attribute{
+			"api_key": schema.StringAttribute{
+				MarkdownDescription: "Meraki Dashboard API key. This can also be set as the MERAKI_API_KEY environment variable.",
+				Optional:            true,
+				Sensitive:           true,
+			},
+			"base_url": schema.StringAttribute{
+				MarkdownDescription: "Base URL to be used. The default value is `https://api.meraki.com/api/v1`. This can also be set as the MERAKI_BASE_URL environment variable.",
+				Optional:            true,
+			},
+			"req_timeout": schema.StringAttribute{
+				MarkdownDescription: "Timeout for a single HTTPS request made to REST API before it is retried. This can also be set as the MERAKI_REQTIMEOUT environment variable. A string like `\"1s\"` means one second. Defaults to `\"5s\"`.",
+				Optional:            true,
+			},
+			"retries": schema.Int64Attribute{
+				MarkdownDescription: "Number of retries for REST API calls. This can also be set as the MERAKI_RETRIES environment variable. Defaults to `3`.",
+				Optional:            true,
+				Validators: []validator.Int64{
+					int64validator.Between(0, 9),
+				},
+			},
+		},
+	}
+}
+
+func (p *MerakiProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) {
+	// Retrieve provider data from configuration
+	var config MerakiProviderModel
+	diags := req.Config.Get(ctx, &config)
+	resp.Diagnostics.Append(diags...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	// User must provide an API key to the provider
+	var apiKey string
+	if config.ApiKey.IsUnknown() {
+		// Cannot connect to client with an unknown value
+		resp.Diagnostics.AddWarning(
+			"Unable to create client",
+			"Cannot use unknown value as API key",
+		)
+		return
+	}
+
+	if config.ApiKey.IsNull() {
+		apiKey = os.Getenv("MERAKI_API_KEY")
+	} else {
+		apiKey = config.ApiKey.ValueString()
+	}
+
+	if apiKey == "" {
+		// Error vs warning - empty value must stop execution
+		resp.Diagnostics.AddError(
+			"Unable to find API key",
+			"API key cannot be an empty string",
+		)
+		return
+	}
+
+	// User can provide a Base URL to the provider
+	var baseUrl string
+	if config.BaseUrl.IsUnknown() {
+		// Cannot connect to client with an unknown value
+		resp.Diagnostics.AddWarning(
+			"Unable to create client",
+			"Cannot use unknown value as base url",
+		)
+		return
+	}
+
+	if config.BaseUrl.IsNull() {
+		baseUrl = os.Getenv("MERAKI_BASE_URL")
+		if baseUrl == "" {
+			baseUrl = "https://api.meraki.com/api/v1"
+		}
+	} else {
+		baseUrl = config.BaseUrl.ValueString()
+	}
+
+	var reqTimeout time.Duration
+	if config.ReqTimeout.IsUnknown() {
+		// Cannot connect to client with an unknown value
+		resp.Diagnostics.AddWarning(
+			"Unable to create client",
+			"Cannot use unknown value as req_timeout",
+		)
+		return
+	}
+
+	var reqTimeoutStr string
+	if config.ReqTimeout.IsNull() {
+		reqTimeoutStr = os.Getenv("MERAKI_REQTIMEOUT")
+		if reqTimeoutStr == "" {
+			reqTimeoutStr = "5s"
+		}
+	} else {
+		reqTimeoutStr = config.ReqTimeout.ValueString()
+	}
+	reqTimeout, err := time.ParseDuration(reqTimeoutStr)
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Unable to create client",
+			fmt.Sprintf("Cannot parse the req_timeout string: %v", err),
+		)
+		return
+	}
+
+	var retries int64
+	if config.Retries.IsUnknown() {
+		// Cannot connect to client with an unknown value
+		resp.Diagnostics.AddWarning(
+			"Unable to create client",
+			"Cannot use unknown value as retries",
+		)
+		return
+	}
+
+	if config.Retries.IsNull() {
+		retriesStr := os.Getenv("MERAKI_RETRIES")
+		if retriesStr == "" {
+			retries = 3
+		} else {
+			retries, _ = strconv.ParseInt(retriesStr, 0, 64)
+		}
+	} else {
+		retries = config.Retries.ValueInt64()
+	}
+
+	tflog.Debug(ctx, fmt.Sprint("Creating a new Meraki client",
+		"  base_url=", baseUrl,
+		"  req_timeout=", reqTimeout,
+		"  retries=", retries,
+	))
+
+	// Create a new Meraki client and set it to the provider client
+	c, err := meraki.NewClient(apiKey, meraki.BaseUrl(baseUrl), meraki.MaxRetries(int(retries)), meraki.RequestTimeout(reqTimeout))
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Unable to create client",
+			"Unable to create meraki client:\n\n"+err.Error(),
+		)
+		return
+	}
+
+	data := MerakiProviderData{Client: &c}
+	resp.DataSourceData = &data
+	resp.ResourceData = &data
+}
+
+func (p *MerakiProvider) Resources(ctx context.Context) []func() resource.Resource {
+	return []func() resource.Resource{
+		{{- range .}}
+		New{{camelCase .}}Resource,
+		{{- end}}
+	}
+}
+
+func (p *MerakiProvider) DataSources(ctx context.Context) []func() datasource.DataSource {
+	return []func() datasource.DataSource{
+		{{- range .}}
+		New{{camelCase .}}DataSource,
+		{{- end}}
+	}
+}
+
+func New(version string) func() provider.Provider {
+	return func() provider.Provider {
+		return &MerakiProvider{
+			version: version,
+		}
+	}
+}
+
+// End of section. //template:end provider
diff --git a/gen/templates/resource.go b/gen/templates/resource.go
new file mode 100644
index 00000000..d89d5e72
--- /dev/null
+++ b/gen/templates/resource.go
@@ -0,0 +1,640 @@
+//go:build ignore
+// Copyright © 2024 Cisco Systems, Inc. and its affiliates.
+// All rights reserved.
+//
+// Licensed under the Mozilla Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://mozilla.org/MPL/2.0/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+// Section below is generated&owned by "gen/generator.go". //template:begin imports
+import (
+	"context"
+	"fmt"
+	"net/url"
+	"strings"
+	"sync"
+
+	"github.com/hashicorp/terraform-plugin-framework-validators/int64validator"
+	"github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
+	"github.com/hashicorp/terraform-plugin-framework/path"
+	"github.com/hashicorp/terraform-plugin-framework/resource"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/schema/validator"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+	"github.com/hashicorp/terraform-plugin-log/tflog"
+	"github.com/netascode/go-meraki"
+	"github.com/netascode/terraform-provider-meraki/internal/provider/helpers"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
+)
+
+// End of section. //template:end imports
+
+// Section below is generated&owned by "gen/generator.go". //template:begin model
+
+// Ensure provider defined types fully satisfy framework interfaces
+var (
+	_ resource.Resource                = &{{camelCase .Name}}Resource{}
+	_ resource.ResourceWithImportState = &{{camelCase .Name}}Resource{}
+)
+
+func New{{camelCase .Name}}Resource() resource.Resource {
+	return &{{camelCase .Name}}Resource{}
+}
+
+type {{camelCase .Name}}Resource struct {
+	client *meraki.Client
+}
+
+func (r *{{camelCase .Name}}Resource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
+	resp.TypeName = req.ProviderTypeName + "_{{snakeCase .Name}}"
+}
+
+func (r *{{camelCase .Name}}Resource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
+	resp.Schema = schema.Schema{
+		// This description is used by the documentation generator and the language server.
+		MarkdownDescription: helpers.NewAttributeDescription("{{.ResDescription}}").String,
+
+		Attributes: map[string]schema.Attribute{
+			"id": schema.StringAttribute{
+				MarkdownDescription: "The id of the object",
+				Computed:            true,
+				PlanModifiers: []planmodifier.String{
+					stringplanmodifier.UseStateForUnknown(),
+				},
+			},
+			{{- range  .Attributes}}
+			{{- if not .Value}}
+			"{{.TfName}}": schema.{{if isNestedListMapSet .}}{{.Type}}Nested{{else if isList .}}List{{else if isSet .}}Set{{else if eq .Type "Versions"}}List{{else if eq .Type "Version"}}Int64{{else}}{{.Type}}{{end}}Attribute{
+				MarkdownDescription: helpers.NewAttributeDescription("{{.Description}}")
+					{{- if len .EnumValues -}}
+					.AddStringEnumDescription({{range .EnumValues}}"{{.}}", {{end}})
+					{{- end -}}
+					{{- if or (ne .MinInt 0) (ne .MaxInt 0) -}}
+					.AddIntegerRangeDescription({{.MinInt}}, {{.MaxInt}})
+					{{- end -}}
+					{{- if or (ne .MinFloat 0.0) (ne .MaxFloat 0.0) -}}
+					.AddFloatRangeDescription({{.MinFloat}}, {{.MaxFloat}})
+					{{- end -}}
+					{{- if .DefaultValue -}}
+					.AddDefaultValueDescription("{{.DefaultValue}}")
+					{{- end -}}
+					.String,
+				{{- if isListSet .}}
+				ElementType:         types.{{.ElementType}}Type,
+				{{- end}}
+				{{- if or .Reference .Mandatory}}
+				Required:            true,
+				{{- else if not .ResourceId}}
+				Optional:            true,
+				{{- end}}
+				{{- if or (len .DefaultValue) .ResourceId}}
+				Computed:            true,
+				{{- end}}
+				{{- if len .EnumValues}}
+				Validators: []validator.String{
+					stringvalidator.OneOf({{range .EnumValues}}"{{.}}", {{end}}),
+				},
+				{{- else if or (len .StringPatterns) (ne .StringMinLength 0) (ne .StringMaxLength 0) }}
+				Validators: []validator.String{
+					{{- if or (ne .StringMinLength 0) (ne .StringMaxLength 0)}}
+					stringvalidator.LengthBetween({{.StringMinLength}}, {{.StringMaxLength}}),
+					{{- end}}
+					{{- range .StringPatterns}}
+					stringvalidator.RegexMatches(regexp.MustCompile(`{{.}}`), ""),
+					{{- end}}
+				},
+				{{- else if or (ne .MinInt 0) (ne .MaxInt 0)}}
+				Validators: []validator.Int64{
+					int64validator.Between({{.MinInt}}, {{.MaxInt}}),
+				},
+				{{- else if or (ne .MinFloat 0.0) (ne .MaxFloat 0.0)}}
+				Validators: []validator.Float64{
+					float64validator.Between({{.MinFloat}}, {{.MaxFloat}}),
+				},
+				{{- end}}
+				{{- if and (len .DefaultValue) (eq .Type "Int64")}}
+				Default:             int64default.StaticInt64({{.DefaultValue}}),
+				{{- else if and (len .DefaultValue) (eq .Type "Bool")}}
+				Default:             booldefault.StaticBool({{.DefaultValue}}),
+				{{- else if and (len .DefaultValue) (eq .Type "String")}}
+				Default:             stringdefault.StaticString("{{.DefaultValue}}"),
+				{{- end}}
+				{{- if or .Id .Reference .RequiresReplace}}
+				PlanModifiers: []planmodifier.{{.Type}}{
+					{{snakeCase .Type}}planmodifier.RequiresReplace(),
+				},
+				{{- end}}
+				{{- if isNestedListMapSet .}}
+				{{- $useStateForUnknown := isNestedMap .}}
+				NestedObject: schema.NestedAttributeObject{
+					Attributes: map[string]schema.Attribute{
+						{{- range  .Attributes}}
+						{{- if not .Value}}
+						"{{.TfName}}": schema.{{if isNestedListMapSet .}}{{.Type}}Nested{{else if isList .}}List{{else if isSet .}}Set{{else if eq .Type "Versions"}}List{{else if eq .Type "Version"}}Int64{{else}}{{.Type}}{{end}}Attribute{
+							MarkdownDescription: helpers.NewAttributeDescription("{{.Description}}")
+								{{- if len .EnumValues -}}
+								.AddStringEnumDescription({{range .EnumValues}}"{{.}}", {{end}})
+								{{- end -}}
+								{{- if or (ne .MinInt 0) (ne .MaxInt 0) -}}
+								.AddIntegerRangeDescription({{.MinInt}}, {{.MaxInt}})
+								{{- end -}}
+								{{- if or (ne .MinFloat 0.0) (ne .MaxFloat 0.0) -}}
+								.AddFloatRangeDescription({{.MinFloat}}, {{.MaxFloat}})
+								{{- end -}}
+								{{- if .DefaultValue -}}
+								.AddDefaultValueDescription("{{.DefaultValue}}")
+								{{- end -}}
+								.String,
+							{{- if isListSet .}}
+							ElementType:         types.{{.ElementType}}Type,
+							{{- end}}
+							{{- if or .Reference .Mandatory}}
+							Required:            true,
+							{{- else if not .ResourceId}}
+							Optional:            true,
+							{{- end}}
+							{{- if or (len .DefaultValue) .ResourceId}}
+							Computed:            true,
+							{{- end}}
+							{{- if len .EnumValues}}
+							Validators: []validator.String{
+								stringvalidator.OneOf({{range .EnumValues}}"{{.}}", {{end}}),
+							},
+							{{- else if or (len .StringPatterns) (ne .StringMinLength 0) (ne .StringMaxLength 0) }}
+							Validators: []validator.String{
+								{{- if or (ne .StringMinLength 0) (ne .StringMaxLength 0)}}
+								stringvalidator.LengthBetween({{.StringMinLength}}, {{.StringMaxLength}}),
+								{{- end}}
+								{{- range .StringPatterns}}
+								stringvalidator.RegexMatches(regexp.MustCompile(`{{.}}`), ""),
+								{{- end}}
+							},
+							{{- else if or (ne .MinInt 0) (ne .MaxInt 0)}}
+							Validators: []validator.Int64{
+								int64validator.Between({{.MinInt}}, {{.MaxInt}}),
+							},
+							{{- else if or (ne .MinFloat 0.0) (ne .MaxFloat 0.0)}}
+							Validators: []validator.Float64{
+								float64validator.Between({{.MinFloat}}, {{.MaxFloat}}),
+							},
+							{{- end}}
+							{{- if and (len .DefaultValue) (eq .Type "Int64")}}
+							Default:             int64default.StaticInt64({{.DefaultValue}}),
+							{{- else if and (len .DefaultValue) (eq .Type "Bool")}}
+							Default:             booldefault.StaticBool({{.DefaultValue}}),
+							{{- else if and (len .DefaultValue) (eq .Type "String")}}
+							Default:             stringdefault.StaticString("{{.DefaultValue}}"),
+							{{- end}}
+							{{- if and .ResourceId $useStateForUnknown}}
+							PlanModifiers: []planmodifier.{{.Type}}{
+								{{snakeCase .Type}}planmodifier.UseStateForUnknown(),
+							},
+							{{- else if .RequiresReplace}}
+							PlanModifiers: []planmodifier.{{.Type}}{
+								{{snakeCase .Type}}planmodifier.RequiresReplace(),
+							},
+							{{- end}}
+							{{- if isNestedListMapSet .}}
+							NestedObject: schema.NestedAttributeObject{
+								Attributes: map[string]schema.Attribute{
+									{{- range  .Attributes}}
+									{{- if not .Value}}
+									"{{.TfName}}": schema.{{if isNestedListMapSet .}}{{.Type}}Nested{{else if isList .}}List{{else if isSet .}}Set{{else if eq .Type "Versions"}}List{{else if eq .Type "Version"}}Int64{{else}}{{.Type}}{{end}}Attribute{
+										MarkdownDescription: helpers.NewAttributeDescription("{{.Description}}")
+											{{- if len .EnumValues -}}
+											.AddStringEnumDescription({{range .EnumValues}}"{{.}}", {{end}})
+											{{- end -}}
+											{{- if or (ne .MinInt 0) (ne .MaxInt 0) -}}
+											.AddIntegerRangeDescription({{.MinInt}}, {{.MaxInt}})
+											{{- end -}}
+											{{- if or (ne .MinFloat 0.0) (ne .MaxFloat 0.0) -}}
+											.AddFloatRangeDescription({{.MinFloat}}, {{.MaxFloat}})
+											{{- end -}}
+											{{- if .DefaultValue -}}
+											.AddDefaultValueDescription("{{.DefaultValue}}")
+											{{- end -}}
+											.String,
+										{{- if isListSet .}}
+										ElementType:         types.{{.ElementType}}Type,
+										{{- end}}
+										{{- if or .Reference .Mandatory}}
+										Required:            true,
+										{{- else if not .ResourceId}}
+										Optional:            true,
+										{{- end}}
+										{{- if or (len .DefaultValue) .ResourceId}}
+										Computed:            true,
+										{{- end}}
+										{{- if len .EnumValues}}
+										Validators: []validator.String{
+											stringvalidator.OneOf({{range .EnumValues}}"{{.}}", {{end}}),
+										},
+										{{- else if or (len .StringPatterns) (ne .StringMinLength 0) (ne .StringMaxLength 0) }}
+										Validators: []validator.String{
+											{{- if or (ne .StringMinLength 0) (ne .StringMaxLength 0)}}
+											stringvalidator.LengthBetween({{.StringMinLength}}, {{.StringMaxLength}}),
+											{{- end}}
+											{{- range .StringPatterns}}
+											stringvalidator.RegexMatches(regexp.MustCompile(`{{.}}`), ""),
+											{{- end}}
+										},
+										{{- else if or (ne .MinInt 0) (ne .MaxInt 0)}}
+										Validators: []validator.Int64{
+											int64validator.Between({{.MinInt}}, {{.MaxInt}}),
+										},
+										{{- else if or (ne .MinFloat 0.0) (ne .MaxFloat 0.0)}}
+										Validators: []validator.Float64{
+											float64validator.Between({{.MinFloat}}, {{.MaxFloat}}),
+										},
+										{{- end}}
+										{{- if and (len .DefaultValue) (eq .Type "Int64")}}
+										Default:             int64default.StaticInt64({{.DefaultValue}}),
+										{{- else if and (len .DefaultValue) (eq .Type "Bool")}}
+										Default:             booldefault.StaticBool({{.DefaultValue}}),
+										{{- else if and (len .DefaultValue) (eq .Type "String")}}
+										Default:             stringdefault.StaticString("{{.DefaultValue}}"),
+										{{- end}}
+										{{- if .RequiresReplace}}
+										PlanModifiers: []planmodifier.{{.Type}}{
+											{{snakeCase .Type}}planmodifier.RequiresReplace(),
+										},
+										{{- end}}
+										{{- if isNestedListMapSet .}}
+										NestedObject: schema.NestedAttributeObject{
+											Attributes: map[string]schema.Attribute{
+												{{- range  .Attributes}}
+												{{- if not .Value}}
+												"{{.TfName}}": schema.{{if isNestedListMapSet .}}{{.Type}}Nested{{else if isList .}}List{{else if isSet .}}Set{{else if eq .Type "Versions"}}List{{else if eq .Type "Version"}}Int64{{else}}{{.Type}}{{end}}Attribute{
+													MarkdownDescription: helpers.NewAttributeDescription("{{.Description}}")
+														{{- if len .EnumValues -}}
+														.AddStringEnumDescription({{range .EnumValues}}"{{.}}", {{end}})
+														{{- end -}}
+														{{- if or (ne .MinInt 0) (ne .MaxInt 0) -}}
+														.AddIntegerRangeDescription({{.MinInt}}, {{.MaxInt}})
+														{{- end -}}
+														{{- if or (ne .MinFloat 0.0) (ne .MaxFloat 0.0) -}}
+														.AddFloatRangeDescription({{.MinFloat}}, {{.MaxFloat}})
+														{{- end -}}
+														{{- if .DefaultValue -}}
+														.AddDefaultValueDescription("{{.DefaultValue}}")
+														{{- end -}}
+														.String,
+													{{- if isListSet .}}
+													ElementType:         types.{{.ElementType}}Type,
+													{{- end}}
+													{{- if or .Reference .Mandatory}}
+													Required:            true,
+													{{- else if not .ResourceId}}
+													Optional:            true,
+													{{- end}}
+													{{- if or (len .DefaultValue) .ResourceId}}
+													Computed:            true,
+													{{- end}}
+													{{- if len .EnumValues}}
+													Validators: []validator.String{
+														stringvalidator.OneOf({{range .EnumValues}}"{{.}}", {{end}}),
+													},
+													{{- else if or (len .StringPatterns) (ne .StringMinLength 0) (ne .StringMaxLength 0) }}
+													Validators: []validator.String{
+														{{- if or (ne .StringMinLength 0) (ne .StringMaxLength 0)}}
+														stringvalidator.LengthBetween({{.StringMinLength}}, {{.StringMaxLength}}),
+														{{- end}}
+														{{- range .StringPatterns}}
+														stringvalidator.RegexMatches(regexp.MustCompile(`{{.}}`), ""),
+														{{- end}}
+													},
+													{{- else if or (ne .MinInt 0) (ne .MaxInt 0)}}
+													Validators: []validator.Int64{
+														int64validator.Between({{.MinInt}}, {{.MaxInt}}),
+													},
+													{{- else if or (ne .MinFloat 0.0) (ne .MaxFloat 0.0)}}
+													Validators: []validator.Float64{
+														float64validator.Between({{.MinFloat}}, {{.MaxFloat}}),
+													},
+													{{- end}}
+													{{- if and (len .DefaultValue) (eq .Type "Int64")}}
+													Default:             int64default.StaticInt64({{.DefaultValue}}),
+													{{- else if and (len .DefaultValue) (eq .Type "Bool")}}
+													Default:             booldefault.StaticBool({{.DefaultValue}}),
+													{{- else if and (len .DefaultValue) (eq .Type "String")}}
+													Default:             stringdefault.StaticString("{{.DefaultValue}}"),
+													{{- end}}
+													{{- if .RequiresReplace}}
+													PlanModifiers: []planmodifier.{{.Type}}{
+														{{snakeCase .Type}}planmodifier.RequiresReplace(),
+													},
+													{{- end}}
+												},
+												{{- end}}
+												{{- end}}
+											},
+										},
+										{{- if or (ne .MinList 0) (ne .MaxList 0)}}
+										Validators: []validator.List{
+											{{- if ne .MinList 0}}
+											listvalidator.SizeAtLeast({{.MinList}}),
+											{{- end}}
+											{{- if ne .MaxList 0}}
+											listvalidator.SizeAtMost({{.MaxList}}),
+											{{- end}}
+										},
+										{{- end}}
+										{{- end}}
+									},
+									{{- end}}
+									{{- end}}
+								},
+							},
+							{{- if or (ne .MinList 0) (ne .MaxList 0)}}
+							Validators: []validator.List{
+								{{- if ne .MinList 0}}
+								listvalidator.SizeAtLeast({{.MinList}}),
+								{{- end}}
+								{{- if ne .MaxList 0}}
+								listvalidator.SizeAtMost({{.MaxList}}),
+								{{- end}}
+							},
+							{{- end}}
+							{{- end}}
+						},
+						{{- end}}
+						{{- end}}
+					},
+				},
+				{{- if or (ne .MinList 0) (ne .MaxList 0)}}
+				Validators: []validator.List{
+					{{- if ne .MinList 0}}
+					listvalidator.SizeAtLeast({{.MinList}}),
+					{{- end}}
+					{{- if ne .MaxList 0}}
+					listvalidator.SizeAtMost({{.MaxList}}),
+					{{- end}}
+				},
+				{{- end}}
+				{{- end}}
+			},
+			{{- end}}
+			{{- end}}
+		},
+	}
+}
+
+func (r *{{camelCase .Name}}Resource) Configure(_ context.Context, req resource.ConfigureRequest, _ *resource.ConfigureResponse) {
+	if req.ProviderData == nil {
+		return
+	}
+
+	r.client = req.ProviderData.(*MerakiProviderData).Client
+}
+
+// End of section. //template:end model
+
+// Section below is generated&owned by "gen/generator.go". //template:begin create
+
+func (r *{{camelCase .Name}}Resource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
+	var plan {{camelCase .Name}}
+
+	// Read plan
+	diags := req.Plan.Get(ctx, &plan)
+	if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() {
+		return
+	}
+
+	{{- if .PutCreate}}
+	tflog.Debug(ctx, fmt.Sprintf("%s: considering object name %s", plan.Id, plan.Name))
+
+	if plan.Id.ValueString() == "" && plan.Name.ValueString() != "" {
+		res, err := r.client.Get(plan.getPath())
+		if err != nil {
+			resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err))
+			return
+		}
+		if len(res.Array()) > 0 {
+			res.ForEach(func(k, v gjson.Result) bool {
+				if plan.Name.ValueString() == v.Get("name").String() {
+					plan.Id = types.StringValue(v.Get("id").String())
+					tflog.Debug(ctx, fmt.Sprintf("%s: Found object with name '%s', id: %s", plan.Id, plan.Name.ValueString(), plan.Id))
+					return false
+				}
+				return true
+			})
+		}
+
+		if plan.Id.ValueString() == "" {
+			resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to find object with name: %s", plan.Name.ValueString()))
+			return
+		}
+	}
+	{{- end}}
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Create", plan.Id.ValueString()))
+
+	// Create object
+	body := plan.toBody(ctx, {{camelCase .Name}}{})
+
+	{{- if .PutCreate}}
+	res, err := r.client.Put(plan.getPath()+"/"+url.PathEscape(plan.Id.ValueString()), body)
+	{{- else}}
+	res, err := r.client.Post(plan.getPath(), body)
+	{{- end}}
+	if err != nil {
+		resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to configure object (POST/PUT), got error: %s, %s", err, res.String()))
+		return
+	}
+	plan.Id = types.StringValue(res.Get("id").String())
+
+	{{- if hasResourceId .Attributes}}
+	res, err = r.client.Get(plan.getPath() + "/" + url.QueryEscape(plan.Id.ValueString()))
+	if err != nil {
+		resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve object (GET), got error: %s, %s", err, res.String()))
+		return
+	}
+	plan.fromBodyUnknowns(ctx, res)
+	{{- end}}
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Create finished successfully", plan.Id.ValueString()))
+
+	diags = resp.State.Set(ctx, &plan)
+	resp.Diagnostics.Append(diags...)
+
+	helpers.SetFlagImporting(ctx, false, resp.Private, &resp.Diagnostics)
+}
+
+// End of section. //template:end create
+
+// Section below is generated&owned by "gen/generator.go". //template:begin read
+
+func (r *{{camelCase .Name}}Resource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
+	var state {{camelCase .Name}}
+
+	// Read state
+	diags := req.State.Get(ctx, &state)
+	if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() {
+		return
+	}
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Read", state.Id.String()))
+
+	{{- if .GetFromAll}}
+	res, err := r.client.Get(state.getPath())
+	{{- else}}
+	res, err := r.client.Get(state.getPath() + "/" + url.QueryEscape(state.Id.ValueString()))
+	{{- end}}
+	if err != nil && strings.Contains(err.Error(), "StatusCode 404") {
+		resp.State.RemoveResource(ctx)
+		return
+	} else if err != nil {
+		resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve object (GET), got error: %s, %s", err, res.String()))
+		return
+	}
+	{{- if .GetFromAll}}
+	if len(res.Array()) > 0 {
+		res.ForEach(func(k, v gjson.Result) bool {
+			if state.Id.ValueString() == v.Get("id").String() {
+				res = v
+				return false
+			}
+			return true
+		})
+	}
+	{{- end}}
+
+	imp, diags := helpers.IsFlagImporting(ctx, req)
+	if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() {
+		return
+	}
+
+	// After `terraform import` we switch to a full read.
+	if imp {
+		state.fromBody(ctx, res)
+	} else {
+		state.fromBodyPartial(ctx, res)
+	}
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Read finished successfully", state.Id.ValueString()))
+
+	diags = resp.State.Set(ctx, &state)
+	resp.Diagnostics.Append(diags...)
+
+	helpers.SetFlagImporting(ctx, false, resp.Private, &resp.Diagnostics)
+}
+
+// End of section. //template:end read
+
+// Section below is generated&owned by "gen/generator.go". //template:begin update
+
+func (r *{{camelCase .Name}}Resource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
+	var plan, state {{camelCase .Name}}
+
+	// Read plan
+	diags := req.Plan.Get(ctx, &plan)
+	if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() {
+		return
+	}
+
+	// Read state
+	diags = req.State.Get(ctx, &state)
+	if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() {
+		return
+	}
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Update", plan.Id.ValueString()))
+	{{- if not .NoUpdate}}
+
+	body := plan.toBody(ctx, state)
+	res, err := r.client.Put(plan.getPath() + "/" + url.QueryEscape(plan.Id.ValueString()), body)
+	if err != nil {
+		resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to configure object (PUT), got error: %s, %s", err, res.String()))
+		return
+	}
+
+	{{- if hasResourceId .Attributes}}
+	res, err = r.client.Get(plan.getPath() + "/" + url.QueryEscape(plan.Id.ValueString()))
+	if err != nil {
+		resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve object (GET), got error: %s, %s", err, res.String()))
+		return
+	}
+	plan.fromBodyUnknowns(ctx, res)
+	{{- end}}
+	{{- end}}
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Update finished successfully", plan.Id.ValueString()))
+
+	diags = resp.State.Set(ctx, &plan)
+	resp.Diagnostics.Append(diags...)
+}
+
+// End of section. //template:end update
+
+// Section below is generated&owned by "gen/generator.go". //template:begin delete
+
+func (r *{{camelCase .Name}}Resource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
+	var state {{camelCase .Name}}
+
+	// Read state
+	diags := req.State.Get(ctx, &state)
+	if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() {
+		return
+	}
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Delete", state.Id.ValueString()))
+
+	{{- if not .NoDelete}}
+	res, err := r.client.Delete(state.getPath() + "/" + url.QueryEscape(state.Id.ValueString()))
+	if err != nil {
+		resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to delete object (DELETE), got error: %s, %s", err, res.String()))
+		return
+	}
+	{{- end}}
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Delete finished successfully", state.Id.ValueString()))
+
+	resp.State.RemoveResource(ctx)
+}
+
+// End of section. //template:end delete
+
+// Section below is generated&owned by "gen/generator.go". //template:begin import
+
+func (r *{{camelCase .Name}}Resource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
+	{{- if hasReference .Attributes}}
+	idParts := strings.Split(req.ID, ",")
+
+	if len(idParts) != {{importParts .Attributes}}{{range $index, $attr := .Attributes}}{{if $attr.Reference}} || idParts[{{$index}}] == ""{{end}}{{end}}  || idParts[{{subtract (importParts .Attributes) 1}}] == "" {
+		resp.Diagnostics.AddError(
+			"Unexpected Import Identifier",
+			fmt.Sprintf("Expected import identifier with format: {{range $index, $attr := .Attributes}}{{if $attr.Reference}}{{if $index}},{{end}}<{{$attr.TfName}}>{{end}}{{end}},<id>. Got: %q", req.ID),
+		)
+		return
+	}
+
+	{{- range $index, $attr := .Attributes}}
+	{{- if or $attr.Reference $attr.Id}}
+	resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("{{$attr.TfName}}"), idParts[{{$index}}])...)
+	{{- end}}
+	{{- end}}
+	resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("id"), idParts[{{subtract (importParts .Attributes) 1}}])...)
+	{{- else}}
+	resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
+	{{- end}}
+
+	helpers.SetFlagImporting(ctx, true, resp.Private, &resp.Diagnostics)
+}
+
+// End of section. //template:end import
diff --git a/gen/templates/resource.tf b/gen/templates/resource.tf
new file mode 100644
index 00000000..8a93716c
--- /dev/null
+++ b/gen/templates/resource.tf
@@ -0,0 +1,53 @@
+resource "meraki_{{snakeCase .Name}}" "example" {
+{{- range  .Attributes}}
+{{- if and (not .ExcludeExample) (not .Value) (not .ResourceId)}}
+{{- if isNestedListMapSet .}}
+  {{.TfName}} =
+  {{- if isNestedListSet . -}}
+  [
+    {
+  {{- else -}}
+  {
+    {{.MapKeyExample}} = {
+  {{- end}}
+      {{- range  .Attributes}}
+      {{- if and (not .ExcludeExample) (not .Value)}}
+      {{- if isNestedListSet .}}
+        {{.TfName}} = [
+          {
+          {{- range  .Attributes}}
+          {{- if and (not .ExcludeExample) (not .Value)}}
+          {{- if isNestedListSet .}}
+            {{.TfName}} = [
+              {
+                {{- range  .Attributes}}
+                {{- if and (not .ExcludeExample) (not .Value)}}
+                {{.TfName}} = {{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}
+                {{- end}}
+                {{- end}}
+              }
+            ]
+          {{- else}}
+          {{.TfName}} = {{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}
+          {{- end}}
+          {{- end}}
+          {{- end}}
+          }
+        ]
+      {{- else}}
+      {{.TfName}} = {{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}
+      {{- end}}
+      {{- end}}
+      {{- end}}
+    }
+  {{- if isNestedListSet .}}
+  ]
+  {{- else}}
+  }
+  {{- end}}
+{{- else}}
+  {{.TfName}} = {{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}
+{{- end}}
+{{- end}}
+{{- end}}
+}
diff --git a/gen/templates/resource_test.go b/gen/templates/resource_test.go
new file mode 100644
index 00000000..4fd6fcea
--- /dev/null
+++ b/gen/templates/resource_test.go
@@ -0,0 +1,333 @@
+//go:build ignore
+// Copyright © 2024 Cisco Systems, Inc. and its affiliates.
+// All rights reserved.
+//
+// Licensed under the Mozilla Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://mozilla.org/MPL/2.0/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+// Section below is generated&owned by "gen/generator.go". //template:begin imports
+import (
+	"testing"
+
+	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+// End of section. //template:end imports
+
+// Section below is generated&owned by "gen/generator.go". //template:begin testAcc
+
+func TestAccMeraki{{camelCase .Name}}(t *testing.T) {
+	{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} && {{end}}os.Getenv("{{$e}}") == ""{{end}} {
+        t.Skip("skipping test, set environment variable {{range $i, $e := .TestTags}}{{if $i}} or {{end}}{{$e}}{{end}}")
+	}
+	{{- end}}
+	var checks []resource.TestCheckFunc
+	{{- $name := .Name }}
+	{{- range  .Attributes}}
+	{{- if and (not .WriteOnly) (not .ExcludeTest) (not .Value) (not .TestValue) (not .ResourceId)}}
+	{{- if isNestedListSet .}}
+	{{- $list := .TfName }}
+	{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+	{{- end}}
+	{{- range  .Attributes}}
+	{{- if and (not .WriteOnly) (not .ExcludeTest) (not .Value) (not .TestValue)}}
+	{{- if isNestedListSet .}}
+	{{- $clist := .TfName }}
+	{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+	{{- end}}
+	{{- range  .Attributes}}
+	{{- if and (not .WriteOnly) (not .ExcludeTest) (not .Value) (not .TestValue)}}
+	{{- if isNestedListSet .}}
+	{{- $cclist := .TfName }}
+	{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+	{{- end}}
+	{{- range  .Attributes}}
+	{{- if and (not .WriteOnly) (not .ExcludeTest) (not .Value) (not .TestValue) (not (isSet .))}}
+	{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+		checks = append(checks, resource.TestCheckResourceAttr("meraki_{{snakeCase $name}}.test", "{{$list}}.0.{{$clist}}.0.{{$cclist}}.0.{{.TfName}}{{if isList .}}.0{{end}}", "{{.Example}}"))
+	}
+	{{- else}}
+	checks = append(checks, resource.TestCheckResourceAttr("meraki_{{snakeCase $name}}.test", "{{$list}}.0.{{$clist}}.0.{{$cclist}}.0.{{.TfName}}{{if isList .}}.0{{end}}", "{{.Example}}"))
+	{{- end}}
+	{{- end}}
+	{{- end}}
+	{{- if len .TestTags}}
+	}
+	{{- end}}
+	{{- else if not (or (isSet .) (isNestedMap .))}}
+	{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+		checks = append(checks, resource.TestCheckResourceAttr("meraki_{{snakeCase $name}}.test", "{{$list}}.0.{{$clist}}.0.{{.TfName}}{{if isList .}}.0{{end}}", "{{.Example}}"))
+	}
+	{{- else}}
+	checks = append(checks, resource.TestCheckResourceAttr("meraki_{{snakeCase $name}}.test", "{{$list}}.0.{{$clist}}.0.{{.TfName}}{{if isList .}}.0{{end}}", "{{.Example}}"))
+	{{- end}}
+	{{- end}}
+	{{- end}}
+	{{- end}}
+	{{- if len .TestTags}}
+	}
+	{{- end}}
+	{{- else if not (or (isSet .) (isNestedMap .))}}
+	{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+		checks = append(checks, resource.TestCheckResourceAttr("meraki_{{snakeCase $name}}.test", "{{$list}}.0.{{.TfName}}{{if isList .}}.0{{end}}", "{{.Example}}"))
+	}
+	{{- else}}
+	checks = append(checks, resource.TestCheckResourceAttr("meraki_{{snakeCase $name}}.test", "{{$list}}.0.{{.TfName}}{{if isList .}}.0{{end}}", "{{.Example}}"))
+	{{- end}}
+	{{- end}}
+	{{- end}}
+	{{- end}}
+	{{- if len .TestTags}}
+	}
+	{{- end}}
+	{{- else if not (or (isSet .) (isNestedMap .))}}
+	{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+		checks = append(checks, resource.TestCheckResourceAttr("meraki_{{snakeCase $name}}.test", "{{.TfName}}{{if isList .}}.0{{end}}", "{{.Example}}"))
+	}
+	{{- else}}
+	checks = append(checks, resource.TestCheckResourceAttr("meraki_{{snakeCase $name}}.test", "{{.TfName}}{{if isList .}}.0{{end}}", "{{.Example}}"))
+	{{- end}}
+	{{- end}}
+	{{- end}}
+	{{- end}}
+
+	var steps []resource.TestStep
+	{{- if not .SkipMinimumTest}}
+	if os.Getenv("SKIP_MINIMUM_TEST") == "" {
+		steps = append(steps, resource.TestStep{
+			Config: {{if .TestPrerequisites}}testAccMeraki{{camelCase .Name}}PrerequisitesConfig+{{end}}testAccMeraki{{camelCase .Name}}Config_minimum(),
+		})
+	}
+	{{- end}}
+	steps = append(steps, resource.TestStep{
+		Config: {{if .TestPrerequisites}}testAccMeraki{{camelCase .Name}}PrerequisitesConfig+{{end}}testAccMeraki{{camelCase .Name}}Config_all(),
+		Check: resource.ComposeTestCheckFunc(checks...),
+	})
+	{{- if not (hasReference .Attributes)}}
+	steps = append(steps, resource.TestStep{
+		ResourceName:  "meraki_{{snakeCase $name}}.test",
+		ImportState:   true,
+	})
+	{{- end}}
+
+	resource.Test(t, resource.TestCase{
+		PreCheck:                 func() { testAccPreCheck(t) },
+		ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+		Steps: steps,
+	})
+}
+
+// End of section. //template:end testAcc
+
+// Section below is generated&owned by "gen/generator.go". //template:begin testPrerequisites
+{{- if .TestPrerequisites}}
+
+const testAccMeraki{{camelCase .Name}}PrerequisitesConfig = `
+{{.TestPrerequisites}}
+`
+
+{{- end}}
+// End of section. //template:end testPrerequisites
+
+// Section below is generated&owned by "gen/generator.go". //template:begin testAccConfigMinimal
+
+func testAccMeraki{{camelCase .Name}}Config_minimum() string {
+	config := `resource "meraki_{{snakeCase $name}}" "test" {` + "\n"
+	{{- range  .Attributes}}
+	{{- if or .Id .Reference .Mandatory .MinimumTestValue}}
+	{{- if isNestedListSet .}}
+	{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+	{{- end}}
+	config += `	{{.TfName}} = [{` + "\n"
+		{{- range  .Attributes}}
+		{{- if or .Id .Reference .Mandatory .MinimumTestValue}}
+		{{- if isNestedListSet .}}
+		{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+		{{- end}}
+	config += `		{{.TfName}} = [{` + "\n"
+			{{- range  .Attributes}}
+			{{- if or .Id .Reference .Mandatory .MinimumTestValue}}
+			{{- if isNestedListSet .}}
+			{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+			{{- end}}
+	config += `			{{.TfName}} = [{` + "\n"
+				{{- range  .Attributes}}
+				{{- if or .Id .Reference .Mandatory .MinimumTestValue}}
+				{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+		config += `				{{.TfName}} = {{if .MinimumTestValue}}{{.MinimumTestValue}}{{else if .TestValue}}{{.TestValue}}{{else}}{{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}{{end}}` + "\n"
+	}
+				{{- else}}
+	config += `				{{.TfName}} = {{if .MinimumTestValue}}{{.MinimumTestValue}}{{else if .TestValue}}{{.TestValue}}{{else}}{{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}{{end}}` + "\n"
+				{{- end}}
+				{{- end}}
+				{{- end}}
+	config += `			}]` + "\n"
+			{{- if len .TestTags}}
+	}
+			{{- end}}
+			{{- else}}
+			{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+		config += `		{{.TfName}} = {{if .MinimumTestValue}}{{.MinimumTestValue}}{{else if .TestValue}}{{.TestValue}}{{else}}{{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}{{end}}` + "\n"
+	}
+			{{- else}}
+	config += `		{{.TfName}} = {{if .MinimumTestValue}}{{.MinimumTestValue}}{{else if .TestValue}}{{.TestValue}}{{else}}{{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}{{end}}` + "\n"
+			{{- end}}
+			{{- end}}
+			{{- end}}
+			{{- end}}
+	config += `		}]` + "\n"
+		{{- if len .TestTags}}
+	}
+		{{- end}}
+		{{- else}}
+		{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+		config += `		{{.TfName}} = {{if .MinimumTestValue}}{{.MinimumTestValue}}{{else if .TestValue}}{{.TestValue}}{{else}}{{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}{{end}}` + "\n"
+	}
+			{{- else}}
+	config += `		{{.TfName}} = {{if .MinimumTestValue}}{{.MinimumTestValue}}{{else if .TestValue}}{{.TestValue}}{{else}}{{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}{{end}}` + "\n"
+		{{- end}}
+		{{- end}}
+		{{- end}}
+		{{- end}}
+	config += `	}]` + "\n"
+		{{- if len .TestTags}}
+	}
+		{{- end}}
+	{{- else}}
+	{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+		config += `	{{.TfName}} = {{if .MinimumTestValue}}{{.MinimumTestValue}}{{else if .TestValue}}{{.TestValue}}{{else}}{{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}{{end}}` + "\n"
+	}
+	{{- else}}
+	config += `	{{.TfName}} = {{if .MinimumTestValue}}{{.MinimumTestValue}}{{else if .TestValue}}{{.TestValue}}{{else}}{{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}{{end}}` + "\n"
+	{{- end}}
+	{{- end}}
+	{{- end}}
+	{{- end}}
+	config += `}` + "\n"
+	return config
+}
+
+// End of section. //template:end testAccConfigMinimal
+
+// Section below is generated&owned by "gen/generator.go". //template:begin testAccConfigAll
+
+func testAccMeraki{{camelCase .Name}}Config_all() string {
+	config := `resource "meraki_{{snakeCase $name}}" "test" {` + "\n"
+	{{- range  .Attributes}}
+	{{- if and (not .ExcludeTest) (not .Value) (not .ResourceId)}}
+	{{- if isNestedListMapSet .}}
+	{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+	{{- end}}
+	{{- if isNestedListSet .}}
+	config += `	{{.TfName}} = [{` + "\n"
+	{{- else if isNestedMap .}}
+	config += `	{{.TfName}} = { "{{.MapKeyExample}}" = {` + "\n"
+	{{- end}}
+		{{- range  .Attributes}}
+		{{- if and (not .ExcludeTest) (not .Value)}}
+		{{- if isNestedListSet .}}
+		{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+		{{- end}}
+	config += `		{{.TfName}} = [{` + "\n"
+			{{- range  .Attributes}}
+			{{- if and (not .ExcludeTest) (not .Value)}}
+			{{- if isNestedListSet .}}
+			{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+			{{- end}}
+	config += `			{{.TfName}} = [{` + "\n"
+				{{- range  .Attributes}}
+				{{- if and (not .ExcludeTest) (not .Value)}}
+				{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+		config += `				{{.TfName}} = {{if .TestValue}}{{.TestValue}}{{else}}{{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}{{end}}` + "\n"
+	}
+				{{- else}}
+	config += `				{{.TfName}} = {{if .TestValue}}{{.TestValue}}{{else}}{{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}{{end}}` + "\n"
+				{{- end}}
+				{{- end}}
+				{{- end}}
+	config += `			}]` + "\n"
+			{{- if len .TestTags}}
+	}
+			{{- end}}
+			{{- else}}
+			{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+		config += `			{{.TfName}} = {{if .TestValue}}{{.TestValue}}{{else}}{{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}{{end}}` + "\n"
+	}
+			{{- else}}
+	config += `			{{.TfName}} = {{if .TestValue}}{{.TestValue}}{{else}}{{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}{{end}}` + "\n"
+			{{- end}}
+			{{- end}}
+			{{- end}}
+			{{- end}}
+	config += `		}]` + "\n"
+		{{- if len .TestTags}}
+	}
+		{{- end}}
+		{{- else}}
+		{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+		config += `		{{.TfName}} = {{if .TestValue}}{{.TestValue}}{{else}}{{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}{{end}}` + "\n"
+	}
+			{{- else}}
+	config += `		{{.TfName}} = {{if .TestValue}}{{.TestValue}}{{else}}{{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}{{end}}` + "\n"
+		{{- end}}
+		{{- end}}
+		{{- end}}
+		{{- end}}
+	{{- if isNestedListSet .}}
+	config += `	}]` + "\n"
+	{{- else if isNestedMap .}}
+	config += `	}}` + "\n"
+	{{- end}}
+		{{- if len .TestTags}}
+	}
+		{{- end}}
+	{{- else}}
+	{{- if len .TestTags}}
+	if {{range $i, $e := .TestTags}}{{if $i}} || {{end}}os.Getenv("{{$e}}") != ""{{end}} {
+		config += `	{{.TfName}} = {{if .TestValue}}{{.TestValue}}{{else}}{{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}{{end}}` + "\n"
+	}
+	{{- else}}
+	config += `	{{.TfName}} = {{if .TestValue}}{{.TestValue}}{{else}}{{if eq .Type "String"}}"{{.Example}}"{{else if isStringListSet .}}["{{.Example}}"]{{else if isInt64ListSet .}}[{{.Example}}]{{else}}{{.Example}}{{end}}{{end}}` + "\n"
+	{{- end}}
+	{{- end}}
+	{{- end}}
+	{{- end}}
+	config += `}` + "\n"
+	return config
+}
+
+// End of section. //template:end testAccConfigAll
diff --git a/go.mod b/go.mod
new file mode 100644
index 00000000..97da5a6c
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,92 @@
+module github.com/netascode/terraform-provider-meraki
+
+go 1.22
+
+require (
+	github.com/hashicorp/terraform-plugin-docs v0.19.4
+	github.com/hashicorp/terraform-plugin-framework v1.11.0
+	github.com/hashicorp/terraform-plugin-framework-validators v0.13.0
+	github.com/hashicorp/terraform-plugin-go v0.23.0
+	github.com/hashicorp/terraform-plugin-log v0.9.0
+	github.com/hashicorp/terraform-plugin-testing v1.10.0
+	github.com/netascode/go-meraki v0.0.0-20240901102824-a67592c39438
+	github.com/tidwall/gjson v1.17.3
+	github.com/tidwall/sjson v1.2.5
+	golang.org/x/tools v0.24.0
+	gopkg.in/yaml.v3 v3.0.1
+)
+
+require (
+	github.com/BurntSushi/toml v1.2.1 // indirect
+	github.com/Kunde21/markdownfmt/v3 v3.1.0 // indirect
+	github.com/Masterminds/goutils v1.1.1 // indirect
+	github.com/Masterminds/semver/v3 v3.2.0 // indirect
+	github.com/Masterminds/sprig/v3 v3.2.3 // indirect
+	github.com/ProtonMail/go-crypto v1.1.0-alpha.2 // indirect
+	github.com/agext/levenshtein v1.2.2 // indirect
+	github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
+	github.com/armon/go-radix v1.0.0 // indirect
+	github.com/bgentry/speakeasy v0.1.0 // indirect
+	github.com/bmatcuk/doublestar/v4 v4.6.1 // indirect
+	github.com/cloudflare/circl v1.3.7 // indirect
+	github.com/fatih/color v1.17.0 // indirect
+	github.com/golang/protobuf v1.5.4 // indirect
+	github.com/google/go-cmp v0.6.0 // indirect
+	github.com/google/uuid v1.6.0 // indirect
+	github.com/hashicorp/cli v1.1.6 // indirect
+	github.com/hashicorp/errwrap v1.1.0 // indirect
+	github.com/hashicorp/go-checkpoint v0.5.0 // indirect
+	github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
+	github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 // indirect
+	github.com/hashicorp/go-hclog v1.6.3 // indirect
+	github.com/hashicorp/go-multierror v1.1.1 // indirect
+	github.com/hashicorp/go-plugin v1.6.1 // indirect
+	github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
+	github.com/hashicorp/go-uuid v1.0.3 // indirect
+	github.com/hashicorp/go-version v1.7.0 // indirect
+	github.com/hashicorp/hc-install v0.8.0 // indirect
+	github.com/hashicorp/hcl/v2 v2.21.0 // indirect
+	github.com/hashicorp/logutils v1.0.0 // indirect
+	github.com/hashicorp/terraform-exec v0.21.0 // indirect
+	github.com/hashicorp/terraform-json v0.22.1 // indirect
+	github.com/hashicorp/terraform-plugin-sdk/v2 v2.34.0 // indirect
+	github.com/hashicorp/terraform-registry-address v0.2.3 // indirect
+	github.com/hashicorp/terraform-svchost v0.1.1 // indirect
+	github.com/hashicorp/yamux v0.1.1 // indirect
+	github.com/huandu/xstrings v1.3.3 // indirect
+	github.com/imdario/mergo v0.3.15 // indirect
+	github.com/juju/ratelimit v1.0.2 // indirect
+	github.com/mattn/go-colorable v0.1.13 // indirect
+	github.com/mattn/go-isatty v0.0.20 // indirect
+	github.com/mattn/go-runewidth v0.0.9 // indirect
+	github.com/mitchellh/copystructure v1.2.0 // indirect
+	github.com/mitchellh/go-testing-interface v1.14.1 // indirect
+	github.com/mitchellh/go-wordwrap v1.0.0 // indirect
+	github.com/mitchellh/mapstructure v1.5.0 // indirect
+	github.com/mitchellh/reflectwalk v1.0.2 // indirect
+	github.com/oklog/run v1.1.0 // indirect
+	github.com/posener/complete v1.2.3 // indirect
+	github.com/shopspring/decimal v1.3.1 // indirect
+	github.com/spf13/cast v1.5.0 // indirect
+	github.com/tidwall/match v1.1.1 // indirect
+	github.com/tidwall/pretty v1.2.1 // indirect
+	github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
+	github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
+	github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
+	github.com/yuin/goldmark v1.7.1 // indirect
+	github.com/yuin/goldmark-meta v1.1.0 // indirect
+	github.com/zclconf/go-cty v1.15.0 // indirect
+	go.abhg.dev/goldmark/frontmatter v0.2.0 // indirect
+	golang.org/x/crypto v0.26.0 // indirect
+	golang.org/x/exp v0.0.0-20230809150735-7b3493d9a819 // indirect
+	golang.org/x/mod v0.20.0 // indirect
+	golang.org/x/net v0.28.0 // indirect
+	golang.org/x/sync v0.8.0 // indirect
+	golang.org/x/sys v0.24.0 // indirect
+	golang.org/x/text v0.17.0 // indirect
+	google.golang.org/appengine v1.6.8 // indirect
+	google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed // indirect
+	google.golang.org/grpc v1.66.0 // indirect
+	google.golang.org/protobuf v1.34.2 // indirect
+	gopkg.in/yaml.v2 v2.3.0 // indirect
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 00000000..35f3d272
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,303 @@
+dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
+dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
+github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
+github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
+github.com/Kunde21/markdownfmt/v3 v3.1.0 h1:KiZu9LKs+wFFBQKhrZJrFZwtLnCCWJahL+S+E/3VnM0=
+github.com/Kunde21/markdownfmt/v3 v3.1.0/go.mod h1:tPXN1RTyOzJwhfHoon9wUr4HGYmWgVxSQN6VBJDkrVc=
+github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
+github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
+github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g=
+github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
+github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=
+github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
+github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
+github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
+github.com/ProtonMail/go-crypto v1.1.0-alpha.2 h1:bkyFVUP+ROOARdgCiJzNQo2V2kiB97LyUpzH9P6Hrlg=
+github.com/ProtonMail/go-crypto v1.1.0-alpha.2/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
+github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE=
+github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
+github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec=
+github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY=
+github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=
+github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI=
+github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY=
+github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+github.com/bmatcuk/doublestar/v4 v4.6.1 h1:FH9SifrbvJhnlQpztAx++wlkk70QBf0iBWDwNy7PA4I=
+github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
+github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA=
+github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8=
+github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
+github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
+github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
+github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
+github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
+github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
+github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
+github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
+github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
+github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
+github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
+github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
+github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU=
+github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow=
+github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys=
+github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY=
+github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
+github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
+github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
+github.com/hashicorp/cli v1.1.6 h1:CMOV+/LJfL1tXCOKrgAX0uRKnzjj/mpmqNXloRSy2K8=
+github.com/hashicorp/cli v1.1.6/go.mod h1:MPon5QYlgjjo0BSoAiN0ESeT5fRzDjVRp+uioJ0piz4=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
+github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-checkpoint v0.5.0 h1:MFYpPZCnQqQTE18jFwSII6eUQrD/oxMFp3mlgcqk5mU=
+github.com/hashicorp/go-checkpoint v0.5.0/go.mod h1:7nfLNL10NsxqO4iWuW6tWW0HjZuDrwkBuEQsVcpCOgg=
+github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
+github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
+github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
+github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 h1:1/D3zfFHttUKaCaGKZ/dR2roBXv0vKbSCnssIldfQdI=
+github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320/go.mod h1:EiZBMaudVLy8fmjf9Npq1dq9RalhveqZG5w/yz3mHWs=
+github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
+github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
+github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
+github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
+github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
+github.com/hashicorp/go-plugin v1.6.1 h1:P7MR2UP6gNKGPp+y7EZw2kOiq4IR9WiqLvp0XOsVdwI=
+github.com/hashicorp/go-plugin v1.6.1/go.mod h1:XPHFku2tFo3o3QKFgSYo+cghcUhw1NA1hZyMK0PWAw0=
+github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
+github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
+github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
+github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
+github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/hashicorp/hc-install v0.8.0 h1:LdpZeXkZYMQhoKPCecJHlKvUkQFixN/nvyR1CdfOLjI=
+github.com/hashicorp/hc-install v0.8.0/go.mod h1:+MwJYjDfCruSD/udvBmRB22Nlkwwkwf5sAB6uTIhSaU=
+github.com/hashicorp/hcl/v2 v2.21.0 h1:lve4q/o/2rqwYOgUg3y3V2YPyD1/zkCLGjIV74Jit14=
+github.com/hashicorp/hcl/v2 v2.21.0/go.mod h1:62ZYHrXgPoX8xBnzl8QzbWq4dyDsDtfCRgIq1rbJEvA=
+github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y=
+github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
+github.com/hashicorp/terraform-exec v0.21.0 h1:uNkLAe95ey5Uux6KJdua6+cv8asgILFVWkd/RG0D2XQ=
+github.com/hashicorp/terraform-exec v0.21.0/go.mod h1:1PPeMYou+KDUSSeRE9szMZ/oHf4fYUmB923Wzbq1ICg=
+github.com/hashicorp/terraform-json v0.22.1 h1:xft84GZR0QzjPVWs4lRUwvTcPnegqlyS7orfb5Ltvec=
+github.com/hashicorp/terraform-json v0.22.1/go.mod h1:JbWSQCLFSXFFhg42T7l9iJwdGXBYV8fmmD6o/ML4p3A=
+github.com/hashicorp/terraform-plugin-docs v0.19.4 h1:G3Bgo7J22OMtegIgn8Cd/CaSeyEljqjH3G39w28JK4c=
+github.com/hashicorp/terraform-plugin-docs v0.19.4/go.mod h1:4pLASsatTmRynVzsjEhbXZ6s7xBlUw/2Kt0zfrq8HxA=
+github.com/hashicorp/terraform-plugin-framework v1.11.0 h1:M7+9zBArexHFXDx/pKTxjE6n/2UCXY6b8FIq9ZYhwfE=
+github.com/hashicorp/terraform-plugin-framework v1.11.0/go.mod h1:qBXLDn69kM97NNVi/MQ9qgd1uWWsVftGSnygYG1tImM=
+github.com/hashicorp/terraform-plugin-framework-validators v0.13.0 h1:bxZfGo9DIUoLLtHMElsu+zwqI4IsMZQBRRy4iLzZJ8E=
+github.com/hashicorp/terraform-plugin-framework-validators v0.13.0/go.mod h1:wGeI02gEhj9nPANU62F2jCaHjXulejm/X+af4PdZaNo=
+github.com/hashicorp/terraform-plugin-go v0.23.0 h1:AALVuU1gD1kPb48aPQUjug9Ir/125t+AAurhqphJ2Co=
+github.com/hashicorp/terraform-plugin-go v0.23.0/go.mod h1:1E3Cr9h2vMlahWMbsSEcNrOCxovCZhOOIXjFHbjc/lQ=
+github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0=
+github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow=
+github.com/hashicorp/terraform-plugin-sdk/v2 v2.34.0 h1:kJiWGx2kiQVo97Y5IOGR4EMcZ8DtMswHhUuFibsCQQE=
+github.com/hashicorp/terraform-plugin-sdk/v2 v2.34.0/go.mod h1:sl/UoabMc37HA6ICVMmGO+/0wofkVIRxf+BMb/dnoIg=
+github.com/hashicorp/terraform-plugin-testing v1.10.0 h1:2+tmRNhvnfE4Bs8rB6v58S/VpqzGC6RCh9Y8ujdn+aw=
+github.com/hashicorp/terraform-plugin-testing v1.10.0/go.mod h1:iWRW3+loP33WMch2P/TEyCxxct/ZEcCGMquSLSCVsrc=
+github.com/hashicorp/terraform-registry-address v0.2.3 h1:2TAiKJ1A3MAkZlH1YI/aTVcLZRu7JseiXNRHbOAyoTI=
+github.com/hashicorp/terraform-registry-address v0.2.3/go.mod h1:lFHA76T8jfQteVfT7caREqguFrW3c4MFSPhZB7HHgUM=
+github.com/hashicorp/terraform-svchost v0.1.1 h1:EZZimZ1GxdqFRinZ1tpJwVxxt49xc/S52uzrw4x0jKQ=
+github.com/hashicorp/terraform-svchost v0.1.1/go.mod h1:mNsjQfZyf/Jhz35v6/0LWcv26+X7JPS+buii2c9/ctc=
+github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
+github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
+github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4=
+github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
+github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
+github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM=
+github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
+github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
+github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
+github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c=
+github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo=
+github.com/juju/ratelimit v1.0.2 h1:sRxmtRiajbvrcLQT7S+JbqU0ntsb9W2yhSdNN8tWfaI=
+github.com/juju/ratelimit v1.0.2/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk=
+github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
+github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
+github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
+github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
+github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
+github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
+github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
+github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU=
+github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=
+github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4=
+github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
+github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
+github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
+github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
+github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
+github.com/netascode/go-meraki v0.0.0-20240901102824-a67592c39438 h1:dsFYRJ2aXEddmIz76weQAZ6QzliSmMpVaZxGlW4wTUA=
+github.com/netascode/go-meraki v0.0.0-20240901102824-a67592c39438/go.mod h1:xZ/kiJA+SZY32p5t1J9Jdhvtig9BU4SMbxKnfAJrmLE=
+github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA=
+github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU=
+github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
+github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo=
+github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
+github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
+github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
+github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
+github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
+github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
+github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
+github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
+github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A=
+github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo=
+github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
+github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
+github.com/tidwall/gjson v1.17.3 h1:bwWLZU7icoKRG+C+0PNwIKC6FCJO/Q3p2pZvuP0jN94=
+github.com/tidwall/gjson v1.17.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
+github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
+github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
+github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
+github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
+github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
+github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
+github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
+github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
+github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI=
+github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
+github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
+github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
+github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
+github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
+github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
+github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
+github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+github.com/yuin/goldmark v1.7.1 h1:3bajkSilaCbjdKVsKdZjZCLBNPL9pYzrCakKaf4U49U=
+github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
+github.com/yuin/goldmark-meta v1.1.0 h1:pWw+JLHGZe8Rk0EGsMVssiNb/AaPMHfSRszZeUeiOUc=
+github.com/yuin/goldmark-meta v1.1.0/go.mod h1:U4spWENafuA7Zyg+Lj5RqK/MF+ovMYtBvXi1lBb2VP0=
+github.com/zclconf/go-cty v1.15.0 h1:tTCRWxsexYUmtt/wVxgDClUe+uQusuI443uL6e+5sXQ=
+github.com/zclconf/go-cty v1.15.0/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
+github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo=
+github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM=
+go.abhg.dev/goldmark/frontmatter v0.2.0 h1:P8kPG0YkL12+aYk2yU3xHv4tcXzeVnN+gU0tJ5JnxRw=
+go.abhg.dev/goldmark/frontmatter v0.2.0/go.mod h1:XqrEkZuM57djk7zrlRUB02x8I5J0px76YjkOzhB4YlU=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
+golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
+golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
+golang.org/x/exp v0.0.0-20230809150735-7b3493d9a819 h1:EDuYyU/MkFXllv9QF9819VlI9a4tzGuCbhG0ExK9o1U=
+golang.org/x/exp v0.0.0-20230809150735-7b3493d9a819/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
+golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
+golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
+golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
+golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
+golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
+golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
+golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
+golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
+google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed h1:J6izYgfBXAI3xTKLgxzTmUltdYaLsuBxFCgDHWJ/eXg=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
+google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c=
+google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
+google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/h2non/gock.v1 v1.1.2 h1:jBbHXgGBK/AoPVfJh5x4r/WxIrElvbLel8TCZkkZJoY=
+gopkg.in/h2non/gock.v1 v1.1.2/go.mod h1:n7UGz/ckNChHiK05rDoiC4MYSunEC/lyaUm2WWaDva0=
+gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
+gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
+gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/internal/provider/data_source_meraki_admin.go b/internal/provider/data_source_meraki_admin.go
new file mode 100644
index 00000000..8463631a
--- /dev/null
+++ b/internal/provider/data_source_meraki_admin.go
@@ -0,0 +1,202 @@
+// Copyright © 2024 Cisco Systems, Inc. and its affiliates.
+// All rights reserved.
+//
+// Licensed under the Mozilla Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://mozilla.org/MPL/2.0/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+// Section below is generated&owned by "gen/generator.go". //template:begin imports
+import (
+	"context"
+	"fmt"
+
+	"github.com/hashicorp/terraform-plugin-framework-validators/datasourcevalidator"
+	"github.com/hashicorp/terraform-plugin-framework/datasource"
+	"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/path"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+	"github.com/hashicorp/terraform-plugin-log/tflog"
+	"github.com/netascode/go-meraki"
+	"github.com/tidwall/gjson"
+)
+
+// End of section. //template:end imports
+
+// Section below is generated&owned by "gen/generator.go". //template:begin model
+
+// Ensure the implementation satisfies the expected interfaces.
+var (
+	_ datasource.DataSource              = &AdminDataSource{}
+	_ datasource.DataSourceWithConfigure = &AdminDataSource{}
+)
+
+func NewAdminDataSource() datasource.DataSource {
+	return &AdminDataSource{}
+}
+
+type AdminDataSource struct {
+	client *meraki.Client
+}
+
+func (d *AdminDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
+	resp.TypeName = req.ProviderTypeName + "_admin"
+}
+
+func (d *AdminDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
+	resp.Schema = schema.Schema{
+		// This description is used by the documentation generator and the language server.
+		MarkdownDescription: "This data source can read the `Admin` configuration.",
+
+		Attributes: map[string]schema.Attribute{
+			"id": schema.StringAttribute{
+				MarkdownDescription: "The id of the object",
+				Optional:            true,
+				Computed:            true,
+			},
+			"organization_id": schema.StringAttribute{
+				MarkdownDescription: "Organization ID",
+				Required:            true,
+			},
+			"email": schema.StringAttribute{
+				MarkdownDescription: "The email of the dashboard administrator. This attribute can not be updated.",
+				Computed:            true,
+			},
+			"name": schema.StringAttribute{
+				MarkdownDescription: "The name of the dashboard administrator",
+				Optional:            true,
+				Computed:            true,
+			},
+			"org_access": schema.StringAttribute{
+				MarkdownDescription: "The privilege of the dashboard administrator on the organization. Can be one of `full`, `read-only`, `enterprise` or `none`",
+				Computed:            true,
+			},
+			"networks": schema.ListNestedAttribute{
+				MarkdownDescription: "The list of networks that the dashboard administrator has privileges on",
+				Computed:            true,
+				NestedObject: schema.NestedAttributeObject{
+					Attributes: map[string]schema.Attribute{
+						"access": schema.StringAttribute{
+							MarkdownDescription: "The privilege of the dashboard administrator on the network. Can be one of `full`, `read-only`, `guest-ambassador` or `monitor-only`",
+							Computed:            true,
+						},
+						"id": schema.StringAttribute{
+							MarkdownDescription: "The network ID",
+							Computed:            true,
+						},
+					},
+				},
+			},
+			"tags": schema.ListNestedAttribute{
+				MarkdownDescription: "The list of tags that the dashboard administrator has privileges on",
+				Computed:            true,
+				NestedObject: schema.NestedAttributeObject{
+					Attributes: map[string]schema.Attribute{
+						"access": schema.StringAttribute{
+							MarkdownDescription: "The privilege of the dashboard administrator on the tag. Can be one of `full`, `read-only`, `guest-ambassador` or `monitor-only`",
+							Computed:            true,
+						},
+						"tag": schema.StringAttribute{
+							MarkdownDescription: "The name of the tag",
+							Computed:            true,
+						},
+					},
+				},
+			},
+		},
+	}
+}
+func (d *AdminDataSource) ConfigValidators(ctx context.Context) []datasource.ConfigValidator {
+	return []datasource.ConfigValidator{
+		datasourcevalidator.ExactlyOneOf(
+			path.MatchRoot("id"),
+			path.MatchRoot("name"),
+		),
+	}
+}
+
+func (d *AdminDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, _ *datasource.ConfigureResponse) {
+	if req.ProviderData == nil {
+		return
+	}
+
+	d.client = req.ProviderData.(*MerakiProviderData).Client
+}
+
+// End of section. //template:end model
+
+// Section below is generated&owned by "gen/generator.go". //template:begin read
+
+func (d *AdminDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
+	var config Admin
+
+	// Read config
+	diags := req.Config.Get(ctx, &config)
+	resp.Diagnostics.Append(diags...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Read", config.Id.String()))
+	var res gjson.Result
+	var err error
+	if config.Id.IsNull() && !config.Name.IsNull() {
+		res, err = d.client.Get(config.getPath())
+		if err != nil {
+			resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err))
+			return
+		}
+		if len(res.Array()) > 0 {
+			res.ForEach(func(k, v gjson.Result) bool {
+				if config.Name.ValueString() == v.Get("name").String() {
+					config.Id = types.StringValue(v.Get("id").String())
+					tflog.Debug(ctx, fmt.Sprintf("%s: Found object with name '%v', id: %v", config.Id.String(), config.Name.ValueString(), config.Id.String()))
+					return false
+				}
+				return true
+			})
+		}
+
+		if config.Id.IsNull() {
+			resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to find object with name: %s", config.Name.ValueString()))
+			return
+		}
+	}
+
+	if !res.Exists() {
+		res, err = d.client.Get(config.getPath())
+		if err != nil {
+			resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve object, got error: %s", err))
+			return
+		}
+	}
+	if len(res.Array()) > 0 {
+		res.ForEach(func(k, v gjson.Result) bool {
+			if config.Id.ValueString() == v.Get("id").String() {
+				res = v
+				return false
+			}
+			return true
+		})
+	}
+
+	config.fromBody(ctx, res)
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Read finished successfully", config.Id.ValueString()))
+
+	diags = resp.State.Set(ctx, &config)
+	resp.Diagnostics.Append(diags...)
+}
+
+// End of section. //template:end read
diff --git a/internal/provider/data_source_meraki_admin_test.go b/internal/provider/data_source_meraki_admin_test.go
new file mode 100644
index 00000000..b7f69ee5
--- /dev/null
+++ b/internal/provider/data_source_meraki_admin_test.go
@@ -0,0 +1,125 @@
+// Copyright © 2024 Cisco Systems, Inc. and its affiliates.
+// All rights reserved.
+//
+// Licensed under the Mozilla Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://mozilla.org/MPL/2.0/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+// Section below is generated&owned by "gen/generator.go". //template:begin imports
+import (
+	"testing"
+
+	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+// End of section. //template:end imports
+
+// Section below is generated&owned by "gen/generator.go". //template:begin testAccDataSource
+
+func TestAccDataSourceMerakiAdmin(t *testing.T) {
+	var checks []resource.TestCheckFunc
+	checks = append(checks, resource.TestCheckResourceAttr("data.meraki_admin.test", "email", "miles@meraki.com"))
+	checks = append(checks, resource.TestCheckResourceAttr("data.meraki_admin.test", "name", "Miles Meraki"))
+	checks = append(checks, resource.TestCheckResourceAttr("data.meraki_admin.test", "org_access", "none"))
+	checks = append(checks, resource.TestCheckResourceAttr("data.meraki_admin.test", "networks.0.access", "full"))
+	checks = append(checks, resource.TestCheckResourceAttr("data.meraki_admin.test", "tags.0.access", "read-only"))
+	checks = append(checks, resource.TestCheckResourceAttr("data.meraki_admin.test", "tags.0.tag", "west"))
+	resource.Test(t, resource.TestCase{
+		PreCheck:                 func() { testAccPreCheck(t) },
+		ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+		Steps: []resource.TestStep{
+			{
+				Config: testAccDataSourceMerakiAdminPrerequisitesConfig + testAccDataSourceMerakiAdminConfig(),
+				Check:  resource.ComposeTestCheckFunc(checks...),
+			},
+			{
+				Config: testAccDataSourceMerakiAdminPrerequisitesConfig + testAccNamedDataSourceMerakiAdminConfig(),
+				Check:  resource.ComposeTestCheckFunc(checks...),
+			},
+		},
+	})
+}
+
+// End of section. //template:end testAccDataSource
+
+// Section below is generated&owned by "gen/generator.go". //template:begin testPrerequisites
+
+const testAccDataSourceMerakiAdminPrerequisitesConfig = `
+data "meraki_organization" "test" {
+  name = "TF Test"
+}
+resource "meraki_network" "test" {
+  organization_id = data.meraki_organization.test.id
+  name            = "Network1"
+  product_types   = ["switch"]
+}
+
+`
+
+// End of section. //template:end testPrerequisites
+
+// Section below is generated&owned by "gen/generator.go". //template:begin testAccDataSourceConfig
+
+func testAccDataSourceMerakiAdminConfig() string {
+	config := `resource "meraki_admin" "test" {` + "\n"
+	config += `	organization_id = data.meraki_organization.test.id` + "\n"
+	config += `	email = "miles@meraki.com"` + "\n"
+	config += `	name = "Miles Meraki"` + "\n"
+	config += `	org_access = "none"` + "\n"
+	config += `	networks = [{` + "\n"
+	config += `		access = "full"` + "\n"
+	config += `		id = meraki_network.test.id` + "\n"
+	config += `	}]` + "\n"
+	config += `	tags = [{` + "\n"
+	config += `		access = "read-only"` + "\n"
+	config += `		tag = "west"` + "\n"
+	config += `	}]` + "\n"
+	config += `}` + "\n"
+
+	config += `
+		data "meraki_admin" "test" {
+			id = meraki_admin.test.id
+			organization_id = data.meraki_organization.test.id
+		}
+	`
+	return config
+}
+
+func testAccNamedDataSourceMerakiAdminConfig() string {
+	config := `resource "meraki_admin" "test" {` + "\n"
+	config += `	organization_id = data.meraki_organization.test.id` + "\n"
+	config += `	email = "miles@meraki.com"` + "\n"
+	config += `	name = "Miles Meraki"` + "\n"
+	config += `	org_access = "none"` + "\n"
+	config += `	networks = [{` + "\n"
+	config += `		access = "full"` + "\n"
+	config += `		id = meraki_network.test.id` + "\n"
+	config += `	}]` + "\n"
+	config += `	tags = [{` + "\n"
+	config += `		access = "read-only"` + "\n"
+	config += `		tag = "west"` + "\n"
+	config += `	}]` + "\n"
+	config += `}` + "\n"
+
+	config += `
+		data "meraki_admin" "test" {
+			name = meraki_admin.test.name
+			organization_id = data.meraki_organization.test.id
+		}
+	`
+	return config
+}
+
+// End of section. //template:end testAccDataSourceConfig
diff --git a/internal/provider/data_source_meraki_network.go b/internal/provider/data_source_meraki_network.go
new file mode 100644
index 00000000..b1ba7b02
--- /dev/null
+++ b/internal/provider/data_source_meraki_network.go
@@ -0,0 +1,172 @@
+// Copyright © 2024 Cisco Systems, Inc. and its affiliates.
+// All rights reserved.
+//
+// Licensed under the Mozilla Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://mozilla.org/MPL/2.0/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+// Section below is generated&owned by "gen/generator.go". //template:begin imports
+import (
+	"context"
+	"fmt"
+	"net/url"
+
+	"github.com/hashicorp/terraform-plugin-framework-validators/datasourcevalidator"
+	"github.com/hashicorp/terraform-plugin-framework/datasource"
+	"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/path"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+	"github.com/hashicorp/terraform-plugin-log/tflog"
+	"github.com/netascode/go-meraki"
+	"github.com/tidwall/gjson"
+)
+
+// End of section. //template:end imports
+
+// Section below is generated&owned by "gen/generator.go". //template:begin model
+
+// Ensure the implementation satisfies the expected interfaces.
+var (
+	_ datasource.DataSource              = &NetworkDataSource{}
+	_ datasource.DataSourceWithConfigure = &NetworkDataSource{}
+)
+
+func NewNetworkDataSource() datasource.DataSource {
+	return &NetworkDataSource{}
+}
+
+type NetworkDataSource struct {
+	client *meraki.Client
+}
+
+func (d *NetworkDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
+	resp.TypeName = req.ProviderTypeName + "_network"
+}
+
+func (d *NetworkDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
+	resp.Schema = schema.Schema{
+		// This description is used by the documentation generator and the language server.
+		MarkdownDescription: "This data source can read the `Network` configuration.",
+
+		Attributes: map[string]schema.Attribute{
+			"id": schema.StringAttribute{
+				MarkdownDescription: "The id of the object",
+				Optional:            true,
+				Computed:            true,
+			},
+			"organization_id": schema.StringAttribute{
+				MarkdownDescription: "Organization ID",
+				Required:            true,
+			},
+			"name": schema.StringAttribute{
+				MarkdownDescription: "The name of the new network",
+				Optional:            true,
+				Computed:            true,
+			},
+			"notes": schema.StringAttribute{
+				MarkdownDescription: "Add any notes or additional information about this network here.",
+				Computed:            true,
+			},
+			"time_zone": schema.StringAttribute{
+				MarkdownDescription: "The timezone of the network. For a list of allowed timezones, please see the 'TZ' column in the table in this article.",
+				Computed:            true,
+			},
+			"product_types": schema.ListAttribute{
+				MarkdownDescription: "The product type(s) of the new network. If more than one type is included, the network will be a combined network.",
+				ElementType:         types.StringType,
+				Computed:            true,
+			},
+			"tags": schema.ListAttribute{
+				MarkdownDescription: "A list of tags to be applied to the network",
+				ElementType:         types.StringType,
+				Computed:            true,
+			},
+		},
+	}
+}
+func (d *NetworkDataSource) ConfigValidators(ctx context.Context) []datasource.ConfigValidator {
+	return []datasource.ConfigValidator{
+		datasourcevalidator.ExactlyOneOf(
+			path.MatchRoot("id"),
+			path.MatchRoot("name"),
+		),
+	}
+}
+
+func (d *NetworkDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, _ *datasource.ConfigureResponse) {
+	if req.ProviderData == nil {
+		return
+	}
+
+	d.client = req.ProviderData.(*MerakiProviderData).Client
+}
+
+// End of section. //template:end model
+
+// Section below is generated&owned by "gen/generator.go". //template:begin read
+
+func (d *NetworkDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
+	var config Network
+
+	// Read config
+	diags := req.Config.Get(ctx, &config)
+	resp.Diagnostics.Append(diags...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Read", config.Id.String()))
+	var res gjson.Result
+	var err error
+	if config.Id.IsNull() && !config.Name.IsNull() {
+		res, err = d.client.Get(config.getPath())
+		if err != nil {
+			resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err))
+			return
+		}
+		if len(res.Array()) > 0 {
+			res.ForEach(func(k, v gjson.Result) bool {
+				if config.Name.ValueString() == v.Get("name").String() {
+					config.Id = types.StringValue(v.Get("id").String())
+					tflog.Debug(ctx, fmt.Sprintf("%s: Found object with name '%v', id: %v", config.Id.String(), config.Name.ValueString(), config.Id.String()))
+					return false
+				}
+				return true
+			})
+		}
+
+		if config.Id.IsNull() {
+			resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to find object with name: %s", config.Name.ValueString()))
+			return
+		}
+	}
+
+	if !res.Exists() {
+		res, err = d.client.Get(config.getPath() + "/" + url.QueryEscape(config.Id.ValueString()))
+		if err != nil {
+			resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve object, got error: %s", err))
+			return
+		}
+	}
+
+	config.fromBody(ctx, res)
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Read finished successfully", config.Id.ValueString()))
+
+	diags = resp.State.Set(ctx, &config)
+	resp.Diagnostics.Append(diags...)
+}
+
+// End of section. //template:end read
diff --git a/internal/provider/data_source_meraki_network_test.go b/internal/provider/data_source_meraki_network_test.go
new file mode 100644
index 00000000..db4f4ff4
--- /dev/null
+++ b/internal/provider/data_source_meraki_network_test.go
@@ -0,0 +1,107 @@
+// Copyright © 2024 Cisco Systems, Inc. and its affiliates.
+// All rights reserved.
+//
+// Licensed under the Mozilla Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://mozilla.org/MPL/2.0/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+// Section below is generated&owned by "gen/generator.go". //template:begin imports
+import (
+	"testing"
+
+	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+// End of section. //template:end imports
+
+// Section below is generated&owned by "gen/generator.go". //template:begin testAccDataSource
+
+func TestAccDataSourceMerakiNetwork(t *testing.T) {
+	var checks []resource.TestCheckFunc
+	checks = append(checks, resource.TestCheckResourceAttr("data.meraki_network.test", "name", "Main Office"))
+	checks = append(checks, resource.TestCheckResourceAttr("data.meraki_network.test", "notes", "Additional description of the network"))
+	checks = append(checks, resource.TestCheckResourceAttr("data.meraki_network.test", "time_zone", "America/Los_Angeles"))
+	checks = append(checks, resource.TestCheckResourceAttr("data.meraki_network.test", "product_types.0", "switch"))
+	checks = append(checks, resource.TestCheckResourceAttr("data.meraki_network.test", "tags.0", "tag1"))
+	resource.Test(t, resource.TestCase{
+		PreCheck:                 func() { testAccPreCheck(t) },
+		ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+		Steps: []resource.TestStep{
+			{
+				Config: testAccDataSourceMerakiNetworkPrerequisitesConfig + testAccDataSourceMerakiNetworkConfig(),
+				Check:  resource.ComposeTestCheckFunc(checks...),
+			},
+			{
+				Config: testAccDataSourceMerakiNetworkPrerequisitesConfig + testAccNamedDataSourceMerakiNetworkConfig(),
+				Check:  resource.ComposeTestCheckFunc(checks...),
+			},
+		},
+	})
+}
+
+// End of section. //template:end testAccDataSource
+
+// Section below is generated&owned by "gen/generator.go". //template:begin testPrerequisites
+
+const testAccDataSourceMerakiNetworkPrerequisitesConfig = `
+data "meraki_organization" "test" {
+  name = "TF Test"
+}
+
+`
+
+// End of section. //template:end testPrerequisites
+
+// Section below is generated&owned by "gen/generator.go". //template:begin testAccDataSourceConfig
+
+func testAccDataSourceMerakiNetworkConfig() string {
+	config := `resource "meraki_network" "test" {` + "\n"
+	config += `	organization_id = data.meraki_organization.test.id` + "\n"
+	config += `	name = "Main Office"` + "\n"
+	config += `	notes = "Additional description of the network"` + "\n"
+	config += `	time_zone = "America/Los_Angeles"` + "\n"
+	config += `	product_types = ["switch"]` + "\n"
+	config += `	tags = ["tag1"]` + "\n"
+	config += `}` + "\n"
+
+	config += `
+		data "meraki_network" "test" {
+			id = meraki_network.test.id
+			organization_id = data.meraki_organization.test.id
+		}
+	`
+	return config
+}
+
+func testAccNamedDataSourceMerakiNetworkConfig() string {
+	config := `resource "meraki_network" "test" {` + "\n"
+	config += `	organization_id = data.meraki_organization.test.id` + "\n"
+	config += `	name = "Main Office"` + "\n"
+	config += `	notes = "Additional description of the network"` + "\n"
+	config += `	time_zone = "America/Los_Angeles"` + "\n"
+	config += `	product_types = ["switch"]` + "\n"
+	config += `	tags = ["tag1"]` + "\n"
+	config += `}` + "\n"
+
+	config += `
+		data "meraki_network" "test" {
+			name = meraki_network.test.name
+			organization_id = data.meraki_organization.test.id
+		}
+	`
+	return config
+}
+
+// End of section. //template:end testAccDataSourceConfig
diff --git a/internal/provider/data_source_meraki_organization.go b/internal/provider/data_source_meraki_organization.go
new file mode 100644
index 00000000..017b6f65
--- /dev/null
+++ b/internal/provider/data_source_meraki_organization.go
@@ -0,0 +1,166 @@
+// Copyright © 2024 Cisco Systems, Inc. and its affiliates.
+// All rights reserved.
+//
+// Licensed under the Mozilla Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://mozilla.org/MPL/2.0/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+// Section below is generated&owned by "gen/generator.go". //template:begin imports
+import (
+	"context"
+	"fmt"
+	"net/url"
+
+	"github.com/hashicorp/terraform-plugin-framework-validators/datasourcevalidator"
+	"github.com/hashicorp/terraform-plugin-framework/datasource"
+	"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/path"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+	"github.com/hashicorp/terraform-plugin-log/tflog"
+	"github.com/netascode/go-meraki"
+	"github.com/tidwall/gjson"
+)
+
+// End of section. //template:end imports
+
+// Section below is generated&owned by "gen/generator.go". //template:begin model
+
+// Ensure the implementation satisfies the expected interfaces.
+var (
+	_ datasource.DataSource              = &OrganizationDataSource{}
+	_ datasource.DataSourceWithConfigure = &OrganizationDataSource{}
+)
+
+func NewOrganizationDataSource() datasource.DataSource {
+	return &OrganizationDataSource{}
+}
+
+type OrganizationDataSource struct {
+	client *meraki.Client
+}
+
+func (d *OrganizationDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
+	resp.TypeName = req.ProviderTypeName + "_organization"
+}
+
+func (d *OrganizationDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
+	resp.Schema = schema.Schema{
+		// This description is used by the documentation generator and the language server.
+		MarkdownDescription: "This data source can read the `Organization` configuration.",
+
+		Attributes: map[string]schema.Attribute{
+			"id": schema.StringAttribute{
+				MarkdownDescription: "The id of the object",
+				Optional:            true,
+				Computed:            true,
+			},
+			"name": schema.StringAttribute{
+				MarkdownDescription: "The name of the organization",
+				Optional:            true,
+				Computed:            true,
+			},
+			"management_details": schema.ListNestedAttribute{
+				MarkdownDescription: "Details related to organization management, possibly empty",
+				Computed:            true,
+				NestedObject: schema.NestedAttributeObject{
+					Attributes: map[string]schema.Attribute{
+						"name": schema.StringAttribute{
+							MarkdownDescription: "Name of management data",
+							Computed:            true,
+						},
+						"value": schema.StringAttribute{
+							MarkdownDescription: "Value of management data",
+							Computed:            true,
+						},
+					},
+				},
+			},
+		},
+	}
+}
+func (d *OrganizationDataSource) ConfigValidators(ctx context.Context) []datasource.ConfigValidator {
+	return []datasource.ConfigValidator{
+		datasourcevalidator.ExactlyOneOf(
+			path.MatchRoot("id"),
+			path.MatchRoot("name"),
+		),
+	}
+}
+
+func (d *OrganizationDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, _ *datasource.ConfigureResponse) {
+	if req.ProviderData == nil {
+		return
+	}
+
+	d.client = req.ProviderData.(*MerakiProviderData).Client
+}
+
+// End of section. //template:end model
+
+// Section below is generated&owned by "gen/generator.go". //template:begin read
+
+func (d *OrganizationDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
+	var config Organization
+
+	// Read config
+	diags := req.Config.Get(ctx, &config)
+	resp.Diagnostics.Append(diags...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Read", config.Id.String()))
+	var res gjson.Result
+	var err error
+	if config.Id.IsNull() && !config.Name.IsNull() {
+		res, err = d.client.Get(config.getPath())
+		if err != nil {
+			resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve objects, got error: %s", err))
+			return
+		}
+		if len(res.Array()) > 0 {
+			res.ForEach(func(k, v gjson.Result) bool {
+				if config.Name.ValueString() == v.Get("name").String() {
+					config.Id = types.StringValue(v.Get("id").String())
+					tflog.Debug(ctx, fmt.Sprintf("%s: Found object with name '%v', id: %v", config.Id.String(), config.Name.ValueString(), config.Id.String()))
+					return false
+				}
+				return true
+			})
+		}
+
+		if config.Id.IsNull() {
+			resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to find object with name: %s", config.Name.ValueString()))
+			return
+		}
+	}
+
+	if !res.Exists() {
+		res, err = d.client.Get(config.getPath() + "/" + url.QueryEscape(config.Id.ValueString()))
+		if err != nil {
+			resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve object, got error: %s", err))
+			return
+		}
+	}
+
+	config.fromBody(ctx, res)
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Read finished successfully", config.Id.ValueString()))
+
+	diags = resp.State.Set(ctx, &config)
+	resp.Diagnostics.Append(diags...)
+}
+
+// End of section. //template:end read
diff --git a/internal/provider/data_source_meraki_organization_test.go b/internal/provider/data_source_meraki_organization_test.go
new file mode 100644
index 00000000..15016c3a
--- /dev/null
+++ b/internal/provider/data_source_meraki_organization_test.go
@@ -0,0 +1,93 @@
+// Copyright © 2024 Cisco Systems, Inc. and its affiliates.
+// All rights reserved.
+//
+// Licensed under the Mozilla Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://mozilla.org/MPL/2.0/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+// Section below is generated&owned by "gen/generator.go". //template:begin imports
+import (
+	"testing"
+
+	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+// End of section. //template:end imports
+
+// Section below is generated&owned by "gen/generator.go". //template:begin testAccDataSource
+
+func TestAccDataSourceMerakiOrganization(t *testing.T) {
+	var checks []resource.TestCheckFunc
+	checks = append(checks, resource.TestCheckResourceAttr("data.meraki_organization.test", "name", "My organization"))
+	checks = append(checks, resource.TestCheckResourceAttr("data.meraki_organization.test", "management_details.0.name", "MSP ID"))
+	checks = append(checks, resource.TestCheckResourceAttr("data.meraki_organization.test", "management_details.0.value", "123456"))
+	resource.Test(t, resource.TestCase{
+		PreCheck:                 func() { testAccPreCheck(t) },
+		ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+		Steps: []resource.TestStep{
+			{
+				Config: testAccDataSourceMerakiOrganizationConfig(),
+				Check:  resource.ComposeTestCheckFunc(checks...),
+			},
+			{
+				Config: testAccNamedDataSourceMerakiOrganizationConfig(),
+				Check:  resource.ComposeTestCheckFunc(checks...),
+			},
+		},
+	})
+}
+
+// End of section. //template:end testAccDataSource
+
+// Section below is generated&owned by "gen/generator.go". //template:begin testPrerequisites
+// End of section. //template:end testPrerequisites
+
+// Section below is generated&owned by "gen/generator.go". //template:begin testAccDataSourceConfig
+
+func testAccDataSourceMerakiOrganizationConfig() string {
+	config := `resource "meraki_organization" "test" {` + "\n"
+	config += `	name = "My organization"` + "\n"
+	config += `	management_details = [{` + "\n"
+	config += `		name = "MSP ID"` + "\n"
+	config += `		value = "123456"` + "\n"
+	config += `	}]` + "\n"
+	config += `}` + "\n"
+
+	config += `
+		data "meraki_organization" "test" {
+			id = meraki_organization.test.id
+		}
+	`
+	return config
+}
+
+func testAccNamedDataSourceMerakiOrganizationConfig() string {
+	config := `resource "meraki_organization" "test" {` + "\n"
+	config += `	name = "My organization"` + "\n"
+	config += `	management_details = [{` + "\n"
+	config += `		name = "MSP ID"` + "\n"
+	config += `		value = "123456"` + "\n"
+	config += `	}]` + "\n"
+	config += `}` + "\n"
+
+	config += `
+		data "meraki_organization" "test" {
+			name = meraki_organization.test.name
+		}
+	`
+	return config
+}
+
+// End of section. //template:end testAccDataSourceConfig
diff --git a/internal/provider/helpers/description_builder.go b/internal/provider/helpers/description_builder.go
new file mode 100644
index 00000000..a9c33b03
--- /dev/null
+++ b/internal/provider/helpers/description_builder.go
@@ -0,0 +1,60 @@
+// Copyright © 2024 Cisco Systems, Inc. and its affiliates.
+// All rights reserved.
+//
+// Licensed under the Mozilla Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://mozilla.org/MPL/2.0/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+package helpers
+
+import (
+	"fmt"
+	"strings"
+)
+
+type AttributeDescription struct {
+	String string
+}
+
+func NewAttributeDescription(s string) *AttributeDescription {
+	return &AttributeDescription{s}
+}
+
+func (d *AttributeDescription) AddMinimumVersionDescription(minimumVersion string) *AttributeDescription {
+	d.String = fmt.Sprintf("%s\n  - Minimum API version: `%s`", d.String, minimumVersion)
+	return d
+}
+
+func (d *AttributeDescription) AddDefaultValueDescription(defaultValue string) *AttributeDescription {
+	d.String = fmt.Sprintf("%s\n  - Default value: `%s`", d.String, defaultValue)
+	return d
+}
+
+func (d *AttributeDescription) AddStringEnumDescription(values ...string) *AttributeDescription {
+	v := make([]string, len(values))
+	for i, value := range values {
+		v[i] = fmt.Sprintf("`%s`", value)
+	}
+	d.String = fmt.Sprintf("%s\n  - Choices: %s", d.String, strings.Join(v, ", "))
+	return d
+}
+
+func (d *AttributeDescription) AddIntegerRangeDescription(min, max int64) *AttributeDescription {
+	d.String = fmt.Sprintf("%s\n  - Range: `%v`-`%v`", d.String, min, max)
+	return d
+}
+
+func (d *AttributeDescription) AddFloatRangeDescription(min, max float64) *AttributeDescription {
+	d.String = fmt.Sprintf("%s\n  - Range: `%v`-`%v`", d.String, min, max)
+	return d
+}
diff --git a/internal/provider/helpers/flag.go b/internal/provider/helpers/flag.go
new file mode 100644
index 00000000..7f88d2e9
--- /dev/null
+++ b/internal/provider/helpers/flag.go
@@ -0,0 +1,48 @@
+package helpers
+
+import (
+	"context"
+	"slices"
+
+	"github.com/hashicorp/terraform-plugin-framework/diag"
+	"github.com/hashicorp/terraform-plugin-framework/resource"
+)
+
+func IsFlagImporting(ctx context.Context, req resource.ReadRequest) (bool, diag.Diagnostics) {
+	v, diags := req.Private.GetKey(ctx, "importing")
+
+	return slices.Equal(v, []byte("1")), diags
+}
+
+// SetFlagImporting checks the respDiags and if they are error-free it sets the `importing` as a private flag inside
+// SetKeyer. It appends its own results to respDiags.
+//
+// The caller must include in respDiags the result of state modification in the first place, to ensure consistency.
+// The SetKeyer is something like resp.Private.
+func SetFlagImporting(ctx context.Context, importing bool, sk SetKeyer, respDiags *diag.Diagnostics) {
+	if respDiags.HasError() {
+		return
+	}
+
+	b := []byte("0")
+	if importing {
+		b = []byte("1")
+	}
+
+	diags := sk.SetKey(ctx, "importing", b)
+	respDiags.Append(diags...)
+}
+
+// SetKeyer is something like ReadResponse.Private or ImportStateResponse.Private.
+type SetKeyer interface {
+	SetKey(ctx context.Context, key string, value []byte) diag.Diagnostics
+}
+
+var (
+	rr resource.ReadResponse
+	ir resource.ImportStateResponse
+
+	// ensure interface match
+	_ SetKeyer = rr.Private
+	_ SetKeyer = ir.Private
+)
diff --git a/internal/provider/helpers/utils.go b/internal/provider/helpers/utils.go
new file mode 100644
index 00000000..53f9b919
--- /dev/null
+++ b/internal/provider/helpers/utils.go
@@ -0,0 +1,78 @@
+// Copyright © 2024 Cisco Systems, Inc. and its affiliates.
+// All rights reserved.
+//
+// Licensed under the Mozilla Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://mozilla.org/MPL/2.0/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+package helpers
+
+import (
+	"strings"
+
+	"github.com/hashicorp/terraform-plugin-framework/attr"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+	"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
+	"github.com/tidwall/gjson"
+)
+
+func Contains(s []string, str string) bool {
+	for _, v := range s {
+		if v == str {
+			return true
+		}
+	}
+	return false
+}
+
+func GetStringList(result []gjson.Result) types.List {
+	v := make([]attr.Value, len(result))
+	for r := range result {
+		v[r] = types.StringValue(result[r].String())
+	}
+	return types.ListValueMust(types.StringType, v)
+}
+
+func GetInt64List(result []gjson.Result) types.List {
+	v := make([]attr.Value, len(result))
+	for r := range result {
+		v[r] = types.Int64Value(result[r].Int())
+	}
+	return types.ListValueMust(types.Int64Type, v)
+}
+
+func GetStringSet(result []gjson.Result) types.Set {
+	v := make([]attr.Value, len(result))
+	for r := range result {
+		v[r] = types.StringValue(result[r].String())
+	}
+	return types.SetValueMust(types.StringType, v)
+}
+
+func GetInt64Set(result []gjson.Result) types.Set {
+	v := make([]attr.Value, len(result))
+	for r := range result {
+		v[r] = types.Int64Value(result[r].Int())
+	}
+	return types.SetValueMust(types.Int64Type, v)
+}
+
+// ToLower is the same as strings.ToLower, except it cares to not to convert null/unknown strings
+// into empty strings.
+func ToLower(s basetypes.StringValue) basetypes.StringValue {
+	if s.IsUnknown() || s.IsNull() {
+		return s
+	}
+
+	return types.StringValue(strings.ToLower(s.ValueString()))
+}
diff --git a/internal/provider/model_meraki_admin.go b/internal/provider/model_meraki_admin.go
new file mode 100644
index 00000000..dd951be9
--- /dev/null
+++ b/internal/provider/model_meraki_admin.go
@@ -0,0 +1,303 @@
+// Copyright © 2024 Cisco Systems, Inc. and its affiliates.
+// All rights reserved.
+//
+// Licensed under the Mozilla Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://mozilla.org/MPL/2.0/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+// Section below is generated&owned by "gen/generator.go". //template:begin imports
+import (
+	"context"
+	"fmt"
+	"net/url"
+	"slices"
+
+	"github.com/hashicorp/terraform-plugin-framework/types"
+	"github.com/hashicorp/terraform-plugin-log/tflog"
+	"github.com/tidwall/gjson"
+	"github.com/tidwall/sjson"
+)
+
+// End of section. //template:end imports
+
+// Section below is generated&owned by "gen/generator.go". //template:begin types
+
+type Admin struct {
+	Id             types.String    `tfsdk:"id"`
+	OrganizationId types.String    `tfsdk:"organization_id"`
+	Email          types.String    `tfsdk:"email"`
+	Name           types.String    `tfsdk:"name"`
+	OrgAccess      types.String    `tfsdk:"org_access"`
+	Networks       []AdminNetworks `tfsdk:"networks"`
+	Tags           []AdminTags     `tfsdk:"tags"`
+}
+
+type AdminNetworks struct {
+	Access types.String `tfsdk:"access"`
+	Id     types.String `tfsdk:"id"`
+}
+
+type AdminTags struct {
+	Access types.String `tfsdk:"access"`
+	Tag    types.String `tfsdk:"tag"`
+}
+
+// End of section. //template:end types
+
+// Section below is generated&owned by "gen/generator.go". //template:begin getPath
+
+func (data Admin) getPath() string {
+	return fmt.Sprintf("/organizations/%v/admins", url.QueryEscape(data.OrganizationId.ValueString()))
+}
+
+// End of section. //template:end getPath
+
+// Section below is generated&owned by "gen/generator.go". //template:begin toBody
+
+func (data Admin) toBody(ctx context.Context, state Admin) string {
+	body := ""
+	if data.Id.ValueString() != "" {
+		body, _ = sjson.Set(body, "id", data.Id.ValueString())
+	}
+	if !data.Email.IsNull() {
+		body, _ = sjson.Set(body, "email", data.Email.ValueString())
+	}
+	if !data.Name.IsNull() {
+		body, _ = sjson.Set(body, "name", data.Name.ValueString())
+	}
+	if !data.OrgAccess.IsNull() {
+		body, _ = sjson.Set(body, "orgAccess", data.OrgAccess.ValueString())
+	}
+	if len(data.Networks) > 0 {
+		body, _ = sjson.Set(body, "networks", []interface{}{})
+		for _, item := range data.Networks {
+			itemBody := ""
+			if !item.Access.IsNull() {
+				itemBody, _ = sjson.Set(itemBody, "access", item.Access.ValueString())
+			}
+			if !item.Id.IsNull() {
+				itemBody, _ = sjson.Set(itemBody, "id", item.Id.ValueString())
+			}
+			body, _ = sjson.SetRaw(body, "networks.-1", itemBody)
+		}
+	}
+	if len(data.Tags) > 0 {
+		body, _ = sjson.Set(body, "tags", []interface{}{})
+		for _, item := range data.Tags {
+			itemBody := ""
+			if !item.Access.IsNull() {
+				itemBody, _ = sjson.Set(itemBody, "access", item.Access.ValueString())
+			}
+			if !item.Tag.IsNull() {
+				itemBody, _ = sjson.Set(itemBody, "tag", item.Tag.ValueString())
+			}
+			body, _ = sjson.SetRaw(body, "tags.-1", itemBody)
+		}
+	}
+	return body
+}
+
+// End of section. //template:end toBody
+
+// Section below is generated&owned by "gen/generator.go". //template:begin fromBody
+
+func (data *Admin) fromBody(ctx context.Context, res gjson.Result) {
+	if value := res.Get("email"); value.Exists() {
+		data.Email = types.StringValue(value.String())
+	} else {
+		data.Email = types.StringNull()
+	}
+	if value := res.Get("name"); value.Exists() {
+		data.Name = types.StringValue(value.String())
+	} else {
+		data.Name = types.StringNull()
+	}
+	if value := res.Get("orgAccess"); value.Exists() {
+		data.OrgAccess = types.StringValue(value.String())
+	} else {
+		data.OrgAccess = types.StringNull()
+	}
+	if value := res.Get("networks"); value.Exists() {
+		data.Networks = make([]AdminNetworks, 0)
+		value.ForEach(func(k, res gjson.Result) bool {
+			parent := &data
+			data := AdminNetworks{}
+			if value := res.Get("access"); value.Exists() {
+				data.Access = types.StringValue(value.String())
+			} else {
+				data.Access = types.StringNull()
+			}
+			if value := res.Get("id"); value.Exists() {
+				data.Id = types.StringValue(value.String())
+			} else {
+				data.Id = types.StringNull()
+			}
+			(*parent).Networks = append((*parent).Networks, data)
+			return true
+		})
+	}
+	if value := res.Get("tags"); value.Exists() {
+		data.Tags = make([]AdminTags, 0)
+		value.ForEach(func(k, res gjson.Result) bool {
+			parent := &data
+			data := AdminTags{}
+			if value := res.Get("access"); value.Exists() {
+				data.Access = types.StringValue(value.String())
+			} else {
+				data.Access = types.StringNull()
+			}
+			if value := res.Get("tag"); value.Exists() {
+				data.Tag = types.StringValue(value.String())
+			} else {
+				data.Tag = types.StringNull()
+			}
+			(*parent).Tags = append((*parent).Tags, data)
+			return true
+		})
+	}
+}
+
+// End of section. //template:end fromBody
+
+// Section below is generated&owned by "gen/generator.go". //template:begin fromBodyPartial
+
+// fromBodyPartial reads values from a gjson.Result into a tfstate model. It ignores null attributes in order to
+// uncouple the provider from the exact values that the backend API might summon to replace nulls. (Such behavior might
+// easily change across versions of the backend API.) For List/Set/Map attributes, the func only updates the
+// "managed" elements, instead of all elements.
+func (data *Admin) fromBodyPartial(ctx context.Context, res gjson.Result) {
+	if value := res.Get("email"); value.Exists() && !data.Email.IsNull() {
+		data.Email = types.StringValue(value.String())
+	} else {
+		data.Email = types.StringNull()
+	}
+	if value := res.Get("name"); value.Exists() && !data.Name.IsNull() {
+		data.Name = types.StringValue(value.String())
+	} else {
+		data.Name = types.StringNull()
+	}
+	if value := res.Get("orgAccess"); value.Exists() && !data.OrgAccess.IsNull() {
+		data.OrgAccess = types.StringValue(value.String())
+	} else {
+		data.OrgAccess = types.StringNull()
+	}
+	for i := 0; i < len(data.Networks); i++ {
+		keys := [...]string{"access", "id"}
+		keyValues := [...]string{data.Networks[i].Access.ValueString(), data.Networks[i].Id.ValueString()}
+
+		parent := &data
+		data := (*parent).Networks[i]
+		parentRes := &res
+		var res gjson.Result
+
+		parentRes.Get("networks").ForEach(
+			func(_, v gjson.Result) bool {
+				found := false
+				for ik := range keys {
+					if v.Get(keys[ik]).String() != keyValues[ik] {
+						found = false
+						break
+					}
+					found = true
+				}
+				if found {
+					res = v
+					return false
+				}
+				return true
+			},
+		)
+		if !res.Exists() {
+			tflog.Debug(ctx, fmt.Sprintf("removing Networks[%d] = %+v",
+				i,
+				(*parent).Networks[i],
+			))
+			(*parent).Networks = slices.Delete((*parent).Networks, i, i+1)
+			i--
+
+			continue
+		}
+		if value := res.Get("access"); value.Exists() && !data.Access.IsNull() {
+			data.Access = types.StringValue(value.String())
+		} else {
+			data.Access = types.StringNull()
+		}
+		if value := res.Get("id"); value.Exists() && !data.Id.IsNull() {
+			data.Id = types.StringValue(value.String())
+		} else {
+			data.Id = types.StringNull()
+		}
+		(*parent).Networks[i] = data
+	}
+	for i := 0; i < len(data.Tags); i++ {
+		keys := [...]string{"access", "tag"}
+		keyValues := [...]string{data.Tags[i].Access.ValueString(), data.Tags[i].Tag.ValueString()}
+
+		parent := &data
+		data := (*parent).Tags[i]
+		parentRes := &res
+		var res gjson.Result
+
+		parentRes.Get("tags").ForEach(
+			func(_, v gjson.Result) bool {
+				found := false
+				for ik := range keys {
+					if v.Get(keys[ik]).String() != keyValues[ik] {
+						found = false
+						break
+					}
+					found = true
+				}
+				if found {
+					res = v
+					return false
+				}
+				return true
+			},
+		)
+		if !res.Exists() {
+			tflog.Debug(ctx, fmt.Sprintf("removing Tags[%d] = %+v",
+				i,
+				(*parent).Tags[i],
+			))
+			(*parent).Tags = slices.Delete((*parent).Tags, i, i+1)
+			i--
+
+			continue
+		}
+		if value := res.Get("access"); value.Exists() && !data.Access.IsNull() {
+			data.Access = types.StringValue(value.String())
+		} else {
+			data.Access = types.StringNull()
+		}
+		if value := res.Get("tag"); value.Exists() && !data.Tag.IsNull() {
+			data.Tag = types.StringValue(value.String())
+		} else {
+			data.Tag = types.StringNull()
+		}
+		(*parent).Tags[i] = data
+	}
+}
+
+// End of section. //template:end fromBodyPartial
+
+// Section below is generated&owned by "gen/generator.go". //template:begin fromBodyUnknowns
+
+// fromBodyUnknowns updates the Unknown Computed tfstate values from a JSON.
+// Known values are not changed (usual for Computed attributes with UseStateForUnknown or with Default).
+func (data *Admin) fromBodyUnknowns(ctx context.Context, res gjson.Result) {
+}
+
+// End of section. //template:end fromBodyUnknowns
diff --git a/internal/provider/model_meraki_network.go b/internal/provider/model_meraki_network.go
new file mode 100644
index 00000000..0493f179
--- /dev/null
+++ b/internal/provider/model_meraki_network.go
@@ -0,0 +1,162 @@
+// Copyright © 2024 Cisco Systems, Inc. and its affiliates.
+// All rights reserved.
+//
+// Licensed under the Mozilla Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://mozilla.org/MPL/2.0/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+// Section below is generated&owned by "gen/generator.go". //template:begin imports
+import (
+	"context"
+	"fmt"
+	"net/url"
+
+	"github.com/hashicorp/terraform-plugin-framework/types"
+	"github.com/netascode/terraform-provider-meraki/internal/provider/helpers"
+	"github.com/tidwall/gjson"
+	"github.com/tidwall/sjson"
+)
+
+// End of section. //template:end imports
+
+// Section below is generated&owned by "gen/generator.go". //template:begin types
+
+type Network struct {
+	Id             types.String `tfsdk:"id"`
+	OrganizationId types.String `tfsdk:"organization_id"`
+	Name           types.String `tfsdk:"name"`
+	Notes          types.String `tfsdk:"notes"`
+	TimeZone       types.String `tfsdk:"time_zone"`
+	ProductTypes   types.List   `tfsdk:"product_types"`
+	Tags           types.List   `tfsdk:"tags"`
+}
+
+// End of section. //template:end types
+
+// Section below is generated&owned by "gen/generator.go". //template:begin getPath
+
+func (data Network) getPath() string {
+	return fmt.Sprintf("/organizations/%v/networks", url.QueryEscape(data.OrganizationId.ValueString()))
+}
+
+// End of section. //template:end getPath
+
+// Section below is generated&owned by "gen/generator.go". //template:begin toBody
+
+func (data Network) toBody(ctx context.Context, state Network) string {
+	body := ""
+	if data.Id.ValueString() != "" {
+		body, _ = sjson.Set(body, "id", data.Id.ValueString())
+	}
+	if !data.Name.IsNull() {
+		body, _ = sjson.Set(body, "name", data.Name.ValueString())
+	}
+	if !data.Notes.IsNull() {
+		body, _ = sjson.Set(body, "notes", data.Notes.ValueString())
+	}
+	if !data.TimeZone.IsNull() {
+		body, _ = sjson.Set(body, "timeZone", data.TimeZone.ValueString())
+	}
+	if !data.ProductTypes.IsNull() {
+		var values []string
+		data.ProductTypes.ElementsAs(ctx, &values, false)
+		body, _ = sjson.Set(body, "productTypes", values)
+	}
+	if !data.Tags.IsNull() {
+		var values []string
+		data.Tags.ElementsAs(ctx, &values, false)
+		body, _ = sjson.Set(body, "tags", values)
+	}
+	return body
+}
+
+// End of section. //template:end toBody
+
+// Section below is generated&owned by "gen/generator.go". //template:begin fromBody
+
+func (data *Network) fromBody(ctx context.Context, res gjson.Result) {
+	if value := res.Get("name"); value.Exists() {
+		data.Name = types.StringValue(value.String())
+	} else {
+		data.Name = types.StringNull()
+	}
+	if value := res.Get("notes"); value.Exists() {
+		data.Notes = types.StringValue(value.String())
+	} else {
+		data.Notes = types.StringNull()
+	}
+	if value := res.Get("timeZone"); value.Exists() {
+		data.TimeZone = types.StringValue(value.String())
+	} else {
+		data.TimeZone = types.StringNull()
+	}
+	if value := res.Get("productTypes"); value.Exists() {
+		data.ProductTypes = helpers.GetStringList(value.Array())
+	} else {
+		data.ProductTypes = types.ListNull(types.StringType)
+	}
+	if value := res.Get("tags"); value.Exists() {
+		data.Tags = helpers.GetStringList(value.Array())
+	} else {
+		data.Tags = types.ListNull(types.StringType)
+	}
+}
+
+// End of section. //template:end fromBody
+
+// Section below is generated&owned by "gen/generator.go". //template:begin fromBodyPartial
+
+// fromBodyPartial reads values from a gjson.Result into a tfstate model. It ignores null attributes in order to
+// uncouple the provider from the exact values that the backend API might summon to replace nulls. (Such behavior might
+// easily change across versions of the backend API.) For List/Set/Map attributes, the func only updates the
+// "managed" elements, instead of all elements.
+func (data *Network) fromBodyPartial(ctx context.Context, res gjson.Result) {
+	if value := res.Get("name"); value.Exists() && !data.Name.IsNull() {
+		data.Name = types.StringValue(value.String())
+	} else {
+		data.Name = types.StringNull()
+	}
+	if value := res.Get("notes"); value.Exists() && !data.Notes.IsNull() {
+		data.Notes = types.StringValue(value.String())
+	} else {
+		data.Notes = types.StringNull()
+	}
+	if value := res.Get("timeZone"); value.Exists() && !data.TimeZone.IsNull() {
+		data.TimeZone = types.StringValue(value.String())
+	} else {
+		data.TimeZone = types.StringNull()
+	}
+	if value := res.Get("productTypes"); value.Exists() && !data.ProductTypes.IsNull() {
+		data.ProductTypes = helpers.GetStringList(value.Array())
+	} else {
+		data.ProductTypes = types.ListNull(types.StringType)
+	}
+	if value := res.Get("tags"); value.Exists() && !data.Tags.IsNull() {
+		data.Tags = helpers.GetStringList(value.Array())
+	} else {
+		data.Tags = types.ListNull(types.StringType)
+	}
+}
+
+// End of section. //template:end fromBodyPartial
+
+// Section below is generated&owned by "gen/generator.go". //template:begin fromBodyUnknowns
+
+// fromBodyUnknowns updates the Unknown Computed tfstate values from a JSON.
+// Known values are not changed (usual for Computed attributes with UseStateForUnknown or with Default).
+func (data *Network) fromBodyUnknowns(ctx context.Context, res gjson.Result) {
+}
+
+// End of section. //template:end fromBodyUnknowns
diff --git a/internal/provider/model_meraki_organization.go b/internal/provider/model_meraki_organization.go
new file mode 100644
index 00000000..cbbf7675
--- /dev/null
+++ b/internal/provider/model_meraki_organization.go
@@ -0,0 +1,187 @@
+// Copyright © 2024 Cisco Systems, Inc. and its affiliates.
+// All rights reserved.
+//
+// Licensed under the Mozilla Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://mozilla.org/MPL/2.0/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+// Section below is generated&owned by "gen/generator.go". //template:begin imports
+import (
+	"context"
+	"fmt"
+	"slices"
+
+	"github.com/hashicorp/terraform-plugin-framework/types"
+	"github.com/hashicorp/terraform-plugin-log/tflog"
+	"github.com/tidwall/gjson"
+	"github.com/tidwall/sjson"
+)
+
+// End of section. //template:end imports
+
+// Section below is generated&owned by "gen/generator.go". //template:begin types
+
+type Organization struct {
+	Id                types.String                    `tfsdk:"id"`
+	Name              types.String                    `tfsdk:"name"`
+	ManagementDetails []OrganizationManagementDetails `tfsdk:"management_details"`
+}
+
+type OrganizationManagementDetails struct {
+	Name  types.String `tfsdk:"name"`
+	Value types.String `tfsdk:"value"`
+}
+
+// End of section. //template:end types
+
+// Section below is generated&owned by "gen/generator.go". //template:begin getPath
+
+func (data Organization) getPath() string {
+	return "/organizations"
+}
+
+// End of section. //template:end getPath
+
+// Section below is generated&owned by "gen/generator.go". //template:begin toBody
+
+func (data Organization) toBody(ctx context.Context, state Organization) string {
+	body := ""
+	if data.Id.ValueString() != "" {
+		body, _ = sjson.Set(body, "id", data.Id.ValueString())
+	}
+	if !data.Name.IsNull() {
+		body, _ = sjson.Set(body, "name", data.Name.ValueString())
+	}
+	if len(data.ManagementDetails) > 0 {
+		body, _ = sjson.Set(body, "management.details", []interface{}{})
+		for _, item := range data.ManagementDetails {
+			itemBody := ""
+			if !item.Name.IsNull() {
+				itemBody, _ = sjson.Set(itemBody, "name", item.Name.ValueString())
+			}
+			if !item.Value.IsNull() {
+				itemBody, _ = sjson.Set(itemBody, "value", item.Value.ValueString())
+			}
+			body, _ = sjson.SetRaw(body, "management.details.-1", itemBody)
+		}
+	}
+	return body
+}
+
+// End of section. //template:end toBody
+
+// Section below is generated&owned by "gen/generator.go". //template:begin fromBody
+
+func (data *Organization) fromBody(ctx context.Context, res gjson.Result) {
+	if value := res.Get("name"); value.Exists() {
+		data.Name = types.StringValue(value.String())
+	} else {
+		data.Name = types.StringNull()
+	}
+	if value := res.Get("management.details"); value.Exists() {
+		data.ManagementDetails = make([]OrganizationManagementDetails, 0)
+		value.ForEach(func(k, res gjson.Result) bool {
+			parent := &data
+			data := OrganizationManagementDetails{}
+			if value := res.Get("name"); value.Exists() {
+				data.Name = types.StringValue(value.String())
+			} else {
+				data.Name = types.StringNull()
+			}
+			if value := res.Get("value"); value.Exists() {
+				data.Value = types.StringValue(value.String())
+			} else {
+				data.Value = types.StringNull()
+			}
+			(*parent).ManagementDetails = append((*parent).ManagementDetails, data)
+			return true
+		})
+	}
+}
+
+// End of section. //template:end fromBody
+
+// Section below is generated&owned by "gen/generator.go". //template:begin fromBodyPartial
+
+// fromBodyPartial reads values from a gjson.Result into a tfstate model. It ignores null attributes in order to
+// uncouple the provider from the exact values that the backend API might summon to replace nulls. (Such behavior might
+// easily change across versions of the backend API.) For List/Set/Map attributes, the func only updates the
+// "managed" elements, instead of all elements.
+func (data *Organization) fromBodyPartial(ctx context.Context, res gjson.Result) {
+	if value := res.Get("name"); value.Exists() && !data.Name.IsNull() {
+		data.Name = types.StringValue(value.String())
+	} else {
+		data.Name = types.StringNull()
+	}
+	for i := 0; i < len(data.ManagementDetails); i++ {
+		keys := [...]string{"name"}
+		keyValues := [...]string{data.ManagementDetails[i].Name.ValueString()}
+
+		parent := &data
+		data := (*parent).ManagementDetails[i]
+		parentRes := &res
+		var res gjson.Result
+
+		parentRes.Get("management.details").ForEach(
+			func(_, v gjson.Result) bool {
+				found := false
+				for ik := range keys {
+					if v.Get(keys[ik]).String() != keyValues[ik] {
+						found = false
+						break
+					}
+					found = true
+				}
+				if found {
+					res = v
+					return false
+				}
+				return true
+			},
+		)
+		if !res.Exists() {
+			tflog.Debug(ctx, fmt.Sprintf("removing ManagementDetails[%d] = %+v",
+				i,
+				(*parent).ManagementDetails[i],
+			))
+			(*parent).ManagementDetails = slices.Delete((*parent).ManagementDetails, i, i+1)
+			i--
+
+			continue
+		}
+		if value := res.Get("name"); value.Exists() && !data.Name.IsNull() {
+			data.Name = types.StringValue(value.String())
+		} else {
+			data.Name = types.StringNull()
+		}
+		if value := res.Get("value"); value.Exists() && !data.Value.IsNull() {
+			data.Value = types.StringValue(value.String())
+		} else {
+			data.Value = types.StringNull()
+		}
+		(*parent).ManagementDetails[i] = data
+	}
+}
+
+// End of section. //template:end fromBodyPartial
+
+// Section below is generated&owned by "gen/generator.go". //template:begin fromBodyUnknowns
+
+// fromBodyUnknowns updates the Unknown Computed tfstate values from a JSON.
+// Known values are not changed (usual for Computed attributes with UseStateForUnknown or with Default).
+func (data *Organization) fromBodyUnknowns(ctx context.Context, res gjson.Result) {
+}
+
+// End of section. //template:end fromBodyUnknowns
diff --git a/internal/provider/provider.go b/internal/provider/provider.go
new file mode 100644
index 00000000..c00c0031
--- /dev/null
+++ b/internal/provider/provider.go
@@ -0,0 +1,242 @@
+// Copyright © 2024 Cisco Systems, Inc. and its affiliates.
+// All rights reserved.
+//
+// Licensed under the Mozilla Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://mozilla.org/MPL/2.0/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+// Section below is generated&owned by "gen/generator.go". //template:begin provider
+import (
+	"context"
+	"fmt"
+	"os"
+	"strconv"
+	"time"
+
+	"github.com/hashicorp/terraform-plugin-framework-validators/int64validator"
+	"github.com/hashicorp/terraform-plugin-framework/datasource"
+	"github.com/hashicorp/terraform-plugin-framework/provider"
+	"github.com/hashicorp/terraform-plugin-framework/provider/schema"
+	"github.com/hashicorp/terraform-plugin-framework/resource"
+	"github.com/hashicorp/terraform-plugin-framework/schema/validator"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+	"github.com/hashicorp/terraform-plugin-log/tflog"
+	"github.com/netascode/go-meraki"
+)
+
+// MerakiProvider defines the provider implementation.
+type MerakiProvider struct {
+	// version is set to the provider version on release, "dev" when the
+	// provider is built and ran locally, and "test" when running acceptance
+	// testing.
+	version string
+}
+
+// MerakiProviderModel describes the provider data model.
+type MerakiProviderModel struct {
+	ApiKey     types.String `tfsdk:"api_key"`
+	BaseUrl    types.String `tfsdk:"base_url"`
+	ReqTimeout types.String `tfsdk:"req_timeout"`
+	Retries    types.Int64  `tfsdk:"retries"`
+}
+
+// MerakiProviderData describes the data maintained by the provider.
+type MerakiProviderData struct {
+	Client *meraki.Client
+}
+
+// Metadata returns the provider type name.
+func (p *MerakiProvider) Metadata(_ context.Context, _ provider.MetadataRequest, resp *provider.MetadataResponse) {
+	resp.TypeName = "meraki"
+	resp.Version = p.version
+}
+
+func (p *MerakiProvider) Schema(ctx context.Context, req provider.SchemaRequest, resp *provider.SchemaResponse) {
+	resp.Schema = schema.Schema{
+		Attributes: map[string]schema.Attribute{
+			"api_key": schema.StringAttribute{
+				MarkdownDescription: "Meraki Dashboard API key. This can also be set as the MERAKI_API_KEY environment variable.",
+				Optional:            true,
+				Sensitive:           true,
+			},
+			"base_url": schema.StringAttribute{
+				MarkdownDescription: "Base URL to be used. The default value is `https://api.meraki.com/api/v1`. This can also be set as the MERAKI_BASE_URL environment variable.",
+				Optional:            true,
+			},
+			"req_timeout": schema.StringAttribute{
+				MarkdownDescription: "Timeout for a single HTTPS request made to REST API before it is retried. This can also be set as the MERAKI_REQTIMEOUT environment variable. A string like `\"1s\"` means one second. Defaults to `\"5s\"`.",
+				Optional:            true,
+			},
+			"retries": schema.Int64Attribute{
+				MarkdownDescription: "Number of retries for REST API calls. This can also be set as the MERAKI_RETRIES environment variable. Defaults to `3`.",
+				Optional:            true,
+				Validators: []validator.Int64{
+					int64validator.Between(0, 9),
+				},
+			},
+		},
+	}
+}
+
+func (p *MerakiProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) {
+	// Retrieve provider data from configuration
+	var config MerakiProviderModel
+	diags := req.Config.Get(ctx, &config)
+	resp.Diagnostics.Append(diags...)
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	// User must provide an API key to the provider
+	var apiKey string
+	if config.ApiKey.IsUnknown() {
+		// Cannot connect to client with an unknown value
+		resp.Diagnostics.AddWarning(
+			"Unable to create client",
+			"Cannot use unknown value as API key",
+		)
+		return
+	}
+
+	if config.ApiKey.IsNull() {
+		apiKey = os.Getenv("MERAKI_API_KEY")
+	} else {
+		apiKey = config.ApiKey.ValueString()
+	}
+
+	if apiKey == "" {
+		// Error vs warning - empty value must stop execution
+		resp.Diagnostics.AddError(
+			"Unable to find API key",
+			"API key cannot be an empty string",
+		)
+		return
+	}
+
+	// User can provide a Base URL to the provider
+	var baseUrl string
+	if config.BaseUrl.IsUnknown() {
+		// Cannot connect to client with an unknown value
+		resp.Diagnostics.AddWarning(
+			"Unable to create client",
+			"Cannot use unknown value as base url",
+		)
+		return
+	}
+
+	if config.BaseUrl.IsNull() {
+		baseUrl = os.Getenv("MERAKI_BASE_URL")
+		if baseUrl == "" {
+			baseUrl = "https://api.meraki.com/api/v1"
+		}
+	} else {
+		baseUrl = config.BaseUrl.ValueString()
+	}
+
+	var reqTimeout time.Duration
+	if config.ReqTimeout.IsUnknown() {
+		// Cannot connect to client with an unknown value
+		resp.Diagnostics.AddWarning(
+			"Unable to create client",
+			"Cannot use unknown value as req_timeout",
+		)
+		return
+	}
+
+	var reqTimeoutStr string
+	if config.ReqTimeout.IsNull() {
+		reqTimeoutStr = os.Getenv("MERAKI_REQTIMEOUT")
+		if reqTimeoutStr == "" {
+			reqTimeoutStr = "5s"
+		}
+	} else {
+		reqTimeoutStr = config.ReqTimeout.ValueString()
+	}
+	reqTimeout, err := time.ParseDuration(reqTimeoutStr)
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Unable to create client",
+			fmt.Sprintf("Cannot parse the req_timeout string: %v", err),
+		)
+		return
+	}
+
+	var retries int64
+	if config.Retries.IsUnknown() {
+		// Cannot connect to client with an unknown value
+		resp.Diagnostics.AddWarning(
+			"Unable to create client",
+			"Cannot use unknown value as retries",
+		)
+		return
+	}
+
+	if config.Retries.IsNull() {
+		retriesStr := os.Getenv("MERAKI_RETRIES")
+		if retriesStr == "" {
+			retries = 3
+		} else {
+			retries, _ = strconv.ParseInt(retriesStr, 0, 64)
+		}
+	} else {
+		retries = config.Retries.ValueInt64()
+	}
+
+	tflog.Debug(ctx, fmt.Sprint("Creating a new Meraki client",
+		"  base_url=", baseUrl,
+		"  req_timeout=", reqTimeout,
+		"  retries=", retries,
+	))
+
+	// Create a new Meraki client and set it to the provider client
+	c, err := meraki.NewClient(apiKey, meraki.BaseUrl(baseUrl), meraki.MaxRetries(int(retries)), meraki.RequestTimeout(reqTimeout))
+	if err != nil {
+		resp.Diagnostics.AddError(
+			"Unable to create client",
+			"Unable to create meraki client:\n\n"+err.Error(),
+		)
+		return
+	}
+
+	data := MerakiProviderData{Client: &c}
+	resp.DataSourceData = &data
+	resp.ResourceData = &data
+}
+
+func (p *MerakiProvider) Resources(ctx context.Context) []func() resource.Resource {
+	return []func() resource.Resource{
+		NewAdminResource,
+		NewNetworkResource,
+		NewOrganizationResource,
+	}
+}
+
+func (p *MerakiProvider) DataSources(ctx context.Context) []func() datasource.DataSource {
+	return []func() datasource.DataSource{
+		NewAdminDataSource,
+		NewNetworkDataSource,
+		NewOrganizationDataSource,
+	}
+}
+
+func New(version string) func() provider.Provider {
+	return func() provider.Provider {
+		return &MerakiProvider{
+			version: version,
+		}
+	}
+}
+
+// End of section. //template:end provider
diff --git a/internal/provider/provider_test.go b/internal/provider/provider_test.go
new file mode 100644
index 00000000..d0d01d42
--- /dev/null
+++ b/internal/provider/provider_test.go
@@ -0,0 +1,43 @@
+// Copyright © 2024 Cisco Systems, Inc. and its affiliates.
+// All rights reserved.
+//
+// Licensed under the Mozilla Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://mozilla.org/MPL/2.0/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+import (
+	"os"
+	"testing"
+
+	"github.com/hashicorp/terraform-plugin-framework/providerserver"
+	"github.com/hashicorp/terraform-plugin-go/tfprotov6"
+)
+
+// testAccProtoV6ProviderFactories are used to instantiate a provider during
+// acceptance testing. The factory function will be invoked for every Terraform
+// CLI command executed to create a provider server to which the CLI can
+// reattach.
+var testAccProtoV6ProviderFactories = map[string]func() (tfprotov6.ProviderServer, error){
+	"meraki": providerserver.NewProtocol6WithError(New("test")()),
+}
+
+func testAccPreCheck(t *testing.T) {
+	// You can add code here to run prior to any test case execution, for example assertions
+	// about the appropriate environment variables being set are common to see in a pre-check
+	// function.
+	if v := os.Getenv("MERAKI_API_KEY"); v == "" {
+		t.Fatal("MERAKI_API_KEY env variable must be set for acceptance tests")
+	}
+}
diff --git a/internal/provider/resource_meraki_admin.go b/internal/provider/resource_meraki_admin.go
new file mode 100644
index 00000000..cd29f2ef
--- /dev/null
+++ b/internal/provider/resource_meraki_admin.go
@@ -0,0 +1,311 @@
+// Copyright © 2024 Cisco Systems, Inc. and its affiliates.
+// All rights reserved.
+//
+// Licensed under the Mozilla Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://mozilla.org/MPL/2.0/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+// Section below is generated&owned by "gen/generator.go". //template:begin imports
+import (
+	"context"
+	"fmt"
+	"net/url"
+	"strings"
+
+	"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
+	"github.com/hashicorp/terraform-plugin-framework/path"
+	"github.com/hashicorp/terraform-plugin-framework/resource"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/schema/validator"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+	"github.com/hashicorp/terraform-plugin-log/tflog"
+	"github.com/netascode/go-meraki"
+	"github.com/netascode/terraform-provider-meraki/internal/provider/helpers"
+	"github.com/tidwall/gjson"
+)
+
+// End of section. //template:end imports
+
+// Section below is generated&owned by "gen/generator.go". //template:begin model
+
+// Ensure provider defined types fully satisfy framework interfaces
+var (
+	_ resource.Resource                = &AdminResource{}
+	_ resource.ResourceWithImportState = &AdminResource{}
+)
+
+func NewAdminResource() resource.Resource {
+	return &AdminResource{}
+}
+
+type AdminResource struct {
+	client *meraki.Client
+}
+
+func (r *AdminResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
+	resp.TypeName = req.ProviderTypeName + "_admin"
+}
+
+func (r *AdminResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
+	resp.Schema = schema.Schema{
+		// This description is used by the documentation generator and the language server.
+		MarkdownDescription: helpers.NewAttributeDescription("This resource can manage the `Admin` configuration.").String,
+
+		Attributes: map[string]schema.Attribute{
+			"id": schema.StringAttribute{
+				MarkdownDescription: "The id of the object",
+				Computed:            true,
+				PlanModifiers: []planmodifier.String{
+					stringplanmodifier.UseStateForUnknown(),
+				},
+			},
+			"organization_id": schema.StringAttribute{
+				MarkdownDescription: helpers.NewAttributeDescription("Organization ID").String,
+				Required:            true,
+				PlanModifiers: []planmodifier.String{
+					stringplanmodifier.RequiresReplace(),
+				},
+			},
+			"email": schema.StringAttribute{
+				MarkdownDescription: helpers.NewAttributeDescription("The email of the dashboard administrator. This attribute can not be updated.").String,
+				Required:            true,
+			},
+			"name": schema.StringAttribute{
+				MarkdownDescription: helpers.NewAttributeDescription("The name of the dashboard administrator").String,
+				Required:            true,
+			},
+			"org_access": schema.StringAttribute{
+				MarkdownDescription: helpers.NewAttributeDescription("The privilege of the dashboard administrator on the organization. Can be one of `full`, `read-only`, `enterprise` or `none`").AddStringEnumDescription("full", "read-only", "enterprise", "none").String,
+				Required:            true,
+				Validators: []validator.String{
+					stringvalidator.OneOf("full", "read-only", "enterprise", "none"),
+				},
+			},
+			"networks": schema.ListNestedAttribute{
+				MarkdownDescription: helpers.NewAttributeDescription("The list of networks that the dashboard administrator has privileges on").String,
+				Optional:            true,
+				NestedObject: schema.NestedAttributeObject{
+					Attributes: map[string]schema.Attribute{
+						"access": schema.StringAttribute{
+							MarkdownDescription: helpers.NewAttributeDescription("The privilege of the dashboard administrator on the network. Can be one of `full`, `read-only`, `guest-ambassador` or `monitor-only`").AddStringEnumDescription("full", "read-only", "guest-ambassador", "monitor-only").String,
+							Required:            true,
+							Validators: []validator.String{
+								stringvalidator.OneOf("full", "read-only", "guest-ambassador", "monitor-only"),
+							},
+						},
+						"id": schema.StringAttribute{
+							MarkdownDescription: helpers.NewAttributeDescription("The network ID").String,
+							Required:            true,
+						},
+					},
+				},
+			},
+			"tags": schema.ListNestedAttribute{
+				MarkdownDescription: helpers.NewAttributeDescription("The list of tags that the dashboard administrator has privileges on").String,
+				Optional:            true,
+				NestedObject: schema.NestedAttributeObject{
+					Attributes: map[string]schema.Attribute{
+						"access": schema.StringAttribute{
+							MarkdownDescription: helpers.NewAttributeDescription("The privilege of the dashboard administrator on the tag. Can be one of `full`, `read-only`, `guest-ambassador` or `monitor-only`").AddStringEnumDescription("full", "read-only", "guest-ambassador", "monitor-only").String,
+							Required:            true,
+							Validators: []validator.String{
+								stringvalidator.OneOf("full", "read-only", "guest-ambassador", "monitor-only"),
+							},
+						},
+						"tag": schema.StringAttribute{
+							MarkdownDescription: helpers.NewAttributeDescription("The name of the tag").String,
+							Required:            true,
+						},
+					},
+				},
+			},
+		},
+	}
+}
+
+func (r *AdminResource) Configure(_ context.Context, req resource.ConfigureRequest, _ *resource.ConfigureResponse) {
+	if req.ProviderData == nil {
+		return
+	}
+
+	r.client = req.ProviderData.(*MerakiProviderData).Client
+}
+
+// End of section. //template:end model
+
+// Section below is generated&owned by "gen/generator.go". //template:begin create
+
+func (r *AdminResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
+	var plan Admin
+
+	// Read plan
+	diags := req.Plan.Get(ctx, &plan)
+	if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() {
+		return
+	}
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Create", plan.Id.ValueString()))
+
+	// Create object
+	body := plan.toBody(ctx, Admin{})
+	res, err := r.client.Post(plan.getPath(), body)
+	if err != nil {
+		resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to configure object (POST/PUT), got error: %s, %s", err, res.String()))
+		return
+	}
+	plan.Id = types.StringValue(res.Get("id").String())
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Create finished successfully", plan.Id.ValueString()))
+
+	diags = resp.State.Set(ctx, &plan)
+	resp.Diagnostics.Append(diags...)
+
+	helpers.SetFlagImporting(ctx, false, resp.Private, &resp.Diagnostics)
+}
+
+// End of section. //template:end create
+
+// Section below is generated&owned by "gen/generator.go". //template:begin read
+
+func (r *AdminResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
+	var state Admin
+
+	// Read state
+	diags := req.State.Get(ctx, &state)
+	if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() {
+		return
+	}
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Read", state.Id.String()))
+	res, err := r.client.Get(state.getPath())
+	if err != nil && strings.Contains(err.Error(), "StatusCode 404") {
+		resp.State.RemoveResource(ctx)
+		return
+	} else if err != nil {
+		resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve object (GET), got error: %s, %s", err, res.String()))
+		return
+	}
+	if len(res.Array()) > 0 {
+		res.ForEach(func(k, v gjson.Result) bool {
+			if state.Id.ValueString() == v.Get("id").String() {
+				res = v
+				return false
+			}
+			return true
+		})
+	}
+
+	imp, diags := helpers.IsFlagImporting(ctx, req)
+	if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() {
+		return
+	}
+
+	// After `terraform import` we switch to a full read.
+	if imp {
+		state.fromBody(ctx, res)
+	} else {
+		state.fromBodyPartial(ctx, res)
+	}
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Read finished successfully", state.Id.ValueString()))
+
+	diags = resp.State.Set(ctx, &state)
+	resp.Diagnostics.Append(diags...)
+
+	helpers.SetFlagImporting(ctx, false, resp.Private, &resp.Diagnostics)
+}
+
+// End of section. //template:end read
+
+// Section below is generated&owned by "gen/generator.go". //template:begin update
+
+func (r *AdminResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
+	var plan, state Admin
+
+	// Read plan
+	diags := req.Plan.Get(ctx, &plan)
+	if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() {
+		return
+	}
+
+	// Read state
+	diags = req.State.Get(ctx, &state)
+	if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() {
+		return
+	}
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Update", plan.Id.ValueString()))
+
+	body := plan.toBody(ctx, state)
+	res, err := r.client.Put(plan.getPath()+"/"+url.QueryEscape(plan.Id.ValueString()), body)
+	if err != nil {
+		resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to configure object (PUT), got error: %s, %s", err, res.String()))
+		return
+	}
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Update finished successfully", plan.Id.ValueString()))
+
+	diags = resp.State.Set(ctx, &plan)
+	resp.Diagnostics.Append(diags...)
+}
+
+// End of section. //template:end update
+
+// Section below is generated&owned by "gen/generator.go". //template:begin delete
+
+func (r *AdminResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
+	var state Admin
+
+	// Read state
+	diags := req.State.Get(ctx, &state)
+	if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() {
+		return
+	}
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Delete", state.Id.ValueString()))
+	res, err := r.client.Delete(state.getPath() + "/" + url.QueryEscape(state.Id.ValueString()))
+	if err != nil {
+		resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to delete object (DELETE), got error: %s, %s", err, res.String()))
+		return
+	}
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Delete finished successfully", state.Id.ValueString()))
+
+	resp.State.RemoveResource(ctx)
+}
+
+// End of section. //template:end delete
+
+// Section below is generated&owned by "gen/generator.go". //template:begin import
+
+func (r *AdminResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
+	idParts := strings.Split(req.ID, ",")
+
+	if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" {
+		resp.Diagnostics.AddError(
+			"Unexpected Import Identifier",
+			fmt.Sprintf("Expected import identifier with format: <organization_id>,<id>. Got: %q", req.ID),
+		)
+		return
+	}
+	resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("organization_id"), idParts[0])...)
+	resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("id"), idParts[1])...)
+
+	helpers.SetFlagImporting(ctx, true, resp.Private, &resp.Diagnostics)
+}
+
+// End of section. //template:end import
diff --git a/internal/provider/resource_meraki_admin_test.go b/internal/provider/resource_meraki_admin_test.go
new file mode 100644
index 00000000..e48102aa
--- /dev/null
+++ b/internal/provider/resource_meraki_admin_test.go
@@ -0,0 +1,111 @@
+// Copyright © 2024 Cisco Systems, Inc. and its affiliates.
+// All rights reserved.
+//
+// Licensed under the Mozilla Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://mozilla.org/MPL/2.0/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+// Section below is generated&owned by "gen/generator.go". //template:begin imports
+import (
+	"os"
+	"testing"
+
+	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+// End of section. //template:end imports
+
+// Section below is generated&owned by "gen/generator.go". //template:begin testAcc
+
+func TestAccMerakiAdmin(t *testing.T) {
+	var checks []resource.TestCheckFunc
+	checks = append(checks, resource.TestCheckResourceAttr("meraki_admin.test", "email", "miles@meraki.com"))
+	checks = append(checks, resource.TestCheckResourceAttr("meraki_admin.test", "name", "Miles Meraki"))
+	checks = append(checks, resource.TestCheckResourceAttr("meraki_admin.test", "org_access", "none"))
+	checks = append(checks, resource.TestCheckResourceAttr("meraki_admin.test", "networks.0.access", "full"))
+	checks = append(checks, resource.TestCheckResourceAttr("meraki_admin.test", "tags.0.access", "read-only"))
+	checks = append(checks, resource.TestCheckResourceAttr("meraki_admin.test", "tags.0.tag", "west"))
+
+	var steps []resource.TestStep
+	if os.Getenv("SKIP_MINIMUM_TEST") == "" {
+		steps = append(steps, resource.TestStep{
+			Config: testAccMerakiAdminPrerequisitesConfig + testAccMerakiAdminConfig_minimum(),
+		})
+	}
+	steps = append(steps, resource.TestStep{
+		Config: testAccMerakiAdminPrerequisitesConfig + testAccMerakiAdminConfig_all(),
+		Check:  resource.ComposeTestCheckFunc(checks...),
+	})
+
+	resource.Test(t, resource.TestCase{
+		PreCheck:                 func() { testAccPreCheck(t) },
+		ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+		Steps:                    steps,
+	})
+}
+
+// End of section. //template:end testAcc
+
+// Section below is generated&owned by "gen/generator.go". //template:begin testPrerequisites
+
+const testAccMerakiAdminPrerequisitesConfig = `
+data "meraki_organization" "test" {
+  name = "TF Test"
+}
+resource "meraki_network" "test" {
+  organization_id = data.meraki_organization.test.id
+  name            = "Network1"
+  product_types   = ["switch"]
+}
+
+`
+
+// End of section. //template:end testPrerequisites
+
+// Section below is generated&owned by "gen/generator.go". //template:begin testAccConfigMinimal
+
+func testAccMerakiAdminConfig_minimum() string {
+	config := `resource "meraki_admin" "test" {` + "\n"
+	config += `	organization_id = data.meraki_organization.test.id` + "\n"
+	config += `	email = "miles@meraki.com"` + "\n"
+	config += `	name = "Miles Meraki"` + "\n"
+	config += `	org_access = "full"` + "\n"
+	config += `}` + "\n"
+	return config
+}
+
+// End of section. //template:end testAccConfigMinimal
+
+// Section below is generated&owned by "gen/generator.go". //template:begin testAccConfigAll
+
+func testAccMerakiAdminConfig_all() string {
+	config := `resource "meraki_admin" "test" {` + "\n"
+	config += `	organization_id = data.meraki_organization.test.id` + "\n"
+	config += `	email = "miles@meraki.com"` + "\n"
+	config += `	name = "Miles Meraki"` + "\n"
+	config += `	org_access = "none"` + "\n"
+	config += `	networks = [{` + "\n"
+	config += `		access = "full"` + "\n"
+	config += `		id = meraki_network.test.id` + "\n"
+	config += `	}]` + "\n"
+	config += `	tags = [{` + "\n"
+	config += `		access = "read-only"` + "\n"
+	config += `		tag = "west"` + "\n"
+	config += `	}]` + "\n"
+	config += `}` + "\n"
+	return config
+}
+
+// End of section. //template:end testAccConfigAll
diff --git a/internal/provider/resource_meraki_network.go b/internal/provider/resource_meraki_network.go
new file mode 100644
index 00000000..f582d586
--- /dev/null
+++ b/internal/provider/resource_meraki_network.go
@@ -0,0 +1,268 @@
+// Copyright © 2024 Cisco Systems, Inc. and its affiliates.
+// All rights reserved.
+//
+// Licensed under the Mozilla Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://mozilla.org/MPL/2.0/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+// Section below is generated&owned by "gen/generator.go". //template:begin imports
+import (
+	"context"
+	"fmt"
+	"net/url"
+	"strings"
+
+	"github.com/hashicorp/terraform-plugin-framework/path"
+	"github.com/hashicorp/terraform-plugin-framework/resource"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+	"github.com/hashicorp/terraform-plugin-log/tflog"
+	"github.com/netascode/go-meraki"
+	"github.com/netascode/terraform-provider-meraki/internal/provider/helpers"
+)
+
+// End of section. //template:end imports
+
+// Section below is generated&owned by "gen/generator.go". //template:begin model
+
+// Ensure provider defined types fully satisfy framework interfaces
+var (
+	_ resource.Resource                = &NetworkResource{}
+	_ resource.ResourceWithImportState = &NetworkResource{}
+)
+
+func NewNetworkResource() resource.Resource {
+	return &NetworkResource{}
+}
+
+type NetworkResource struct {
+	client *meraki.Client
+}
+
+func (r *NetworkResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
+	resp.TypeName = req.ProviderTypeName + "_network"
+}
+
+func (r *NetworkResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
+	resp.Schema = schema.Schema{
+		// This description is used by the documentation generator and the language server.
+		MarkdownDescription: helpers.NewAttributeDescription("This resource can manage the `Network` configuration.").String,
+
+		Attributes: map[string]schema.Attribute{
+			"id": schema.StringAttribute{
+				MarkdownDescription: "The id of the object",
+				Computed:            true,
+				PlanModifiers: []planmodifier.String{
+					stringplanmodifier.UseStateForUnknown(),
+				},
+			},
+			"organization_id": schema.StringAttribute{
+				MarkdownDescription: helpers.NewAttributeDescription("Organization ID").String,
+				Required:            true,
+				PlanModifiers: []planmodifier.String{
+					stringplanmodifier.RequiresReplace(),
+				},
+			},
+			"name": schema.StringAttribute{
+				MarkdownDescription: helpers.NewAttributeDescription("The name of the new network").String,
+				Required:            true,
+			},
+			"notes": schema.StringAttribute{
+				MarkdownDescription: helpers.NewAttributeDescription("Add any notes or additional information about this network here.").String,
+				Optional:            true,
+			},
+			"time_zone": schema.StringAttribute{
+				MarkdownDescription: helpers.NewAttributeDescription("The timezone of the network. For a list of allowed timezones, please see the 'TZ' column in the table in this article.").String,
+				Optional:            true,
+			},
+			"product_types": schema.ListAttribute{
+				MarkdownDescription: helpers.NewAttributeDescription("The product type(s) of the new network. If more than one type is included, the network will be a combined network.").String,
+				ElementType:         types.StringType,
+				Required:            true,
+			},
+			"tags": schema.ListAttribute{
+				MarkdownDescription: helpers.NewAttributeDescription("A list of tags to be applied to the network").String,
+				ElementType:         types.StringType,
+				Optional:            true,
+			},
+		},
+	}
+}
+
+func (r *NetworkResource) Configure(_ context.Context, req resource.ConfigureRequest, _ *resource.ConfigureResponse) {
+	if req.ProviderData == nil {
+		return
+	}
+
+	r.client = req.ProviderData.(*MerakiProviderData).Client
+}
+
+// End of section. //template:end model
+
+// Section below is generated&owned by "gen/generator.go". //template:begin create
+
+func (r *NetworkResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
+	var plan Network
+
+	// Read plan
+	diags := req.Plan.Get(ctx, &plan)
+	if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() {
+		return
+	}
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Create", plan.Id.ValueString()))
+
+	// Create object
+	body := plan.toBody(ctx, Network{})
+	res, err := r.client.Post(plan.getPath(), body)
+	if err != nil {
+		resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to configure object (POST/PUT), got error: %s, %s", err, res.String()))
+		return
+	}
+	plan.Id = types.StringValue(res.Get("id").String())
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Create finished successfully", plan.Id.ValueString()))
+
+	diags = resp.State.Set(ctx, &plan)
+	resp.Diagnostics.Append(diags...)
+
+	helpers.SetFlagImporting(ctx, false, resp.Private, &resp.Diagnostics)
+}
+
+// End of section. //template:end create
+
+// Section below is generated&owned by "gen/generator.go". //template:begin read
+
+func (r *NetworkResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
+	var state Network
+
+	// Read state
+	diags := req.State.Get(ctx, &state)
+	if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() {
+		return
+	}
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Read", state.Id.String()))
+	res, err := r.client.Get(state.getPath() + "/" + url.QueryEscape(state.Id.ValueString()))
+	if err != nil && strings.Contains(err.Error(), "StatusCode 404") {
+		resp.State.RemoveResource(ctx)
+		return
+	} else if err != nil {
+		resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve object (GET), got error: %s, %s", err, res.String()))
+		return
+	}
+
+	imp, diags := helpers.IsFlagImporting(ctx, req)
+	if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() {
+		return
+	}
+
+	// After `terraform import` we switch to a full read.
+	if imp {
+		state.fromBody(ctx, res)
+	} else {
+		state.fromBodyPartial(ctx, res)
+	}
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Read finished successfully", state.Id.ValueString()))
+
+	diags = resp.State.Set(ctx, &state)
+	resp.Diagnostics.Append(diags...)
+
+	helpers.SetFlagImporting(ctx, false, resp.Private, &resp.Diagnostics)
+}
+
+// End of section. //template:end read
+
+// Section below is generated&owned by "gen/generator.go". //template:begin update
+
+func (r *NetworkResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
+	var plan, state Network
+
+	// Read plan
+	diags := req.Plan.Get(ctx, &plan)
+	if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() {
+		return
+	}
+
+	// Read state
+	diags = req.State.Get(ctx, &state)
+	if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() {
+		return
+	}
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Update", plan.Id.ValueString()))
+
+	body := plan.toBody(ctx, state)
+	res, err := r.client.Put(plan.getPath()+"/"+url.QueryEscape(plan.Id.ValueString()), body)
+	if err != nil {
+		resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to configure object (PUT), got error: %s, %s", err, res.String()))
+		return
+	}
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Update finished successfully", plan.Id.ValueString()))
+
+	diags = resp.State.Set(ctx, &plan)
+	resp.Diagnostics.Append(diags...)
+}
+
+// End of section. //template:end update
+
+// Section below is generated&owned by "gen/generator.go". //template:begin delete
+
+func (r *NetworkResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
+	var state Network
+
+	// Read state
+	diags := req.State.Get(ctx, &state)
+	if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() {
+		return
+	}
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Delete", state.Id.ValueString()))
+	res, err := r.client.Delete(state.getPath() + "/" + url.QueryEscape(state.Id.ValueString()))
+	if err != nil {
+		resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to delete object (DELETE), got error: %s, %s", err, res.String()))
+		return
+	}
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Delete finished successfully", state.Id.ValueString()))
+
+	resp.State.RemoveResource(ctx)
+}
+
+// End of section. //template:end delete
+
+// Section below is generated&owned by "gen/generator.go". //template:begin import
+
+func (r *NetworkResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
+	idParts := strings.Split(req.ID, ",")
+
+	if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" {
+		resp.Diagnostics.AddError(
+			"Unexpected Import Identifier",
+			fmt.Sprintf("Expected import identifier with format: <organization_id>,<id>. Got: %q", req.ID),
+		)
+		return
+	}
+	resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("organization_id"), idParts[0])...)
+	resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("id"), idParts[1])...)
+
+	helpers.SetFlagImporting(ctx, true, resp.Private, &resp.Diagnostics)
+}
+
+// End of section. //template:end import
diff --git a/internal/provider/resource_meraki_network_test.go b/internal/provider/resource_meraki_network_test.go
new file mode 100644
index 00000000..a7398d33
--- /dev/null
+++ b/internal/provider/resource_meraki_network_test.go
@@ -0,0 +1,98 @@
+// Copyright © 2024 Cisco Systems, Inc. and its affiliates.
+// All rights reserved.
+//
+// Licensed under the Mozilla Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://mozilla.org/MPL/2.0/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+// Section below is generated&owned by "gen/generator.go". //template:begin imports
+import (
+	"os"
+	"testing"
+
+	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+// End of section. //template:end imports
+
+// Section below is generated&owned by "gen/generator.go". //template:begin testAcc
+
+func TestAccMerakiNetwork(t *testing.T) {
+	var checks []resource.TestCheckFunc
+	checks = append(checks, resource.TestCheckResourceAttr("meraki_network.test", "name", "Main Office"))
+	checks = append(checks, resource.TestCheckResourceAttr("meraki_network.test", "notes", "Additional description of the network"))
+	checks = append(checks, resource.TestCheckResourceAttr("meraki_network.test", "time_zone", "America/Los_Angeles"))
+	checks = append(checks, resource.TestCheckResourceAttr("meraki_network.test", "product_types.0", "switch"))
+	checks = append(checks, resource.TestCheckResourceAttr("meraki_network.test", "tags.0", "tag1"))
+
+	var steps []resource.TestStep
+	if os.Getenv("SKIP_MINIMUM_TEST") == "" {
+		steps = append(steps, resource.TestStep{
+			Config: testAccMerakiNetworkPrerequisitesConfig + testAccMerakiNetworkConfig_minimum(),
+		})
+	}
+	steps = append(steps, resource.TestStep{
+		Config: testAccMerakiNetworkPrerequisitesConfig + testAccMerakiNetworkConfig_all(),
+		Check:  resource.ComposeTestCheckFunc(checks...),
+	})
+
+	resource.Test(t, resource.TestCase{
+		PreCheck:                 func() { testAccPreCheck(t) },
+		ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+		Steps:                    steps,
+	})
+}
+
+// End of section. //template:end testAcc
+
+// Section below is generated&owned by "gen/generator.go". //template:begin testPrerequisites
+
+const testAccMerakiNetworkPrerequisitesConfig = `
+data "meraki_organization" "test" {
+  name = "TF Test"
+}
+
+`
+
+// End of section. //template:end testPrerequisites
+
+// Section below is generated&owned by "gen/generator.go". //template:begin testAccConfigMinimal
+
+func testAccMerakiNetworkConfig_minimum() string {
+	config := `resource "meraki_network" "test" {` + "\n"
+	config += `	organization_id = data.meraki_organization.test.id` + "\n"
+	config += `	name = "Main Office"` + "\n"
+	config += `	product_types = ["switch"]` + "\n"
+	config += `}` + "\n"
+	return config
+}
+
+// End of section. //template:end testAccConfigMinimal
+
+// Section below is generated&owned by "gen/generator.go". //template:begin testAccConfigAll
+
+func testAccMerakiNetworkConfig_all() string {
+	config := `resource "meraki_network" "test" {` + "\n"
+	config += `	organization_id = data.meraki_organization.test.id` + "\n"
+	config += `	name = "Main Office"` + "\n"
+	config += `	notes = "Additional description of the network"` + "\n"
+	config += `	time_zone = "America/Los_Angeles"` + "\n"
+	config += `	product_types = ["switch"]` + "\n"
+	config += `	tags = ["tag1"]` + "\n"
+	config += `}` + "\n"
+	return config
+}
+
+// End of section. //template:end testAccConfigAll
diff --git a/internal/provider/resource_meraki_organization.go b/internal/provider/resource_meraki_organization.go
new file mode 100644
index 00000000..0d9b9673
--- /dev/null
+++ b/internal/provider/resource_meraki_organization.go
@@ -0,0 +1,249 @@
+// Copyright © 2024 Cisco Systems, Inc. and its affiliates.
+// All rights reserved.
+//
+// Licensed under the Mozilla Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://mozilla.org/MPL/2.0/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+// Section below is generated&owned by "gen/generator.go". //template:begin imports
+import (
+	"context"
+	"fmt"
+	"net/url"
+	"strings"
+
+	"github.com/hashicorp/terraform-plugin-framework/path"
+	"github.com/hashicorp/terraform-plugin-framework/resource"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+	"github.com/hashicorp/terraform-plugin-log/tflog"
+	"github.com/netascode/go-meraki"
+	"github.com/netascode/terraform-provider-meraki/internal/provider/helpers"
+)
+
+// End of section. //template:end imports
+
+// Section below is generated&owned by "gen/generator.go". //template:begin model
+
+// Ensure provider defined types fully satisfy framework interfaces
+var (
+	_ resource.Resource                = &OrganizationResource{}
+	_ resource.ResourceWithImportState = &OrganizationResource{}
+)
+
+func NewOrganizationResource() resource.Resource {
+	return &OrganizationResource{}
+}
+
+type OrganizationResource struct {
+	client *meraki.Client
+}
+
+func (r *OrganizationResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
+	resp.TypeName = req.ProviderTypeName + "_organization"
+}
+
+func (r *OrganizationResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
+	resp.Schema = schema.Schema{
+		// This description is used by the documentation generator and the language server.
+		MarkdownDescription: helpers.NewAttributeDescription("This resource can manage the `Organization` configuration.").String,
+
+		Attributes: map[string]schema.Attribute{
+			"id": schema.StringAttribute{
+				MarkdownDescription: "The id of the object",
+				Computed:            true,
+				PlanModifiers: []planmodifier.String{
+					stringplanmodifier.UseStateForUnknown(),
+				},
+			},
+			"name": schema.StringAttribute{
+				MarkdownDescription: helpers.NewAttributeDescription("The name of the organization").String,
+				Required:            true,
+			},
+			"management_details": schema.ListNestedAttribute{
+				MarkdownDescription: helpers.NewAttributeDescription("Details related to organization management, possibly empty").String,
+				Optional:            true,
+				NestedObject: schema.NestedAttributeObject{
+					Attributes: map[string]schema.Attribute{
+						"name": schema.StringAttribute{
+							MarkdownDescription: helpers.NewAttributeDescription("Name of management data").String,
+							Required:            true,
+						},
+						"value": schema.StringAttribute{
+							MarkdownDescription: helpers.NewAttributeDescription("Value of management data").String,
+							Required:            true,
+						},
+					},
+				},
+			},
+		},
+	}
+}
+
+func (r *OrganizationResource) Configure(_ context.Context, req resource.ConfigureRequest, _ *resource.ConfigureResponse) {
+	if req.ProviderData == nil {
+		return
+	}
+
+	r.client = req.ProviderData.(*MerakiProviderData).Client
+}
+
+// End of section. //template:end model
+
+// Section below is generated&owned by "gen/generator.go". //template:begin create
+
+func (r *OrganizationResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
+	var plan Organization
+
+	// Read plan
+	diags := req.Plan.Get(ctx, &plan)
+	if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() {
+		return
+	}
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Create", plan.Id.ValueString()))
+
+	// Create object
+	body := plan.toBody(ctx, Organization{})
+	res, err := r.client.Post(plan.getPath(), body)
+	if err != nil {
+		resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to configure object (POST/PUT), got error: %s, %s", err, res.String()))
+		return
+	}
+	plan.Id = types.StringValue(res.Get("id").String())
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Create finished successfully", plan.Id.ValueString()))
+
+	diags = resp.State.Set(ctx, &plan)
+	resp.Diagnostics.Append(diags...)
+
+	helpers.SetFlagImporting(ctx, false, resp.Private, &resp.Diagnostics)
+}
+
+// End of section. //template:end create
+
+// Section below is generated&owned by "gen/generator.go". //template:begin read
+
+func (r *OrganizationResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
+	var state Organization
+
+	// Read state
+	diags := req.State.Get(ctx, &state)
+	if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() {
+		return
+	}
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Read", state.Id.String()))
+	res, err := r.client.Get(state.getPath() + "/" + url.QueryEscape(state.Id.ValueString()))
+	if err != nil && strings.Contains(err.Error(), "StatusCode 404") {
+		resp.State.RemoveResource(ctx)
+		return
+	} else if err != nil {
+		resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to retrieve object (GET), got error: %s, %s", err, res.String()))
+		return
+	}
+
+	imp, diags := helpers.IsFlagImporting(ctx, req)
+	if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() {
+		return
+	}
+
+	// After `terraform import` we switch to a full read.
+	if imp {
+		state.fromBody(ctx, res)
+	} else {
+		state.fromBodyPartial(ctx, res)
+	}
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Read finished successfully", state.Id.ValueString()))
+
+	diags = resp.State.Set(ctx, &state)
+	resp.Diagnostics.Append(diags...)
+
+	helpers.SetFlagImporting(ctx, false, resp.Private, &resp.Diagnostics)
+}
+
+// End of section. //template:end read
+
+// Section below is generated&owned by "gen/generator.go". //template:begin update
+
+func (r *OrganizationResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
+	var plan, state Organization
+
+	// Read plan
+	diags := req.Plan.Get(ctx, &plan)
+	if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() {
+		return
+	}
+
+	// Read state
+	diags = req.State.Get(ctx, &state)
+	if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() {
+		return
+	}
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Update", plan.Id.ValueString()))
+
+	body := plan.toBody(ctx, state)
+	res, err := r.client.Put(plan.getPath()+"/"+url.QueryEscape(plan.Id.ValueString()), body)
+	if err != nil {
+		resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to configure object (PUT), got error: %s, %s", err, res.String()))
+		return
+	}
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Update finished successfully", plan.Id.ValueString()))
+
+	diags = resp.State.Set(ctx, &plan)
+	resp.Diagnostics.Append(diags...)
+}
+
+// End of section. //template:end update
+
+// Section below is generated&owned by "gen/generator.go". //template:begin delete
+
+func (r *OrganizationResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
+	var state Organization
+
+	// Read state
+	diags := req.State.Get(ctx, &state)
+	if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() {
+		return
+	}
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Beginning Delete", state.Id.ValueString()))
+	res, err := r.client.Delete(state.getPath() + "/" + url.QueryEscape(state.Id.ValueString()))
+	if err != nil {
+		resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to delete object (DELETE), got error: %s, %s", err, res.String()))
+		return
+	}
+
+	tflog.Debug(ctx, fmt.Sprintf("%s: Delete finished successfully", state.Id.ValueString()))
+
+	resp.State.RemoveResource(ctx)
+}
+
+// End of section. //template:end delete
+
+// Section below is generated&owned by "gen/generator.go". //template:begin import
+
+func (r *OrganizationResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
+	resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
+
+	helpers.SetFlagImporting(ctx, true, resp.Private, &resp.Diagnostics)
+}
+
+// End of section. //template:end import
diff --git a/internal/provider/resource_meraki_organization_test.go b/internal/provider/resource_meraki_organization_test.go
new file mode 100644
index 00000000..da5695a7
--- /dev/null
+++ b/internal/provider/resource_meraki_organization_test.go
@@ -0,0 +1,89 @@
+// Copyright © 2024 Cisco Systems, Inc. and its affiliates.
+// All rights reserved.
+//
+// Licensed under the Mozilla Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://mozilla.org/MPL/2.0/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+package provider
+
+// Section below is generated&owned by "gen/generator.go". //template:begin imports
+import (
+	"os"
+	"testing"
+
+	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+// End of section. //template:end imports
+
+// Section below is generated&owned by "gen/generator.go". //template:begin testAcc
+
+func TestAccMerakiOrganization(t *testing.T) {
+	var checks []resource.TestCheckFunc
+	checks = append(checks, resource.TestCheckResourceAttr("meraki_organization.test", "name", "My organization"))
+	checks = append(checks, resource.TestCheckResourceAttr("meraki_organization.test", "management_details.0.name", "MSP ID"))
+	checks = append(checks, resource.TestCheckResourceAttr("meraki_organization.test", "management_details.0.value", "123456"))
+
+	var steps []resource.TestStep
+	if os.Getenv("SKIP_MINIMUM_TEST") == "" {
+		steps = append(steps, resource.TestStep{
+			Config: testAccMerakiOrganizationConfig_minimum(),
+		})
+	}
+	steps = append(steps, resource.TestStep{
+		Config: testAccMerakiOrganizationConfig_all(),
+		Check:  resource.ComposeTestCheckFunc(checks...),
+	})
+	steps = append(steps, resource.TestStep{
+		ResourceName: "meraki_organization.test",
+		ImportState:  true,
+	})
+
+	resource.Test(t, resource.TestCase{
+		PreCheck:                 func() { testAccPreCheck(t) },
+		ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+		Steps:                    steps,
+	})
+}
+
+// End of section. //template:end testAcc
+
+// Section below is generated&owned by "gen/generator.go". //template:begin testPrerequisites
+// End of section. //template:end testPrerequisites
+
+// Section below is generated&owned by "gen/generator.go". //template:begin testAccConfigMinimal
+
+func testAccMerakiOrganizationConfig_minimum() string {
+	config := `resource "meraki_organization" "test" {` + "\n"
+	config += `	name = "My organization"` + "\n"
+	config += `}` + "\n"
+	return config
+}
+
+// End of section. //template:end testAccConfigMinimal
+
+// Section below is generated&owned by "gen/generator.go". //template:begin testAccConfigAll
+
+func testAccMerakiOrganizationConfig_all() string {
+	config := `resource "meraki_organization" "test" {` + "\n"
+	config += `	name = "My organization"` + "\n"
+	config += `	management_details = [{` + "\n"
+	config += `		name = "MSP ID"` + "\n"
+	config += `		value = "123456"` + "\n"
+	config += `	}]` + "\n"
+	config += `}` + "\n"
+	return config
+}
+
+// End of section. //template:end testAccConfigAll
diff --git a/main.go b/main.go
new file mode 100644
index 00000000..6848742e
--- /dev/null
+++ b/main.go
@@ -0,0 +1,66 @@
+// Copyright © 2024 Cisco Systems, Inc. and its affiliates.
+// All rights reserved.
+//
+// Licensed under the Mozilla Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://mozilla.org/MPL/2.0/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+package main
+
+import (
+	"context"
+	"log"
+
+	"github.com/hashicorp/terraform-plugin-framework/providerserver"
+	"github.com/netascode/terraform-provider-meraki/internal/provider"
+)
+
+// Run "go generate" to format example terraform files and generate the docs for the registry/website
+
+// Run the resource and datasource generation tool.
+//go:generate go run gen/generator.go
+
+// Format code and cleanup imports
+//go:generate go run golang.org/x/tools/cmd/goimports -w internal/provider/
+
+// If you do not have terraform installed, you can remove the formatting command, but its suggested to
+// ensure the documentation is formatted properly.
+//go:generate terraform fmt -recursive ./examples/
+
+// Run the docs generation tool, check its repository for more information on how it works and how docs
+// can be customized.
+//go:generate go run github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs
+
+// Update documentation categories.
+//go:generate go run gen/doc_category.go
+
+var (
+	// these will be set by the goreleaser configuration
+	// to appropriate values for the compiled binary
+	version string = "dev"
+
+	// goreleaser can also pass the specific commit if you want
+	// commit  string = ""
+)
+
+func main() {
+	opts := providerserver.ServeOpts{
+		Address: "registry.terraform.io/netascode/meraki",
+	}
+
+	err := providerserver.Serve(context.Background(), provider.New(version), opts)
+
+	if err != nil {
+		log.Fatal(err.Error())
+	}
+}
diff --git a/templates/guides/changelog.md.tmpl b/templates/guides/changelog.md.tmpl
new file mode 100644
index 00000000..19ba619f
--- /dev/null
+++ b/templates/guides/changelog.md.tmpl
@@ -0,0 +1,13 @@
+---
+subcategory: "Guides"
+page_title: "Changelog"
+description: |-
+    Changelog
+---
+
+# Changelog
+
+## 0.1.0 (unreleased)
+
+- Initial release
+
diff --git a/templates/index.md.tmpl b/templates/index.md.tmpl
new file mode 100644
index 00000000..230fa282
--- /dev/null
+++ b/templates/index.md.tmpl
@@ -0,0 +1,24 @@
+
+---
+layout: ""
+page_title: "Provider: Meraki"
+description: |-
+  The Meraki provider provides resources to interact with Cisco Meraki Dashboard.
+
+---
+
+# Meraki Provider
+
+The Meraki provider provides resources to interact with a Cisco Meraki Dashboard. It communicates with Meraki Dashboard via the REST API.
+
+All resources and data sources have been tested with the following API releases.
+
+| API | Version |
+| ---------------- | ------- |
+| Meraki Dashboard | 1.49    |
+
+## Example Usage
+
+{{tffile "examples/provider/provider.tf"}}
+
+{{ .SchemaMarkdown | trimspace }}
diff --git a/terraform-registry-manifest.json b/terraform-registry-manifest.json
new file mode 100644
index 00000000..fec2a569
--- /dev/null
+++ b/terraform-registry-manifest.json
@@ -0,0 +1,6 @@
+{
+    "version": 1,
+    "metadata": {
+        "protocol_versions": ["6.0"]
+    }
+}
diff --git a/tools/tools.go b/tools/tools.go
new file mode 100644
index 00000000..dc5f8a86
--- /dev/null
+++ b/tools/tools.go
@@ -0,0 +1,28 @@
+// Copyright © 2024 Cisco Systems, Inc. and its affiliates.
+// All rights reserved.
+//
+// Licensed under the Mozilla Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://mozilla.org/MPL/2.0/
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: MPL-2.0
+
+//go:build tools
+
+package tools
+
+import (
+	// Documentation generation
+	_ "github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs"
+	// Code generation
+	_ "golang.org/x/tools/cmd/goimports"
+	_ "gopkg.in/yaml.v3"
+)