diff --git a/.codecov.yml b/.codecov.yml
deleted file mode 100644
index b4cd94f..0000000
--- a/.codecov.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-coverage:
-  status:
-    project:
-      default:
-        target: 70%
-    patch:
-      default:
-        target: 60%
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..d921d0f
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,7 @@
+version: 2
+updates:
+- package-ecosystem: gomod
+  directory: "/"
+  schedule:
+    interval: daily
+  open-pull-requests-limit: 10
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
new file mode 100644
index 0000000..1f6a238
--- /dev/null
+++ b/.github/workflows/codeql-analysis.yml
@@ -0,0 +1,71 @@
+# For most projects, this workflow file will not need changing; you simply need
+# to commit it to your repository.
+#
+# You may wish to alter this file to override the set of languages analyzed,
+# or to provide custom queries or build logic.
+#
+# ******** NOTE ********
+# We have attempted to detect the languages in your repository. Please check
+# the `language` matrix defined below to confirm you have the correct set of
+# supported CodeQL languages.
+#
+name: "CodeQL"
+
+on:
+  push:
+    branches: [ master ]
+  pull_request:
+    # The branches below must be a subset of the branches above
+    branches: [ master ]
+  schedule:
+    - cron: '0 3 * * *'
+
+jobs:
+  analyze:
+    name: Analyze
+    runs-on: ubuntu-latest
+    permissions:
+      actions: read
+      contents: read
+      security-events: write
+
+    strategy:
+      fail-fast: false
+      matrix:
+        language: [ 'go' ]
+        # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
+        # Learn more:
+        # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
+
+    steps:
+    - name: Checkout repository
+      uses: actions/checkout@v2
+
+    # Initializes the CodeQL tools for scanning.
+    - name: Initialize CodeQL
+      uses: github/codeql-action/init@v1
+      with:
+        languages: ${{ matrix.language }}
+        # If you wish to specify custom queries, you can do so here or in a config file.
+        # By default, queries listed here will override any specified in a config file.
+        # Prefix the list here with "+" to use these queries and those in the config file.
+        # queries: ./path/to/local/query, your-org/your-repo/queries@main
+
+    # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).
+    # If this step fails, then you should remove it and run the build manually (see below)
+    - name: Autobuild
+      uses: github/codeql-action/autobuild@v1
+
+    # ℹī¸ Command-line programs to run using the OS shell.
+    # 📚 https://git.io/JvXDl
+
+    # ✏ī¸ If the Autobuild fails above, remove it and uncomment the following three lines
+    #    and modify them (or add more) to build your code if your project
+    #    uses a compiled language
+
+    #- run: |
+    #   make bootstrap
+    #   make release
+
+    - name: Perform CodeQL Analysis
+      uses: github/codeql-action/analyze@v1
diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml
new file mode 100644
index 0000000..4d1a4de
--- /dev/null
+++ b/.github/workflows/coverage.yml
@@ -0,0 +1,65 @@
+name: "Unit/Coverage Tests"
+
+on:
+  push:
+    branches:
+      - master
+  pull_request_target:
+    branches:
+      - master
+
+jobs:
+  coverage:
+    runs-on: ubuntu-latest
+    outputs:
+      msg: ${{ steps.results.outputs.content }}
+    steps:
+      - uses: actions/checkout@v2
+
+      - name: Setup Go
+        uses: actions/setup-go@v2
+        with:
+          go-version: 1.17
+
+      - name: Run unit tests and coverage test
+        id: test-coverage
+        run: |
+          go test -cover -v > output.txt
+
+      - name: Transform output
+        id: results
+        if: always()
+        run: |
+          CONTENT=$(cat output.txt)
+          CONTENT="${CONTENT//'%'/'%25'}"
+          CONTENT="${CONTENT//$'\n'/'%0A'}"
+          CONTENT="${CONTENT//$'\r'/'%0D'}"
+          echo "::set-output name=content::$CONTENT"
+
+  comment:
+    runs-on: ubuntu-latest
+    if: github.event_name != 'push'
+    needs: coverage
+    steps:
+      - name: Add Comment
+        uses: actions/github-script@v5
+        if: always()
+        with:
+          script: |
+            const output = `### Unit Tests and Coverage
+            <details><summary>Show Output</summary>
+
+            \`\`\`
+            ${{ needs.coverage.outputs.msg }}
+            \`\`\`
+            </details>
+
+            *Pusher: @${{ github.actor }}, Action: \`${{ github.event_name }}\`*`;
+
+            await github.rest.issues.createComment({
+              issue_number: context.issue.number,
+              owner: context.repo.owner,
+              repo: context.repo.repo,
+              body: output
+            })
+
diff --git a/.github/workflows/gochecks.yml b/.github/workflows/gochecks.yml
new file mode 100644
index 0000000..a7b3a11
--- /dev/null
+++ b/.github/workflows/gochecks.yml
@@ -0,0 +1,56 @@
+name: Checks
+
+on:
+  push:
+    branches:
+      - master
+  pull_request:
+    branches:
+      - master
+
+jobs:
+  Go-Lint:
+    runs-on: ubuntu-latest
+
+    steps:
+      - uses: actions/checkout@v2
+      - name: Setup Go
+        uses: actions/setup-go@v2
+        with:
+          go-version: '1.16.6'
+
+      - name: Install dependencies
+        run: |
+          go version
+          go get -u golang.org/x/lint/golint
+
+      - name: Run Lint
+        run: |
+          golint_files=$(golint .)
+          if [[ -n ${golint_files} ]]; then
+              echo 'fix the following linting errors:'
+              echo "${golint_files}"
+              exit 1
+          fi
+          exit 0
+
+  Go-Fmt:
+    runs-on: ubuntu-latest
+
+    steps:
+      - uses: actions/checkout@v2
+      - name: Setup Go
+        uses: actions/setup-go@v2
+        with:
+          go-version: '1.16.6'
+
+      - name: Run fmt
+        run: |
+          gofmt_files=$(gofmt -l .)
+          if [[ -n ${gofmt_files} ]]; then
+              echo 'gofmt needs running on the following files:'
+              echo "${gofmt_files}"
+              exit 1
+          fi
+          exit 0
+
diff --git a/.github/workflows/notify-issue.yml b/.github/workflows/notify-issue.yml
new file mode 100644
index 0000000..9fe655b
--- /dev/null
+++ b/.github/workflows/notify-issue.yml
@@ -0,0 +1,18 @@
+name: notify-issue
+
+on:
+  issues:
+    types: [opened]
+
+jobs:
+  issue:
+    runs-on: ubuntu-latest
+    name: New Issue Notification
+    steps:
+      - run: |
+          echo "{\"text\":\"GoVultr : New Issue https://github.com/vultr/govultr/issues/${{ github.event.issue.number }} \"}" > mattermost.json
+      - uses: mattermost/action-mattermost-notify@master
+        env:
+          MATTERMOST_WEBHOOK_URL: ${{ secrets.MATTERMOST_WEBHOOK_URL }}
+          MATTERMOST_USERNAME: ${{ secrets.MATTERMOST_USERNAME}}
+          MATTERMOST_ICON: ${{ secrets.MATTERMOST_ICON }}
diff --git a/.github/workflows/notify-pr.yml b/.github/workflows/notify-pr.yml
new file mode 100644
index 0000000..8970ad1
--- /dev/null
+++ b/.github/workflows/notify-pr.yml
@@ -0,0 +1,16 @@
+name: notify-pr
+
+on: pull_request_target
+
+jobs:
+  pr:
+    runs-on: ubuntu-latest
+    name: Pull Request Notification
+    steps:
+      - run: |
+          echo "{\"text\":\"GoVultr : PR https://github.com/vultr/govultr/pull/${{ github.event.number }} \"}" > mattermost.json
+      - uses: mattermost/action-mattermost-notify@master
+        env:
+          MATTERMOST_WEBHOOK_URL: ${{ secrets.MATTERMOST_WEBHOOK_URL }}
+          MATTERMOST_USERNAME: ${{ secrets.MATTERMOST_USERNAME}}
+          MATTERMOST_ICON: ${{ secrets.MATTERMOST_ICON }}
diff --git a/.github/workflows/releaser.yml b/.github/workflows/releaser.yml
new file mode 100644
index 0000000..5724956
--- /dev/null
+++ b/.github/workflows/releaser.yml
@@ -0,0 +1,78 @@
+name: "Automatic Releaser"
+
+on:
+  push:
+    branches:
+      - master
+
+permissions:
+  contents: write
+
+jobs:
+  check-commit:
+    runs-on: ubuntu-latest
+    outputs:
+      msg_check: ${{ steps.check-msg.outputs.match }}
+    steps:
+      - name: Check Message
+        id: check-msg
+        run: |
+          pattern="^Release v[0-9]+.[0-9]+.[0-9]+ #(minor|major|patch)$"
+          if [[ "${{ github.event.head_commit.message }}" =~ ${pattern} ]]; then
+              echo ::set-output name=match::true
+          fi
+  create-tag:
+    runs-on: ubuntu-latest
+    if: needs.check-commit.outputs.msg_check == 'true'
+    needs: check-commit
+    outputs:
+      new_tag: ${{ steps.tagger.outputs.new_tag }}
+    steps:
+    - uses: actions/checkout@v2
+      with:
+        fetch-depth: '0'
+
+    - name: Bump version and push tag
+      id: tagger
+      uses: anothrNick/github-tag-action@1.36.0
+      env:
+        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+        WITH_V: true
+        DEFAULT_BUMP: "none"
+
+  goreleaser:
+    runs-on: ubuntu-latest
+    needs: create-tag
+    steps:
+      -
+        name: Checkout
+        uses: actions/checkout@v2
+        with:
+          fetch-depth: 0
+      -
+        name: Set up Go
+        uses: actions/setup-go@v2
+        with:
+          go-version: 1.16
+      -
+        name: Run GoReleaser
+        uses: goreleaser/goreleaser-action@v2
+        with:
+          distribution: goreleaser
+          version: latest
+          args: release --rm-dist
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+  release:
+    runs-on: ubuntu-latest
+    needs: ["goreleaser", "create-tag"]
+    name: Release Notification
+    steps:
+      - run: |
+          echo "{\"text\":\"GoVultr : Release https://github.com/${{ github.repository }}/releases/tag/${{ needs.create-tag.outputs.new_tag }} \"}" > mattermost.json
+      - uses: mattermost/action-mattermost-notify@master
+        env:
+          MATTERMOST_WEBHOOK_URL: ${{ secrets.MATTERMOST_WEBHOOK_URL }}
+          MATTERMOST_USERNAME: ${{ secrets.MATTERMOST_USERNAME}}
+          MATTERMOST_ICON: ${{ secrets.MATTERMOST_ICON }}
diff --git a/.goreleaser.yml b/.goreleaser.yml
new file mode 100644
index 0000000..e683e43
--- /dev/null
+++ b/.goreleaser.yml
@@ -0,0 +1,25 @@
+before:
+  hooks:
+    - go mod download
+    - go generate ./...
+builds:
+ - skip: true
+
+checksum:
+  name_template: "{{ .ProjectName }}_v{{ .Version }}_checksums.txt"
+  algorithm: sha256
+
+snapshot:
+  name_template: "{{ .ProjectName }}_v{{ .Version }}"
+
+changelog:
+  sort: asc
+  filters:
+    exclude:
+      - '^docs:'
+      - '^test:'
+
+release:
+  github:
+    owner: Vultr
+    name: govultr
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index b1d3559..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,16 +0,0 @@
-language: go
-
-go:
-  - 1.13.x
-  - 1.14.x
-  - tip
-
-matrix:
-  allow_failures:
-    - go: tip
-
-script:
-  - go test -race -coverprofile=coverage.txt -covermode=atomic
-
-after_success:
-  - bash <(curl -s https://codecov.io/bash)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8856811..02eb6f6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,115 +1,139 @@
 # Change Log
 
-## [v0.4.2](https://github.com/vultr/govultr/compare/v0.4.1..v0.4.2) (2020-06-02)
-### Bug Fix
-*  DNS Records: Allow DNS Records on updates to have priority of 0 [#67](https://github.com/vultr/govultr/pull/67)
+## GoVultr v1 changelog is located [here](https://github.com/vultr/govultr/blob/v1/CHANGELOG.md)
 
-## [v0.4.1](https://github.com/vultr/govultr/compare/v0.4.0..v0.4.1) (2020-05-08)
+## [v2.14.2](https://github.com/vultr/govultr/compare/v2.14.1..v2.14.2) (2022-03-23)
 ### Bug Fix
-*  LoadBalancers: Fix nil pointer in create call [#65](https://github.com/vultr/govultr/pull/65)
+* Instances : restore support requestBody [206](https://github.com/vultr/govultr/pull/206) Thanks @andrake81
 
-## [v0.4.0](https://github.com/vultr/govultr/compare/v0.3.3..v0.4.0) (2020-04-29)
+## [v2.14.1](https://github.com/vultr/govultr/compare/v2.14.0..v2.14.1) (2022-02-02)
 ### Enhancement
-*  LoadBalancers: Proxy protocol is now available as an option [#62](https://github.com/vultr/govultr/pull/62)
-*  LoadBalancers: Ability to attach instances during Create (note this adds a new param to create call) [#62](https://github.com/vultr/govultr/pull/62)
+* Improved retry error response [204](https://github.com/vultr/govultr/pull/204)
 
-### Bug Fix
-*  LoadBalancers: Create call will now properly pass your algorithm [#61](https://github.com/vultr/govultr/pull/61)
+## [v2.14.0](https://github.com/vultr/govultr/compare/v2.13.0..v2.14.0) (2022-01-21)
+### Enhancement
+* ListOptions : [Added query param Region](https://www.vultr.com/api/#operation/list-instances) that can be used with `Instance.List`  [200](https://github.com/vultr/govultr/pull/200)
+* ListOptions : [Added query param Description](https://www.vultr.com/api/#operation/list-snapshots) that can be used with `Snapshot.List`  [202](https://github.com/vultr/govultr/pull/202)
+* Snapshot : `CreateFromURL` has new optional field called `description` which lets you set a custom description [202](https://github.com/vultr/govultr/pull/202)
+
+## [v2.13.0](https://github.com/vultr/govultr/compare/v2.12.0..v2.13.0) (2022-01-05)
+### Enhancement
+* ListOptions : [Added query params](https://www.vultr.com/api/#operation/list-instances) that can be used with `Instance.List`  [197](https://github.com/vultr/govultr/pull/197)
+
+## [v2.12.0](https://github.com/vultr/govultr/compare/v2.11.1..v2.12.0) (2021-12-01)
+### Breaking Changes
+* Plans : Changed `MonthlyCost` from `int` to `float32` [192](https://github.com/vultr/govultr/pull/192)
 
-### CI/CD
-* Drop go 1.12 and add 1.14 [#63](https://github.com/vultr/govultr/pull/63)
+## [v2.11.1](https://github.com/vultr/govultr/compare/v2.11.0..v2.11.1) (2021-11-26)
+### Bug fixes
+* LoadBalancers : Fixed SSL struct json params to the proper API fields [189](https://github.com/vultr/govultr/pull/189)
 
-## [v0.3.3](https://github.com/vultr/govultr/compare/v0.3.2..v0.3.3) (2020-04-15)
-### Dependencies
-*  go-retryablehttp 0.6.4 -> 0.6.6 [#58](https://github.com/vultr/govultr/pull/58)
+## [v2.11.0](https://github.com/vultr/govultr/compare/v2.10.0..v2.11.0) (2021-11-18)
+### Breaking Changes
+* Instances : Update call will now return `*Instance` in addition to `error` [185](https://github.com/vultr/govultr/pull/185)
+* Instances : Reinstall call now allows changing of hostname and also returns `*Instance` in addition to `error` [181](https://github.com/vultr/govultr/pull/181)
 
-## [v0.3.2](https://github.com/vultr/govultr/compare/v0.3.1..v0.3.2) (2020-03-25)
 ### Enhancement
-*  Added support to live attach/detach blockstorage [#55](https://github.com/vultr/govultr/pull/55)
+* Instances : The hostname of the instance is now returned in any call that returns Instance data [187](https://github.com/vultr/govultr/pull/187)
+* Domains : There is a new field called `dns_sec` which will return `enabled` or `disabled` depending on how your domain is configured [184](https://github.com/vultr/govultr/pull/184)
 
-## [v0.3.1](https://github.com/vultr/govultr/compare/v0.3.0..v0.3.1) (2020-03-11)
+## [v2.10.0](https://github.com/vultr/govultr/compare/v2.9.2..v2.10.0) (2021-11-03)
 ### Enhancement
-*  Added support for Load Balancers SSL Calls [#53](https://github.com/vultr/govultr/pull/53)
-### Bug Fix
-* Fixed InstanceList type from string to int [#50](https://github.com/vultr/govultr/pull/50)
-* Fixed struct json marshalling issue [#48](https://github.com/vultr/govultr/pull/48)
-### Dependencies
-* go-retryablehttp 0.6.3 -> 0.6.4 [#51](https://github.com/vultr/govultr/pull/51)
+* Billing : Added support for billing [178](https://github.com/vultr/govultr/pull/178)
+
+## [v2.9.2](https://github.com/vultr/govultr/compare/v2.9.1..v2.9.2) (2021-10-20)
+### Change
+* Iso : Changed `client` field to be unexported [168](https://github.com/vultr/govultr/pull/168)
+* Snapshot : Changed `client` field to be unexported  [168](https://github.com/vultr/govultr/pull/168)
+* Plans : Changed `client` field to be unexported  [168](https://github.com/vultr/govultr/pull/168)
+* Regions : Changed `client` field to be unexported  [168](https://github.com/vultr/govultr/pull/168)
 
-## [v0.3.0](https://github.com/vultr/govultr/compare/v0.2.0..v0.3.0) (2020-02-24)
+## [v2.9.1](https://github.com/vultr/govultr/compare/v2.9.0..v2.9.1) (2021-10-18)
 ### Enhancement
-*  Added support for Load Balancers [#44](https://github.com/vultr/govultr/pull/44)
-### Bug Fix
-* Fixed Object Storage Get call [#46](https://github.com/vultr/govultr/pull/46)
+* Kubernetes : Added `Tag` support for nodepools [164](https://github.com/vultr/govultr/pull/164)
+
+## [v2.9.0](https://github.com/vultr/govultr/compare/v2.8.1..v2.9.0) (2021-09-27)
+### Breaking Change
+* Kubernetes : PlanID is now Plan and Count is now NodeQuantity to follow API pattern [161](https://github.com/vultr/govultr/pull/161)
+
+### Enhancement
+* Snapshots : Add compressed size field [162](https://github.com/vultr/govultr/pull/162)
+
+## [v2.8.1](https://github.com/vultr/govultr/compare/v2.8.0..v2.8.1) (2021-08-31)
+### Enhancement
+* Kubernetes : Add support for deletion with resources [159](https://github.com/vultr/govultr/pull/159)
+* Kubernetes : Add support for getting available versions[159](https://github.com/vultr/govultr/pull/159)
+
+### Dependency Update
+* Bump Go version to 1.16 [158](https://github.com/vultr/govultr/pull/158)
 
-## [v0.2.0](https://github.com/vultr/govultr/compare/v0.1.7..v0.2.0) (2020-02-06)
+## [v2.8.0](https://github.com/vultr/govultr/compare/v2.7.1..v2.8.0) (2021-08-18)
 ### Enhancement
-*  Added support for Object Storage [#39](https://github.com/vultr/govultr/pull/39)
+* Added support for Vultr Kubernetes Engine [156](https://github.com/vultr/govultr/pull/156)
 
-## [v0.1.7](https://github.com/vultr/govultr/compare/v0.1.6..v0.1.7) (2019-11-11)
+## [v2.7.1](https://github.com/vultr/govultr/compare/v2.7.0..v2.7.1) (2021-07-15)
 ### Enhancement
-*  Version number was missing in v0.1.6 - Attempt was made to fix however it will not work. Cutting new release to remedy this.
+* BareMetal : Add support for `image_id` on update [152](https://github.com/vultr/govultr/pull/152)
+* Instances : Add support for `image_id` on update [152](https://github.com/vultr/govultr/pull/152)
 
-## [v0.1.6](https://github.com/vultr/govultr/compare/v0.1.5..v0.1.6) (2019-11-07)
+## [v2.7.0](https://github.com/vultr/govultr/compare/v2.6.0..v2.7.0) (2021-07-14)
 ### Enhancement
-*  Retry rate-limited requests with exponential backoff[#28](https://github.com/vultr/govultr/pull/28)
+* BareMetal : Add support for `image_id` [150](https://github.com/vultr/govultr/pull/150)
+* Instances : Add support for `image_id` [150](https://github.com/vultr/govultr/pull/150)
+* Applications : added support for marketplace applications [150](https://github.com/vultr/govultr/pull/150)
 
-## [v0.1.5](https://github.com/vultr/govultr/compare/v0.1.4..v0.1.5) (2019-10-16)
+## [v2.6.0](https://github.com/vultr/govultr/compare/v2.5.1..v2.6.0) (2021-07-02)
 ### Enhancement
-*  Whitelisting public endpoints that do not require the api key[#24](https://github.com/vultr/govultr/pull/24)
+* BareMetal : Add support for `persistent_pxe` [148](https://github.com/vultr/govultr/pull/148)
 
-## [v0.1.4](https://github.com/vultr/govultr/compare/v0.1.3..v0.1.4) (2019-07-14)
-### Bug Fixes
-* Fix panic on request failure [#20](https://github.com/vultr/govultr/pull/20)
+## [v2.5.1](https://github.com/vultr/govultr/compare/v2.5.0..v2.5.1) (2021-05-10)
+### Bug fix
+* Instances : BackupScheduleReq change DOW + Hour to pointers  [145](https://github.com/vultr/govultr/pull/145)
 
-## [v0.1.3](https://github.com/vultr/govultr/compare/v0.1.2..v0.1.3) (2019-06-13)
-### Features
-* added `GetVc2zList` to Plans to retrieve `high-frequency compute` plans [#13](https://github.com/vultr/govultr/pull/13)
+## [v2.5.0](https://github.com/vultr/govultr/compare/v2.4.2..v2.5.0) (2021-05-06)
+### Enhancement
+* LoadBalancers : New Features and endpoints [143](https://github.com/vultr/govultr/pull/143)
+  * Ability to attach private networks
+  * Ability to set firewalls
+  * Get Firewall Rules
+  * List Firewall Rules 
+
+## [v2.4.2](https://github.com/vultr/govultr/compare/v2.4.1..v2.4.2) (2021-05-03)
+### Bug fix
+* Instances : ListPrivateNetworks missing paging ability [140](https://github.com/vultr/govultr/pull/140)
+
+## [v2.4.1](https://github.com/vultr/govultr/compare/v2.4.0..v2.4.1) (2021-05-03)
+### Dependency updates
+* Bump github.com/hashicorp/go-retryablehttp from 0.6.8 to 0.7.0 [138](https://github.com/vultr/govultr/pull/138)
+* Bump github.com/google/go-querystring from 1.0.0 to 1.1.0 [137](https://github.com/vultr/govultr/pull/137)
+
+## [v2.4.0](https://github.com/vultr/govultr/compare/v2.3.2..v2.4.0) (2021-02-11)
+### Enhancement
+* Block Storage - add `mount_id` field to BlockStorage struct [131](https://github.com/vultr/govultr/pull/131)
+* Plans - add `disk_count` field to Plan and BareMetalPlan struct [130](https://github.com/vultr/govultr/pull/130)
 
-### Breaking Changes
-* Renamed all variables named `vpsID` to `instanceID` [#14](https://github.com/vultr/govultr/pull/14)
-* Server
-    * Renamed Server struct field `VpsID` to `InstanceID` [#14](https://github.com/vultr/govultr/pull/14)
-* Plans
-    * Renamed Plan struct field `VpsID` to `PlanID` [#14](https://github.com/vultr/govultr/pull/14)
-    * Renamed BareMetalPlan struct field `BareMetalID` to `PlanID` [#14](https://github.com/vultr/govultr/pull/14)
-    * Renamed VCPlan struct field `VpsID` to `PlanID` [#14](https://github.com/vultr/govultr/pull/14)
-    * Renamed Plan struct field `VCPUCount` to `vCPUs` [#13](https://github.com/vultr/govultr/pull/13)
-    * Renamed BareMetalPlan struct field `CPUCount` to `CPUs` [#13](https://github.com/vultr/govultr/pull/13)
-    * Renamed VCPlan struct field `VCPUCount` to `vCPUs` [#13](https://github.com/vultr/govultr/pull/13)
-    * Renamed VCPlan struct field `Cost` to `Price` [#13](https://github.com/vultr/govultr/pull/13)
-
-## [v0.1.2](https://github.com/vultr/govultr/compare/v0.1.1..v0.1.2) (2019-05-29)
-### Fixes
-* Fixed Server Option `NotifyActivate` bug that ignored a `false` value
-* Fixed Bare Metal Server Option `UserData` to be based64encoded 
-### Breaking Changes
-* Renamed all methods named `GetList` to `List`
-* Renamed all methods named `Destroy` to `Delete`
-* Server Service
-    * Renamed `GetListByLabel` to `ListByLabel`
-    * Renamed `GetListByMainIP` to `ListByMainIP`
-    * Renamed `GetListByTag` to `ListByTag`
-* Bare Metal Server Service
-    * Renamed `GetListByLabel` to `ListByLabel`
-    * Renamed `GetListByMainIP` to `ListByMainIP`
-    * Renamed `GetListByTag` to `ListByTag`
-
-## [v0.1.1](https://github.com/vultr/govultr/compare/v0.1.0..v0.1.1) (2019-05-20)
-### Features
-* add `SnapshotID` to ServerOptions as an option during server creation
-* bumped default RateLimit from `.2` to `.6` seconds
-### Breaking Changes
-* Iso
-  * Renamed all instances of `Iso` to `ISO`.  
-* BlockStorage
-  * Renamed `Cost` to `CostPerMonth`
-  * Renamed `Size` to `SizeGB` 
-* BareMetal & Server 
-  * Change `SSHKeyID` to `SSHKeyIDs` which are now `[]string` instead of `string`
-  * Renamed `OS` to `Os`    
-
-## v0.1.0 (2019-05-10)
-### Features
-* Initial release
-* Supports all available API endpoints that Vultr has to offer
+## [v2.3.2](https://github.com/vultr/govultr/compare/v2.3.1..v2.3.2) (2021-01-06)
+### Bug Fix
+* Instances - Fixed DetachPrivateNetwork which had wrong URI [122](https://github.com/vultr/govultr/pull/122)
+
+## [v2.3.1](https://github.com/vultr/govultr/compare/v2.3.0..v2.3.1) (2021-01-04)
+### Bug Fix
+* Domain Record - removed `omitempty` on `name` field in `DomainRecordReq` to allow creation of nameless records. [120](https://github.com/vultr/govultr/pull/120)
+
+## [v2.3.0](https://github.com/vultr/govultr/compare/v2.2.0..v2.3.0) (2020-12-17)
+### Enhancement
+* Bare Metal - Start call added [118](https://github.com/vultr/govultr/pull/118)
+
+## [v2.2.0](https://github.com/vultr/govultr/compare/v2.1.0..v2.2.0) (2020-12-07)
+### Breaking Change
+* All bools have been updated to pointers to avoid issues where false values not being sent in request. Thanks @Static-Flow [115](https://github.com/vultr/govultr/pull/115)
+
+## [v2.1.0](https://github.com/vultr/govultr/compare/v2.0.0..v2.1.0) (2020-11-30)
+### Bug fixes
+* ReservedIP - Attach call creates proper json. [112](https://github.com/vultr/govultr/pull/112)
+* User - APIEnabled takes pointer of bool [112](https://github.com/vultr/govultr/pull/112)
+
+## v2.0.0 (2020-11-20)
+### Initial Release
+* GoVultr v2.0.0 Release - Uses Vultr API v2.
+* GoVultr v1.0.0 is now on [branch v1](https://github.com/vultr/govultr/tree/v1)
diff --git a/README.md b/README.md
index b777b9b..d73fdcf 100644
--- a/README.md
+++ b/README.md
@@ -1,36 +1,31 @@
 # GoVultr
 
-[![Build Status](https://travis-ci.org/vultr/govultr.svg?branch=master)](https://travis-ci.org/vultr/govultr)
-[![GoDoc](https://godoc.org/github.com/vultr/govultr?status.svg)](https://godoc.org/github.com/vultr/govultr)
-[![codecov](https://codecov.io/gh/vultr/govultr/branch/master/graph/badge.svg?token=PDJXBc7Rci)](https://codecov.io/gh/vultr/govultr)
+[![Automatic Releaser](https://github.com/vultr/govultr/actions/workflows/releaser.yml/badge.svg)](https://github.com/vultr/govultr/actions/workflows/releaser.yml)
+[![PkgGoDev](https://pkg.go.dev/badge/github.com/vultr/govultr/v2)](https://pkg.go.dev/github.com/vultr/govultr/v2)
+[![Unit/Coverage Tests](https://github.com/vultr/govultr/actions/workflows/coverage.yml/badge.svg)](https://github.com/vultr/govultr/actions/workflows/coverage.yml)
 [![Go Report Card](https://goreportcard.com/badge/github.com/vultr/govultr)](https://goreportcard.com/report/github.com/vultr/govultr)
 
-The official Vultr Go client - GoVultr allows you to interact with the Vultr V1 API.
+The official Vultr Go client - GoVultr allows you to interact with the Vultr V2 API.
+
+GoVultr V1 that interacts with Vultr V1 API is now on the [v1 branch](https://github.com/vultr/govultr/tree/v1)
 
 ## Installation
 
 ```sh
-go get -u github.com/vultr/govultr
+go get -u github.com/vultr/govultr/v2
 ```
 
 ## Usage
 
-Vultr uses a PAT (Personal Access token) to interact/authenticate with the APIs. An API Key can be generated and acquired from the API menu in [settings](https://my.vultr.com/settings/#settingsapi).
-
-To instantiate a govultr client you invoke `NewClient()`.
-
-This takes in two parameters:
+Vultr uses a PAT (Personal Access token) to interact/authenticate with the APIs. Generate an API Key from the [API menu](https://my.vultr.com/settings/#settingsapi) in the Vultr Customer Portal.
 
-- \*http.Client
-- API Key
+To instantiate a GoVultr client, invoke `NewClient()`. You must pass your `PAT` to an `oauth2` library to create the `*http.Client`, which configures the `Authorization` header with your PAT as the `bearer api-key`.
 
-You can define your own `http.Client` however if you pass in `nil` then you will be defaulted to use `http.DefaultClient`. For the API key, we recommend you store this as a environment variable and not hard code it.
+The client has three optional parameters:
 
-There are also three optional parameters you may change regarding the client:
-
-- BaseUrl: allows you to override the base URL that Vultr defaults to
-- UserAgent: allows you to override the UserAgent that Vultr defaults to
-- RateLimit: Vultr currently rate limits how fast you can make calls back to back. This lets you configure if you want a delay in between calls
+- BaseUrl: Change the Vultr default base URL
+- UserAgent: Change the Vultr default UserAgent
+- RateLimit: Set a delay between calls. Vultr limits the rate of back-to-back calls. Use this parameter to avoid rate-limit errors.
 
 ### Example Client Setup
 
@@ -38,19 +33,25 @@ There are also three optional parameters you may change regarding the client:
 package main
 
 import (
-	"github.com/vultr/govultr"
-	"os"
+  "context"
+  "os"
+
+  "github.com/vultr/govultr/v2"
+  "golang.org/x/oauth2"
 )
 
 func main() {
-	apiKey := os.Getenv("VultrAPIKey")
+  apiKey := os.Getenv("VultrAPIKey")
 
-	vultrClient := govultr.NewClient(nil, apiKey)
+  config := &oauth2.Config{}
+  ctx := context.Background()
+  ts := config.TokenSource(ctx, &oauth2.Token{AccessToken: apiKey})
+  vultrClient := govultr.NewClient(oauth2.NewClient(ctx, ts))
 
-	// Optional changes
-	_ = vultrClient.SetBaseURL("https://api.vultr.com")
-	vultrClient.SetUserAgent("mycool-app")
-	vultrClient.SetRateLimit(500)
+  // Optional changes
+  _ = vultrClient.SetBaseURL("https://api.vultr.com")
+  vultrClient.SetUserAgent("mycool-app")
+  vultrClient.SetRateLimit(500)
 }
 ```
 
@@ -59,31 +60,73 @@ func main() {
 Create a VPS
 
 ```go
-vpsOptions := &govultr.ServerOptions{
-	Label:                "awesome-go-app",
-	Hostname:             "awesome-go.com",
-	EnablePrivateNetwork: true,
-	AutoBackups:          true,
-	EnableIPV6:           true,
+instanceOptions := &govultr.InstanceCreateReq{
+  Label:                "awesome-go-app",
+  Hostname:             "awesome-go.com",
+  Backups:              "enabled",
+  EnableIPv6:           BoolToBoolPtr(false),
+  OsID:                 362,
+  Plan:                 "vc2-1c-2gb",   
+  Region:               "ewr",
 }
 
-// RegionId, VpsPlanID, OsID can be grabbed from their respective API calls
-res, err := vultrClient.Server.Create(context.Background(), 1, 201, 1, vpsOptions)
+res, err := vultrClient.Instance.Create(context.Background(), instanceOptions)
 
 if err != nil {
-	fmt.Println(err)
+  fmt.Println(err)
 }
 ```
 
+## Pagination
+
+GoVultr v2 introduces pagination for all list calls. Each list call returns a `meta` struct containing the total amount of items in the list and next/previous links to navigate the paging.
+
+```go
+// Meta represents the available pagination information
+type Meta struct {
+  Total int `json:"total"`
+  Links *Links
+}
+
+// Links represent the next/previous cursor in your pagination calls
+type Links struct {
+  Next string `json:"next"`
+  Prev string `json:"prev"`
+}
+
+```
+Pass a `per_page` value to the `list_options` struct to adjust the number of items returned per call. The default is 100 items per page and max is 500 items per page. 
+
+This example demonstrates how to retrieve all of your instances, with one instance per page.
+
+```go
+listOptions := &govultr.ListOptions{PerPage: 1}
+for {
+    i, meta, err := client.Instance.List(ctx, listOptions)
+    if err != nil {
+        return nil, err
+    }
+    for _, v := range i {
+        fmt.Println(v)
+    }
+
+    if meta.Links.Next == "" {
+        break
+    } else {
+        listOptions.Cursor = meta.Links.Next
+        continue
+    }
+}    
+```
 ## Versioning
 
 This project follows [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/vultr/govultr/tags).
 
 ## Documentation
 
-For detailed information about our V1 API head over to our [API documentation](https://www.vultr.com/api/).
+See our documentation for [detailed information about API v2](https://www.vultr.com/api/).
 
-If you want more details about this client's functionality then check out our [GoDoc](https://godoc.org/github.com/vultr/govultr) documentation.
+See our [GoDoc](https://pkg.go.dev/github.com/vultr/govultr/v2) documentation for more details about this client's functionality.
 
 ## Contributing
 
diff --git a/account.go b/account.go
index 33a16df..ef3e622 100644
--- a/account.go
+++ b/account.go
@@ -6,9 +6,9 @@ import (
 )
 
 // AccountService is the interface to interact with Accounts endpoint on the Vultr API
-// Link: https://www.vultr.com/api/#account
+// Link : https://www.vultr.com/api/#tag/account
 type AccountService interface {
-	GetInfo(ctx context.Context) (*Account, error)
+	Get(ctx context.Context) (*Account, error)
 }
 
 // AccountServiceHandler handles interaction with the account methods for the Vultr API
@@ -16,30 +16,33 @@ type AccountServiceHandler struct {
 	client *Client
 }
 
+type accountBase struct {
+	Account *Account `json:"account"`
+}
+
 // Account represents a Vultr account
 type Account struct {
-	Balance           string `json:"balance"`
-	PendingCharges    string `json:"pending_charges"`
-	LastPaymentDate   string `json:"last_payment_date"`
-	LastPaymentAmount string `json:"last_payment_amount"`
+	Balance           float32  `json:"balance"`
+	PendingCharges    float32  `json:"pending_charges"`
+	LastPaymentDate   string   `json:"last_payment_date"`
+	LastPaymentAmount float32  `json:"last_payment_amount"`
+	Name              string   `json:"name"`
+	Email             string   `json:"email"`
+	ACL               []string `json:"acls"`
 }
 
-// GetInfo Vultr account info
-func (a *AccountServiceHandler) GetInfo(ctx context.Context) (*Account, error) {
-
-	uri := "/v1/account/info"
+// Get Vultr account info
+func (a *AccountServiceHandler) Get(ctx context.Context) (*Account, error) {
+	uri := "/v2/account"
 	req, err := a.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
 	if err != nil {
 		return nil, err
 	}
 
-	account := new(Account)
-	err = a.client.DoWithContext(ctx, req, account)
-
-	if err != nil {
+	account := new(accountBase)
+	if err = a.client.DoWithContext(ctx, req, account); err != nil {
 		return nil, err
 	}
 
-	return account, nil
+	return account.Account, nil
 }
diff --git a/account_test.go b/account_test.go
index 7f5e83c..ef2c973 100644
--- a/account_test.go
+++ b/account_test.go
@@ -7,55 +7,42 @@ import (
 	"testing"
 )
 
-func TestAccountServiceHandler_GetInfo(t *testing.T) {
+func TestAccountServiceHandler_Get(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/account/info", func(w http.ResponseWriter, r *http.Request) {
+	mux.HandleFunc("/v2/account", func(w http.ResponseWriter, r *http.Request) {
 
 		response := `
-		{
-		"balance": "-5519.11",
-		"pending_charges": "57.03",
-		"last_payment_date": "2014-07-18 15:31:01",
-		"last_payment_amount": "-1.00"
+		{		
+		"account" : {
+			"balance": -5519.11,
+			"pending_charges": 57.03,
+			"last_payment_date": "2014-07-18 15:31:01",
+			"last_payment_amount": -1.00,
+			"name": "Test Tester",
+			"email" : "example@vultr.com",
+			"acls": [
+				"subscriptions",
+				"billing",
+				"support",
+				"provisioning"
+			]
+		}
 		}
 		`
 
 		fmt.Fprint(w, response)
 	})
 
-	account, err := client.Account.GetInfo(ctx)
-	if err != nil {
-		t.Errorf("Account.GetInfo returned error: %v", err)
-	}
-
-	expected := &Account{Balance: "-5519.11", PendingCharges: "57.03", LastPaymentDate: "2014-07-18 15:31:01", LastPaymentAmount: "-1.00"}
-
-	if !reflect.DeepEqual(account, expected) {
-		t.Errorf("Account.GetInfo returned %+v, expected %+v", account, expected)
-	}
-}
-
-func TestAccountServiceHandler_GetInfoEmpty(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/account/info", func(w http.ResponseWriter, r *http.Request) {
-
-		response := `[]`
-
-		fmt.Fprint(w, response)
-	})
-
-	account, err := client.Account.GetInfo(ctx)
+	account, err := client.Account.Get(ctx)
 	if err != nil {
-		t.Errorf("Account.GetInfo returned error: %v", err)
+		t.Errorf("Account.Get returned error: %v", err)
 	}
 
-	expected := &Account{}
+	expected := &Account{Balance: -5519.11, PendingCharges: 57.03, LastPaymentDate: "2014-07-18 15:31:01", LastPaymentAmount: -1.00, Name: "Test Tester", Email: "example@vultr.com", ACL: []string{"subscriptions", "billing", "support", "provisioning"}}
 
 	if !reflect.DeepEqual(account, expected) {
-		t.Errorf("Account.GetInfo returned %+v, expected %+v", account, expected)
+		t.Errorf("Account.Get returned %+v, expected %+v", account, expected)
 	}
 }
diff --git a/api.go b/api.go
deleted file mode 100644
index 2ebfb99..0000000
--- a/api.go
+++ /dev/null
@@ -1,44 +0,0 @@
-package govultr
-
-import (
-	"context"
-	"net/http"
-)
-
-// APIService is the interface to interact with the API endpoint on the Vultr API
-// Link: https://www.vultr.com/api/#auth
-type APIService interface {
-	GetInfo(ctx context.Context) (*API, error)
-}
-
-// APIServiceHandler handles interaction with the API methods for the Vultr API
-type APIServiceHandler struct {
-	client *Client
-}
-
-// API represents Vultr API information
-type API struct {
-	ACL   []string `json:"acls"`
-	Email string   `json:"email"`
-	Name  string   `json:"name"`
-}
-
-// GetInfo Vultr API auth information
-func (a *APIServiceHandler) GetInfo(ctx context.Context) (*API, error) {
-	uri := "/v1/auth/info"
-
-	req, err := a.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
-	if err != nil {
-		return nil, err
-	}
-
-	api := new(API)
-	err = a.client.DoWithContext(ctx, req, api)
-
-	if err != nil {
-		return nil, err
-	}
-
-	return api, nil
-}
diff --git a/api_test.go b/api_test.go
deleted file mode 100644
index c2e55af..0000000
--- a/api_test.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package govultr
-
-import (
-	"fmt"
-	"net/http"
-	"reflect"
-	"testing"
-)
-
-func TestAPIServiceHandler_GetInfo(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/auth/info", func(writer http.ResponseWriter, request *http.Request) {
-		response := `
-		{
-    	"acls": [
-        	"subscriptions",
-        	"billing",
-        	"support",
-        	"provisioning"
-    	],
-    	"email": "example@vultr.com",
-    	"name": "Example Account"
-		}`
-		fmt.Fprint(writer, response)
-	})
-
-	apiAuth, err := client.API.GetInfo(ctx)
-
-	if err != nil {
-		t.Errorf("Account.GetInfo returned error: %v", err)
-	}
-
-	expected := &API{ACL: []string{"subscriptions", "billing", "support", "provisioning"}, Email: "example@vultr.com", Name: "Example Account"}
-	if !reflect.DeepEqual(apiAuth, expected) {
-		t.Errorf("API.GetInfo returned %+v, expected %+v", apiAuth, expected)
-	}
-}
diff --git a/application.go b/application.go
index 9199bd9..817220e 100644
--- a/application.go
+++ b/application.go
@@ -3,49 +3,58 @@ package govultr
 import (
 	"context"
 	"net/http"
+
+	"github.com/google/go-querystring/query"
 )
 
-// ApplicationService is the interface to interact with the Application endpoint on the Vultr API
-// Link: https://www.vultr.com/api/#app
+// ApplicationService is the interface to interact with the Application endpoint on the Vultr API.
+// Link : https://www.vultr.com/api/#tag/application
 type ApplicationService interface {
-	List(ctx context.Context) ([]Application, error)
+	List(ctx context.Context, options *ListOptions) ([]Application, *Meta, error)
 }
 
-// ApplicationServiceHandler handles interaction with the application methods for the Vultr API
+// ApplicationServiceHandler handles interaction with the application methods for the Vultr API.
 type ApplicationServiceHandler struct {
 	client *Client
 }
 
-// Application represents a Vultr application
+// Application represents all available apps that can be used to deployed with vultr Instances.
 type Application struct {
-	AppID      string  `json:"APPID"`
-	Name       string  `json:"name"`
-	ShortName  string  `json:"short_name"`
-	DeployName string  `json:"deploy_name"`
-	Surcharge  float64 `json:"surcharge"`
+	ID         int    `json:"id"`
+	Name       string `json:"name"`
+	ShortName  string `json:"short_name"`
+	DeployName string `json:"deploy_name"`
+	Type       string `json:"type"`
+	Vendor     string `json:"vendor"`
+	ImageID    string `json:"image_id"`
+}
+
+type applicationBase struct {
+	Applications []Application `json:"applications"`
+	Meta         *Meta         `json:"meta"`
 }
 
-// List retrieves a list of available applications that can be launched when creating a Vultr VPS
-func (a *ApplicationServiceHandler) List(ctx context.Context) ([]Application, error) {
+// List retrieves a list of available applications that can be launched when creating a Vultr instance
+func (a *ApplicationServiceHandler) List(ctx context.Context, options *ListOptions) ([]Application, *Meta, error) {
+	uri := "/v2/applications"
 
-	uri := "/v1/app/list"
 	req, err := a.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	appsMap := make(map[string]Application)
-
-	err = a.client.DoWithContext(ctx, req, &appsMap)
+	newValues, err := query.Values(options)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	var apps []Application
-	for _, app := range appsMap {
-		apps = append(apps, app)
+	req.URL.RawQuery = newValues.Encode()
+	apps := new(applicationBase)
+
+	err = a.client.DoWithContext(ctx, req, apps)
+	if err != nil {
+		return nil, nil, err
 	}
 
-	return apps, nil
+	return apps.Applications, apps.Meta, nil
 }
diff --git a/application_test.go b/application_test.go
index 025d71e..2bd9a6f 100644
--- a/application_test.go
+++ b/application_test.go
@@ -11,62 +11,68 @@ func TestApplicationServiceHandler_List(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/app/list", func(w http.ResponseWriter, r *http.Request) {
+	mux.HandleFunc("/v2/applications", func(w http.ResponseWriter, r *http.Request) {
 
 		response := `
 		{
-			"1": {
-				"APPID": "1",
-				"name": "LEMP",
-				"short_name": "lemp",
-				"deploy_name": "LEMP on CentOS 6 x64",
-				"surcharge": 0
-			}
+		"applications": [
+			{
+            	"id": 1,
+            	"name": "LEMP",
+            	"short_name": "lemp",
+            	"deploy_name": "LEMP on CentOS 6 x64",
+				"type": "one-click",
+				"vendor": "",
+				"image_id": ""
+        	}
+    	],
+    	"meta": {
+        	"total": 29,
+        	"links": {
+            	"next": "bmV4dF9fNDM=",
+            	"prev": ""
+        		}
+    		}
 		}
 		`
 
 		fmt.Fprint(w, response)
 	})
 
-	apps, err := client.Application.List(ctx)
+	options := &ListOptions{
+		PerPage: 1,
+		Cursor:  "",
+	}
+	apps, meta, err := client.Application.List(ctx, options)
 	if err != nil {
 		t.Errorf("Application.List returned error: %v", err)
 	}
 
 	expected := []Application{
 		{
-			AppID:      "1",
+			ID:         1,
 			Name:       "LEMP",
 			ShortName:  "lemp",
 			DeployName: "LEMP on CentOS 6 x64",
-			Surcharge:  0,
+			Vendor:     "",
+			Type:       "one-click",
+			ImageID:    "",
 		},
 	}
 
 	if !reflect.DeepEqual(apps, expected) {
-		t.Errorf("Application.List returned %+v, expected %+v", apps, expected)
+		t.Errorf("Application.List apps returned %+v, expected %+v", apps, expected)
 	}
-}
-
-func TestApplicationServiceHandler_ListEmpty(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/app/list", func(w http.ResponseWriter, r *http.Request) {
 
-		response := `[]`
-
-		fmt.Fprint(w, response)
-	})
-
-	apps, err := client.Application.List(ctx)
-	if err != nil {
-		t.Errorf("Application.List returned error: %v", err)
+	expectedMeta := &Meta{
+		Total: 29,
+		Links: &Links{
+			Next: "bmV4dF9fNDM=",
+			Prev: "",
+		},
 	}
 
-	var expected []Application
-
-	if !reflect.DeepEqual(apps, expected) {
-		t.Errorf("Application.List returned %+v, expected %+v", apps, expected)
+	if !reflect.DeepEqual(meta, expectedMeta) {
+		t.Errorf("Application.List meta returned %+v, expected %+v", meta, expectedMeta)
 	}
 }
diff --git a/backup.go b/backup.go
index 0a87c64..2b2f1e2 100644
--- a/backup.go
+++ b/backup.go
@@ -2,15 +2,17 @@ package govultr
 
 import (
 	"context"
+	"fmt"
 	"net/http"
+
+	"github.com/google/go-querystring/query"
 )
 
 // BackupService is the interface to interact with the backup endpoint on the Vultr API
-// Link: https://www.vultr.com/api/#backup
+// Link : https://www.vultr.com/api/#tag/backup
 type BackupService interface {
-	List(ctx context.Context) ([]Backup, error)
 	Get(ctx context.Context, backupID string) (*Backup, error)
-	ListBySub(ctx context.Context, subID string) ([]Backup, error)
+	List(ctx context.Context, options *ListOptions) ([]Backup, *Meta, error)
 }
 
 // BackupServiceHandler handles interaction with the backup methods for the Vultr API
@@ -20,86 +22,59 @@ type BackupServiceHandler struct {
 
 // Backup represents a Vultr backup
 type Backup struct {
-	BackupID    string `json:"BACKUPID"`
+	ID          string `json:"id"`
 	DateCreated string `json:"date_created"`
 	Description string `json:"description"`
-	Size        string `json:"size"`
+	Size        int    `json:"size"`
 	Status      string `json:"status"`
 }
 
-// List retrieves a list of all backups on the current account
-func (b *BackupServiceHandler) List(ctx context.Context) ([]Backup, error) {
-	uri := "/v1/backup/list"
-	req, err := b.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
-	if err != nil {
-		return nil, err
-	}
-
-	backupsMap := make(map[string]Backup)
-	err = b.client.DoWithContext(ctx, req, &backupsMap)
-	if err != nil {
-		return nil, err
-	}
-
-	var backups []Backup
-	for _, backup := range backupsMap {
-		backups = append(backups, backup)
-	}
+type backupsBase struct {
+	Backups []Backup `json:"backups"`
+	Meta    *Meta    `json:"meta"`
+}
 
-	return backups, nil
+type backupBase struct {
+	Backup *Backup `json:"backup"`
 }
 
 // Get retrieves a backup that matches the given backupID
 func (b *BackupServiceHandler) Get(ctx context.Context, backupID string) (*Backup, error) {
-	uri := "/v1/backup/list"
+	uri := fmt.Sprintf("/v2/backups/%s", backupID)
 	req, err := b.client.NewRequest(ctx, http.MethodGet, uri, nil)
 
 	if err != nil {
 		return nil, err
 	}
 
-	q := req.URL.Query()
-	q.Add("BACKUPID", backupID)
-	req.URL.RawQuery = q.Encode()
-
-	backupsMap := make(map[string]Backup)
-	err = b.client.DoWithContext(ctx, req, &backupsMap)
-	if err != nil {
+	backup := new(backupBase)
+	if err := b.client.DoWithContext(ctx, req, backup); err != nil {
 		return nil, err
 	}
 
-	backup := new(Backup)
-	for _, bk := range backupsMap {
-		backup = &bk
-	}
-
-	return backup, nil
+	return backup.Backup, nil
 }
 
-// ListBySub retrieves a list of all backups on the current account that match the given subID
-func (b *BackupServiceHandler) ListBySub(ctx context.Context, subID string) ([]Backup, error) {
-	uri := "/v1/backup/list"
+// List retrieves a list of all backups on the current account
+func (b *BackupServiceHandler) List(ctx context.Context, options *ListOptions) ([]Backup, *Meta, error) {
+	uri := "/v2/backups"
 	req, err := b.client.NewRequest(ctx, http.MethodGet, uri, nil)
 
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	q := req.URL.Query()
-	q.Add("SUBID", subID)
-	req.URL.RawQuery = q.Encode()
-
-	backupsMap := make(map[string]Backup)
-	err = b.client.DoWithContext(ctx, req, &backupsMap)
+	newValues, err := query.Values(options)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	var backups []Backup
-	for _, backup := range backupsMap {
-		backups = append(backups, backup)
+	req.URL.RawQuery = newValues.Encode()
+
+	backups := new(backupsBase)
+	if err = b.client.DoWithContext(ctx, req, backups); err != nil {
+		return nil, nil, err
 	}
 
-	return backups, nil
+	return backups.Backups, backups.Meta, nil
 }
diff --git a/backup_test.go b/backup_test.go
index 9851644..45dfee1 100644
--- a/backup_test.go
+++ b/backup_test.go
@@ -11,16 +11,25 @@ func TestBackupServiceHandler_List(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/backup/list", func(w http.ResponseWriter, r *http.Request) {
+	mux.HandleFunc("/v2/backups", func(w http.ResponseWriter, r *http.Request) {
 
 		response := `
 		{
-			"543d34149403a": {
-				"BACKUPID": "543d34149403a",
+			"backups": [
+				{
+				"id": "543d34149403a",
 				"date_created": "2014-10-14 12:40:40",
 				"description": "Automatic server backup",
-				"size": "42949672960",
+				"size": 42949672960,
 				"status": "complete"
+				}
+			],
+			"meta": {
+				"total":8,
+				"links": {
+					"next":"",
+					"prev":""
+				}
 			}
 		}
 		`
@@ -28,63 +37,50 @@ func TestBackupServiceHandler_List(t *testing.T) {
 		fmt.Fprint(w, response)
 	})
 
-	backups, err := client.Backup.List(ctx)
+	backups, meta, err := client.Backup.List(ctx, nil)
 	if err != nil {
 		t.Errorf("Backup.List returned error: %v", err)
 	}
 
 	expected := []Backup{
 		{
-			BackupID:    "543d34149403a",
+			ID:          "543d34149403a",
 			DateCreated: "2014-10-14 12:40:40",
 			Description: "Automatic server backup",
-			Size:        "42949672960",
+			Size:        42949672960,
 			Status:      "complete",
 		},
 	}
 
-	if !reflect.DeepEqual(backups, expected) {
-		t.Errorf("Backup.List returned %+v, expected %+v", backups, expected)
+	expectedMeta := &Meta{
+		Total: 8,
+		Links: &Links{},
 	}
-}
-
-func TestBackupServiceHandler_ListEmpty(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/backup/list", func(w http.ResponseWriter, r *http.Request) {
-
-		response := `[]`
-
-		fmt.Fprint(w, response)
-	})
-
-	backups, err := client.Backup.List(ctx)
-	if err != nil {
-		t.Errorf("Backup.List returned error: %v", err)
-	}
-
-	var expected []Backup
 
 	if !reflect.DeepEqual(backups, expected) {
 		t.Errorf("Backup.List returned %+v, expected %+v", backups, expected)
 	}
+
+	if !reflect.DeepEqual(meta, expectedMeta) {
+		t.Errorf("Backup.List returned %+v, expected %+v", meta, expectedMeta)
+	}
 }
 
-func TestBackupServiceHandler_ListBySub(t *testing.T) {
+func TestBackupServiceHandler_ListEmpty(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/backup/list", func(w http.ResponseWriter, r *http.Request) {
+	mux.HandleFunc("/v2/backups", func(w http.ResponseWriter, r *http.Request) {
 
 		response := `
 		{
-			"543d34149403a": {
-				"BACKUPID": "543d34149403a",
-				"date_created": "2014-10-14 12:40:40",
-				"description": "Automatic server backup",
-				"size": "42949672960",
-				"status": "complete"
+			"backups": [],
+			"meta": {
+				"total":0,
+				"links": {
+					"next":"",
+					"prev":""
+				}
 			}
 		}
 		`
@@ -92,46 +88,27 @@ func TestBackupServiceHandler_ListBySub(t *testing.T) {
 		fmt.Fprint(w, response)
 	})
 
-	backups, err := client.Backup.ListBySub(ctx, "test-backupID")
+	backups, meta, err := client.Backup.List(ctx, nil)
 	if err != nil {
-		t.Errorf("Backup.ListBySub returned error: %v", err)
+		t.Errorf("Backup.List returned error: %v", err)
 	}
 
-	expected := []Backup{
-		{
-			BackupID:    "543d34149403a",
-			DateCreated: "2014-10-14 12:40:40",
-			Description: "Automatic server backup",
-			Size:        "42949672960",
-			Status:      "complete",
-		},
-	}
+	expected := []Backup{}
 
 	if !reflect.DeepEqual(backups, expected) {
-		t.Errorf("Backup.ListBySub returned %+v, expected %+v", backups, expected)
+		t.Errorf("Backup.List returned %+v, expected %+v", backups, expected)
 	}
-}
-
-func TestBackupServiceHandler_ListBySubEmpty(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/backup/list", func(w http.ResponseWriter, r *http.Request) {
 
-		response := `[]`
-
-		fmt.Fprint(w, response)
-	})
-
-	backups, err := client.Backup.ListBySub(ctx, "test-backupID")
-	if err != nil {
-		t.Errorf("Backup.ListBySub returned error: %v", err)
+	expectedMeta := &Meta{
+		Total: 0,
+		Links: &Links{
+			Next: "",
+			Prev: "",
+		},
 	}
 
-	var expected []Backup
-
-	if !reflect.DeepEqual(backups, expected) {
-		t.Errorf("Backup.ListBySub returned %+v, expected %+v", backups, expected)
+	if !reflect.DeepEqual(meta, expectedMeta) {
+		t.Errorf("Backup.List meta returned %+v, expected %+v", meta, expectedMeta)
 	}
 }
 
@@ -139,15 +116,15 @@ func TestBackupServiceHandler_Get(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/backup/list", func(w http.ResponseWriter, r *http.Request) {
+	mux.HandleFunc("/v2/backups/543d34149403a", func(w http.ResponseWriter, r *http.Request) {
 
 		response := `
 		{
-			"543d34149403a": {
-				"BACKUPID": "543d34149403a",
+			"backup": {
+				"id": "543d34149403a",
 				"date_created": "2014-10-14 12:40:40",
 				"description": "Automatic server backup",
-				"size": "42949672960",
+				"size": 42949672960,
 				"status": "complete"
 			}
 		}
@@ -162,10 +139,10 @@ func TestBackupServiceHandler_Get(t *testing.T) {
 	}
 
 	expected := &Backup{
-		BackupID:    "543d34149403a",
+		ID:          "543d34149403a",
 		DateCreated: "2014-10-14 12:40:40",
 		Description: "Automatic server backup",
-		Size:        "42949672960",
+		Size:        42949672960,
 		Status:      "complete",
 	}
 
@@ -178,14 +155,17 @@ func TestBackupServiceHandler_GetEmpty(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/backup/list", func(w http.ResponseWriter, r *http.Request) {
-
-		response := `[]`
+	mux.HandleFunc("/v2/backups/543d34149403a", func(w http.ResponseWriter, r *http.Request) {
+		response := `			
+			{
+				"backup": {}
+			}
+		`
 
 		fmt.Fprint(w, response)
 	})
 
-	backup, err := client.Backup.Get(ctx, "test-backupID")
+	backup, err := client.Backup.Get(ctx, "543d34149403a")
 	if err != nil {
 		t.Errorf("Backup.Get returned error: %v", err)
 	}
diff --git a/bare_metal_server.go b/bare_metal_server.go
index 22ce436..5de564e 100644
--- a/bare_metal_server.go
+++ b/bare_metal_server.go
@@ -2,789 +2,415 @@ package govultr
 
 import (
 	"context"
-	"encoding/base64"
-	"encoding/json"
 	"fmt"
 	"net/http"
-	"net/url"
-	"strconv"
-	"strings"
+
+	"github.com/google/go-querystring/query"
 )
 
-// BareMetalServerService is the interface to interact with the bare metal endpoints on the Vultr API
-// Link: https://www.vultr.com/api/#baremetal
+const bmPath = "/v2/bare-metals"
+
+// BareMetalServerService is the interface to interact with the Bare Metal endpoints on the Vultr API
+// Link : https://www.vultr.com/api/#tag/baremetal
 type BareMetalServerService interface {
-	AppInfo(ctx context.Context, serverID string) (*AppInfo, error)
-	Bandwidth(ctx context.Context, serverID string) ([]map[string]string, error)
-	ChangeApp(ctx context.Context, serverID, appID string) error
-	ChangeOS(ctx context.Context, serverID, osID string) error
-	Create(ctx context.Context, regionID, planID, osID string, options *BareMetalServerOptions) (*BareMetalServer, error)
+	Create(ctx context.Context, bmCreate *BareMetalCreate) (*BareMetalServer, error)
+	Get(ctx context.Context, serverID string) (*BareMetalServer, error)
+	Update(ctx context.Context, serverID string, bmReq *BareMetalUpdate) (*BareMetalServer, error)
 	Delete(ctx context.Context, serverID string) error
-	EnableIPV6(ctx context.Context, serverID string) error
-	List(ctx context.Context) ([]BareMetalServer, error)
-	ListByLabel(ctx context.Context, label string) ([]BareMetalServer, error)
-	ListByMainIP(ctx context.Context, mainIP string) ([]BareMetalServer, error)
-	ListByTag(ctx context.Context, tag string) ([]BareMetalServer, error)
-	GetServer(ctx context.Context, serverID string) (*BareMetalServer, error)
+	List(ctx context.Context, options *ListOptions) ([]BareMetalServer, *Meta, error)
+
+	GetBandwidth(ctx context.Context, serverID string) (*Bandwidth, error)
 	GetUserData(ctx context.Context, serverID string) (*UserData, error)
+	GetVNCUrl(ctx context.Context, serverID string) (*VNCUrl, error)
+
+	ListIPv4s(ctx context.Context, serverID string, options *ListOptions) ([]IPv4, *Meta, error)
+	ListIPv6s(ctx context.Context, serverID string, options *ListOptions) ([]IPv6, *Meta, error)
+
 	Halt(ctx context.Context, serverID string) error
-	IPV4Info(ctx context.Context, serverID string) ([]BareMetalServerIPV4, error)
-	IPV6Info(ctx context.Context, serverID string) ([]BareMetalServerIPV6, error)
-	ListApps(ctx context.Context, serverID string) ([]Application, error)
-	ListOS(ctx context.Context, serverID string) ([]OS, error)
 	Reboot(ctx context.Context, serverID string) error
-	Reinstall(ctx context.Context, serverID string) error
-	SetLabel(ctx context.Context, serverID, label string) error
-	SetTag(ctx context.Context, serverID, tag string) error
-	SetUserData(ctx context.Context, serverID, userData string) error
+	Start(ctx context.Context, serverID string) error
+	Reinstall(ctx context.Context, serverID string) (*BareMetalServer, error)
+
+	MassStart(ctx context.Context, serverList []string) error
+	MassHalt(ctx context.Context, serverList []string) error
+	MassReboot(ctx context.Context, serverList []string) error
+
+	GetUpgrades(ctx context.Context, serverID string) (*Upgrades, error)
 }
 
-// BareMetalServerServiceHandler handles interaction with the bare metal methods for the Vultr API
+// BareMetalServerServiceHandler handles interaction with the Bare Metal methods for the Vultr API
 type BareMetalServerServiceHandler struct {
 	client *Client
 }
 
-// BareMetalServer represents a bare metal server on Vultr
+// BareMetalServer represents a Bare Metal server on Vultr
 type BareMetalServer struct {
-	BareMetalServerID string      `json:"SUBID"`
-	Os                string      `json:"os"`
-	RAM               string      `json:"ram"`
-	Disk              string      `json:"disk"`
-	MainIP            string      `json:"main_ip"`
-	CPUs              int         `json:"cpu_count"`
-	Location          string      `json:"location"`
-	RegionID          int         `json:"DCID"`
-	DefaultPassword   string      `json:"default_password"`
-	DateCreated       string      `json:"date_created"`
-	Status            string      `json:"status"`
-	NetmaskV4         string      `json:"netmask_v4"`
-	GatewayV4         string      `json:"gateway_v4"`
-	BareMetalPlanID   int         `json:"METALPLANID"`
-	V6Networks        []V6Network `json:"v6_networks"`
-	Label             string      `json:"label"`
-	Tag               string      `json:"tag"`
-	OsID              string      `json:"OSID"`
-	AppID             string      `json:"APPID"`
-}
-
-// BareMetalServerOptions represents the optional parameters that can be set when creating a bare metal server
-type BareMetalServerOptions struct {
-	StartupScriptID string
-	SnapshotID      string
-	EnableIPV6      string
-	Label           string
-	SSHKeyIDs       []string
-	AppID           string
-	UserData        string
-	NotifyActivate  string
-	Hostname        string
-	Tag             string
-	ReservedIPV4    string
-}
-
-// BareMetalServerIPV4 represents IPV4 information for a bare metal server
-type BareMetalServerIPV4 struct {
-	IP      string `json:"ip"`
-	Netmask string `json:"netmask"`
-	Gateway string `json:"gateway"`
-	Type    string `json:"type"`
-}
-
-// BareMetalServerIPV6 represents IPV6 information for a bare metal server
-type BareMetalServerIPV6 struct {
-	IP          string `json:"ip"`
-	Network     string `json:"network"`
-	NetworkSize int    `json:"network_size"`
-	Type        string `json:"type"`
-}
-
-// UnmarshalJSON implements a custom unmarshaler on BareMetalServer
-// This is done to help reduce data inconsistency with V1 of the Vultr API
-func (b *BareMetalServer) UnmarshalJSON(data []byte) error {
-	if b == nil {
-		*b = BareMetalServer{}
-	}
-
-	var v map[string]interface{}
-	if err := json.Unmarshal(data, &v); err != nil {
-		return err
-	}
-
-	cpu, err := b.unmarshalInt(fmt.Sprintf("%v", v["cpu_count"]))
-	if err != nil {
-		return err
-	}
-	b.CPUs = cpu
-
-	region, err := b.unmarshalInt(fmt.Sprintf("%v", v["DCID"]))
-	if err != nil {
-		return err
-	}
-	b.RegionID = region
-
-	plan, err := b.unmarshalInt(fmt.Sprintf("%v", v["METALPLANID"]))
-	if err != nil {
-		return err
-	}
-	b.BareMetalPlanID = plan
-
-	b.BareMetalServerID = b.unmarshalStr(fmt.Sprintf("%v", v["SUBID"]))
-	b.Os = b.unmarshalStr(fmt.Sprintf("%v", v["os"]))
-	b.RAM = b.unmarshalStr(fmt.Sprintf("%v", v["ram"]))
-	b.Label = b.unmarshalStr(fmt.Sprintf("%v", v["label"]))
-	b.Disk = b.unmarshalStr(fmt.Sprintf("%v", v["disk"]))
-	b.MainIP = b.unmarshalStr(fmt.Sprintf("%v", v["main_ip"]))
-	b.Location = b.unmarshalStr(fmt.Sprintf("%v", v["location"]))
-	b.DefaultPassword = b.unmarshalStr(fmt.Sprintf("%v", v["default_password"]))
-	b.DateCreated = b.unmarshalStr(fmt.Sprintf("%v", v["date_created"]))
-	b.Status = b.unmarshalStr(fmt.Sprintf("%v", v["status"]))
-	b.NetmaskV4 = b.unmarshalStr(fmt.Sprintf("%v", v["netmask_v4"]))
-	b.GatewayV4 = b.unmarshalStr(fmt.Sprintf("%v", v["gateway_v4"]))
-	b.Tag = b.unmarshalStr(fmt.Sprintf("%v", v["tag"]))
-	b.OsID = b.unmarshalStr(fmt.Sprintf("%v", v["OSID"]))
-	b.AppID = b.unmarshalStr(fmt.Sprintf("%v", v["APPID"]))
-
-	v6networks := make([]V6Network, 0)
-	if networks, ok := v["v6_networks"].([]interface{}); ok {
-		for _, network := range networks {
-			if network, ok := network.(map[string]interface{}); ok {
-				v6network := V6Network{
-					Network:     fmt.Sprintf("%v", network["v6_network"]),
-					MainIP:      fmt.Sprintf("%v", network["v6_main_ip"]),
-					NetworkSize: fmt.Sprintf("%v", network["v6_network_size"]),
-				}
-				v6networks = append(v6networks, v6network)
-			}
-		}
-		b.V6Networks = v6networks
-	}
-
-	return nil
-}
-
-func (b *BareMetalServer) unmarshalInt(value string) (int, error) {
-	if len(value) == 0 || value == "<nil>" {
-		value = "0"
-	}
-
-	v, err := strconv.Atoi(value)
-	if err != nil {
-		return 0, err
-	}
-
-	return v, nil
-}
-
-func (b *BareMetalServer) unmarshalStr(value string) string {
-	if value == "<nil>" {
-		value = ""
-	}
-
-	return value
-}
-
-// AppInfo retrieves the application information for a given server ID
-func (b *BareMetalServerServiceHandler) AppInfo(ctx context.Context, serverID string) (*AppInfo, error) {
-	uri := "/v1/baremetal/get_app_info"
-
-	req, err := b.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
+	ID              string   `json:"id"`
+	Os              string   `json:"os"`
+	RAM             string   `json:"ram"`
+	Disk            string   `json:"disk"`
+	MainIP          string   `json:"main_ip"`
+	CPUCount        int      `json:"cpu_count"`
+	Region          string   `json:"region"`
+	DefaultPassword string   `json:"default_password"`
+	DateCreated     string   `json:"date_created"`
+	Status          string   `json:"status"`
+	NetmaskV4       string   `json:"netmask_v4"`
+	GatewayV4       string   `json:"gateway_v4"`
+	Plan            string   `json:"plan"`
+	V6Network       string   `json:"v6_network"`
+	V6MainIP        string   `json:"v6_main_ip"`
+	V6NetworkSize   int      `json:"v6_network_size"`
+	MacAddress      int      `json:"mac_address"`
+	Label           string   `json:"label"`
+	Tag             string   `json:"tag"`
+	OsID            int      `json:"os_id"`
+	AppID           int      `json:"app_id"`
+	ImageID         string   `json:"image_id"`
+	Features        []string `json:"features"`
+}
+
+// BareMetalCreate represents the optional parameters that can be set when creating a Bare Metal server
+type BareMetalCreate struct {
+	Region          string   `json:"region,omitempty"`
+	Plan            string   `json:"plan,omitempty"`
+	OsID            int      `json:"os_id,omitempty"`
+	StartupScriptID string   `json:"script_id,omitempty"`
+	SnapshotID      string   `json:"snapshot_id,omitempty"`
+	EnableIPv6      *bool    `json:"enable_ipv6,omitempty"`
+	Label           string   `json:"label,omitempty"`
+	SSHKeyIDs       []string `json:"sshkey_id,omitempty"`
+	AppID           int      `json:"app_id,omitempty"`
+	ImageID         string   `json:"image_id,omitempty"`
+	UserData        string   `json:"user_data,omitempty"`
+	ActivationEmail *bool    `json:"activation_email,omitempty"`
+	Hostname        string   `json:"hostname,omitempty"`
+	Tag             string   `json:"tag,omitempty"`
+	ReservedIPv4    string   `json:"reserved_ipv4,omitempty"`
+	PersistentPxe   *bool    `json:"persistent_pxe,omitempty"`
+}
+
+// BareMetalUpdate represents the optional parameters that can be set when updating a Bare Metal server
+type BareMetalUpdate struct {
+	OsID       int    `json:"os_id,omitempty"`
+	EnableIPv6 *bool  `json:"enable_ipv6,omitempty"`
+	Label      string `json:"label,omitempty"`
+	AppID      int    `json:"app_id,omitempty"`
+	ImageID    string `json:"image_id,omitempty"`
+	UserData   string `json:"user_data,omitempty"`
+	Tag        string `json:"tag,omitempty"`
+}
+
+// BareMetalServerBandwidth represents bandwidth information for a Bare Metal server
+type BareMetalServerBandwidth struct {
+	IncomingBytes int `json:"incoming_bytes"`
+	OutgoingBytes int `json:"outgoing_bytes"`
+}
+
+type bareMetalsBase struct {
+	BareMetals []BareMetalServer `json:"bare_metals"`
+	Meta       *Meta             `json:"meta"`
+}
+
+type bareMetalBase struct {
+	BareMetal *BareMetalServer `json:"bare_metal"`
+}
+
+// BMBareMetalBase ...
+type BMBareMetalBase struct {
+	BareMetalBandwidth map[string]BareMetalServerBandwidth `json:"bandwidth"`
+}
+
+type vncBase struct {
+	VNCUrl *VNCUrl `json:"vnc"`
+}
+
+// VNCUrl contains the URL for a given Bare Metals VNC
+type VNCUrl struct {
+	URL string `json:"url"`
+}
+
+// Create a new Bare Metal server.
+func (b *BareMetalServerServiceHandler) Create(ctx context.Context, bmCreate *BareMetalCreate) (*BareMetalServer, error) {
+	req, err := b.client.NewRequest(ctx, http.MethodPost, bmPath, bmCreate)
 	if err != nil {
 		return nil, err
 	}
 
-	q := req.URL.Query()
-	q.Add("SUBID", serverID)
-	req.URL.RawQuery = q.Encode()
-
-	appInfo := new(AppInfo)
-
-	err = b.client.DoWithContext(ctx, req, appInfo)
-
-	if err != nil {
+	bm := new(bareMetalBase)
+	if err = b.client.DoWithContext(ctx, req, bm); err != nil {
 		return nil, err
 	}
 
-	return appInfo, nil
+	return bm.BareMetal, nil
 }
 
-// Bandwidth will get the bandwidth used by a bare metal server
-func (b *BareMetalServerServiceHandler) Bandwidth(ctx context.Context, serverID string) ([]map[string]string, error) {
-	uri := "/v1/baremetal/bandwidth"
-
+// Get information for a Bare Metal instance.
+func (b *BareMetalServerServiceHandler) Get(ctx context.Context, serverID string) (*BareMetalServer, error) {
+	uri := fmt.Sprintf("%s/%s", bmPath, serverID)
 	req, err := b.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
 	if err != nil {
 		return nil, err
 	}
 
-	q := req.URL.Query()
-	q.Add("SUBID", serverID)
-	req.URL.RawQuery = q.Encode()
-
-	var bandwidthMap map[string][][]interface{}
-	err = b.client.DoWithContext(ctx, req, &bandwidthMap)
-
-	if err != nil {
+	bms := new(bareMetalBase)
+	if err = b.client.DoWithContext(ctx, req, bms); err != nil {
 		return nil, err
 	}
 
-	var bandwidth []map[string]string
-
-	for _, b := range bandwidthMap["incoming_bytes"] {
-		inMap := make(map[string]string)
-		inMap["date"] = fmt.Sprintf("%v", b[0])
-		var bytes int64
-		switch b[1].(type) {
-		case float64:
-			bytes = int64(b[1].(float64))
-		case int64:
-			bytes = b[1].(int64)
-		}
-		inMap["incoming"] = fmt.Sprintf("%v", bytes)
-		bandwidth = append(bandwidth, inMap)
-	}
-
-	for _, b := range bandwidthMap["outgoing_bytes"] {
-		for i := range bandwidth {
-			if bandwidth[i]["date"] == b[0] {
-				var bytes int64
-				switch b[1].(type) {
-				case float64:
-					bytes = int64(b[1].(float64))
-				case int64:
-					bytes = b[1].(int64)
-				}
-				bandwidth[i]["outgoing"] = fmt.Sprintf("%v", bytes)
-				break
-			}
-		}
-	}
-
-	return bandwidth, nil
+	return bms.BareMetal, nil
 }
 
-// ChangeApp changes the bare metal server to a different application.
-func (b *BareMetalServerServiceHandler) ChangeApp(ctx context.Context, serverID, appID string) error {
-	uri := "/v1/baremetal/app_change"
-
-	values := url.Values{
-		"SUBID": {serverID},
-		"APPID": {appID},
-	}
-
-	req, err := b.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = b.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// ChangeOS changes the bare metal server to a different operating system. All data will be permanently lost.
-func (b *BareMetalServerServiceHandler) ChangeOS(ctx context.Context, serverID, osID string) error {
-	uri := "/v1/baremetal/os_change"
-
-	values := url.Values{
-		"SUBID": {serverID},
-		"OSID":  {osID},
-	}
-
-	req, err := b.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = b.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// Create a new bare metal server.
-func (b *BareMetalServerServiceHandler) Create(ctx context.Context, regionID, planID, osID string, options *BareMetalServerOptions) (*BareMetalServer, error) {
-	uri := "/v1/baremetal/create"
-
-	values := url.Values{
-		"DCID":        {regionID},
-		"METALPLANID": {planID},
-		"OSID":        {osID},
-	}
-
-	if options != nil {
-		if options.StartupScriptID != "" {
-			values.Add("SCRIPTID", options.StartupScriptID)
-		}
-		if options.SnapshotID != "" {
-			values.Add("SNAPSHOTID", options.SnapshotID)
-		}
-		if options.EnableIPV6 != "" {
-			values.Add("enable_ipv6", options.EnableIPV6)
-		}
-		if options.Label != "" {
-			values.Add("label", options.Label)
-		}
-		if options.SSHKeyIDs != nil && len(options.SSHKeyIDs) != 0 {
-			values.Add("SSHKEYID", strings.Join(options.SSHKeyIDs, ","))
-		}
-		if options.AppID != "" {
-			values.Add("APPID", options.AppID)
-		}
-		if options.UserData != "" {
-			values.Add("userdata", base64.StdEncoding.EncodeToString([]byte(options.UserData)))
-		}
-		if options.NotifyActivate != "" {
-			values.Add("notify_activate", options.NotifyActivate)
-		}
-		if options.Hostname != "" {
-			values.Add("hostname", options.Hostname)
-		}
-		if options.Tag != "" {
-			values.Add("tag", options.Tag)
-		}
-		if options.ReservedIPV4 != "" {
-			values.Add("reserved_ip_v4", options.ReservedIPV4)
-		}
-	}
-
-	req, err := b.client.NewRequest(ctx, http.MethodPost, uri, values)
-
+// Update a Bare Metal server
+func (b *BareMetalServerServiceHandler) Update(ctx context.Context, serverID string, bmReq *BareMetalUpdate) (*BareMetalServer, error) {
+	uri := fmt.Sprintf("%s/%s", bmPath, serverID)
+	req, err := b.client.NewRequest(ctx, http.MethodPatch, uri, bmReq)
 	if err != nil {
 		return nil, err
 	}
 
-	bm := new(BareMetalServer)
-
-	err = b.client.DoWithContext(ctx, req, bm)
-
-	if err != nil {
+	bms := new(bareMetalBase)
+	if err = b.client.DoWithContext(ctx, req, bms); err != nil {
 		return nil, err
 	}
 
-	return bm, nil
+	return bms.BareMetal, nil
 }
 
-// Delete a bare metal server.
-// All data will be permanently lost, and the IP address will be released. There is no going back from this call.
+// Delete a Bare Metal server.
 func (b *BareMetalServerServiceHandler) Delete(ctx context.Context, serverID string) error {
-	uri := "/v1/baremetal/destroy"
-
-	values := url.Values{
-		"SUBID": {serverID},
-	}
-
-	req, err := b.client.NewRequest(ctx, http.MethodPost, uri, values)
-
+	uri := fmt.Sprintf("%s/%s", bmPath, serverID)
+	req, err := b.client.NewRequest(ctx, http.MethodDelete, uri, nil)
 	if err != nil {
 		return err
 	}
 
-	err = b.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
+	return b.client.DoWithContext(ctx, req, nil)
 }
 
-// EnableIPV6 enables IPv6 networking on a bare metal server by assigning an IPv6 subnet to it.
-// The server will not be rebooted when the subnet is assigned.
-func (b *BareMetalServerServiceHandler) EnableIPV6(ctx context.Context, serverID string) error {
-	uri := "/v1/baremetal/ipv6_enable"
-
-	values := url.Values{
-		"SUBID": {serverID},
-	}
-
-	req, err := b.client.NewRequest(ctx, http.MethodPost, uri, values)
-
+// List all Bare Metal instances in your account.
+func (b *BareMetalServerServiceHandler) List(ctx context.Context, options *ListOptions) ([]BareMetalServer, *Meta, error) {
+	req, err := b.client.NewRequest(ctx, http.MethodGet, bmPath, nil)
 	if err != nil {
-		return err
+		return nil, nil, err
 	}
 
-	err = b.client.DoWithContext(ctx, req, nil)
-
+	newValues, err := query.Values(options)
 	if err != nil {
-		return err
+		return nil, nil, err
 	}
 
-	return nil
-}
-
-// List lists all bare metal servers on the current account. This includes both pending and active servers.
-func (b *BareMetalServerServiceHandler) List(ctx context.Context) ([]BareMetalServer, error) {
-	return b.list(ctx, "", "")
-}
-
-// ListByLabel lists all bare metal servers that match the given label on the current account. This includes both pending and active servers.
-func (b *BareMetalServerServiceHandler) ListByLabel(ctx context.Context, label string) ([]BareMetalServer, error) {
-	return b.list(ctx, "label", label)
-}
-
-// ListByMainIP lists all bare metal servers that match the given IP address on the current account. This includes both pending and active servers.
-func (b *BareMetalServerServiceHandler) ListByMainIP(ctx context.Context, mainIP string) ([]BareMetalServer, error) {
-	return b.list(ctx, "main_ip", mainIP)
-}
+	req.URL.RawQuery = newValues.Encode()
 
-// ListByTag lists all bare metal servers that match the given tag on the current account. This includes both pending and active servers.
-func (b *BareMetalServerServiceHandler) ListByTag(ctx context.Context, tag string) ([]BareMetalServer, error) {
-	return b.list(ctx, "tag", tag)
-}
-
-func (b *BareMetalServerServiceHandler) list(ctx context.Context, key, value string) ([]BareMetalServer, error) {
-	uri := "/v1/baremetal/list"
-
-	req, err := b.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
-	if err != nil {
-		return nil, err
-	}
-
-	if key != "" {
-		q := req.URL.Query()
-		q.Add(key, value)
-		req.URL.RawQuery = q.Encode()
+	bms := new(bareMetalsBase)
+	if err = b.client.DoWithContext(ctx, req, bms); err != nil {
+		return nil, nil, err
 	}
 
-	bmsMap := make(map[string]BareMetalServer)
-	err = b.client.DoWithContext(ctx, req, &bmsMap)
-	if err != nil {
-		return nil, err
-	}
-
-	var bms []BareMetalServer
-	for _, bm := range bmsMap {
-		bms = append(bms, bm)
-	}
-
-	return bms, nil
+	return bms.BareMetals, bms.Meta, nil
 }
 
-// GetServer gets the server with the given ID
-func (b *BareMetalServerServiceHandler) GetServer(ctx context.Context, serverID string) (*BareMetalServer, error) {
-	uri := "/v1/baremetal/list"
-
+// GetBandwidth  used by a Bare Metal server.
+func (b *BareMetalServerServiceHandler) GetBandwidth(ctx context.Context, serverID string) (*Bandwidth, error) {
+	uri := fmt.Sprintf("%s/%s/bandwidth", bmPath, serverID)
 	req, err := b.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
 	if err != nil {
 		return nil, err
 	}
 
-	q := req.URL.Query()
-	q.Add("SUBID", serverID)
-	req.URL.RawQuery = q.Encode()
-
-	bms := new(BareMetalServer)
-	err = b.client.DoWithContext(ctx, req, bms)
-	if err != nil {
+	bms := new(Bandwidth)
+	if err = b.client.DoWithContext(ctx, req, &bms); err != nil {
 		return nil, err
 	}
 
 	return bms, nil
 }
 
-// GetUserData retrieves the (base64 encoded) user-data for this bare metal server
+// GetUserData for a Bare Metal server. The userdata returned will be in base64 encoding.
 func (b *BareMetalServerServiceHandler) GetUserData(ctx context.Context, serverID string) (*UserData, error) {
-	uri := "/v1/baremetal/get_user_data"
-
+	uri := fmt.Sprintf("%s/%s/user-data", bmPath, serverID)
 	req, err := b.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
 	if err != nil {
 		return nil, err
 	}
 
-	q := req.URL.Query()
-	q.Add("SUBID", serverID)
-	req.URL.RawQuery = q.Encode()
-
-	userData := new(UserData)
-	err = b.client.DoWithContext(ctx, req, userData)
-
-	if err != nil {
+	userData := new(userDataBase)
+	if err = b.client.DoWithContext(ctx, req, userData); err != nil {
 		return nil, err
 	}
 
-	return userData, nil
-}
-
-// Halt a bare metal server.
-// This is a hard power off, meaning that the power to the machine is severed.
-// The data on the machine will not be modified, and you will still be billed for the machine.
-func (b *BareMetalServerServiceHandler) Halt(ctx context.Context, serverID string) error {
-	uri := "/v1/baremetal/halt"
-
-	values := url.Values{
-		"SUBID": {serverID},
-	}
-
-	req, err := b.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = b.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
+	return userData.UserData, nil
 }
 
-// IPV4Info will List the IPv4 information of a bare metal server.
-// IP information is only available for bare metal servers in the "active" state.
-func (b *BareMetalServerServiceHandler) IPV4Info(ctx context.Context, serverID string) ([]BareMetalServerIPV4, error) {
-	uri := "/v1/baremetal/list_ipv4"
-
+// GetVNCUrl gets the vnc url for a given Bare Metal server.
+func (b *BareMetalServerServiceHandler) GetVNCUrl(ctx context.Context, serverID string) (*VNCUrl, error) {
+	uri := fmt.Sprintf("%s/%s/vnc", bmPath, serverID)
 	req, err := b.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
 	if err != nil {
 		return nil, err
 	}
 
-	q := req.URL.Query()
-	q.Add("SUBID", serverID)
-
-	req.URL.RawQuery = q.Encode()
-
-	var ipMap map[string][]BareMetalServerIPV4
-	err = b.client.DoWithContext(ctx, req, &ipMap)
-
-	if err != nil {
+	vnc := new(vncBase)
+	if err = b.client.DoWithContext(ctx, req, vnc); err != nil {
 		return nil, err
 	}
 
-	var ipv4 []BareMetalServerIPV4
-	for _, i := range ipMap {
-		ipv4 = i
-	}
-
-	return ipv4, nil
+	return vnc.VNCUrl, nil
 }
 
-// IPV6Info ists the IPv6 information of a bare metal server.
-// IP information is only available for bare metal servers in the "active" state.
-// If the bare metal server does not have IPv6 enabled, then an empty array is returned.
-func (b *BareMetalServerServiceHandler) IPV6Info(ctx context.Context, serverID string) ([]BareMetalServerIPV6, error) {
-	uri := "/v1/baremetal/list_ipv6"
-
+// ListIPv4s information of a Bare Metal server.
+// IP information is only available for Bare Metal servers in the "active" state.
+func (b *BareMetalServerServiceHandler) ListIPv4s(ctx context.Context, serverID string, options *ListOptions) ([]IPv4, *Meta, error) {
+	uri := fmt.Sprintf("%s/%s/ipv4", bmPath, serverID)
 	req, err := b.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	q := req.URL.Query()
-	q.Add("SUBID", serverID)
-	req.URL.RawQuery = q.Encode()
-
-	var ipMap map[string][]BareMetalServerIPV6
-	err = b.client.DoWithContext(ctx, req, &ipMap)
-
+	newValues, err := query.Values(options)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	var ipv6 []BareMetalServerIPV6
-	for _, i := range ipMap {
-		ipv6 = i
+	req.URL.RawQuery = newValues.Encode()
+
+	ipv4 := new(ipBase)
+	if err = b.client.DoWithContext(ctx, req, ipv4); err != nil {
+		return nil, nil, err
 	}
 
-	return ipv6, nil
+	return ipv4.IPv4s, ipv4.Meta, nil
 }
 
-// ListApps retrieves a list of Vultr one-click applications to which a bare metal server can be changed.
-// Always check against this list before trying to switch applications because it is not possible to switch between every application combination.
-func (b *BareMetalServerServiceHandler) ListApps(ctx context.Context, serverID string) ([]Application, error) {
-	uri := "/v1/baremetal/app_change_list"
-
+// ListIPv6s information of a Bare Metal server.
+// IP information is only available for Bare Metal servers in the "active" state.
+// If the Bare Metal server does not have IPv6 enabled, then an empty array is returned.
+func (b *BareMetalServerServiceHandler) ListIPv6s(ctx context.Context, serverID string, options *ListOptions) ([]IPv6, *Meta, error) {
+	uri := fmt.Sprintf("%s/%s/ipv6", bmPath, serverID)
 	req, err := b.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	q := req.URL.Query()
-	q.Add("SUBID", serverID)
-	req.URL.RawQuery = q.Encode()
-
-	var appMap map[string]Application
-	err = b.client.DoWithContext(ctx, req, &appMap)
-
+	newValues, err := query.Values(options)
 	if err != nil {
-		return nil, err
-	}
-
-	var appList []Application
-	for _, a := range appMap {
-		appList = append(appList, a)
+		return nil, nil, err
 	}
 
-	return appList, nil
-}
-
-// ListOS retrieves a list of operating systems to which a bare metal server can be changed.
-// Always check against this list before trying to switch operating systems because it is not possible to switch between every operating system combination.
-func (b *BareMetalServerServiceHandler) ListOS(ctx context.Context, serverID string) ([]OS, error) {
-	uri := "/v1/baremetal/os_change_list"
-
-	req, err := b.client.NewRequest(ctx, http.MethodGet, uri, nil)
+	req.URL.RawQuery = newValues.Encode()
 
-	if err != nil {
-		return nil, err
+	ipv6 := new(ipBase)
+	if err = b.client.DoWithContext(ctx, req, ipv6); err != nil {
+		return nil, nil, err
 	}
 
-	q := req.URL.Query()
-	q.Add("SUBID", serverID)
-	req.URL.RawQuery = q.Encode()
-
-	var osMap map[string]OS
-	err = b.client.DoWithContext(ctx, req, &osMap)
+	return ipv6.IPv6s, ipv6.Meta, nil
+}
 
+// Halt a Bare Metal server.
+// This is a hard power off, meaning that the power to the machine is severed.
+// The data on the machine will not be modified, and you will still be billed for the machine.
+func (b *BareMetalServerServiceHandler) Halt(ctx context.Context, serverID string) error {
+	uri := fmt.Sprintf("%s/%s/halt", bmPath, serverID)
+	req, err := b.client.NewRequest(ctx, http.MethodPost, uri, nil)
 	if err != nil {
-		return nil, err
-	}
-
-	var os []OS
-	for _, o := range osMap {
-		os = append(os, o)
+		return err
 	}
 
-	return os, nil
+	return b.client.DoWithContext(ctx, req, nil)
 }
 
-// Reboot a bare metal server. This is a hard reboot, which means that the server is powered off, then back on.
+// Reboot a Bare Metal server. This is a hard reboot, which means that the server is powered off, then back on.
 func (b *BareMetalServerServiceHandler) Reboot(ctx context.Context, serverID string) error {
-	uri := "/v1/baremetal/reboot"
-
-	values := url.Values{
-		"SUBID": {serverID},
-	}
-
-	req, err := b.client.NewRequest(ctx, http.MethodPost, uri, values)
+	uri := fmt.Sprintf("%s/%s/reboot", bmPath, serverID)
 
+	req, err := b.client.NewRequest(ctx, http.MethodPost, uri, nil)
 	if err != nil {
 		return err
 	}
 
-	err = b.client.DoWithContext(ctx, req, nil)
+	return b.client.DoWithContext(ctx, req, nil)
+}
 
+// Start a Bare Metal server.
+func (b *BareMetalServerServiceHandler) Start(ctx context.Context, serverID string) error {
+	uri := fmt.Sprintf("%s/%s/start", bmPath, serverID)
+	req, err := b.client.NewRequest(ctx, http.MethodPost, uri, nil)
 	if err != nil {
 		return err
 	}
 
-	return nil
+	return b.client.DoWithContext(ctx, req, nil)
 }
 
-// Reinstall the operating system on a bare metal server.
-// All data will be permanently lost, but the IP address will remain the same. There is no going back from this call.
-func (b *BareMetalServerServiceHandler) Reinstall(ctx context.Context, serverID string) error {
-	uri := "/v1/baremetal/reinstall"
-
-	values := url.Values{
-		"SUBID": {serverID},
-	}
-
-	req, err := b.client.NewRequest(ctx, http.MethodPost, uri, values)
-
+// Reinstall the operating system on a Bare Metal server.
+// All data will be permanently lost, but the IP address will remain the same.
+func (b *BareMetalServerServiceHandler) Reinstall(ctx context.Context, serverID string) (*BareMetalServer, error) {
+	uri := fmt.Sprintf("%s/%s/reinstall", bmPath, serverID)
+	req, err := b.client.NewRequest(ctx, http.MethodPost, uri, nil)
 	if err != nil {
-		return err
+		return nil, err
 	}
 
-	err = b.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
+	bms := new(bareMetalBase)
+	if err = b.client.DoWithContext(ctx, req, bms); err != nil {
+		return nil, err
 	}
 
-	return nil
+	return bms.BareMetal, nil
 }
 
-// SetLabel sets the label of a bare metal server.
-func (b *BareMetalServerServiceHandler) SetLabel(ctx context.Context, serverID, label string) error {
-	uri := "/v1/baremetal/label_set"
-
-	values := url.Values{
-		"SUBID": {serverID},
-		"label": {label},
-	}
-
-	req, err := b.client.NewRequest(ctx, http.MethodPost, uri, values)
+// MassStart will start a list of Bare Metal servers the machine is already running, it will be restarted.
+func (b *BareMetalServerServiceHandler) MassStart(ctx context.Context, serverList []string) error {
+	uri := fmt.Sprintf("%s/start", bmPath)
 
+	reqBody := RequestBody{"baremetal_ids": serverList}
+	req, err := b.client.NewRequest(ctx, http.MethodPost, uri, reqBody)
 	if err != nil {
 		return err
 	}
 
-	err = b.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
+	return b.client.DoWithContext(ctx, req, nil)
 }
 
-// SetTag sets the tag of a bare metal server.
-func (b *BareMetalServerServiceHandler) SetTag(ctx context.Context, serverID, tag string) error {
-	uri := "/v1/baremetal/tag_set"
-
-	values := url.Values{
-		"SUBID": {serverID},
-		"tag":   {tag},
-	}
-
-	req, err := b.client.NewRequest(ctx, http.MethodPost, uri, values)
+// MassHalt a list of Bare Metal servers.
+func (b *BareMetalServerServiceHandler) MassHalt(ctx context.Context, serverList []string) error {
+	uri := fmt.Sprintf("%s/halt", bmPath)
 
+	reqBody := RequestBody{"baremetal_ids": serverList}
+	req, err := b.client.NewRequest(ctx, http.MethodPost, uri, reqBody)
 	if err != nil {
 		return err
 	}
 
-	err = b.client.DoWithContext(ctx, req, nil)
+	return b.client.DoWithContext(ctx, req, nil)
+}
+
+// MassReboot a list of Bare Metal servers.
+func (b *BareMetalServerServiceHandler) MassReboot(ctx context.Context, serverList []string) error {
+	uri := fmt.Sprintf("%s/reboot", bmPath)
 
+	reqBody := RequestBody{"baremetal_ids": serverList}
+	req, err := b.client.NewRequest(ctx, http.MethodPost, uri, reqBody)
 	if err != nil {
 		return err
 	}
 
-	return nil
+	return b.client.DoWithContext(ctx, req, nil)
 }
 
-// SetUserData sets the user-data for this server.
-// User-data is a generic data store, which some provisioning tools and cloud operating systems use as a configuration file.
-// It is generally consumed only once after an instance has been launched, but individual needs may vary.
-func (b *BareMetalServerServiceHandler) SetUserData(ctx context.Context, serverID, userData string) error {
-	uri := "/v1/baremetal/set_user_data"
-
-	encodedUserData := base64.StdEncoding.EncodeToString([]byte(userData))
-
-	values := url.Values{
-		"SUBID":    {serverID},
-		"userdata": {encodedUserData},
-	}
-
-	req, err := b.client.NewRequest(ctx, http.MethodPost, uri, values)
-
+// GetUpgrades that are available for a Bare Metal server.
+func (b *BareMetalServerServiceHandler) GetUpgrades(ctx context.Context, serverID string) (*Upgrades, error) {
+	uri := fmt.Sprintf("%s/%s/upgrades", bmPath, serverID)
+	req, err := b.client.NewRequest(ctx, http.MethodGet, uri, nil)
 	if err != nil {
-		return err
+		return nil, err
 	}
 
-	err = b.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
+	upgrades := new(upgradeBase)
+	if err = b.client.DoWithContext(ctx, req, upgrades); err != nil {
+		return nil, err
 	}
 
-	return nil
+	return upgrades.Upgrades, nil
 }
diff --git a/bare_metal_server_test.go b/bare_metal_server_test.go
index f906cf1..c9b1bec 100644
--- a/bare_metal_server_test.go
+++ b/bare_metal_server_test.go
@@ -7,606 +7,353 @@ import (
 	"testing"
 )
 
-func TestBareMetalServerServiceHandler_AppInfo(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/baremetal/get_app_info", func(writer http.ResponseWriter, request *http.Request) {
-		response := `
-		{
-			"app_info": "Minecraft Server Details\n\nYour Minecraft server is accessible at: \n\n45.74.196.185:25565\n\nYou can access the console of your Minecraft server by using the \"screen\" utility from the following login:\nUser: minecraft\nPass: NXwdsdZjwJasdZbsc\n\nRead more about this app on Vultr Docs: \n\nhttps://www.vultr.com/docs/one-click-minecraft\n"
-		}
-		`
-		fmt.Fprint(writer, response)
-	})
-
-	appInfo, err := client.BareMetalServer.AppInfo(ctx, "900000")
-
-	if err != nil {
-		t.Errorf("BareMetalServer.AppInfo returned error: %v", err)
-	}
-
-	expected := &AppInfo{
-		AppInfo: "Minecraft Server Details\n\nYour Minecraft server is accessible at: \n\n45.74.196.185:25565\n\nYou can access the console of your Minecraft server by using the \"screen\" utility from the following login:\nUser: minecraft\nPass: NXwdsdZjwJasdZbsc\n\nRead more about this app on Vultr Docs: \n\nhttps://www.vultr.com/docs/one-click-minecraft\n",
-	}
-
-	if !reflect.DeepEqual(appInfo, expected) {
-		t.Errorf("BareMetalServer.AppInfo returned %+v, expected %+v", appInfo, expected)
-	}
-}
-
-func TestBareMetalServerServiceHandler_Bandwidth(t *testing.T) {
+func TestBareMetalServerServiceHandler_GetServer(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/baremetal/bandwidth", func(writer http.ResponseWriter, request *http.Request) {
+	mux.HandleFunc("/v2/bare-metals/abc123", func(writer http.ResponseWriter, request *http.Request) {
 		response := `
 		{
-			"incoming_bytes": [
-				[
-					"2017-04-01",
-					91571055
-				],
-				[
-					"2017-04-02",
-					78355758
-				],
-				[
-					"2017-04-03",
-					85827590
-				]
-			],
-			"outgoing_bytes": [
-				[
-					"2017-04-01",
-					3084731
-				],
-				[
-					"2017-04-02",
-					1810478
-				],
-				[
-					"2017-04-03",
-					2729604
-				]
-			]
+			"bare_metal": {
+				"id": "abc123",
+				"os": "CentOS 6 x64",
+				"ram": "65536 MB",
+				"disk": "2x 240 GB SSD",
+				"main_ip": "203.0.113.10",
+				"cpu_count": 1,
+				"region": "ewr",
+				"date_created": "2017-04-12 18:45:41",
+				"status": "active",
+				"netmask_v4": "255.255.255.0",
+				"gateway_v4": "203.0.113.1",
+				"plan": "vbm-4c-32gb",
+				"v6_network": "2001:DB8:9000::",
+				"v6_main_ip": "2001:DB8:9000::100",
+				"v6_network_size": 64,
+				"mac_address": 2199756823533,
+				"label": "my label",
+				"tag": "my tag",
+				"os_id": 127,
+				"app_id": 0
+			}
 		}
 		`
 		fmt.Fprint(writer, response)
 	})
 
-	bandwidth, err := client.BareMetalServer.Bandwidth(ctx, "123")
-
-	if err != nil {
-		t.Errorf("BareMetalServer.Bandwidth returned %+v", err)
-	}
-
-	expected := []map[string]string{
-		{"date": "2017-04-01", "incoming": "91571055", "outgoing": "3084731"},
-		{"date": "2017-04-02", "incoming": "78355758", "outgoing": "1810478"},
-		{"date": "2017-04-03", "incoming": "85827590", "outgoing": "2729604"},
-	}
-
-	if !reflect.DeepEqual(bandwidth, expected) {
-		t.Errorf("BareMetalServer.Bandwidth returned %+v, expected %+v", bandwidth, expected)
-	}
-}
-
-func TestBareMetalServerServiceHandler_ChangeApp(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/baremetal/app_change", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.BareMetalServer.ChangeApp(ctx, "900000", "15")
-
+	bm, err := client.BareMetalServer.Get(ctx, "abc123")
 	if err != nil {
-		t.Errorf("BareMetalServer.ChangeApp returned %+v, ", err)
-	}
-}
-
-func TestBareMetalServerServiceHandler_ChangeOS(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/baremetal/os_change", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.BareMetalServer.ChangeOS(ctx, "900000", "302")
-
-	if err != nil {
-		t.Errorf("BareMetalServer.ChangeOS return %+v ", err)
-	}
-}
-
-func TestBareMetalServerServiceHandler_Create(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/baremetal/create", func(writer http.ResponseWriter, request *http.Request) {
-		response := `
-		{
-			"SUBID": "900000"
-		}
-		`
-		fmt.Fprint(writer, response)
-	})
-
-	options := &BareMetalServerOptions{
-		StartupScriptID: "1",
-		SnapshotID:      "1",
-		EnableIPV6:      "yes",
-		Label:           "go-bm-test",
-		SSHKeyIDs:       []string{"6b80207b1821f"},
-		AppID:           "1",
-		UserData:        "echo Hello World",
-		NotifyActivate:  "yes",
-		Hostname:        "test",
-		Tag:             "go-test",
-		ReservedIPV4:    "111.111.111.111",
+		t.Errorf("BareMetalServer.GetServer returned error: %v", err)
 	}
 
-	bm, err := client.BareMetalServer.Create(ctx, "1", "1", "1", options)
-
-	if err != nil {
-		t.Errorf("BareMetalServer.Create returned error: %v", err)
+	expected := &BareMetalServer{
+		ID:            "abc123",
+		Os:            "CentOS 6 x64",
+		RAM:           "65536 MB",
+		Disk:          "2x 240 GB SSD",
+		MainIP:        "203.0.113.10",
+		CPUCount:      1,
+		Region:        "ewr",
+		DateCreated:   "2017-04-12 18:45:41",
+		Status:        "active",
+		NetmaskV4:     "255.255.255.0",
+		GatewayV4:     "203.0.113.1",
+		Plan:          "vbm-4c-32gb",
+		V6Network:     "2001:DB8:9000::",
+		V6MainIP:      "2001:DB8:9000::100",
+		V6NetworkSize: 64,
+		MacAddress:    2199756823533,
+		Label:         "my label",
+		Tag:           "my tag",
+		OsID:          127,
+		AppID:         0,
 	}
 
-	expected := &BareMetalServer{BareMetalServerID: "900000"}
-
 	if !reflect.DeepEqual(bm, expected) {
-		t.Errorf("BareMetalServer.Create returned %+v, expected %+v", bm, expected)
-	}
-}
-
-func TestBareMetalServerServiceHandler_Delete(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/baremetal/destroy", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.BareMetalServer.Delete(ctx, "900000")
-
-	if err != nil {
-		t.Errorf("BareMetalServer.Delete returned %+v, expected %+v", err, nil)
-	}
-}
-
-func TestBareMetalServerServiceHandler_EnableIPV6(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/baremetal/ipv6_enable", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.BareMetalServer.EnableIPV6(ctx, "900000")
-
-	if err != nil {
-		t.Errorf("BareMetalServer.EnableIPV6 returned %+v", err)
+		t.Errorf("BareMetalServer.GetServer returned %+v, expected %+v", bm, expected)
 	}
 }
 
-func TestBareMetalServerServiceHandler_List(t *testing.T) {
+func TestBareMetalServerServiceHandler_Create(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/baremetal/list", func(writer http.ResponseWriter, request *http.Request) {
+	mux.HandleFunc("/v2/bare-metals", func(writer http.ResponseWriter, request *http.Request) {
 		response := `
 			{
-				"900000": {
-					"SUBID": "900000",
+				"bare_metal": {
+					"id": "900000",
 					"os": "CentOS 6 x64",
 					"ram": "65536 MB",
 					"disk": "2x 240 GB SSD",
 					"main_ip": "203.0.113.10",
 					"cpu_count": 1,
-					"location": "New Jersey",
-					"DCID": "1",
+					"region": "ewr",
 					"default_password": "ab81u!ryranq",
 					"date_created": "2017-04-12 18:45:41",
 					"status": "active",
 					"netmask_v4": "255.255.255.0",
 					"gateway_v4": "203.0.113.1",
-					"METALPLANID": 28,
-					"v6_networks": [
-						{
-							"v6_network": "2001:DB8:9000::",
-							"v6_main_ip": "2001:DB8:9000::100",
-							"v6_network_size": 64
-						}
-					],
-					"label": "my label",
+					"plan": "vbm-4c-32gb",
+					"v6_network": "2001:DB8:9000::",
+					"v6_main_ip": "2001:DB8:9000::100",
+					"v6_network_size": 64,
+					"mac_address": 0,
+					"label": "go-bm-test",
 					"tag": "my tag",
-					"OSID": "127",
-					"APPID": "0"
+					"os_id": 127,
+					"app_id": 0
 				}
 			}
 		`
 		fmt.Fprint(writer, response)
 	})
 
-	bm, err := client.BareMetalServer.List(ctx)
+	options := &BareMetalCreate{
+		StartupScriptID: "1",
+		Region:          "ewr",
+		Plan:            "vbm-4c-32gb",
+		SnapshotID:      "1",
+		EnableIPv6:      BoolToBoolPtr(true),
+		Label:           "go-bm-test",
+		SSHKeyIDs:       []string{"6b80207b1821f"},
+		AppID:           1,
+		UserData:        "echo Hello World",
+		ActivationEmail: BoolToBoolPtr(true),
+		Hostname:        "test",
+		Tag:             "go-test",
+		ReservedIPv4:    "111.111.111.111",
+		PersistentPxe:   BoolToBoolPtr(true),
+	}
+
+	bm, err := client.BareMetalServer.Create(ctx, options)
 
 	if err != nil {
-		t.Errorf("BareMetalServer.List returned error: %v", err)
+		t.Errorf("BareMetalServer.Create returned error: %v", err)
 	}
 
-	expected := []BareMetalServer{
-		{
-			BareMetalServerID: "900000",
-			Os:                "CentOS 6 x64",
-			RAM:               "65536 MB",
-			Disk:              "2x 240 GB SSD",
-			MainIP:            "203.0.113.10",
-			CPUs:              1,
-			Location:          "New Jersey",
-			RegionID:          1,
-			DefaultPassword:   "ab81u!ryranq",
-			DateCreated:       "2017-04-12 18:45:41",
-			Status:            "active",
-			NetmaskV4:         "255.255.255.0",
-			GatewayV4:         "203.0.113.1",
-			BareMetalPlanID:   28,
-			V6Networks: []V6Network{
-				{
-					Network:     "2001:DB8:9000::",
-					MainIP:      "2001:DB8:9000::100",
-					NetworkSize: "64",
-				},
-			},
-			Label: "my label",
-			Tag:   "my tag",
-			OsID:  "127",
-			AppID: "0",
-		},
+	expected := &BareMetalServer{
+		ID:              "900000",
+		Os:              "CentOS 6 x64",
+		RAM:             "65536 MB",
+		Disk:            "2x 240 GB SSD",
+		MainIP:          "203.0.113.10",
+		CPUCount:        1,
+		DefaultPassword: "ab81u!ryranq",
+		DateCreated:     "2017-04-12 18:45:41",
+		Status:          "active",
+		NetmaskV4:       "255.255.255.0",
+		GatewayV4:       "203.0.113.1",
+		Plan:            "vbm-4c-32gb",
+		V6Network:       "2001:DB8:9000::",
+		V6MainIP:        "2001:DB8:9000::100",
+		V6NetworkSize:   64,
+		Label:           "go-bm-test",
+		Tag:             "my tag",
+		MacAddress:      0,
+		OsID:            127,
+		Region:          "ewr",
+		AppID:           0,
 	}
 
 	if !reflect.DeepEqual(bm, expected) {
-		t.Errorf("BareMetalServer.List returned %+v, expected %+v", bm, expected)
+		t.Errorf("BareMetalServer.Create returned %+v, expected %+v", bm, expected)
 	}
 }
 
-func TestBareMetalServerServiceHandler_ListByLabel(t *testing.T) {
+func TestBareMetalServerServiceHandler_Update(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/baremetal/list", func(writer http.ResponseWriter, request *http.Request) {
+	mux.HandleFunc("/v2/bare-metals/dev-preview-abc123", func(writer http.ResponseWriter, request *http.Request) {
 		response := `
 			{
-				"900000": {
-					"SUBID": "900000",
+				"bare_metal": {
+					"id": "900000",
 					"os": "CentOS 6 x64",
 					"ram": "65536 MB",
 					"disk": "2x 240 GB SSD",
 					"main_ip": "203.0.113.10",
 					"cpu_count": 1,
-					"location": "New Jersey",
-					"DCID": "1",
+					"region": "ewr",
 					"default_password": "ab81u!ryranq",
 					"date_created": "2017-04-12 18:45:41",
 					"status": "active",
 					"netmask_v4": "255.255.255.0",
 					"gateway_v4": "203.0.113.1",
-					"METALPLANID": 28,
-					"v6_networks": [
-						{
-							"v6_network": "2001:DB8:9000::",
-							"v6_main_ip": "2001:DB8:9000::100",
-							"v6_network_size": 64
-						}
-					],
-					"label": "my label",
+					"plan": "vbm-4c-32gb",
+					"v6_network": "2001:DB8:9000::",
+					"v6_main_ip": "2001:DB8:9000::100",
+					"v6_network_size": 64,
+					"label": "my new label",
 					"tag": "my tag",
-					"OSID": "127",
-					"APPID": "0"
+					"os_id": 127,
+					"app_id": 0
 				}
 			}
 		`
 		fmt.Fprint(writer, response)
 	})
 
-	bm, err := client.BareMetalServer.ListByLabel(ctx, "my label")
+	options := &BareMetalUpdate{
+		Label: "my new label",
+	}
 
+	bm, err := client.BareMetalServer.Update(ctx, "dev-preview-abc123", options)
 	if err != nil {
-		t.Errorf("BareMetalServer.ListByLabel returned error: %v", err)
+		t.Errorf("BareMetal.Update returned %+v, expected %+v", err, nil)
 	}
 
-	expected := []BareMetalServer{
-		{
-			BareMetalServerID: "900000",
-			Os:                "CentOS 6 x64",
-			RAM:               "65536 MB",
-			Disk:              "2x 240 GB SSD",
-			MainIP:            "203.0.113.10",
-			CPUs:              1,
-			Location:          "New Jersey",
-			RegionID:          1,
-			DefaultPassword:   "ab81u!ryranq",
-			DateCreated:       "2017-04-12 18:45:41",
-			Status:            "active",
-			NetmaskV4:         "255.255.255.0",
-			GatewayV4:         "203.0.113.1",
-			BareMetalPlanID:   28,
-			V6Networks: []V6Network{
-				{
-					Network:     "2001:DB8:9000::",
-					MainIP:      "2001:DB8:9000::100",
-					NetworkSize: "64",
-				},
-			},
-			Label: "my label",
-			Tag:   "my tag",
-			OsID:  "127",
-			AppID: "0",
-		},
+	expected := &BareMetalServer{
+		ID:              "900000",
+		Os:              "CentOS 6 x64",
+		RAM:             "65536 MB",
+		Disk:            "2x 240 GB SSD",
+		MainIP:          "203.0.113.10",
+		CPUCount:        1,
+		DefaultPassword: "ab81u!ryranq",
+		DateCreated:     "2017-04-12 18:45:41",
+		Status:          "active",
+		NetmaskV4:       "255.255.255.0",
+		GatewayV4:       "203.0.113.1",
+		Plan:            "vbm-4c-32gb",
+		V6Network:       "2001:DB8:9000::",
+		V6MainIP:        "2001:DB8:9000::100",
+		V6NetworkSize:   64,
+		Label:           "my new label",
+		Tag:             "my tag",
+		OsID:            127,
+		Region:          "ewr",
+		AppID:           0,
 	}
 
 	if !reflect.DeepEqual(bm, expected) {
-		t.Errorf("BareMetalServer.ListByLabel returned %+v, expected %+v", bm, expected)
+		t.Errorf("BareMetalServer.Update returned %+v, expected %+v", bm, expected)
 	}
 }
 
-func TestBareMetalServerServiceHandler_ListByMainIP(t *testing.T) {
+func TestBareMetalServerServiceHandler_Delete(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/baremetal/list", func(writer http.ResponseWriter, request *http.Request) {
-		response := `
-			{
-				"900000": {
-					"SUBID": "900000",
-					"os": "CentOS 6 x64",
-					"ram": "65536 MB",
-					"disk": "2x 240 GB SSD",
-					"main_ip": "203.0.113.10",
-					"cpu_count": 1,
-					"location": "New Jersey",
-					"DCID": "1",
-					"default_password": "ab81u!ryranq",
-					"date_created": "2017-04-12 18:45:41",
-					"status": "active",
-					"netmask_v4": "255.255.255.0",
-					"gateway_v4": "203.0.113.1",
-					"METALPLANID": 28,
-					"v6_networks": [
-						{
-							"v6_network": "2001:DB8:9000::",
-							"v6_main_ip": "2001:DB8:9000::100",
-							"v6_network_size": 64
-						}
-					],
-					"label": "my label",
-					"tag": "my tag",
-					"OSID": "127",
-					"APPID": "0"
-				}
-			}
-		`
-		fmt.Fprint(writer, response)
+	mux.HandleFunc("/v2/bare-metals/900000", func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
 	})
 
-	bm, err := client.BareMetalServer.ListByMainIP(ctx, "203.0.113.10")
+	err := client.BareMetalServer.Delete(ctx, "900000")
 
 	if err != nil {
-		t.Errorf("BareMetalServer.ListByMainIP returned error: %v", err)
-	}
-
-	expected := []BareMetalServer{
-		{
-			BareMetalServerID: "900000",
-			Os:                "CentOS 6 x64",
-			RAM:               "65536 MB",
-			Disk:              "2x 240 GB SSD",
-			MainIP:            "203.0.113.10",
-			CPUs:              1,
-			Location:          "New Jersey",
-			RegionID:          1,
-			DefaultPassword:   "ab81u!ryranq",
-			DateCreated:       "2017-04-12 18:45:41",
-			Status:            "active",
-			NetmaskV4:         "255.255.255.0",
-			GatewayV4:         "203.0.113.1",
-			BareMetalPlanID:   28,
-			V6Networks: []V6Network{
-				{
-					Network:     "2001:DB8:9000::",
-					MainIP:      "2001:DB8:9000::100",
-					NetworkSize: "64",
-				},
-			},
-			Label: "my label",
-			Tag:   "my tag",
-			OsID:  "127",
-			AppID: "0",
-		},
-	}
-
-	if !reflect.DeepEqual(bm, expected) {
-		t.Errorf("BareMetalServer.ListByMainIP returned %+v, expected %+v", bm, expected)
+		t.Errorf("BareMetalServer.Delete returned %+v, expected %+v", err, nil)
 	}
 }
 
-func TestBareMetalServerServiceHandler_ListByTag(t *testing.T) {
+func TestBareMetalServerServiceHandler_List(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/baremetal/list", func(writer http.ResponseWriter, request *http.Request) {
+	mux.HandleFunc("/v2/bare-metals", func(writer http.ResponseWriter, request *http.Request) {
 		response := `
 			{
-				"900000": {
-					"SUBID": "900000",
+				"bare_metals": [{
+					"id": "90000",
 					"os": "CentOS 6 x64",
 					"ram": "65536 MB",
 					"disk": "2x 240 GB SSD",
 					"main_ip": "203.0.113.10",
 					"cpu_count": 1,
-					"location": "New Jersey",
-					"DCID": "1",
-					"default_password": "ab81u!ryranq",
+					"region": "ewr",
 					"date_created": "2017-04-12 18:45:41",
 					"status": "active",
 					"netmask_v4": "255.255.255.0",
 					"gateway_v4": "203.0.113.1",
-					"METALPLANID": 28,
-					"v6_networks": [
-						{
-							"v6_network": "2001:DB8:9000::",
-							"v6_main_ip": "2001:DB8:9000::100",
-							"v6_network_size": 64
-						}
-					],
+					"plan": "vbm-4c-32gb",
+					"v6_network": "2001:DB8:9000::",
+					"v6_main_ip": "2001:DB8:9000::100",
+					"v6_network_size": 64,
+					"mac_address": 2199756823533,
 					"label": "my label",
 					"tag": "my tag",
-					"OSID": "127",
-					"APPID": "0"
-				}
+					"os_id": 127,
+					"app_id": 0
+				}]
 			}
 		`
 		fmt.Fprint(writer, response)
 	})
 
-	bm, err := client.BareMetalServer.ListByTag(ctx, "my tag")
+	bm, _, err := client.BareMetalServer.List(ctx, nil)
 
 	if err != nil {
-		t.Errorf("BareMetalServer.ListByTag returned error: %v", err)
+		t.Errorf("BareMetalServer.List returned error: %v", err)
 	}
 
 	expected := []BareMetalServer{
 		{
-			BareMetalServerID: "900000",
-			Os:                "CentOS 6 x64",
-			RAM:               "65536 MB",
-			Disk:              "2x 240 GB SSD",
-			MainIP:            "203.0.113.10",
-			CPUs:              1,
-			Location:          "New Jersey",
-			RegionID:          1,
-			DefaultPassword:   "ab81u!ryranq",
-			DateCreated:       "2017-04-12 18:45:41",
-			Status:            "active",
-			NetmaskV4:         "255.255.255.0",
-			GatewayV4:         "203.0.113.1",
-			BareMetalPlanID:   28,
-			V6Networks: []V6Network{
-				{
-					Network:     "2001:DB8:9000::",
-					MainIP:      "2001:DB8:9000::100",
-					NetworkSize: "64",
-				},
-			},
-			Label: "my label",
-			Tag:   "my tag",
-			OsID:  "127",
-			AppID: "0",
+			ID:            "90000",
+			Os:            "CentOS 6 x64",
+			RAM:           "65536 MB",
+			Disk:          "2x 240 GB SSD",
+			MainIP:        "203.0.113.10",
+			CPUCount:      1,
+			Region:        "ewr",
+			DateCreated:   "2017-04-12 18:45:41",
+			Status:        "active",
+			NetmaskV4:     "255.255.255.0",
+			GatewayV4:     "203.0.113.1",
+			Plan:          "vbm-4c-32gb",
+			V6Network:     "2001:DB8:9000::",
+			V6MainIP:      "2001:DB8:9000::100",
+			V6NetworkSize: 64,
+			MacAddress:    2199756823533,
+			Label:         "my label",
+			Tag:           "my tag",
+			OsID:          127,
+			AppID:         0,
 		},
 	}
 
 	if !reflect.DeepEqual(bm, expected) {
-		t.Errorf("BareMetalServer.ListByTag returned %+v, expected %+v", bm, expected)
+		t.Errorf("BareMetalServer.List returned %+v, expected %+v", bm, expected)
 	}
 }
 
-func TestBareMetalServerServiceHandler_GetServer(t *testing.T) {
+func TestBareMetalServerServiceHandler_GetBandwidth(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/baremetal/list", func(writer http.ResponseWriter, request *http.Request) {
+	mux.HandleFunc("/v2/bare-metals/dev-preview-abc123/bandwidth", func(writer http.ResponseWriter, request *http.Request) {
 		response := `
-			{
-				"SUBID": "900000",
-				"os": "CentOS 6 x64",
-				"ram": "65536 MB",
-				"disk": "2x 240 GB SSD",
-				"main_ip": "203.0.113.10",
-				"cpu_count": 1,
-				"location": "New Jersey",
-				"DCID": "1",
-				"default_password": "ab81u!ryranq",
-				"date_created": "2017-04-12 18:45:41",
-				"status": "active",
-				"netmask_v4": "255.255.255.0",
-				"gateway_v4": "203.0.113.1",
-				"METALPLANID": 28,
-				"v6_networks": [
-					{
-						"v6_network": "2001:DB8:9000::",
-						"v6_main_ip": "2001:DB8:9000::100",
-						"v6_network_size": 64
-					}
-				],
-				"label": "my label",
-				"tag": "my tag",
-				"OSID": "127",
-				"APPID": "0"
+		{
+			"bandwidth": {
+				"2017-04-01": {
+					"incoming_bytes": 91571055,
+					"outgoing_bytes": 3084731
+				}
 			}
+		}
 		`
 		fmt.Fprint(writer, response)
 	})
 
-	bm, err := client.BareMetalServer.GetServer(ctx, "900000")
-
+	bandwidth, err := client.BareMetalServer.GetBandwidth(ctx, "dev-preview-abc123")
 	if err != nil {
-		t.Errorf("BareMetalServer.GetServer returned error: %v", err)
+		t.Errorf("BareMetalServer.GetBandwidth returned %+v", err)
 	}
 
-	expected := &BareMetalServer{
-		BareMetalServerID: "900000",
-		Os:                "CentOS 6 x64",
-		RAM:               "65536 MB",
-		Disk:              "2x 240 GB SSD",
-		MainIP:            "203.0.113.10",
-		CPUs:              1,
-		Location:          "New Jersey",
-		RegionID:          1,
-		DefaultPassword:   "ab81u!ryranq",
-		DateCreated:       "2017-04-12 18:45:41",
-		Status:            "active",
-		NetmaskV4:         "255.255.255.0",
-		GatewayV4:         "203.0.113.1",
-		BareMetalPlanID:   28,
-		V6Networks: []V6Network{
-			{
-				Network:     "2001:DB8:9000::",
-				MainIP:      "2001:DB8:9000::100",
-				NetworkSize: "64",
+	expected := &Bandwidth{
+		Bandwidth: map[string]struct {
+			IncomingBytes int `json:"incoming_bytes"`
+			OutgoingBytes int `json:"outgoing_bytes"`
+		}{
+			"2017-04-01": {
+				IncomingBytes: 91571055,
+				OutgoingBytes: 3084731,
 			},
 		},
-		Label: "my label",
-		Tag:   "my tag",
-		OsID:  "127",
-		AppID: "0",
-	}
-
-	if !reflect.DeepEqual(bm, expected) {
-		t.Errorf("BareMetalServer.GetServer returned %+v, expected %+v", bm, expected)
-	}
-}
-
-func TestBareMetalServerServiceHandler_GetUserData(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/baremetal/get_user_data", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"userdata": "ZWNobyBIZWxsbyBXb3JsZA=="}`
-		fmt.Fprint(writer, response)
-	})
-
-	userData, err := client.BareMetalServer.GetUserData(ctx, "900000")
-
-	if err != nil {
-		t.Errorf("BareMetalServer.GetUserData return %+v ", err)
 	}
 
-	expected := &UserData{UserData: "ZWNobyBIZWxsbyBXb3JsZA=="}
-
-	if !reflect.DeepEqual(userData, expected) {
-		t.Errorf("BareMetalServer.GetUserData returned %+v, expected %+v", userData, expected)
+	if !reflect.DeepEqual(bandwidth, expected) {
+		t.Errorf("BareMetalServer.GetBandwidth returned %+v, expected %+v", bandwidth, expected)
 	}
 }
 
@@ -614,7 +361,7 @@ func TestBareMetalServerServiceHandler_Halt(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/baremetal/halt", func(writer http.ResponseWriter, request *http.Request) {
+	mux.HandleFunc("/v2/bare-metals/900000/halt", func(writer http.ResponseWriter, request *http.Request) {
 		fmt.Fprint(writer)
 	})
 
@@ -625,54 +372,62 @@ func TestBareMetalServerServiceHandler_Halt(t *testing.T) {
 	}
 }
 
-func TestBareMetalServerServiceHandler_IPV4Info(t *testing.T) {
+func TestBareMetalServerServiceHandler_ListIPv4s(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/baremetal/list_ipv4", func(writer http.ResponseWriter, request *http.Request) {
+	mux.HandleFunc("/v2/bare-metals/900000/ipv4", func(writer http.ResponseWriter, request *http.Request) {
 		response := `
 		{
-			"900000": [
+			"ipv4s": [
 				{
 					"ip": "203.0.113.10",
 					"netmask": "255.255.255.0",
 					"gateway": "203.0.113.1",
-					"type": "main_ip"
+					"type": "main_ip",
+					"reverse": "203.0.113.10.vultr.com"
 				}
-			]
+			],
+			"meta": {
+				"total": 1,
+				"links": {
+				"next": "",
+				"prev": ""
+				}
+			}
 		}
 		`
 		fmt.Fprint(writer, response)
 	})
 
-	ipv4, err := client.BareMetalServer.IPV4Info(ctx, "900000")
-
+	ipv4, _, err := client.BareMetalServer.ListIPv4s(ctx, "900000", nil)
 	if err != nil {
-		t.Errorf("BareMetalServer.IPV4Info returned %+v", err)
+		t.Errorf("BareMetalServer.ListIPv4s returned %+v", err)
 	}
 
-	expected := []BareMetalServerIPV4{
+	expected := []IPv4{
 		{
 			IP:      "203.0.113.10",
 			Netmask: "255.255.255.0",
 			Gateway: "203.0.113.1",
 			Type:    "main_ip",
+			Reverse: "203.0.113.10.vultr.com",
 		},
 	}
 
 	if !reflect.DeepEqual(ipv4, expected) {
-		t.Errorf("BareMetalServer.IPV4Info returned %+v, expected %+v", ipv4, expected)
+		t.Errorf("BareMetalServer.ListIPv4s returned %+v, expected %+v", ipv4, expected)
 	}
 }
 
-func TestBareMetalServerServiceHandler_IPV6Info(t *testing.T) {
+func TestBareMetalServerServiceHandler_ListIPv6s(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/baremetal/list_ipv6", func(writer http.ResponseWriter, request *http.Request) {
+	mux.HandleFunc("/v2/bare-metals/900000/ipv6", func(writer http.ResponseWriter, request *http.Request) {
 		response := `
 		{
-			"900000": [
+			"ipv6s": [
 				{
 					"ip": "2001:DB8:9000::100",
 					"network": "2001:DB8:9000::",
@@ -685,13 +440,13 @@ func TestBareMetalServerServiceHandler_IPV6Info(t *testing.T) {
 		fmt.Fprint(writer, response)
 	})
 
-	ipv4, err := client.BareMetalServer.IPV6Info(ctx, "900000")
+	ipv6, _, err := client.BareMetalServer.ListIPv6s(ctx, "900000", nil)
 
 	if err != nil {
 		t.Errorf("BareMetalServer.IPV6Info returned %+v", err)
 	}
 
-	expected := []BareMetalServerIPV6{
+	expected := []IPv6{
 		{
 			IP:          "2001:DB8:9000::100",
 			Network:     "2001:DB8:9000::",
@@ -700,163 +455,344 @@ func TestBareMetalServerServiceHandler_IPV6Info(t *testing.T) {
 		},
 	}
 
-	if !reflect.DeepEqual(ipv4, expected) {
-		t.Errorf("BareMetalServer.IPV6Info returned %+v, expected %+v", ipv4, expected)
+	if !reflect.DeepEqual(ipv6, expected) {
+		t.Errorf("BareMetalServer.ListIPv6s returned %+v, expected %+v", ipv6, expected)
 	}
 }
 
-func TestBareMetalServerServiceHandler_ListApps(t *testing.T) {
+func TestBareMetalServerServiceHandler_Reboot(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/baremetal/app_change_list", func(writer http.ResponseWriter, request *http.Request) {
+	mux.HandleFunc("/v2/bare-metals/900000/reboot", func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
+	})
+
+	err := client.BareMetalServer.Reboot(ctx, "900000")
+
+	if err != nil {
+		t.Errorf("BareMetalServer.Reboot returned %+v, expected %+v", err, nil)
+	}
+}
+
+func TestBareMetalServerServiceHandler_Reinstall(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/bare-metals/900000/reinstall", func(writer http.ResponseWriter, request *http.Request) {
 		response := `
-		{
-			"1": {
-				"APPID": "1",
-				"name": "LEMP",
-				"short_name": "lemp",
-				"deploy_name": "LEMP on CentOS 6 x64",
-				"surcharge": 0
+			{
+				"bare_metal": {
+					"id": "900000",
+					"os": "CentOS 6 x64",
+					"ram": "65536 MB",
+					"disk": "2x 240 GB SSD",
+					"main_ip": "203.0.113.10",
+					"cpu_count": 1,
+					"region": "ewr",
+					"default_password": "ab81u!ryranq",
+					"date_created": "2017-04-12 18:45:41",
+					"status": "active",
+					"netmask_v4": "255.255.255.0",
+					"gateway_v4": "203.0.113.1",
+					"plan": "vbm-4c-32gb",
+					"v6_network": "2001:DB8:9000::",
+					"v6_main_ip": "2001:DB8:9000::100",
+					"v6_network_size": 64,
+					"label": "go-bm-test",
+					"tag": "my tag",
+					"os_id": 127,
+					"app_id": 0
+				}
 			}
-		}
 		`
 		fmt.Fprint(writer, response)
 	})
 
-	application, err := client.BareMetalServer.ListApps(ctx, "900000")
-
+	bm, err := client.BareMetalServer.Reinstall(ctx, "900000")
 	if err != nil {
-		t.Errorf("BareMetalServer.ListApps returned %+v, ", err)
+		t.Errorf("BareMetalServer.Reinstall returned %+v, expected %+v", err, nil)
 	}
 
-	expected := []Application{
-		{
-			AppID:      "1",
-			Name:       "LEMP",
-			ShortName:  "lemp",
-			DeployName: "LEMP on CentOS 6 x64",
-			Surcharge:  0,
-		},
+	expected := &BareMetalServer{
+		ID:              "900000",
+		Os:              "CentOS 6 x64",
+		RAM:             "65536 MB",
+		Disk:            "2x 240 GB SSD",
+		MainIP:          "203.0.113.10",
+		CPUCount:        1,
+		DefaultPassword: "ab81u!ryranq",
+		DateCreated:     "2017-04-12 18:45:41",
+		Status:          "active",
+		NetmaskV4:       "255.255.255.0",
+		GatewayV4:       "203.0.113.1",
+		Plan:            "vbm-4c-32gb",
+		V6Network:       "2001:DB8:9000::",
+		V6MainIP:        "2001:DB8:9000::100",
+		V6NetworkSize:   64,
+		Label:           "go-bm-test",
+		Tag:             "my tag",
+		OsID:            127,
+		Region:          "ewr",
+		AppID:           0,
 	}
 
-	if !reflect.DeepEqual(application, expected) {
-		t.Errorf("BareMetalServer.ListApps returned %+v, expected %+v", application, expected)
+	if !reflect.DeepEqual(bm, expected) {
+		t.Errorf("BareMetalServer.Reinstall returned %+v, expected %+v", bm, expected)
 	}
 }
 
-func TestBareMetalServerServiceHandler_ListOS(t *testing.T) {
+func TestBareMetalServerServiceHandler_Start(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/baremetal/os_change_list", func(writer http.ResponseWriter, request *http.Request) {
-		response := `
-		{
-			"127": {
-				"OSID": "127",
-				"name": "CentOS 6 x64",
-				"arch": "x64",
-				"family": "centos",
-				"windows": false,
-				"surcharge": 0
-			}
-		}
-		`
-		fmt.Fprint(writer, response)
+	mux.HandleFunc("/v2/bare-metals/42018b7b-a4e3-4c7e-be74-663afeb142aa/start", func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
 	})
 
-	os, err := client.BareMetalServer.ListOS(ctx, "900000")
+	err := client.BareMetalServer.Start(ctx, "42018b7b-a4e3-4c7e-be74-663afeb142aa")
 
 	if err != nil {
-		t.Errorf("BareMetalServer.ListOS return %+v ", err)
+		t.Errorf("BareMetalServer.Start returned %+v, expected %+v", err, nil)
 	}
+}
 
-	expected := []OS{
-		{
-			OsID:    127,
-			Name:    "CentOS 6 x64",
-			Arch:    "x64",
-			Family:  "centos",
-			Windows: false,
-		},
+func TestBareMetalServerServiceHandler_GetUserData(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/bare-metals/dev-preview-abc123/user-data", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"user_data": {"data" : "ZWNobyBIZWxsbyBXb3JsZA=="}}`
+		fmt.Fprint(writer, response)
+	})
+
+	userData, err := client.BareMetalServer.GetUserData(ctx, "dev-preview-abc123")
+	if err != nil {
+		t.Errorf("BareMetalServer.GetUserData return %+v ", err)
 	}
 
-	if !reflect.DeepEqual(os, expected) {
-		t.Errorf("BareMetalServer.ListOS returned %+v, expected %+v", os, expected)
+	expected := &UserData{Data: "ZWNobyBIZWxsbyBXb3JsZA=="}
+
+	if !reflect.DeepEqual(userData, expected) {
+		t.Errorf("BareMetalServer.GetUserData returned %+v, expected %+v", userData, expected)
 	}
 }
 
-func TestBareMetalServerServiceHandler_Reboot(t *testing.T) {
+func TestBareMetalServerServiceHandler_GetUpgrades(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/baremetal/reboot", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
+	mux.HandleFunc("/v2/bare-metals/dev-preview-abc123/upgrades", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{
+   "upgrades":{
+      "os":[
+         {
+            "id":127,
+            "name":"CentOS 6 x64",
+            "arch":"x64",
+            "family":"centos"
+         }
+      ],
+      "applications":[
+         {
+            "id":1,
+            "name":"LEMP",
+            "short_name":"lemp",
+            "deploy_name":"LEMP on CentOS 6"
+         }
+      ],
+      "plans":[
+         "vc2-2c-4gb"
+      ]
+   }
+}`
+		fmt.Fprint(writer, response)
 	})
 
-	err := client.BareMetalServer.Reboot(ctx, "900000")
+	server, err := client.BareMetalServer.GetUpgrades(ctx, "dev-preview-abc123")
+	if err != nil {
+		t.Errorf("BareMetalServer.GetUpgrades returned %+v", err)
+	}
+
+	expected := &Upgrades{
+		Applications: []Application{
+			{
+				ID:         1,
+				Name:       "LEMP",
+				ShortName:  "lemp",
+				DeployName: "LEMP on CentOS 6",
+			},
+		},
+		OS: []OS{
+			{
+				ID:     127,
+				Name:   "CentOS 6 x64",
+				Arch:   "x64",
+				Family: "centos",
+			},
+		},
+		Plans: []string{
+			"vc2-2c-4gb",
+		},
+	}
+
+	if !reflect.DeepEqual(server, expected) {
+		t.Errorf("BareMetalServer.GetUpgrades returned %+v, expected %+v", server, expected)
+
+	}
+}
+func TestBareMetalServerServiceHandler_GetVNCUrl(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/bare-metals/dev-preview-abc123/vnc", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"vnc": {"url" : "https://my.vultr.com/subs/baremetal/novnc/api.php?data=djJ8U3ZUTjBYaE3HaCMy1yZ0paVUh8wOldmbw"}}`
+		fmt.Fprint(writer, response)
+	})
 
+	vnc, err := client.BareMetalServer.GetVNCUrl(ctx, "dev-preview-abc123")
 	if err != nil {
-		t.Errorf("BareMetalServer.Reboot returned %+v, expected %+v", err, nil)
+		t.Errorf("BareMetalServer.GetVNCUrl return %+v ", err)
+	}
+
+	expected := &VNCUrl{URL: "https://my.vultr.com/subs/baremetal/novnc/api.php?data=djJ8U3ZUTjBYaE3HaCMy1yZ0paVUh8wOldmbw"}
+
+	if !reflect.DeepEqual(vnc, expected) {
+		t.Errorf("BareMetalServer.GetVNCUrl returned %+v, expected %+v", vnc, expected)
 	}
 }
 
-func TestBareMetalServerServiceHandler_Reinstall(t *testing.T) {
+func TestBareMetalServerServiceHandler_MassStart(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/baremetal/reinstall", func(writer http.ResponseWriter, request *http.Request) {
+	mux.HandleFunc("/v2/bare-metals/start", func(writer http.ResponseWriter, request *http.Request) {
 		fmt.Fprint(writer)
 	})
 
-	err := client.BareMetalServer.Reinstall(ctx, "900000")
+	err := client.BareMetalServer.MassStart(ctx, []string{"42018b7b-a4e3-4c7e-be74-663afeb142aa"})
 
 	if err != nil {
-		t.Errorf("BareMetalServer.Reinstall returned %+v, expected %+v", err, nil)
+		t.Errorf("BareMetalServer.MassStart returned %+v, expected %+v", err, nil)
 	}
 }
 
-func TestBareMetalServerServiceHandler_SetLabel(t *testing.T) {
+func TestBareMetalServerServiceHandler_MassReboot(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/baremetal/label_set", func(writer http.ResponseWriter, request *http.Request) {
+	mux.HandleFunc("/v2/bare-metals/reboot", func(writer http.ResponseWriter, request *http.Request) {
 		fmt.Fprint(writer)
 	})
 
-	err := client.BareMetalServer.SetLabel(ctx, "900000", "new label")
+	err := client.BareMetalServer.MassReboot(ctx, []string{"42018b7b-a4e3-4c7e-be74-663afeb142aa"})
 
 	if err != nil {
-		t.Errorf("BareMetalServer.SetLabel returned %+v, expected %+v", err, nil)
+		t.Errorf("BareMetalServer.Reboot returned %+v, expected %+v", err, nil)
 	}
 }
 
-func TestBareMetalServerServiceHandler_SetTag(t *testing.T) {
+func TestBareMetalServerServiceHandler_MassHalt(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/baremetal/tag_set", func(writer http.ResponseWriter, request *http.Request) {
+	mux.HandleFunc("/v2/bare-metals/halt", func(writer http.ResponseWriter, request *http.Request) {
 		fmt.Fprint(writer)
 	})
 
-	err := client.BareMetalServer.SetTag(ctx, "900000", "new tag")
+	err := client.BareMetalServer.MassHalt(ctx, []string{"42018b7b-a4e3-4c7e-be74-663afeb142aa"})
 
 	if err != nil {
-		t.Errorf("BareMetalServer.SetTag returned %+v, expected %+v", err, nil)
+		t.Errorf("BareMetalServer.MassHalf returned %+v, expected %+v", err, nil)
 	}
 }
 
-func TestBareMetalServerServiceHandler_SetUserData(t *testing.T) {
+func TestBareMetalServerServiceHandler_CreateMarketplaceImage(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/baremetal/set_user_data", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
+	mux.HandleFunc("/v2/bare-metals", func(writer http.ResponseWriter, request *http.Request) {
+		response := `
+			{
+				"bare_metal": {
+					"id": "900000",
+					"os": "CentOS 6 x64",
+					"ram": "65536 MB",
+					"disk": "2x 240 GB SSD",
+					"main_ip": "203.0.113.10",
+					"cpu_count": 1,
+					"region": "ewr",
+					"default_password": "ab81u!ryranq",
+					"date_created": "2017-04-12 18:45:41",
+					"status": "active",
+					"netmask_v4": "255.255.255.0",
+					"gateway_v4": "203.0.113.1",
+					"plan": "vbm-4c-32gb",
+					"v6_network": "2001:DB8:9000::",
+					"v6_main_ip": "2001:DB8:9000::100",
+					"v6_network_size": 64,
+					"mac_address": 0,
+					"label": "go-bm-test",
+					"tag": "my tag",
+					"os_id": 127,
+					"app_id": 0,
+					"image_id": "test"
+				}
+			}
+		`
+		fmt.Fprint(writer, response)
 	})
 
-	err := client.BareMetalServer.SetUserData(ctx, "900000", "user-test-data")
+	options := &BareMetalCreate{
+		StartupScriptID: "1",
+		Region:          "ewr",
+		Plan:            "vbm-4c-32gb",
+		SnapshotID:      "1",
+		EnableIPv6:      BoolToBoolPtr(true),
+		Label:           "go-bm-test",
+		SSHKeyIDs:       []string{"6b80207b1821f"},
+		AppID:           1,
+		UserData:        "echo Hello World",
+		ActivationEmail: BoolToBoolPtr(true),
+		Hostname:        "test",
+		Tag:             "go-test",
+		ReservedIPv4:    "111.111.111.111",
+		PersistentPxe:   BoolToBoolPtr(true),
+		ImageID:         "test",
+	}
+
+	bm, err := client.BareMetalServer.Create(ctx, options)
 
 	if err != nil {
-		t.Errorf("Server.SetUserData return %+v ", err)
+		t.Errorf("BareMetalServer.Create returned error: %v", err)
+	}
+
+	expected := &BareMetalServer{
+		ID:              "900000",
+		Os:              "CentOS 6 x64",
+		RAM:             "65536 MB",
+		Disk:            "2x 240 GB SSD",
+		MainIP:          "203.0.113.10",
+		CPUCount:        1,
+		DefaultPassword: "ab81u!ryranq",
+		DateCreated:     "2017-04-12 18:45:41",
+		Status:          "active",
+		NetmaskV4:       "255.255.255.0",
+		GatewayV4:       "203.0.113.1",
+		Plan:            "vbm-4c-32gb",
+		V6Network:       "2001:DB8:9000::",
+		V6MainIP:        "2001:DB8:9000::100",
+		V6NetworkSize:   64,
+		Label:           "go-bm-test",
+		Tag:             "my tag",
+		MacAddress:      0,
+		OsID:            127,
+		Region:          "ewr",
+		AppID:           0,
+		ImageID:         "test",
+	}
+
+	if !reflect.DeepEqual(bm, expected) {
+		t.Errorf("BareMetalServer.Create returned %+v, expected %+v", bm, expected)
 	}
 }
diff --git a/billing.go b/billing.go
new file mode 100644
index 0000000..f9475d7
--- /dev/null
+++ b/billing.go
@@ -0,0 +1,159 @@
+package govultr
+
+import (
+	"context"
+	"fmt"
+	"net/http"
+
+	"github.com/google/go-querystring/query"
+)
+
+// BillingService is the interface to interact with the billing endpoint on the Vultr API
+// Link : https://www.vultr.com/api/#tag/billing
+type BillingService interface {
+	ListHistory(ctx context.Context, options *ListOptions) ([]History, *Meta, error)
+	ListInvoices(ctx context.Context, options *ListOptions) ([]Invoice, *Meta, error)
+	GetInvoice(ctx context.Context, invoiceID string) (*Invoice, error)
+	ListInvoiceItems(ctx context.Context, invoiceID int, options *ListOptions) ([]InvoiceItem, *Meta, error)
+}
+
+// BillingServiceHandler handles interaction with the billing methods for the Vultr API
+type BillingServiceHandler struct {
+	client *Client
+}
+
+// History represents a billing history item on an account
+type History struct {
+	ID          int     `json:"id"`
+	Date        string  `json:"date"`
+	Type        string  `json:"type"`
+	Description string  `json:"description"`
+	Amount      float32 `json:"amount"`
+	Balance     float32 `json:"balance"`
+}
+
+// Invoice represents an invoice on an account
+type Invoice struct {
+	ID          int     `json:"id"`
+	Date        string  `json:"date"`
+	Description string  `json:"description"`
+	Amount      float32 `json:"amount"`
+	Balance     float32 `json:"balance"`
+}
+
+// InvoiceItem represents an item on an accounts invoice
+type InvoiceItem struct {
+	Description string  `json:"description"`
+	Product     string  `json:"product"`
+	StartDate   string  `json:"start_date"`
+	EndDate     string  `json:"end_date"`
+	Units       int     `json:"units"`
+	UnitType    string  `json:"unit_type"`
+	UnitPrice   float32 `json:"unit_price"`
+	Total       float32 `json:"total"`
+}
+
+type billingHistoryBase struct {
+	History []History `json:"billing_history"`
+	Meta    *Meta     `json:"meta"`
+}
+
+type invoicesBase struct {
+	Invoice []Invoice `json:"billing_invoices"`
+	Meta    *Meta     `json:"meta"`
+}
+
+type invoiceBase struct {
+	Invoice *Invoice `json:"billing_invoice"`
+}
+
+type invoiceItemsBase struct {
+	InvoiceItems []InvoiceItem `json:"invoice_items"`
+	Meta         *Meta         `json:"meta"`
+}
+
+// ListHistory retrieves a list of all billing history on the current account
+func (b *BillingServiceHandler) ListHistory(ctx context.Context, options *ListOptions) ([]History, *Meta, error) {
+	uri := "/v2/billing/history"
+	req, err := b.client.NewRequest(ctx, http.MethodGet, uri, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	newValues, err := query.Values(options)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	req.URL.RawQuery = newValues.Encode()
+
+	invoices := new(billingHistoryBase)
+	if err = b.client.DoWithContext(ctx, req, invoices); err != nil {
+		return nil, nil, err
+	}
+
+	return invoices.History, invoices.Meta, nil
+}
+
+// ListInvoices retrieves a list of all billing invoices on the current account
+func (b *BillingServiceHandler) ListInvoices(ctx context.Context, options *ListOptions) ([]Invoice, *Meta, error) {
+	uri := "/v2/billing/invoices"
+	req, err := b.client.NewRequest(ctx, http.MethodGet, uri, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	newValues, err := query.Values(options)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	req.URL.RawQuery = newValues.Encode()
+
+	invoices := new(invoicesBase)
+	if err = b.client.DoWithContext(ctx, req, invoices); err != nil {
+		return nil, nil, err
+	}
+
+	return invoices.Invoice, invoices.Meta, nil
+}
+
+// GetInvoice retrieves an invoice that matches the given invoiceID
+func (b *BillingServiceHandler) GetInvoice(ctx context.Context, invoiceID string) (*Invoice, error) {
+	uri := fmt.Sprintf("/v2/billing/invoices/%s", invoiceID)
+	req, err := b.client.NewRequest(ctx, http.MethodGet, uri, nil)
+
+	if err != nil {
+		return nil, err
+	}
+
+	invoice := new(invoiceBase)
+	if err := b.client.DoWithContext(ctx, req, invoice); err != nil {
+		return nil, err
+	}
+
+	return invoice.Invoice, nil
+}
+
+// ListInvoiceItems retrieves items in an invoice that matches the given invoiceID
+func (b *BillingServiceHandler) ListInvoiceItems(ctx context.Context, invoiceID int, options *ListOptions) ([]InvoiceItem, *Meta, error) {
+	uri := fmt.Sprintf("/v2/billing/invoices/%d/items", invoiceID)
+	req, err := b.client.NewRequest(ctx, http.MethodGet, uri, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	newValues, err := query.Values(options)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	req.URL.RawQuery = newValues.Encode()
+
+	invoice := new(invoiceItemsBase)
+	if err := b.client.DoWithContext(ctx, req, invoice); err != nil {
+		return nil, nil, err
+	}
+
+	return invoice.InvoiceItems, invoice.Meta, nil
+}
diff --git a/billing_test.go b/billing_test.go
new file mode 100644
index 0000000..44aee00
--- /dev/null
+++ b/billing_test.go
@@ -0,0 +1,323 @@
+package govultr
+
+import (
+	"fmt"
+	"net/http"
+	"reflect"
+	"testing"
+)
+
+func TestBillingServiceHandler_ListHistory(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/billing/history", func(w http.ResponseWriter, r *http.Request) {
+
+		response := `
+		{
+			"billing_history": [
+				{
+					"id": 5317720,
+					"date": "2018-04-01T00:30:05+00:00",
+					"type": "invoice",
+					"description": "Invoice #5317720",
+					"amount": 2.35,
+					"balance": -497.65
+				  }
+			],
+			"meta": {
+				"total":1,
+				"links": {
+					"next":"",
+					"prev":""
+				}
+			}
+		}
+		`
+
+		fmt.Fprint(w, response)
+	})
+
+	history, meta, err := client.Billing.ListHistory(ctx, nil)
+	if err != nil {
+		t.Errorf("Billing.ListHistory returned error: %v", err)
+	}
+
+	expected := []History{
+		{
+			ID:          5317720,
+			Date:        "2018-04-01T00:30:05+00:00",
+			Type:        "invoice",
+			Description: "Invoice #5317720",
+			Amount:      2.35,
+			Balance:     -497.65,
+		},
+	}
+
+	expectedMeta := &Meta{
+		Total: 1,
+		Links: &Links{},
+	}
+
+	if !reflect.DeepEqual(history, expected) {
+		t.Errorf("Billing.ListHistory returned %+v, expected %+v", history, expected)
+	}
+
+	if !reflect.DeepEqual(meta, expectedMeta) {
+		t.Errorf("Billing.ListHistory returned %+v, expected %+v", meta, expectedMeta)
+	}
+}
+
+func TestBillingServiceHandler_ListInvoices(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/billing/invoices", func(w http.ResponseWriter, r *http.Request) {
+
+		response := `
+		{
+			"billing_invoices": [
+				{
+					"id": 5317720,
+					"date": "2018-04-01T00:30:05+00:00",
+					"description": "Invoice #5317720",
+					"amount": 2.35,
+					"balance": -497.65
+				  }
+			],
+			"meta": {
+				"total":1,
+				"links": {
+					"next":"",
+					"prev":""
+				}
+			}
+		}
+		`
+
+		fmt.Fprint(w, response)
+	})
+
+	invoices, meta, err := client.Billing.ListInvoices(ctx, nil)
+	if err != nil {
+		t.Errorf("Billing.ListInvoices returned error: %v", err)
+	}
+
+	expected := []Invoice{
+		{
+			ID:          5317720,
+			Date:        "2018-04-01T00:30:05+00:00",
+			Description: "Invoice #5317720",
+			Amount:      2.35,
+			Balance:     -497.65,
+		},
+	}
+
+	expectedMeta := &Meta{
+		Total: 1,
+		Links: &Links{},
+	}
+
+	if !reflect.DeepEqual(invoices, expected) {
+		t.Errorf("Billing.ListInvoices returned %+v, expected %+v", invoices, expected)
+	}
+
+	if !reflect.DeepEqual(meta, expectedMeta) {
+		t.Errorf("Billing.ListInvoices returned %+v, expected %+v", meta, expectedMeta)
+	}
+}
+
+func TestBillingServiceHandler_ListHistoryEmpty(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/billing/history", func(w http.ResponseWriter, r *http.Request) {
+
+		response := `
+		{
+			"billing_history": [],
+			"meta": {
+				"total":0,
+				"links": {
+					"next":"",
+					"prev":""
+				}
+			}
+		}
+		`
+
+		fmt.Fprint(w, response)
+	})
+
+	history, meta, err := client.Billing.ListHistory(ctx, nil)
+	if err != nil {
+		t.Errorf("Billing.ListHistory returned error: %v", err)
+	}
+
+	expected := []History{}
+
+	if !reflect.DeepEqual(history, expected) {
+		t.Errorf("Billing.ListHistory returned %+v, expected %+v", history, expected)
+	}
+
+	expectedMeta := &Meta{
+		Total: 0,
+		Links: &Links{
+			Next: "",
+			Prev: "",
+		},
+	}
+
+	if !reflect.DeepEqual(meta, expectedMeta) {
+		t.Errorf("Billing.ListHistory meta returned %+v, expected %+v", meta, expectedMeta)
+	}
+}
+
+func TestBillingServiceHandler_ListInvoicesEmpty(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/billing/invoices", func(w http.ResponseWriter, r *http.Request) {
+
+		response := `
+		{
+			"billing_invoices": [],
+			"meta": {
+				"total":0,
+				"links": {
+					"next":"",
+					"prev":""
+				}
+			}
+		}
+		`
+
+		fmt.Fprint(w, response)
+	})
+
+	invoices, meta, err := client.Billing.ListInvoices(ctx, nil)
+	if err != nil {
+		t.Errorf("Billing.ListInvoices returned error: %v", err)
+	}
+
+	expected := []Invoice{}
+
+	if !reflect.DeepEqual(invoices, expected) {
+		t.Errorf("Billing.ListInvoices returned %+v, expected %+v", invoices, expected)
+	}
+
+	expectedMeta := &Meta{
+		Total: 0,
+		Links: &Links{
+			Next: "",
+			Prev: "",
+		},
+	}
+
+	if !reflect.DeepEqual(meta, expectedMeta) {
+		t.Errorf("Billing.ListInvoices meta returned %+v, expected %+v", meta, expectedMeta)
+	}
+}
+
+func TestBillingServiceHandler_GetInvoice(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/billing/invoices/123456", func(w http.ResponseWriter, r *http.Request) {
+
+		response := `
+		{
+			"billing_invoice": {
+				"id": 123456,
+				"date": "2018-04-01T00:30:05+00:00",
+				"description": "Invoice #5317782",
+				"amount": 2.35,
+				"balance": -497.65
+			  }
+		}
+		`
+
+		fmt.Fprint(w, response)
+	})
+
+	invoice, err := client.Billing.GetInvoice(ctx, "123456")
+	if err != nil {
+		t.Errorf("Billing.GetInvoice returned error: %v", err)
+	}
+
+	expected := &Invoice{
+		ID:          123456,
+		Date:        "2018-04-01T00:30:05+00:00",
+		Description: "Invoice #5317782",
+		Amount:      2.35,
+		Balance:     -497.65,
+	}
+
+	if !reflect.DeepEqual(invoice, expected) {
+		t.Errorf("Billing.GetInvoice returned %+v, expected %+v", invoice, expected)
+	}
+}
+
+func TestBillingServiceHandler_ListInvoiceItems(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/billing/invoices/123456/items", func(w http.ResponseWriter, r *http.Request) {
+
+		response := `
+		{
+			"invoice_items": [
+				{
+					"description": "1.1.1.1 (1024 MB)",
+					"product": "Vultr Cloud Compute",
+					"start_date": "2018-03-18T21:57:58+00:00",
+					"end_date": "2018-04-01T00:00:00+00:00",
+					"units": 315,
+					"unit_type": "hours",
+					"unit_price": 0.0074,
+					"total": 2.35
+				}
+			],
+			"meta": {
+				"total":1,
+				"links": {
+					"next":"",
+					"prev":""
+				}
+			}
+		}
+		`
+
+		fmt.Fprint(w, response)
+	})
+	invoices, meta, err := client.Billing.ListInvoiceItems(ctx, 123456, nil)
+	if err != nil {
+		t.Errorf("Billing.ListInvoiceItems returned error: %v", err)
+	}
+
+	expected := []InvoiceItem{
+		{
+			Description: "1.1.1.1 (1024 MB)",
+			Product:     "Vultr Cloud Compute",
+			StartDate:   "2018-03-18T21:57:58+00:00",
+			EndDate:     "2018-04-01T00:00:00+00:00",
+			Units:       315,
+			UnitType:    "hours",
+			UnitPrice:   0.0074,
+			Total:       2.35,
+		},
+	}
+
+	expectedMeta := &Meta{
+		Total: 1,
+		Links: &Links{},
+	}
+
+	if !reflect.DeepEqual(invoices, expected) {
+		t.Errorf("Billing.ListInvoiceItems returned %+v, expected %+v", invoices, expected)
+	}
+
+	if !reflect.DeepEqual(meta, expectedMeta) {
+		t.Errorf("Billing.ListInvoiceItems returned %+v, expected %+v", meta, expectedMeta)
+	}
+}
diff --git a/block_storage.go b/block_storage.go
index d89dbd9..2abfebb 100644
--- a/block_storage.go
+++ b/block_storage.go
@@ -2,24 +2,23 @@ package govultr
 
 import (
 	"context"
-	"encoding/json"
 	"fmt"
 	"net/http"
-	"net/url"
-	"strconv"
+
+	"github.com/google/go-querystring/query"
 )
 
 // BlockStorageService is the interface to interact with Block-Storage endpoint on the Vultr API
-// Link: https://www.vultr.com/api/#block
+// Link : https://www.vultr.com/api/#tag/block
 type BlockStorageService interface {
-	Attach(ctx context.Context, blockID, InstanceID, liveAttach string) error
-	Create(ctx context.Context, regionID, size int, label string) (*BlockStorage, error)
-	Delete(ctx context.Context, blockID string) error
-	Detach(ctx context.Context, blockID, liveDetach string) error
-	SetLabel(ctx context.Context, blockID, label string) error
-	List(ctx context.Context) ([]BlockStorage, error)
+	Create(ctx context.Context, blockReq *BlockStorageCreate) (*BlockStorage, error)
 	Get(ctx context.Context, blockID string) (*BlockStorage, error)
-	Resize(ctx context.Context, blockID string, size int) error
+	Update(ctx context.Context, blockID string, blockReq *BlockStorageUpdate) error
+	Delete(ctx context.Context, blockID string) error
+	List(ctx context.Context, options *ListOptions) ([]BlockStorage, *Meta, error)
+
+	Attach(ctx context.Context, blockID string, attach *BlockStorageAttach) error
+	Detach(ctx context.Context, blockID string, detach *BlockStorageDetach) error
 }
 
 // BlockStorageServiceHandler handles interaction with the block-storage methods for the Vultr API
@@ -29,301 +28,154 @@ type BlockStorageServiceHandler struct {
 
 // BlockStorage represents Vultr Block-Storage
 type BlockStorage struct {
-	BlockStorageID string `json:"SUBID"`
-	DateCreated    string `json:"date_created"`
-	CostPerMonth   string `json:"cost_per_month"`
-	Status         string `json:"status"`
-	SizeGB         int    `json:"size_gb"`
-	RegionID       int    `json:"DCID"`
-	InstanceID     string `json:"attached_to_SUBID"`
-	Label          string `json:"label"`
+	ID                 string  `json:"id"`
+	Cost               float32 `json:"cost"`
+	Status             string  `json:"status"`
+	SizeGB             int     `json:"size_gb"`
+	Region             string  `json:"region"`
+	DateCreated        string  `json:"date_created"`
+	AttachedToInstance string  `json:"attached_to_instance"`
+	Label              string  `json:"label"`
+	MountID            string  `json:"mount_id"`
 }
 
-// UnmarshalJSON implements json.Unmarshaller on BlockStorage to handle the inconsistent types returned from the Vultr v1 API.
-func (b *BlockStorage) UnmarshalJSON(data []byte) (err error) {
-	if b == nil {
-		*b = BlockStorage{}
-	}
-
-	var v map[string]interface{}
-	if err := json.Unmarshal(data, &v); err != nil {
-		return err
-	}
-
-	b.BlockStorageID, err = b.unmarshalStr(fmt.Sprintf("%v", v["SUBID"]))
-	if err != nil {
-		return err
-	}
-
-	b.RegionID, err = b.unmarshalInt(fmt.Sprintf("%v", v["DCID"]))
-	if err != nil {
-		return err
-	}
-
-	b.SizeGB, err = b.unmarshalInt(fmt.Sprintf("%v", v["size_gb"]))
-	if err != nil {
-		return err
-	}
-
-	b.InstanceID, err = b.unmarshalStr(fmt.Sprintf("%v", v["attached_to_SUBID"]))
-	if err != nil {
-		return err
-	}
-
-	b.CostPerMonth, err = b.unmarshalStr(fmt.Sprintf("%v", v["cost_per_month"]))
-	if err != nil {
-		return err
-	}
-
-	date := fmt.Sprintf("%v", v["date_created"])
-	if date == "<nil>" {
-		date = ""
-	}
-	b.DateCreated = date
-
-	status := fmt.Sprintf("%v", v["status"])
-	if status == "<nil>" {
-		status = ""
-	}
-	b.Status = status
-
-	b.Label = fmt.Sprintf("%v", v["label"])
-
-	return nil
+// BlockStorageCreate struct is used for creating Block Storage.
+type BlockStorageCreate struct {
+	Region string `json:"region"`
+	SizeGB int    `json:"size_gb"`
+	Label  string `json:"label,omitempty"`
 }
 
-func (b *BlockStorage) unmarshalInt(value string) (int, error) {
-	if len(value) == 0 || value == "<nil>" {
-		value = "0"
-	}
-
-	i, err := strconv.ParseInt(value, 10, 64)
-	if err != nil {
-		return 0, err
-	}
-
-	return int(i), nil
+// BlockStorageUpdate struct is used to update Block Storage.
+type BlockStorageUpdate struct {
+	SizeGB int    `json:"size_gb,omitempty"`
+	Label  string `json:"label,omitempty"`
 }
 
-func (b *BlockStorage) unmarshalStr(value string) (string, error) {
-	if len(value) == 0 || value == "<nil>" || value == "0" || value == "false" {
-		return "", nil
-	}
-
-	f, err := strconv.ParseFloat(value, 64)
-	if err != nil {
-		return "", err
-	}
-
-	return strconv.FormatFloat(f, 'f', -1, 64), nil
+// BlockStorageAttach struct used to define if a attach should be restart the instance.
+type BlockStorageAttach struct {
+	InstanceID string `json:"instance_id"`
+	Live       *bool  `json:"live,omitempty"`
 }
 
-// Attach will link a given block storage to a given Vultr vps
-// If liveAttach is set to "yes" the block storage will be attached without reloading the instance
-func (b *BlockStorageServiceHandler) Attach(ctx context.Context, blockID, InstanceID, liveAttach string) error {
-
-	uri := "/v1/block/attach"
-
-	values := url.Values{
-		"SUBID":           {blockID},
-		"attach_to_SUBID": {InstanceID},
-	}
-
-	if liveAttach == "yes" {
-		values.Add("live", "yes")
-	}
-
-	req, err := b.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = b.client.DoWithContext(ctx, req, nil)
+// BlockStorageDetach struct used to define if a detach should be restart the instance.
+type BlockStorageDetach struct {
+	Live *bool `json:"live,omitempty"`
+}
 
-	if err != nil {
-		return err
-	}
+type blockStoragesBase struct {
+	Blocks []BlockStorage `json:"blocks"`
+	Meta   *Meta          `json:"meta"`
+}
 
-	return nil
+type blockStorageBase struct {
+	Block *BlockStorage `json:"block"`
 }
 
 // Create builds out a block storage
-func (b *BlockStorageServiceHandler) Create(ctx context.Context, regionID, sizeGB int, label string) (*BlockStorage, error) {
-
-	uri := "/v1/block/create"
-
-	values := url.Values{
-		"DCID":    {strconv.Itoa(regionID)},
-		"size_gb": {strconv.Itoa(sizeGB)},
-		"label":   {label},
-	}
-
-	req, err := b.client.NewRequest(ctx, http.MethodPost, uri, values)
+func (b *BlockStorageServiceHandler) Create(ctx context.Context, blockReq *BlockStorageCreate) (*BlockStorage, error) {
+	uri := "/v2/blocks"
 
+	req, err := b.client.NewRequest(ctx, http.MethodPost, uri, blockReq)
 	if err != nil {
 		return nil, err
 	}
 
-	blockStorage := new(BlockStorage)
-
-	err = b.client.DoWithContext(ctx, req, blockStorage)
-
-	if err != nil {
+	block := new(blockStorageBase)
+	if err = b.client.DoWithContext(ctx, req, block); err != nil {
 		return nil, err
 	}
 
-	blockStorage.RegionID = regionID
-	blockStorage.Label = label
-	blockStorage.SizeGB = sizeGB
-
-	return blockStorage, nil
+	return block.Block, nil
 }
 
-// Delete will remove block storage instance from your Vultr account
-func (b *BlockStorageServiceHandler) Delete(ctx context.Context, blockID string) error {
-
-	uri := "/v1/block/delete"
-
-	values := url.Values{
-		"SUBID": {blockID},
-	}
-
-	req, err := b.client.NewRequest(ctx, http.MethodPost, uri, values)
+// Get returns a single block storage instance based ony our blockID you provide from your Vultr Account
+func (b *BlockStorageServiceHandler) Get(ctx context.Context, blockID string) (*BlockStorage, error) {
+	uri := fmt.Sprintf("/v2/blocks/%s", blockID)
 
+	req, err := b.client.NewRequest(ctx, http.MethodGet, uri, nil)
 	if err != nil {
-		return err
+		return nil, err
 	}
 
-	err = b.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
+	block := new(blockStorageBase)
+	if err = b.client.DoWithContext(ctx, req, block); err != nil {
+		return nil, err
 	}
 
-	return nil
+	return block.Block, nil
 }
 
-// Detach will de-link a given block storage to the Vultr vps it is attached to
-// If liveDetach is set to "yes" the block storage will be detached without reloading the instance
-func (b *BlockStorageServiceHandler) Detach(ctx context.Context, blockID, liveDetach string) error {
-
-	uri := "/v1/block/detach"
-
-	values := url.Values{
-		"SUBID": {blockID},
-	}
-
-	if liveDetach == "yes" {
-		values.Add("live", "yes")
-	}
-
-	req, err := b.client.NewRequest(ctx, http.MethodPost, uri, values)
+// Update a block storage subscription.
+func (b *BlockStorageServiceHandler) Update(ctx context.Context, blockID string, blockReq *BlockStorageUpdate) error {
+	uri := fmt.Sprintf("/v2/blocks/%s", blockID)
 
+	req, err := b.client.NewRequest(ctx, http.MethodPatch, uri, blockReq)
 	if err != nil {
 		return err
 	}
 
-	err = b.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
+	return b.client.DoWithContext(ctx, req, nil)
 }
 
-// SetLabel allows you to set/update the label on your Vultr Block storage
-func (b *BlockStorageServiceHandler) SetLabel(ctx context.Context, blockID, label string) error {
-	uri := "/v1/block/label_set"
-
-	values := url.Values{
-		"SUBID": {blockID},
-		"label": {label},
-	}
-
-	req, err := b.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = b.client.DoWithContext(ctx, req, nil)
+// Delete a block storage subscription from your Vultr account
+func (b *BlockStorageServiceHandler) Delete(ctx context.Context, blockID string) error {
+	uri := fmt.Sprintf("/v2/blocks/%s", blockID)
 
+	req, err := b.client.NewRequest(ctx, http.MethodDelete, uri, nil)
 	if err != nil {
 		return err
 	}
 
-	return nil
+	return b.client.DoWithContext(ctx, req, nil)
 }
 
 // List returns a list of all block storage instances on your Vultr Account
-func (b *BlockStorageServiceHandler) List(ctx context.Context) ([]BlockStorage, error) {
-
-	uri := "/v1/block/list"
+func (b *BlockStorageServiceHandler) List(ctx context.Context, options *ListOptions) ([]BlockStorage, *Meta, error) {
+	uri := "/v2/blocks"
 
 	req, err := b.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
 	if err != nil {
-		return nil, err
-	}
-
-	var blockStorage []BlockStorage
-	err = b.client.DoWithContext(ctx, req, &blockStorage)
-
-	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	return blockStorage, nil
-}
-
-// Get returns a single block storage instance based ony our blockID you provide from your Vultr Account
-func (b *BlockStorageServiceHandler) Get(ctx context.Context, blockID string) (*BlockStorage, error) {
-
-	uri := "/v1/block/list"
-
-	req, err := b.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
+	newValues, err := query.Values(options)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	q := req.URL.Query()
-	q.Add("SUBID", blockID)
-	req.URL.RawQuery = q.Encode()
-
-	blockStorage := new(BlockStorage)
-	err = b.client.DoWithContext(ctx, req, blockStorage)
+	req.URL.RawQuery = newValues.Encode()
 
-	if err != nil {
-		return nil, err
+	blocks := new(blockStoragesBase)
+	if err = b.client.DoWithContext(ctx, req, blocks); err != nil {
+		return nil, nil, err
 	}
 
-	return blockStorage, nil
+	return blocks.Blocks, blocks.Meta, nil
 }
 
-// Resize allows you to resize your Vultr block storage instance
-func (b *BlockStorageServiceHandler) Resize(ctx context.Context, blockID string, sizeGB int) error {
-
-	uri := "/v1/block/resize"
-
-	values := url.Values{
-		"SUBID":   {blockID},
-		"size_gb": {strconv.Itoa(sizeGB)},
-	}
-
-	req, err := b.client.NewRequest(ctx, http.MethodPost, uri, values)
+// Attach will link a given block storage to a given Vultr instance
+// If Live is set to true the block storage will be attached without reloading the instance
+func (b *BlockStorageServiceHandler) Attach(ctx context.Context, blockID string, attach *BlockStorageAttach) error {
+	uri := fmt.Sprintf("/v2/blocks/%s/attach", blockID)
 
+	req, err := b.client.NewRequest(ctx, http.MethodPost, uri, attach)
 	if err != nil {
 		return err
 	}
 
-	err = b.client.DoWithContext(ctx, req, nil)
+	return b.client.DoWithContext(ctx, req, nil)
+}
+
+// Detach will de-link a given block storage to the Vultr instance it is attached to
+// If Live is set to true the block storage will be detached without reloading the instance
+func (b *BlockStorageServiceHandler) Detach(ctx context.Context, blockID string, detach *BlockStorageDetach) error {
+	uri := fmt.Sprintf("/v2/blocks/%s/detach", blockID)
 
+	req, err := b.client.NewRequest(ctx, http.MethodPost, uri, detach)
 	if err != nil {
 		return err
 	}
 
-	return nil
+	return b.client.DoWithContext(ctx, req, nil)
 }
diff --git a/block_storage_test.go b/block_storage_test.go
index 3431a0c..f934482 100644
--- a/block_storage_test.go
+++ b/block_storage_test.go
@@ -7,85 +7,100 @@ import (
 	"testing"
 )
 
-func TestBlockStorageServiceHandler_Attach(t *testing.T) {
+func TestBlockStorageServiceHandler_Create(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/block/attach", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
+	mux.HandleFunc("/v2/blocks", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"block":{"id":"123456","cost":10,"status":"active","size_gb":100,"region":"ewr","attached_to_instance":"","date_created":"01-01-1960","label":"mylabel", "mount_id": "ewr-123abc"}}`
+		fmt.Fprint(writer, response)
 	})
+	blockReq := &BlockStorageCreate{
+		Region: "ewr",
+		SizeGB: 100,
+		Label:  "mylabel",
+	}
+	blockStorage, err := client.BlockStorage.Create(ctx, blockReq)
+	if err != nil {
+		t.Errorf("BlockStorage.Create returned error: %v", err)
+	}
 
-	err := client.BlockStorage.Attach(ctx, "123456", "876521", "yes")
+	expected := &BlockStorage{
+		ID:                 "123456",
+		Cost:               10,
+		Status:             "active",
+		SizeGB:             100,
+		Region:             "ewr",
+		DateCreated:        "01-01-1960",
+		AttachedToInstance: "",
+		Label:              "mylabel",
+		MountID:            "ewr-123abc",
+	}
 
-	if err != nil {
-		t.Errorf("BlockStorage.Attach returned %+v, expected %+v", err, nil)
+	if !reflect.DeepEqual(blockStorage, expected) {
+		t.Errorf("BlockStorage.Create returned %+v, expected %+v", blockStorage, expected)
 	}
 }
 
-func TestBlockStorageServiceHandler_Create(t *testing.T) {
+func TestBlockStorageServiceHandler_Get(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/block/create", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"SUBID": "1234566"}`
+	mux.HandleFunc("/v2/blocks/123456", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"block":{"id":"123456","cost":10,"status":"active","size_gb":100,"region":"ewr","attached_to_instance":"","date_created":"01-01-1960","label":"mylabel", "mount_id": "123abc"}}`
 		fmt.Fprint(writer, response)
 	})
 
-	blockStorage, err := client.BlockStorage.Create(ctx, 1, 10, "unit-test")
-
+	blockStorage, err := client.BlockStorage.Get(ctx, "123456")
 	if err != nil {
 		t.Errorf("BlockStorage.Create returned error: %v", err)
 	}
 
-	expected := &BlockStorage{BlockStorageID: "1234566", RegionID: 1, SizeGB: 10, Label: "unit-test"}
+	expected := &BlockStorage{
+		ID:                 "123456",
+		Cost:               10,
+		Status:             "active",
+		SizeGB:             100,
+		Region:             "ewr",
+		DateCreated:        "01-01-1960",
+		AttachedToInstance: "",
+		Label:              "mylabel",
+		MountID:            "123abc",
+	}
 
 	if !reflect.DeepEqual(blockStorage, expected) {
 		t.Errorf("BlockStorage.Create returned %+v, expected %+v", blockStorage, expected)
 	}
 }
 
-func TestBlockStorageServiceHandler_Delete(t *testing.T) {
+func TestBlockStorageServiceHandler_Update(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/block/delete", func(writer http.ResponseWriter, request *http.Request) {
+	mux.HandleFunc("/v2/blocks/123456", func(writer http.ResponseWriter, request *http.Request) {
 		fmt.Fprint(writer)
 	})
 
-	err := client.BlockStorage.Delete(ctx, "123456")
-
-	if err != nil {
-		t.Errorf("BlockStorage.Delete returned %+v, expected %+v", err, nil)
+	blockUpdate := &BlockStorageUpdate{
+		Label: "unit-test-label-setter",
 	}
-}
-
-func TestBlockStorageServiceHandler_Detach(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/block/detach", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.BlockStorage.Detach(ctx, "123456", "yes")
-
+	err := client.BlockStorage.Update(ctx, "123456", blockUpdate)
 	if err != nil {
-		t.Errorf("BlockStorage.Detach returned %+v, expected %+v", err, nil)
+		t.Errorf("BlockStorage.SetLabel returned %+v, expected %+v", err, nil)
 	}
 }
 
-func TestBlockStorageServiceHandler_SetLabel(t *testing.T) {
+func TestBlockStorageServiceHandler_Delete(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/block/label_set", func(writer http.ResponseWriter, request *http.Request) {
+	mux.HandleFunc("/v2/blocks/123456", func(writer http.ResponseWriter, request *http.Request) {
 		fmt.Fprint(writer)
 	})
 
-	err := client.BlockStorage.SetLabel(ctx, "123456", "unit-test-label-setter")
-
+	err := client.BlockStorage.Delete(ctx, "123456")
 	if err != nil {
-		t.Errorf("BlockStorage.SetLabel returned %+v, expected %+v", err, nil)
+		t.Errorf("BlockStorage.Delete returned %+v, expected %+v", err, nil)
 	}
 }
 
@@ -93,93 +108,75 @@ func TestBlockStorageServiceHandler_List(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/block/list", func(writer http.ResponseWriter, request *http.Request) {
-		response := `[
-	 	{
-        	"SUBID": 1313216,
-        	"date_created": "2016-03-29 10:10:04",
-        	"cost_per_month": 10,
-        	"status": "pending",
-        	"size_gb": 100,
-        	"DCID": 1,
-        	"attached_to_SUBID": "100",
-        	"label": "files1"
-    	},
-		{
-        	"SUBID": 1313216,
-        	"date_created": "2016-03-29 10:10:04",
-        	"cost_per_month": 10,
-        	"status": "pending",
-        	"size_gb": 100,
-        	"DCID": 1,
-        	"attached_to_SUBID": null,
-        	"label": "files1"
-    	}
-		]
-		`
+	mux.HandleFunc("/v2/blocks", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"blocks":[{"id":"123456","cost":10,"status":"active","size_gb":100,"region":"ewr","attached_to_instance":"","date_created":"01-01-1960","label":"mylabel", "mount_id": "123abc"}],"meta":{"total":1,"links":{"next":"thisismycusror","prev":""}}}`
 		fmt.Fprint(writer, response)
 	})
 
-	blockStorage, err := client.BlockStorage.List(ctx)
-
+	blockStorage, meta, err := client.BlockStorage.List(ctx, nil)
 	if err != nil {
-		t.Errorf("BlockStorage.Get returned error: %v", err)
+		t.Errorf("BlockStorage.Create returned error: %v", err)
 	}
 
 	expected := []BlockStorage{
-		{BlockStorageID: "1313216", DateCreated: "2016-03-29 10:10:04", CostPerMonth: "10", Status: "pending", SizeGB: 100, RegionID: 1, InstanceID: "100", Label: "files1"},
-		{BlockStorageID: "1313216", DateCreated: "2016-03-29 10:10:04", CostPerMonth: "10", Status: "pending", SizeGB: 100, RegionID: 1, InstanceID: "", Label: "files1"},
+		{
+			ID:                 "123456",
+			Cost:               10,
+			Status:             "active",
+			SizeGB:             100,
+			Region:             "ewr",
+			DateCreated:        "01-01-1960",
+			AttachedToInstance: "",
+			Label:              "mylabel",
+			MountID:            "123abc",
+		},
 	}
 
 	if !reflect.DeepEqual(blockStorage, expected) {
-		t.Errorf("BlockStorage.Get returned %+v, expected %+v", blockStorage, expected)
+		t.Errorf("BlockStorage.Create returned %+v, expected %+v", blockStorage, expected)
+	}
+
+	expectedMeta := &Meta{
+		Total: 1,
+		Links: &Links{
+			Next: "thisismycusror",
+			Prev: "",
+		},
+	}
+
+	if !reflect.DeepEqual(meta, expectedMeta) {
+		t.Errorf("User.List meta returned %+v, expected %+v", meta, expectedMeta)
 	}
 }
 
-func TestBlockStorageServiceHandler_Get(t *testing.T) {
+func TestBlockStorageServiceHandler_Attach(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/block/list", func(writer http.ResponseWriter, request *http.Request) {
-		response := `
-	 	{
-        	"SUBID": 1313216,
-        	"date_created": "2016-03-29 10:10:04",
-        	"cost_per_month": 10,
-        	"status": "pending",
-        	"size_gb": 100,
-        	"DCID": 1,
-        	"attached_to_SUBID": null,
-        	"label": "files1"
-    	}
-		`
-		fmt.Fprint(writer, response)
+	mux.HandleFunc("/v2/blocks/12345/attach", func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
 	})
 
-	blockStorage, err := client.BlockStorage.Get(ctx, "1313216")
-
-	if err != nil {
-		t.Errorf("BlockStorage.Get returned error: %v", err)
+	attach := &BlockStorageAttach{
+		InstanceID: "1234",
+		Live:       BoolToBoolPtr(true),
 	}
-
-	expected := &BlockStorage{BlockStorageID: "1313216", DateCreated: "2016-03-29 10:10:04", CostPerMonth: "10", Status: "pending", SizeGB: 100, RegionID: 1, InstanceID: "", Label: "files1"}
-
-	if !reflect.DeepEqual(blockStorage, expected) {
-		t.Errorf("BlockStorage.Get returned %+v, expected %+v", blockStorage, expected)
+	err := client.BlockStorage.Attach(ctx, "12345", attach)
+	if err != nil {
+		t.Errorf("BlockStorage.Attach returned %+v, expected %+v", err, nil)
 	}
 }
 
-func TestBlockStorageServiceHandler_Resize(t *testing.T) {
+func TestBlockStorageServiceHandler_Detach(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/block/resize", func(writer http.ResponseWriter, request *http.Request) {
+	mux.HandleFunc("/v2/blocks/123456/detach", func(writer http.ResponseWriter, request *http.Request) {
 		fmt.Fprint(writer)
 	})
-
-	err := client.BlockStorage.Resize(ctx, "123456", 50)
-
+	detach := &BlockStorageDetach{Live: BoolToBoolPtr(true)}
+	err := client.BlockStorage.Detach(ctx, "123456", detach)
 	if err != nil {
-		t.Errorf("BlockStorage.Resize returned %+v, expected %+v", err, nil)
+		t.Errorf("BlockStorage.Detach returned %+v, expected %+v", err, nil)
 	}
 }
diff --git a/dns_domains.go b/dns_domains.go
deleted file mode 100644
index dbd9913..0000000
--- a/dns_domains.go
+++ /dev/null
@@ -1,209 +0,0 @@
-package govultr
-
-import (
-	"context"
-	"net/http"
-	"net/url"
-)
-
-// DNSDomainService is the interface to interact with the DNS endpoints on the Vultr API
-// Link: https://www.vultr.com/api/#dns
-type DNSDomainService interface {
-	Create(ctx context.Context, domain, InstanceIP string) error
-	Delete(ctx context.Context, domain string) error
-	ToggleDNSSec(ctx context.Context, domain string, enabled bool) error
-	DNSSecInfo(ctx context.Context, domain string) ([]string, error)
-	List(ctx context.Context) ([]DNSDomain, error)
-	GetSoa(ctx context.Context, domain string) (*Soa, error)
-	UpdateSoa(ctx context.Context, domain, nsPrimary, email string) error
-}
-
-// DNSDomainServiceHandler handles interaction with the DNS methods for the Vultr API
-type DNSDomainServiceHandler struct {
-	client *Client
-}
-
-// DNSDomain represents a DNS Domain entry on Vultr
-type DNSDomain struct {
-	Domain      string `json:"domain"`
-	DateCreated string `json:"date_created"`
-}
-
-// Soa represents record information for a domain on Vultr
-type Soa struct {
-	NsPrimary string `json:"nsprimary"`
-	Email     string `json:"email"`
-}
-
-// Create will create a DNS Domain entry on Vultr
-func (d *DNSDomainServiceHandler) Create(ctx context.Context, domain, InstanceIP string) error {
-
-	uri := "/v1/dns/create_domain"
-
-	values := url.Values{
-		"domain":   {domain},
-		"serverip": {InstanceIP},
-	}
-
-	req, err := d.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = d.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-//Delete will delete a domain name and all associated records
-func (d *DNSDomainServiceHandler) Delete(ctx context.Context, domain string) error {
-	uri := "/v1/dns/delete_domain"
-
-	values := url.Values{
-		"domain": {domain},
-	}
-
-	req, err := d.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = d.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// ToggleDNSSec will enable or disable DNSSEC for a domain on Vultr
-func (d *DNSDomainServiceHandler) ToggleDNSSec(ctx context.Context, domain string, enabled bool) error {
-
-	uri := "/v1/dns/dnssec_enable"
-
-	enable := "no"
-	if enabled == true {
-		enable = "yes"
-	}
-
-	values := url.Values{
-		"domain": {domain},
-		"enable": {enable},
-	}
-
-	req, err := d.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = d.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// DNSSecInfo gets the DNSSec keys for a domain (if enabled)
-func (d *DNSDomainServiceHandler) DNSSecInfo(ctx context.Context, domain string) ([]string, error) {
-
-	uri := "/v1/dns/dnssec_info"
-
-	req, err := d.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
-	if err != nil {
-		return nil, err
-	}
-
-	q := req.URL.Query()
-	q.Add("domain", domain)
-	req.URL.RawQuery = q.Encode()
-
-	var DNSSec []string
-	err = d.client.DoWithContext(ctx, req, &DNSSec)
-
-	if err != nil {
-		return nil, err
-	}
-
-	return DNSSec, nil
-}
-
-// List gets all domains associated with the current Vultr account.
-func (d *DNSDomainServiceHandler) List(ctx context.Context) ([]DNSDomain, error) {
-	uri := "/v1/dns/list"
-
-	req, err := d.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
-	if err != nil {
-		return nil, err
-	}
-
-	var dnsDomains []DNSDomain
-	err = d.client.DoWithContext(ctx, req, &dnsDomains)
-
-	if err != nil {
-		return nil, err
-	}
-
-	return dnsDomains, nil
-}
-
-// GetSoa gets the SOA record information for a domain
-func (d *DNSDomainServiceHandler) GetSoa(ctx context.Context, domain string) (*Soa, error) {
-	uri := "/v1/dns/soa_info"
-
-	req, err := d.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
-	if err != nil {
-		return nil, err
-	}
-
-	q := req.URL.Query()
-	q.Add("domain", domain)
-	req.URL.RawQuery = q.Encode()
-
-	soa := new(Soa)
-	err = d.client.DoWithContext(ctx, req, soa)
-
-	if err != nil {
-		return nil, err
-	}
-
-	return soa, nil
-}
-
-// UpdateSoa will update the SOA record information for a domain.
-func (d *DNSDomainServiceHandler) UpdateSoa(ctx context.Context, domain, nsPrimary, email string) error {
-
-	uri := "/v1/dns/soa_update"
-
-	values := url.Values{
-		"domain":    {domain},
-		"nsprimary": {nsPrimary},
-		"email":     {email},
-	}
-
-	req, err := d.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = d.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
diff --git a/dns_domains_test.go b/dns_domains_test.go
deleted file mode 100644
index 45ad247..0000000
--- a/dns_domains_test.go
+++ /dev/null
@@ -1,149 +0,0 @@
-package govultr
-
-import (
-	"fmt"
-	"net/http"
-	"reflect"
-	"testing"
-)
-
-func TestDNSDomainServiceHandler_Create(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/dns/create_domain", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.DNSDomain.Create(ctx, "domain.com", "123456")
-
-	if err != nil {
-		t.Errorf("DNSDomain.Create returned %+v, expected %+v", err, nil)
-	}
-}
-
-func TestDNSDomainServiceHandler_Delete(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/dns/delete_domain", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.DNSDomain.Delete(ctx, "domain.com")
-
-	if err != nil {
-		t.Errorf("DNSDomain.Delete returned %+v, expected %+v", err, nil)
-	}
-}
-
-func TestDNSDomainServiceHandler_ToggleDNSSec(t *testing.T) {
-	setup()
-	defer teardown()
-	mux.HandleFunc("/v1/dns/dnssec_enable", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.DNSDomain.ToggleDNSSec(ctx, "domain.com", true)
-
-	if err != nil {
-		t.Errorf("DNSDomain.ToggleDNSSec returned %+v, expected %+v", err, nil)
-	}
-}
-
-func TestDNSDomainServiceHandler_DNSSecInfo(t *testing.T) {
-	setup()
-	defer teardown()
-	mux.HandleFunc("/v1/dns/dnssec_info", func(writer http.ResponseWriter, request *http.Request) {
-		response := `
-		[
-    	"example.com IN DNSKEY 257 3 13 kRrxANp7YTGqVbaWtMy8hhsK0jcG4ajjICZKMb4fKv79Vx/RSn76vNjzIT7/Uo0BXil01Fk8RRQc4nWZctGJBA==",
-    	"example.com IN DS 27933 13 1 2d9ac457e5c11a104e25d971d0a6254562bddde7",
-    	"example.com IN DS 27933 13 2 8858e7b0dfb881280ce2ca1e0eafcd93d5b53687c21da284d4f8799ba82208a9"
-		]
-		`
-
-		fmt.Fprint(writer, response)
-	})
-
-	dnsSec, err := client.DNSDomain.DNSSecInfo(ctx, "example.com")
-
-	if err != nil {
-		t.Errorf("DNSDomain.DNSSecInfo returned %+v, expected %+v", err, nil)
-	}
-
-	expected := []string{
-		"example.com IN DNSKEY 257 3 13 kRrxANp7YTGqVbaWtMy8hhsK0jcG4ajjICZKMb4fKv79Vx/RSn76vNjzIT7/Uo0BXil01Fk8RRQc4nWZctGJBA==",
-		"example.com IN DS 27933 13 1 2d9ac457e5c11a104e25d971d0a6254562bddde7",
-		"example.com IN DS 27933 13 2 8858e7b0dfb881280ce2ca1e0eafcd93d5b53687c21da284d4f8799ba82208a9",
-	}
-
-	if !reflect.DeepEqual(dnsSec, expected) {
-		t.Errorf("DNSDomain.DNSSecInfo returned %+v, expected %+v", dnsSec, expected)
-	}
-}
-
-func TestDNSDomainServiceHandler_List(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/dns/list", func(writer http.ResponseWriter, request *http.Request) {
-		response := `[{"domain":"example.com","date_created":"2014-12-11 16:20:59"},{"domain":"example.com","date_created":"2014-12-11 16:20:59"}]`
-		fmt.Fprint(writer, response)
-	})
-
-	domainList, err := client.DNSDomain.List(ctx)
-
-	if err != nil {
-		t.Errorf("DNSDomain.List returned %+v, expected %+v", err, nil)
-	}
-
-	expected := []DNSDomain{
-		{Domain: "example.com", DateCreated: "2014-12-11 16:20:59"},
-		{Domain: "example.com", DateCreated: "2014-12-11 16:20:59"},
-	}
-
-	if !reflect.DeepEqual(domainList, expected) {
-		t.Errorf("DNSDomain.List returned %+v, expected %+v", domainList, expected)
-	}
-}
-
-func TestDNSDomainServiceHandler_GetSoa(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/dns/soa_info", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{
-    	"nsprimary": "ns1.vultr.com",
-    	"email": "dnsadm@vultr.com"
-		}`
-		fmt.Fprint(writer, response)
-	})
-
-	soa, err := client.DNSDomain.GetSoa(ctx, "example.com")
-
-	if err != nil {
-		t.Errorf("DNSDomain.GetSoa returned %+v, expected %+v", err, nil)
-	}
-
-	expected := &Soa{NsPrimary: "ns1.vultr.com", Email: "dnsadm@vultr.com"}
-
-	if !reflect.DeepEqual(soa, expected) {
-		t.Errorf("DNSDomain.GetSoa returned %+v, expected %+v", soa, expected)
-	}
-}
-
-func TestDNSDomainServiceHandler_UpdateSoa(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/dns/soa_update", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.DNSDomain.UpdateSoa(ctx, "domain.com", "ns1.domain.com", "example@vultr.com")
-
-	if err != nil {
-		t.Errorf("DNSDomain.UpdateSoa returned %+v, expected %+v", err, nil)
-	}
-}
diff --git a/dns_records.go b/dns_records.go
deleted file mode 100644
index b3d5cb1..0000000
--- a/dns_records.go
+++ /dev/null
@@ -1,150 +0,0 @@
-package govultr
-
-import (
-	"context"
-	"net/http"
-	"net/url"
-	"strconv"
-)
-
-// DNSRecordService is the interface to interact with the DNS Records endpoints on the Vultr API
-// Link: https://www.vultr.com/api/#dns
-type DNSRecordService interface {
-	Create(ctx context.Context, domain, recordType, name, data string, ttl, priority int) error
-	Delete(ctx context.Context, domain, recordID string) error
-	List(ctx context.Context, domain string) ([]DNSRecord, error)
-	Update(ctx context.Context, domain string, dnsRecord *DNSRecord) error
-}
-
-// DNSRecordsServiceHandler handles interaction with the DNS Records methods for the Vultr API
-type DNSRecordsServiceHandler struct {
-	client *Client
-}
-
-// DNSRecord represents a DNS record on Vultr
-type DNSRecord struct {
-	RecordID int    `json:"RECORDID"`
-	Type     string `json:"type"`
-	Name     string `json:"name"`
-	Data     string `json:"data"`
-	Priority *int   `json:"priority"`
-	TTL      int    `json:"ttl"`
-}
-
-// Create will add a DNS record.
-func (d *DNSRecordsServiceHandler) Create(ctx context.Context, domain, recordType, name, data string, ttl, priority int) error {
-
-	uri := "/v1/dns/create_record"
-
-	values := url.Values{
-		"domain":   {domain},
-		"name":     {name},
-		"type":     {recordType},
-		"data":     {data},
-		"ttl":      {strconv.Itoa(ttl)},
-		"priority": {strconv.Itoa(priority)},
-	}
-
-	req, err := d.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = d.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// Delete will delete a domain name and all associated records.
-func (d *DNSRecordsServiceHandler) Delete(ctx context.Context, domain, recordID string) error {
-
-	uri := "/v1/dns/delete_record"
-
-	values := url.Values{
-		"domain":   {domain},
-		"RECORDID": {recordID},
-	}
-
-	req, err := d.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = d.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// List will list all the records associated with a particular domain on Vultr
-func (d *DNSRecordsServiceHandler) List(ctx context.Context, domain string) ([]DNSRecord, error) {
-
-	uri := "/v1/dns/records"
-
-	req, err := d.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
-	if err != nil {
-		return nil, err
-	}
-
-	q := req.URL.Query()
-	q.Add("domain", domain)
-	req.URL.RawQuery = q.Encode()
-
-	var dnsRecord []DNSRecord
-	err = d.client.DoWithContext(ctx, req, &dnsRecord)
-
-	if err != nil {
-		return nil, err
-	}
-
-	return dnsRecord, nil
-}
-
-// Update will update a DNS record
-func (d *DNSRecordsServiceHandler) Update(ctx context.Context, domain string, dnsRecord *DNSRecord) error {
-
-	uri := "/v1/dns/update_record"
-
-	values := url.Values{
-		"domain":   {domain},
-		"RECORDID": {strconv.Itoa(dnsRecord.RecordID)},
-	}
-
-	// Optional
-	if dnsRecord.Name != "" {
-		values.Add("name", dnsRecord.Name)
-	}
-	if dnsRecord.Data != "" {
-		values.Add("data", dnsRecord.Data)
-	}
-	if dnsRecord.TTL != 0 {
-		values.Add("ttl", strconv.Itoa(dnsRecord.TTL))
-	}
-	if dnsRecord.Priority != nil {
-		values.Add("priority", strconv.Itoa(*dnsRecord.Priority))
-	}
-
-	req, err := d.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = d.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
diff --git a/dns_records_test.go b/dns_records_test.go
deleted file mode 100644
index 9170154..0000000
--- a/dns_records_test.go
+++ /dev/null
@@ -1,87 +0,0 @@
-package govultr
-
-import (
-	"fmt"
-	"net/http"
-	"reflect"
-	"testing"
-)
-
-func TestDNSRecordsServiceHandler_Create(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/dns/create_record", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.DNSRecord.Create(ctx, "domain.com", "A", "api", "127.0.0.1", 300, 0)
-
-	if err != nil {
-		t.Errorf("DNSRecord.Create returned %+v, expected %+v", err, nil)
-	}
-}
-
-func TestDNSRecordsServiceHandler_Delete(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/dns/delete_record", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.DNSRecord.Delete(ctx, "domain.com", "12345678")
-
-	if err != nil {
-		t.Errorf("DNSRecord.Delete returned %+v, expected %+v", err, nil)
-	}
-}
-
-func TestDNSRecordsServiceHandler_List(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/dns/records", func(writer http.ResponseWriter, request *http.Request) {
-		response := `[{"type": "A","name": "", "data": "127.0.0.1","priority": 0,"RECORDID": 1265276,"ttl": 300},{"type": "A","name": "", "data": "127.0.0.1","priority": 0,"RECORDID": 1265276,"ttl": 300}]`
-
-		fmt.Fprint(writer, response)
-	})
-
-	records, err := client.DNSRecord.List(ctx, "domain.com")
-	if err != nil {
-		t.Errorf("DNSRecord.List returned %+v, expected %+v", err, nil)
-	}
-	p := 0
-	expected := []DNSRecord{
-		{Type: "A", Name: "", Data: "127.0.0.1", Priority: &p, RecordID: 1265276, TTL: 300},
-		{Type: "A", Name: "", Data: "127.0.0.1", Priority: &p, RecordID: 1265276, TTL: 300},
-	}
-
-	if !reflect.DeepEqual(records, expected) {
-		t.Errorf("DNSRecord.List returned %+v, expected %+v", records, expected)
-	}
-}
-
-func TestDNSRecordsServiceHandler_Update(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/dns/update_record", func(writer http.ResponseWriter, request *http.Request) {
-
-		fmt.Fprint(writer)
-	})
-	p := 10
-	params := &DNSRecord{
-		RecordID: 14283638,
-		Name:     "api",
-		Data:     "turnip.data",
-		TTL:      120,
-		Priority: &p,
-	}
-
-	err := client.DNSRecord.Update(ctx, "turnip.services", params)
-
-	if err != nil {
-		t.Errorf("DNSRecord.Update returned %+v, expected %+v", err, nil)
-	}
-}
diff --git a/domain_records.go b/domain_records.go
new file mode 100644
index 0000000..56249cf
--- /dev/null
+++ b/domain_records.go
@@ -0,0 +1,123 @@
+package govultr
+
+import (
+	"context"
+	"fmt"
+	"net/http"
+
+	"github.com/google/go-querystring/query"
+)
+
+// DomainRecordService is the interface to interact with the DNS Records endpoints on the Vultr API
+// Link: https://www.vultr.com/api/#tag/dns
+type DomainRecordService interface {
+	Create(ctx context.Context, domain string, domainRecordReq *DomainRecordReq) (*DomainRecord, error)
+	Get(ctx context.Context, domain, recordID string) (*DomainRecord, error)
+	Update(ctx context.Context, domain, recordID string, domainRecordReq *DomainRecordReq) error
+	Delete(ctx context.Context, domain, recordID string) error
+	List(ctx context.Context, domain string, options *ListOptions) ([]DomainRecord, *Meta, error)
+}
+
+// DomainRecordsServiceHandler handles interaction with the DNS Records methods for the Vultr API
+type DomainRecordsServiceHandler struct {
+	client *Client
+}
+
+// DomainRecord represents a DNS record on Vultr
+type DomainRecord struct {
+	ID       string `json:"id,omitempty"`
+	Type     string `json:"type,omitempty"`
+	Name     string `json:"name,omitempty"`
+	Data     string `json:"data,omitempty"`
+	Priority int    `json:"priority,omitempty"`
+	TTL      int    `json:"ttl,omitempty"`
+}
+
+// DomainRecordReq struct to use for create/update domain record calls.
+type DomainRecordReq struct {
+	Name     string `json:"name"`
+	Type     string `json:"type,omitempty"`
+	Data     string `json:"data,omitempty"`
+	TTL      int    `json:"ttl,omitempty"`
+	Priority *int   `json:"priority,omitempty"`
+}
+
+type domainRecordsBase struct {
+	Records []DomainRecord `json:"records,omitempty"`
+	Meta    *Meta          `json:"meta,omitempty"`
+}
+
+type domainRecordBase struct {
+	Record *DomainRecord `json:"record,omitempty"`
+}
+
+// Create will add a DNS record.
+func (d *DomainRecordsServiceHandler) Create(ctx context.Context, domain string, domainRecordReq *DomainRecordReq) (*DomainRecord, error) {
+	req, err := d.client.NewRequest(ctx, http.MethodPost, fmt.Sprintf("%s/%s/records", domainPath, domain), domainRecordReq)
+	if err != nil {
+		return nil, err
+	}
+
+	record := new(domainRecordBase)
+	if err = d.client.DoWithContext(ctx, req, record); err != nil {
+		return nil, err
+	}
+
+	return record.Record, nil
+}
+
+// Get record from a domain
+func (d *DomainRecordsServiceHandler) Get(ctx context.Context, domain, recordID string) (*DomainRecord, error) {
+	req, err := d.client.NewRequest(ctx, http.MethodGet, fmt.Sprintf("%s/%s/records/%s", domainPath, domain, recordID), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	record := new(domainRecordBase)
+	if err = d.client.DoWithContext(ctx, req, record); err != nil {
+		return nil, err
+	}
+
+	return record.Record, nil
+}
+
+// Update will update a Domain record
+func (d *DomainRecordsServiceHandler) Update(ctx context.Context, domain, recordID string, domainRecordReq *DomainRecordReq) error {
+	req, err := d.client.NewRequest(ctx, http.MethodPatch, fmt.Sprintf("%s/%s/records/%s", domainPath, domain, recordID), domainRecordReq)
+	if err != nil {
+		return err
+	}
+
+	return d.client.DoWithContext(ctx, req, nil)
+}
+
+// Delete will delete a domain name and all associated records.
+func (d *DomainRecordsServiceHandler) Delete(ctx context.Context, domain, recordID string) error {
+	req, err := d.client.NewRequest(ctx, http.MethodDelete, fmt.Sprintf("%s/%s/records/%s", domainPath, domain, recordID), nil)
+	if err != nil {
+		return err
+	}
+
+	return d.client.DoWithContext(ctx, req, nil)
+}
+
+// List will list all the records associated with a particular domain on Vultr.
+func (d *DomainRecordsServiceHandler) List(ctx context.Context, domain string, options *ListOptions) ([]DomainRecord, *Meta, error) {
+	req, err := d.client.NewRequest(ctx, http.MethodGet, fmt.Sprintf("%s/%s/records", domainPath, domain), nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	newValues, err := query.Values(options)
+	if err != nil {
+		return nil, nil, err
+	}
+	req.URL.RawQuery = newValues.Encode()
+
+	records := new(domainRecordsBase)
+	if err = d.client.DoWithContext(ctx, req, records); err != nil {
+		return nil, nil, err
+	}
+
+	return records.Records, records.Meta, nil
+}
diff --git a/domain_records_test.go b/domain_records_test.go
new file mode 100644
index 0000000..bca6c54
--- /dev/null
+++ b/domain_records_test.go
@@ -0,0 +1,150 @@
+package govultr
+
+import (
+	"fmt"
+	"net/http"
+	"reflect"
+	"testing"
+)
+
+func TestDomainRecordsServiceHandler_Create(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/domains/vultr.com/records", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"record":{"id":"dev-preview-abc123","type":"A","name":"www","data":"127.0.0.1","priority":0,"ttl":300}}`
+		fmt.Fprint(writer, response)
+	})
+	p := 300
+	r := &DomainRecordReq{
+		Name:     "www",
+		Type:     "A",
+		Data:     "127.0.0.1",
+		Priority: &p,
+	}
+	record, err := client.DomainRecord.Create(ctx, "vultr.com", r)
+	if err != nil {
+		t.Errorf("DomainRecord.Create returned %+v, expected %+v", err, nil)
+	}
+
+	expected := &DomainRecord{
+		ID:       "dev-preview-abc123",
+		Type:     "A",
+		Name:     "www",
+		Data:     "127.0.0.1",
+		Priority: 0,
+		TTL:      300,
+	}
+
+	if !reflect.DeepEqual(record, expected) {
+		t.Errorf("DomainRecord.Create returned %+v, expected %+v", record, expected)
+	}
+}
+
+func TestDomainRecordsServiceHandler_Get(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/domains/vultr.com/records/dev-preview-abc123", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"record":{"id":"dev-preview-abc123","type":"A","name":"www","data":"127.0.0.1","priority":0,"ttl":300}}`
+		fmt.Fprint(writer, response)
+	})
+
+	record, err := client.DomainRecord.Get(ctx, "vultr.com", "dev-preview-abc123")
+	if err != nil {
+		t.Errorf("DomainRecord.Get returned %+v, expected %+v", err, nil)
+	}
+
+	expected := &DomainRecord{
+		ID:       "dev-preview-abc123",
+		Type:     "A",
+		Name:     "www",
+		Data:     "127.0.0.1",
+		Priority: 0,
+		TTL:      300,
+	}
+
+	if !reflect.DeepEqual(record, expected) {
+		t.Errorf("DomainRecord.Get returned %+v, expected %+v", record, expected)
+	}
+}
+
+func TestDomainRecordsServiceHandler_Update(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/domains/vultr.com/records/abc123", func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
+	})
+	p := 10
+	r := &DomainRecordReq{
+		Name:     "*",
+		Type:     "A",
+		Data:     "127.0.0.1",
+		TTL:      1200,
+		Priority: &p,
+	}
+	err := client.DomainRecord.Update(ctx, "vultr.com", "abc123", r)
+	if err != nil {
+		t.Errorf("DNSRecord.Update returned %+v, expected %+v", err, nil)
+	}
+}
+
+func TestDomainRecordsServiceHandler_Delete(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/domains/vultr.com/records/abc123", func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
+	})
+
+	err := client.DomainRecord.Delete(ctx, "vultr.com", "abc123")
+	if err != nil {
+		t.Errorf("DomainRecord.Delete returned %+v, expected %+v", err, nil)
+	}
+}
+
+func TestDomainRecordsServiceHandler_List(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/domains/vultr.com/records", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"records":[{"id":"abc123","type":"A","name":"test","data":"127.0.0.1","priority":0,"ttl":300}],"meta":{"total":1,"links":{"next":"thisismycursor","prev":""}}}`
+		fmt.Fprint(writer, response)
+	})
+
+	options := &ListOptions{
+		PerPage: 1,
+	}
+	records, meta, err := client.DomainRecord.List(ctx, "vultr.com", options)
+	if err != nil {
+		t.Errorf("DomainRecord.List returned %+v, expected %+v", err, nil)
+	}
+
+	expectedRecords := []DomainRecord{
+		{
+			ID:       "abc123",
+			Type:     "A",
+			Name:     "test",
+			Data:     "127.0.0.1",
+			Priority: 0,
+			TTL:      300,
+		},
+	}
+
+	expectedMeta := &Meta{
+		Total: 1,
+		Links: &Links{
+			Next: "thisismycursor",
+			Prev: "",
+		},
+	}
+
+	if !reflect.DeepEqual(records, expectedRecords) {
+		t.Errorf("DomainRecord.List returned %+v, expected %+v", records, expectedRecords)
+	}
+
+	if !reflect.DeepEqual(meta, expectedMeta) {
+		t.Errorf("DomainRecord.List meta returned %+v, expected %+v", meta, expectedMeta)
+	}
+}
diff --git a/domains.go b/domains.go
new file mode 100644
index 0000000..938cc86
--- /dev/null
+++ b/domains.go
@@ -0,0 +1,185 @@
+package govultr
+
+import (
+	"context"
+	"fmt"
+	"net/http"
+
+	"github.com/google/go-querystring/query"
+)
+
+const domainPath = "/v2/domains"
+
+// DomainService is the interface to interact with the DNS endpoints on the Vultr API
+// https://www.vultr.com/api/#tag/dns
+type DomainService interface {
+	Create(ctx context.Context, domainReq *DomainReq) (*Domain, error)
+	Get(ctx context.Context, domain string) (*Domain, error)
+	Update(ctx context.Context, domain, dnsSec string) error
+	Delete(ctx context.Context, domain string) error
+	List(ctx context.Context, options *ListOptions) ([]Domain, *Meta, error)
+
+	GetSoa(ctx context.Context, domain string) (*Soa, error)
+	UpdateSoa(ctx context.Context, domain string, soaReq *Soa) error
+
+	GetDNSSec(ctx context.Context, domain string) ([]string, error)
+}
+
+// DomainServiceHandler handles interaction with the DNS methods for the Vultr API
+type DomainServiceHandler struct {
+	client *Client
+}
+
+// Domain represents a Domain entry on Vultr
+type Domain struct {
+	Domain      string `json:"domain,omitempty"`
+	DateCreated string `json:"date_created,omitempty"`
+	DNSSec      string `json:"dns_sec,omitempty"`
+}
+
+// DomainReq is the struct to create a domain
+// If IP is omitted then an empty DNS entry will be created. If supplied the domain will be pre populated with entries
+type DomainReq struct {
+	Domain string `json:"domain,omitempty"`
+	IP     string `json:"ip,omitempty"`
+	DNSSec string `json:"dns_sec,omitempty"`
+}
+
+type domainsBase struct {
+	Domains []Domain `json:"domains"`
+	Meta    *Meta    `json:"meta"`
+}
+
+type domainBase struct {
+	Domain *Domain `json:"domain"`
+}
+
+// Soa information for the Domain
+type Soa struct {
+	NSPrimary string `json:"nsprimary,omitempty"`
+	Email     string `json:"email,omitempty"`
+}
+
+type soaBase struct {
+	DNSSoa *Soa `json:"dns_soa,omitempty"`
+}
+
+type dnsSecBase struct {
+	DNSSec []string `json:"dns_sec,omitempty"`
+}
+
+// Create a domain entry
+func (d *DomainServiceHandler) Create(ctx context.Context, domainReq *DomainReq) (*Domain, error) {
+	req, err := d.client.NewRequest(ctx, http.MethodPost, domainPath, domainReq)
+	if err != nil {
+		return nil, err
+	}
+
+	domain := new(domainBase)
+	if err = d.client.DoWithContext(ctx, req, domain); err != nil {
+		return nil, err
+	}
+
+	return domain.Domain, nil
+}
+
+// Get a domain from your Vultr account.
+func (d *DomainServiceHandler) Get(ctx context.Context, domain string) (*Domain, error) {
+	req, err := d.client.NewRequest(ctx, http.MethodGet, fmt.Sprintf("%s/%s", domainPath, domain), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	dBase := new(domainBase)
+	if err = d.client.DoWithContext(ctx, req, dBase); err != nil {
+		return nil, err
+	}
+
+	return dBase.Domain, nil
+}
+
+// Update allows you to enable or disable DNS Sec on the domain.
+// The two valid options for dnsSec are "enabled" or "disabled"
+func (d *DomainServiceHandler) Update(ctx context.Context, domain, dnsSec string) error {
+	body := &RequestBody{"dns_sec": dnsSec}
+	req, err := d.client.NewRequest(ctx, http.MethodPut, fmt.Sprintf("%s/%s", domainPath, domain), body)
+	if err != nil {
+		return err
+	}
+
+	return d.client.DoWithContext(ctx, req, nil)
+}
+
+// Delete a domain with all associated records.
+func (d *DomainServiceHandler) Delete(ctx context.Context, domain string) error {
+	req, err := d.client.NewRequest(ctx, http.MethodDelete, fmt.Sprintf("%s/%s", domainPath, domain), nil)
+	if err != nil {
+		return err
+	}
+
+	return d.client.DoWithContext(ctx, req, nil)
+}
+
+// List gets all domains associated with the current Vultr account.
+func (d *DomainServiceHandler) List(ctx context.Context, options *ListOptions) ([]Domain, *Meta, error) {
+	req, err := d.client.NewRequest(ctx, http.MethodGet, domainPath, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	newValues, err := query.Values(options)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	req.URL.RawQuery = newValues.Encode()
+
+	domains := new(domainsBase)
+	err = d.client.DoWithContext(ctx, req, domains)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	return domains.Domains, domains.Meta, nil
+}
+
+// GetSoa gets the SOA record information for a domain
+func (d *DomainServiceHandler) GetSoa(ctx context.Context, domain string) (*Soa, error) {
+	req, err := d.client.NewRequest(ctx, http.MethodGet, fmt.Sprintf("%s/%s/soa", domainPath, domain), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	soa := new(soaBase)
+	if err = d.client.DoWithContext(ctx, req, soa); err != nil {
+		return nil, err
+	}
+
+	return soa.DNSSoa, nil
+}
+
+// UpdateSoa will update the SOA record information for a domain.
+func (d *DomainServiceHandler) UpdateSoa(ctx context.Context, domain string, soaReq *Soa) error {
+
+	req, err := d.client.NewRequest(ctx, http.MethodPatch, fmt.Sprintf("%s/%s/soa", domainPath, domain), soaReq)
+	if err != nil {
+		return err
+	}
+
+	return d.client.DoWithContext(ctx, req, nil)
+}
+
+// GetDNSSec gets the DNSSec keys for a domain (if enabled)
+func (d *DomainServiceHandler) GetDNSSec(ctx context.Context, domain string) ([]string, error) {
+	req, err := d.client.NewRequest(ctx, http.MethodGet, fmt.Sprintf("%s/%s/dnssec", domainPath, domain), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	dnsSec := new(dnsSecBase)
+	if err = d.client.DoWithContext(ctx, req, dnsSec); err != nil {
+		return nil, err
+	}
+
+	return dnsSec.DNSSec, nil
+}
diff --git a/domains_test.go b/domains_test.go
new file mode 100644
index 0000000..638b32d
--- /dev/null
+++ b/domains_test.go
@@ -0,0 +1,195 @@
+package govultr
+
+import (
+	"fmt"
+	"net/http"
+	"reflect"
+	"testing"
+)
+
+func TestDomainServiceHandler_Create(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/domains", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"domain": {"domain": "vultr.com","date_created": "2020-05-08 19:09:07"}}`
+		fmt.Fprint(writer, response)
+	})
+
+	req := &DomainReq{
+		Domain: "vultr.com",
+	}
+	domain, err := client.Domain.Create(ctx, req)
+	if err != nil {
+		t.Errorf("DNSDomain.Create returned %+v, expected %+v", err, nil)
+	}
+
+	expected := &Domain{
+		Domain:      "vultr.com",
+		DateCreated: "2020-05-08 19:09:07",
+	}
+
+	if !reflect.DeepEqual(domain, expected) {
+		t.Errorf("Domain.Create returned %+v, expected %+v", domain, expected)
+	}
+}
+
+func TestDomainServiceHandler_Get(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/domains/vultr.com", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"domain": {"domain": "vultr.com","date_created": "2020-05-08 19:09:07"}}`
+		fmt.Fprint(writer, response)
+	})
+
+	domain, err := client.Domain.Get(ctx, "vultr.com")
+	if err != nil {
+		t.Errorf("DNSDomain.Create returned %+v, expected %+v", err, nil)
+	}
+
+	expected := &Domain{
+		Domain:      "vultr.com",
+		DateCreated: "2020-05-08 19:09:07",
+	}
+
+	if !reflect.DeepEqual(domain, expected) {
+		t.Errorf("Domain.Create returned %+v, expected %+v", domain, expected)
+	}
+}
+
+func TestDomainServiceHandler_Update(t *testing.T) {
+	setup()
+	defer teardown()
+	mux.HandleFunc("/v2/domains/vultr.com", func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
+	})
+
+	err := client.Domain.Update(ctx, "vultr.com", "enabled")
+	if err != nil {
+		t.Errorf("Domain.Update returned %+v, expected %+v", err, nil)
+	}
+}
+
+func TestDomainServiceHandler_Delete(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/domains/domain.com", func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
+	})
+
+	err := client.Domain.Delete(ctx, "domain.com")
+	if err != nil {
+		t.Errorf("Domain.Delete returned %+v, expected %+v", err, nil)
+	}
+}
+
+func TestDNSDomainServiceHandler_List(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/domains", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"domains":[{"domain":"vultr.com","date_created":"2020-05-0819:09:07"}],"meta":{"total":1,"links":{"next":"thisismycusror","prev":""}}}`
+		fmt.Fprint(writer, response)
+	})
+
+	options := &ListOptions{
+		PerPage: 1,
+	}
+	domains, meta, err := client.Domain.List(ctx, options)
+	if err != nil {
+		t.Errorf("Domain.List returned %+v, expected %+v", err, nil)
+	}
+
+	expectedDomain := []Domain{
+		{
+			Domain:      "vultr.com",
+			DateCreated: "2020-05-0819:09:07",
+		},
+	}
+
+	expectedMeta := &Meta{
+		Total: 1,
+		Links: &Links{
+			Next: "thisismycusror",
+			Prev: "",
+		},
+	}
+
+	if !reflect.DeepEqual(domains, expectedDomain) {
+		t.Errorf("Domain.List returned %+v, expected %+v", domains, expectedDomain)
+	}
+
+	if !reflect.DeepEqual(meta, expectedMeta) {
+		t.Errorf("Domain.List meta returned %+v, expected %+v", meta, expectedMeta)
+	}
+}
+
+func TestDomainServiceHandler_GetSoa(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/domains/vultr.com/soa", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"dns_soa":{"nsprimary":"ns1.vultr.com","email":"dnsadm@vultr.com"}}`
+		fmt.Fprint(writer, response)
+	})
+
+	soa, err := client.Domain.GetSoa(ctx, "vultr.com")
+	if err != nil {
+		t.Errorf("Domain.GetSoa returned %+v, expected %+v", err, nil)
+	}
+
+	expected := &Soa{NSPrimary: "ns1.vultr.com", Email: "dnsadm@vultr.com"}
+
+	if !reflect.DeepEqual(soa, expected) {
+		t.Errorf("DNSDomain.GetSoa returned %+v, expected %+v", soa, expected)
+	}
+}
+
+func TestDNSDomainServiceHandler_UpdateSoa(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/domains/vultr.com/soa", func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
+	})
+
+	r := &Soa{
+		NSPrimary: "ns4.vultr.com",
+		Email:     "vultr@vultr.com",
+	}
+	err := client.Domain.UpdateSoa(ctx, "vultr.com", r)
+
+	if err != nil {
+		t.Errorf("Domain.UpdateSoa returned %+v, expected %+v", err, nil)
+	}
+}
+
+func TestDNSDomainServiceHandler_DNSSecInfo(t *testing.T) {
+	setup()
+	defer teardown()
+	mux.HandleFunc("/v2/domains/vultr.com/dnssec", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"dns_sec":[
+		"example.com IN DNSKEY 257 3 13 kRrxANp7YTGqVbaWtMy8hhsK0jcG4ajjICZKMb4fKv79Vx/RSn76vNjzIT7/Uo0BXil01Fk8RRQc4nWZctGJBA==",
+		"example.com IN DS 27933 13 1 2d9ac457e5c11a104e25d971d0a6254562bddde7",
+		"example.com IN DS 27933 13 2 8858e7b0dfb881280ce2ca1e0eafcd93d5b53687c21da284d4f8799ba82208a9"
+]}`
+		fmt.Fprint(writer, response)
+	})
+
+	dnsSec, err := client.Domain.GetDNSSec(ctx, "vultr.com")
+	if err != nil {
+		t.Errorf("Domain.GetDnsSec returned %+v, expected %+v", err, nil)
+	}
+
+	expected := []string{
+		"example.com IN DNSKEY 257 3 13 kRrxANp7YTGqVbaWtMy8hhsK0jcG4ajjICZKMb4fKv79Vx/RSn76vNjzIT7/Uo0BXil01Fk8RRQc4nWZctGJBA==",
+		"example.com IN DS 27933 13 1 2d9ac457e5c11a104e25d971d0a6254562bddde7",
+		"example.com IN DS 27933 13 2 8858e7b0dfb881280ce2ca1e0eafcd93d5b53687c21da284d4f8799ba82208a9",
+	}
+
+	if !reflect.DeepEqual(dnsSec, expected) {
+		t.Errorf("Domain.GetDnsSec returned %+v, expected %+v", dnsSec, expected)
+	}
+}
diff --git a/firewall_group.go b/firewall_group.go
index ee874d1..e8a4ea2 100644
--- a/firewall_group.go
+++ b/firewall_group.go
@@ -2,18 +2,20 @@ package govultr
 
 import (
 	"context"
+	"fmt"
 	"net/http"
-	"net/url"
+
+	"github.com/google/go-querystring/query"
 )
 
 // FirewallGroupService is the interface to interact with the firewall group endpoints on the Vultr API
-// Link: https://www.vultr.com/api/#firewall
+// Link : https://www.vultr.com/api/#tag/firewall
 type FirewallGroupService interface {
-	Create(ctx context.Context, description string) (*FirewallGroup, error)
-	Delete(ctx context.Context, groupID string) error
-	List(ctx context.Context) ([]FirewallGroup, error)
+	Create(ctx context.Context, fwGroupReq *FirewallGroupReq) (*FirewallGroup, error)
 	Get(ctx context.Context, groupID string) (*FirewallGroup, error)
-	ChangeDescription(ctx context.Context, groupID, description string) error
+	Update(ctx context.Context, fwGroupID string, fwGroupReq *FirewallGroupReq) error
+	Delete(ctx context.Context, fwGroupID string) error
+	List(ctx context.Context, options *ListOptions) ([]FirewallGroup, *Meta, error)
 }
 
 // FireWallGroupServiceHandler handles interaction with the firewall group methods for the Vultr API
@@ -23,141 +25,107 @@ type FireWallGroupServiceHandler struct {
 
 // FirewallGroup represents a Vultr firewall group
 type FirewallGroup struct {
-	FirewallGroupID string `json:"FIREWALLGROUPID"`
-	Description     string `json:"description"`
-	DateCreated     string `json:"date_created"`
-	DateModified    string `json:"date_modified"`
-	InstanceCount   int    `json:"instance_count"`
-	RuleCount       int    `json:"rule_count"`
-	MaxRuleCount    int    `json:"max_rule_count"`
+	ID            string `json:"id"`
+	Description   string `json:"description"`
+	DateCreated   string `json:"date_created"`
+	DateModified  string `json:"date_modified"`
+	InstanceCount int    `json:"instance_count"`
+	RuleCount     int    `json:"rule_count"`
+	MaxRuleCount  int    `json:"max_rule_count"`
 }
 
-// Create will create a new firewall group on your Vultr account
-func (f *FireWallGroupServiceHandler) Create(ctx context.Context, description string) (*FirewallGroup, error) {
+// FirewallGroupReq struct is used to create and update a Firewall Group.
+type FirewallGroupReq struct {
+	Description string `json:"description"`
+}
 
-	uri := "/v1/firewall/group_create"
+type firewallGroupsBase struct {
+	FirewallGroups []FirewallGroup `json:"firewall_groups"`
+	Meta           *Meta           `json:"meta"`
+}
 
-	values := url.Values{
-		"description": {description},
-	}
+type firewallGroupBase struct {
+	FirewallGroup *FirewallGroup `json:"firewall_group"`
+}
 
-	req, err := f.client.NewRequest(ctx, http.MethodPost, uri, values)
+// Create will create a new firewall group on your Vultr account
+func (f *FireWallGroupServiceHandler) Create(ctx context.Context, fwGroupReq *FirewallGroupReq) (*FirewallGroup, error) {
+	uri := "/v2/firewalls"
 
+	req, err := f.client.NewRequest(ctx, http.MethodPost, uri, fwGroupReq)
 	if err != nil {
 		return nil, err
 	}
 
-	firewall := new(FirewallGroup)
-	err = f.client.DoWithContext(ctx, req, firewall)
-
-	if err != nil {
+	firewall := new(firewallGroupBase)
+	if err = f.client.DoWithContext(ctx, req, firewall); err != nil {
 		return nil, err
 	}
 
-	return firewall, nil
+	return firewall.FirewallGroup, nil
 }
 
-// Delete will delete a firewall group from your Vultr account
-func (f *FireWallGroupServiceHandler) Delete(ctx context.Context, groupID string) error {
-
-	uri := "/v1/firewall/group_delete"
-
-	values := url.Values{
-		"FIREWALLGROUPID": {groupID},
-	}
-
-	req, err := f.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = f.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// List will return a list of  all firewall groups on your Vultr account
-func (f *FireWallGroupServiceHandler) List(ctx context.Context) ([]FirewallGroup, error) {
-
-	uri := "/v1/firewall/group_list"
+// Get will return a firewall group based on provided groupID from your Vultr account
+func (f *FireWallGroupServiceHandler) Get(ctx context.Context, fwGroupID string) (*FirewallGroup, error) {
+	uri := fmt.Sprintf("/v2/firewalls/%s", fwGroupID)
 
 	req, err := f.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
 	if err != nil {
 		return nil, err
 	}
 
-	var firewallGroupMap map[string]FirewallGroup
-	err = f.client.DoWithContext(ctx, req, &firewallGroupMap)
-
-	if err != nil {
+	firewall := new(firewallGroupBase)
+	if err = f.client.DoWithContext(ctx, req, firewall); err != nil {
 		return nil, err
 	}
 
-	var firewallGroup []FirewallGroup
-	for _, f := range firewallGroupMap {
-		firewallGroup = append(firewallGroup, f)
-	}
-
-	return firewallGroup, nil
+	return firewall.FirewallGroup, nil
 }
 
-// Get will return a firewall group based on provided groupID from your Vultr account
-func (f *FireWallGroupServiceHandler) Get(ctx context.Context, groupID string) (*FirewallGroup, error) {
-
-	uri := "/v1/firewall/group_list"
-
-	req, err := f.client.NewRequest(ctx, http.MethodGet, uri, nil)
+// Update will change the description of a firewall group
+func (f *FireWallGroupServiceHandler) Update(ctx context.Context, fwGroupID string, fwGroupReq *FirewallGroupReq) error {
+	uri := fmt.Sprintf("/v2/firewalls/%s", fwGroupID)
 
+	req, err := f.client.NewRequest(ctx, http.MethodPut, uri, fwGroupReq)
 	if err != nil {
-		return nil, err
+		return err
 	}
 
-	q := req.URL.Query()
-	q.Add("FIREWALLGROUPID", groupID)
-	req.URL.RawQuery = q.Encode()
+	return f.client.DoWithContext(ctx, req, nil)
+}
 
-	var firewallGroupMap map[string]FirewallGroup
-	err = f.client.DoWithContext(ctx, req, &firewallGroupMap)
+// Delete will delete a firewall group from your Vultr account
+func (f *FireWallGroupServiceHandler) Delete(ctx context.Context, fwGroupID string) error {
+	uri := fmt.Sprintf("/v2/firewalls/%s", fwGroupID)
 
+	req, err := f.client.NewRequest(ctx, http.MethodDelete, uri, nil)
 	if err != nil {
-		return nil, err
-	}
-
-	firewallGroup := new(FirewallGroup)
-	for _, f := range firewallGroupMap {
-		firewallGroup = &f
+		return err
 	}
 
-	return firewallGroup, nil
+	return f.client.DoWithContext(ctx, req, nil)
 }
 
-// ChangeDescription will change the description of a firewall group
-func (f *FireWallGroupServiceHandler) ChangeDescription(ctx context.Context, groupID, description string) error {
-
-	uri := "/v1/firewall/group_set_description"
+// List will return a list of  all firewall groups on your Vultr account
+func (f *FireWallGroupServiceHandler) List(ctx context.Context, options *ListOptions) ([]FirewallGroup, *Meta, error) {
+	uri := "/v2/firewalls"
 
-	values := url.Values{
-		"FIREWALLGROUPID": {groupID},
-		"description":     {description},
+	req, err := f.client.NewRequest(ctx, http.MethodGet, uri, nil)
+	if err != nil {
+		return nil, nil, err
 	}
 
-	req, err := f.client.NewRequest(ctx, http.MethodPost, uri, values)
-
+	newValues, err := query.Values(options)
 	if err != nil {
-		return err
+		return nil, nil, err
 	}
 
-	err = f.client.DoWithContext(ctx, req, nil)
+	req.URL.RawQuery = newValues.Encode()
 
-	if err != nil {
-		return err
+	firewalls := new(firewallGroupsBase)
+	if err = f.client.DoWithContext(ctx, req, firewalls); err != nil {
+		return nil, nil, err
 	}
 
-	return nil
+	return firewalls.FirewallGroups, firewalls.Meta, nil
 }
diff --git a/firewall_group_test.go b/firewall_group_test.go
index 6490930..22665fe 100644
--- a/firewall_group_test.go
+++ b/firewall_group_test.go
@@ -11,114 +11,127 @@ func TestFireWallGroupServiceHandler_Create(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/firewall/group_create", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"FIREWALLGROUPID":"1234abcd"}`
+	mux.HandleFunc("/v2/firewalls", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"firewall_group":{"id":"44d0f934","description":"govultr test","date_created":"2020-07-0913:53:34","date_modified":"2020-07-0913:53:34","instance_count":15,"rule_count":6,"max_rule_count":999}}`
 		fmt.Fprint(writer, response)
 	})
 
-	firewallGroup, err := client.FirewallGroup.Create(ctx, "firewall-group-name")
-
+	group := &FirewallGroupReq{Description: "govultr test"}
+	firewallGroup, err := client.FirewallGroup.Create(ctx, group)
 	if err != nil {
 		t.Errorf("FirewallGroup.Create returned error: %v", err)
 	}
 
-	expected := &FirewallGroup{FirewallGroupID: "1234abcd"}
+	expected := &FirewallGroup{
+		ID:            "44d0f934",
+		Description:   "govultr test",
+		DateCreated:   "2020-07-0913:53:34",
+		DateModified:  "2020-07-0913:53:34",
+		InstanceCount: 15,
+		RuleCount:     6,
+		MaxRuleCount:  999,
+	}
 
 	if !reflect.DeepEqual(firewallGroup, expected) {
 		t.Errorf("FirewallGroup.Create returned %+v, expected %+v", firewallGroup, expected)
 	}
-
 }
 
-func TestFireWallGroupServiceHandler_Delete(t *testing.T) {
+func TestFireWallGroupServiceHandler_Get(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/firewall/group_delete", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
+	mux.HandleFunc("/v2/firewalls/44d0f934", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"firewall_group":{"id":"44d0f934","description":"govultr test","date_created":"2020-07-0913:53:34","date_modified":"2020-07-0913:53:34","instance_count":15,"rule_count":6,"max_rule_count":999}}`
+		fmt.Fprint(writer, response)
 	})
 
-	err := client.FirewallGroup.Delete(ctx, "12345abcd")
-
+	firewallGroup, err := client.FirewallGroup.Get(ctx, "44d0f934")
 	if err != nil {
-		t.Errorf("FirewallGroup.Delete returned error: %v", err)
+		t.Errorf("FirewallGroup.Create returned error: %v", err)
+	}
+
+	expected := &FirewallGroup{
+		ID:            "44d0f934",
+		Description:   "govultr test",
+		DateCreated:   "2020-07-0913:53:34",
+		DateModified:  "2020-07-0913:53:34",
+		InstanceCount: 15,
+		RuleCount:     6,
+		MaxRuleCount:  999,
+	}
+
+	if !reflect.DeepEqual(firewallGroup, expected) {
+		t.Errorf("FirewallGroup.Create returned %+v, expected %+v", firewallGroup, expected)
 	}
 }
 
-func TestFireWallGroupServiceHandler_List(t *testing.T) {
+func TestFireWallGroupServiceHandler_ChangeDescription(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/firewall/group_list", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"1234abcd": { "FIREWALLGROUPID": "1234abcd", "description": "my http firewall","date_created": "2017-02-14 17:48:40","date_modified": "2017-02-14 17:48:40","instance_count": 2,"rule_count": 2, "max_rule_count": 50}}`
-		fmt.Fprint(writer, response)
+	mux.HandleFunc("/v2/firewalls/abc123", func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
 	})
 
-	firewallGroup, err := client.FirewallGroup.List(ctx)
-
+	put := &FirewallGroupReq{Description: "test"}
+	err := client.FirewallGroup.Update(ctx, "abc123", put)
 	if err != nil {
-		t.Errorf("FirewallGroup.List returned error: %v", err)
+		t.Errorf("FirewallGroup.ChangeDescription returned error: %v", err)
 	}
+}
 
-	expected := []FirewallGroup{
-		{
-			FirewallGroupID: "1234abcd",
-			Description:     "my http firewall",
-			DateCreated:     "2017-02-14 17:48:40",
-			DateModified:    "2017-02-14 17:48:40",
-			InstanceCount:   2,
-			RuleCount:       2,
-			MaxRuleCount:    50,
-		},
-	}
+func TestFireWallGroupServiceHandler_Delete(t *testing.T) {
+	setup()
+	defer teardown()
 
-	if !reflect.DeepEqual(firewallGroup, expected) {
-		t.Errorf("FirewallGroup.List returned %+v, expected %+v", firewallGroup, expected)
-	}
+	mux.HandleFunc("/v2/firewalls/abc123", func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
+	})
 
+	err := client.FirewallGroup.Delete(ctx, "abc123")
+
+	if err != nil {
+		t.Errorf("FirewallGroup.Delete returned error: %v", err)
+	}
 }
 
-func TestFireWallGroupServiceHandler_Get(t *testing.T) {
+func TestFireWallGroupServiceHandler_List(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/firewall/group_list", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"1234abcd": { "FIREWALLGROUPID": "1234abcd", "description": "my http firewall","date_created": "2017-02-14 17:48:40","date_modified": "2017-02-14 17:48:40","instance_count": 2,"rule_count": 2, "max_rule_count": 50}}`
+	mux.HandleFunc("/v2/firewalls", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"firewall_groups":[{"id":"44d0f934","description":"govultr test","date_created":"2020-07-0913:53:34","date_modified":"2020-07-0913:53:34","instance_count":15,"rule_count":6,"max_rule_count":999}],"meta":{"total":5,"links":{"next":"","prev":""}}}`
 		fmt.Fprint(writer, response)
 	})
 
-	firewallGroup, err := client.FirewallGroup.Get(ctx, "1234abcd")
-
+	firewallGroup, meta, err := client.FirewallGroup.List(ctx, nil)
 	if err != nil {
-		t.Errorf("FirewallGroup.Get returned error: %v", err)
+		t.Errorf("FirewallGroup.List returned error: %v", err)
 	}
 
-	expected := &FirewallGroup{
-		FirewallGroupID: "1234abcd",
-		Description:     "my http firewall",
-		DateCreated:     "2017-02-14 17:48:40",
-		DateModified:    "2017-02-14 17:48:40",
-		InstanceCount:   2,
-		RuleCount:       2,
-		MaxRuleCount:    50,
+	expectedGroup := []FirewallGroup{
+		{
+			ID:            "44d0f934",
+			Description:   "govultr test",
+			DateCreated:   "2020-07-0913:53:34",
+			DateModified:  "2020-07-0913:53:34",
+			InstanceCount: 15,
+			RuleCount:     6,
+			MaxRuleCount:  999,
+		},
 	}
 
-	if !reflect.DeepEqual(firewallGroup, expected) {
-		t.Errorf("FirewallGroup.Get returned %+v, expected %+v", firewallGroup, expected)
+	expectedMeta := &Meta{
+		Total: 5,
+		Links: &Links{},
 	}
-}
-
-func TestFireWallGroupServiceHandler_ChangeDescription(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/firewall/group_set_description", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
 
-	err := client.FirewallGroup.ChangeDescription(ctx, "12345abcd", "new description")
+	if !reflect.DeepEqual(firewallGroup, expectedGroup) {
+		t.Errorf("FirewallGroup.List groups returned %+v, expected %+v", firewallGroup, expectedGroup)
+	}
 
-	if err != nil {
-		t.Errorf("FirewallGroup.ChangeDescription returned error: %v", err)
+	if !reflect.DeepEqual(meta, expectedMeta) {
+		t.Errorf("FirewallGroup.List meta returned %+v, expected %+v", meta, expectedMeta)
 	}
 }
diff --git a/firewall_rule.go b/firewall_rule.go
index ab99c1a..73cd54a 100644
--- a/firewall_rule.go
+++ b/firewall_rule.go
@@ -2,22 +2,19 @@ package govultr
 
 import (
 	"context"
-	"encoding/json"
-	"errors"
 	"fmt"
-	"net"
 	"net/http"
-	"net/url"
-	"strconv"
+
+	"github.com/google/go-querystring/query"
 )
 
 // FireWallRuleService is the interface to interact with the firewall rule endpoints on the Vultr API
-// Link: https://www.vultr.com/api/#firewall
+// Link : https://www.vultr.com/api/#tag/firewall
 type FireWallRuleService interface {
-	Create(ctx context.Context, groupID, protocol, port, network, notes string) (*FirewallRule, error)
-	Delete(ctx context.Context, groupID, ruleID string) error
-	ListByIPType(ctx context.Context, groupID, ipType string) ([]FirewallRule, error)
-	List(ctx context.Context, groupID string) ([]FirewallRule, error)
+	Create(ctx context.Context, fwGroupID string, fwRuleReq *FirewallRuleReq) (*FirewallRule, error)
+	Get(ctx context.Context, fwGroupID string, fwRuleID int) (*FirewallRule, error)
+	Delete(ctx context.Context, fwGroupID string, fwRuleID int) error
+	List(ctx context.Context, fwGroupID string, options *ListOptions) ([]FirewallRule, *Meta, error)
 }
 
 // FireWallRuleServiceHandler handles interaction with the firewall rule methods for the Vultr API
@@ -27,239 +24,103 @@ type FireWallRuleServiceHandler struct {
 
 // FirewallRule represents a Vultr firewall rule
 type FirewallRule struct {
-	RuleNumber int        `json:"rulenumber"`
-	Action     string     `json:"action"`
-	Protocol   string     `json:"protocol"`
-	Port       string     `json:"port"`
-	Network    *net.IPNet `json:"network"`
-	Notes      string     `json:"notes"`
+	ID         int    `json:"id"`
+	Action     string `json:"action"`
+	Type       string `json:"type"`
+	Protocol   string `json:"protocol"`
+	Port       string `json:"port"`
+	Subnet     string `json:"subnet"`
+	SubnetSize int    `json:"subnet_size"`
+	Source     string `json:"source"`
+	Notes      string `json:"notes"`
 }
 
-// UnmarshalJSON implements a custom unmarshaler on FirewallRule
-// This is done to help reduce data inconsistency with V1 of the Vultr API
-// It also merges the subnet & subnet_mask into a single type of *net.IPNet
-func (f *FirewallRule) UnmarshalJSON(data []byte) (err error) {
-	if f == nil {
-		*f = FirewallRule{}
-	}
-
-	// Pull out all of the data that was given to us and put it into a map
-	var fields map[string]interface{}
-	err = json.Unmarshal(data, &fields)
-
-	if err != nil {
-		return err
-	}
-
-	// Unmarshal RuleNumber
-	value := fmt.Sprintf("%v", fields["rulenumber"])
-	number, _ := strconv.Atoi(value)
-	f.RuleNumber = number
-
-	// Unmarshal all other strings
-
-	action := fmt.Sprintf("%v", fields["action"])
-	if action == "<nil>" {
-		action = ""
-	}
-	f.Action = action
-
-	protocol := fmt.Sprintf("%v", fields["protocol"])
-	if protocol == "<nil>" {
-		protocol = ""
-	}
-	f.Protocol = protocol
-
-	port := fmt.Sprintf("%v", fields["port"])
-	if port == "<nil>" {
-		port = ""
-	}
-	f.Port = port
-
-	notes := fmt.Sprintf("%v", fields["notes"])
-	if notes == "<nil>" {
-		notes = ""
-	}
-	f.Notes = notes
-
-	// Unmarshal subnet_size & subnet and convert to *net.IP
-	value = fmt.Sprintf("%v", fields["subnet_size"])
-	if len(value) == 0 || value == "<nil>" {
-		value = "0"
-	}
-	subnetSize, _ := strconv.Atoi(value)
-
-	subnet := fmt.Sprintf("%v", fields["subnet"])
-	if subnet == "<nil>" {
-		subnet = ""
-	}
-
-	if len(subnet) > 0 {
-		_, ipNet, err := net.ParseCIDR(fmt.Sprintf("%s/%d", subnet, subnetSize))
-
-		if err != nil {
-			return errors.New("an issue has occurred while parsing subnet")
-		}
+// FirewallRuleReq struct used to create a FirewallRule.
+type FirewallRuleReq struct {
+	IPType     string `json:"ip_type"`
+	Protocol   string `json:"protocol"`
+	Subnet     string `json:"subnet"`
+	SubnetSize int    `json:"subnet_size"`
+	Port       string `json:"port,omitempty"`
+	Source     string `json:"source,omitempty"`
+	Notes      string `json:"notes,omitempty"`
+}
 
-		f.Network = ipNet
-	}
+type firewallRulesBase struct {
+	FirewallRules []FirewallRule `json:"firewall_rules"`
+	Meta          *Meta          `json:"meta"`
+}
 
-	return
+type firewallRuleBase struct {
+	FirewallRule *FirewallRule `json:"firewall_rule"`
 }
 
 // Create will create a rule in a firewall group.
-func (f *FireWallRuleServiceHandler) Create(ctx context.Context, groupID, protocol, port, cdirBlock, notes string) (*FirewallRule, error) {
-
-	uri := "/v1/firewall/rule_create"
-
-	ip, ipNet, err := net.ParseCIDR(cdirBlock)
+func (f *FireWallRuleServiceHandler) Create(ctx context.Context, fwGroupID string, fwRuleReq *FirewallRuleReq) (*FirewallRule, error) {
+	uri := fmt.Sprintf("/v2/firewalls/%s/rules", fwGroupID)
 
+	req, err := f.client.NewRequest(ctx, http.MethodPost, uri, fwRuleReq)
 	if err != nil {
 		return nil, err
 	}
 
-	values := url.Values{
-		"FIREWALLGROUPID": {groupID},
-		"direction":       {"in"},
-		"protocol":        {protocol},
-		"subnet":          {ip.String()},
-	}
-
-	// mask
-	mask, _ := ipNet.Mask.Size()
-	values.Add("subnet_size", strconv.Itoa(mask))
-
-	// ip Type
-	if ipNet.IP.To4() != nil {
-		values.Add("ip_type", "v4")
-	} else {
-		values.Add("ip_type", "v6")
-	}
-
-	// Optional params
-	if port != "" {
-		values.Add("port", port)
+	firewallRule := new(firewallRuleBase)
+	if err = f.client.DoWithContext(ctx, req, firewallRule); err != nil {
+		return nil, err
 	}
 
-	if notes != "" {
-		values.Add("notes", notes)
-	}
+	return firewallRule.FirewallRule, nil
+}
 
-	req, err := f.client.NewRequest(ctx, http.MethodPost, uri, values)
+// Get will get a rule in a firewall group.
+func (f *FireWallRuleServiceHandler) Get(ctx context.Context, fwGroupID string, fwRuleID int) (*FirewallRule, error) {
+	uri := fmt.Sprintf("/v2/firewalls/%s/rules/%d", fwGroupID, fwRuleID)
 
+	req, err := f.client.NewRequest(ctx, http.MethodGet, uri, nil)
 	if err != nil {
 		return nil, err
 	}
 
-	firewallRule := new(FirewallRule)
-	err = f.client.DoWithContext(ctx, req, firewallRule)
-
-	if err != nil {
+	firewallRule := new(firewallRuleBase)
+	if err = f.client.DoWithContext(ctx, req, firewallRule); err != nil {
 		return nil, err
 	}
 
-	return firewallRule, nil
+	return firewallRule.FirewallRule, nil
 }
 
 // Delete will delete a firewall rule on your Vultr account
-func (f *FireWallRuleServiceHandler) Delete(ctx context.Context, groupID, ruleID string) error {
-
-	uri := "/v1/firewall/rule_delete"
-
-	values := url.Values{
-		"FIREWALLGROUPID": {groupID},
-		"rulenumber":      {ruleID},
-	}
-
-	req, err := f.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = f.client.DoWithContext(ctx, req, nil)
+func (f *FireWallRuleServiceHandler) Delete(ctx context.Context, fwGroupID string, fwRuleID int) error {
+	uri := fmt.Sprintf("/v2/firewalls/%s/rules/%d", fwGroupID, fwRuleID)
 
+	req, err := f.client.NewRequest(ctx, http.MethodDelete, uri, nil)
 	if err != nil {
 		return err
 	}
 
-	return nil
-}
-
-// List will list the current firewall rules in a firewall group.
-// ipType values that can be passed in are "v4", "v6"
-func (f *FireWallRuleServiceHandler) ListByIPType(ctx context.Context, groupID, ipType string) ([]FirewallRule, error) {
-
-	uri := "/v1/firewall/rule_list"
-
-	req, err := f.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
-	if err != nil {
-		return nil, err
-	}
-
-	q := req.URL.Query()
-	q.Add("FIREWALLGROUPID", groupID)
-	q.Add("direction", "in")
-	q.Add("ip_type", ipType)
-	req.URL.RawQuery = q.Encode()
-	var firewallRuleMap map[string]FirewallRule
-
-	err = f.client.DoWithContext(ctx, req, &firewallRuleMap)
-
-	if err != nil {
-		return nil, err
-	}
-
-	var firewallRule []FirewallRule
-	for _, f := range firewallRuleMap {
-		firewallRule = append(firewallRule, f)
-	}
-
-	return firewallRule, nil
+	return f.client.DoWithContext(ctx, req, nil)
 }
 
 // List will return both ipv4 an ipv6 firewall rules that are defined within a firewall group
-func (f *FireWallRuleServiceHandler) List(ctx context.Context, groupID string) ([]FirewallRule, error) {
-	uri := "/v1/firewall/rule_list"
+func (f *FireWallRuleServiceHandler) List(ctx context.Context, fwGroupID string, options *ListOptions) ([]FirewallRule, *Meta, error) {
+	uri := fmt.Sprintf("/v2/firewalls/%s/rules", fwGroupID)
 
 	req, err := f.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	q := req.URL.Query()
-	q.Add("FIREWALLGROUPID", groupID)
-	q.Add("direction", "in")
-	q.Add("ip_type", "v4")
-
-	req.URL.RawQuery = q.Encode()
-
-	var firewallRuleMap map[string]FirewallRule
-
-	// V4 call
-	err = f.client.DoWithContext(ctx, req, &firewallRuleMap)
-
+	newValues, err := query.Values(options)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	// V6 call
-	q.Del("ip_type")
-	q.Add("ip_type", "v6")
-	req.URL.RawQuery = q.Encode()
-
-	err = f.client.DoWithContext(ctx, req, &firewallRuleMap)
-
-	if err != nil {
-		return nil, err
-	}
+	req.URL.RawQuery = newValues.Encode()
 
-	var firewallRule []FirewallRule
-	for _, f := range firewallRuleMap {
-		firewallRule = append(firewallRule, f)
+	firewallRule := new(firewallRulesBase)
+	if err = f.client.DoWithContext(ctx, req, firewallRule); err != nil {
+		return nil, nil, err
 	}
 
-	return firewallRule, nil
+	return firewallRule.FirewallRules, firewallRule.Meta, nil
 }
diff --git a/firewall_rule_test.go b/firewall_rule_test.go
index 204edb1..3c16fe1 100644
--- a/firewall_rule_test.go
+++ b/firewall_rule_test.go
@@ -2,7 +2,6 @@ package govultr
 
 import (
 	"fmt"
-	"net"
 	"net/http"
 	"reflect"
 	"testing"
@@ -12,31 +11,36 @@ func TestFireWallRuleServiceHandler_Create(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/firewall/rule_create", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"rulenumber": 2}`
-
+	mux.HandleFunc("/v2/firewalls/abc123/rules", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"firewall_rule":{"id":1,"type":"v4","action":"accept","protocol":"tcp","port":"80","subnet":"127.0.0.1","subnet_size":32,"source":"","notes":"thisisanote"}}`
 		fmt.Fprint(writer, response)
 	})
 
-	firewallRule, err := client.FirewallRule.Create(ctx, "123456", "tcp", "8080", "10.0.0.0/32", "note")
-
-	if err != nil {
-		t.Errorf("FirewallRule.Create returned error: %v", err)
-	}
-
-	expected := &FirewallRule{RuleNumber: 2}
-
-	if !reflect.DeepEqual(firewallRule, expected) {
-		t.Errorf("FirewallRule.Create returned %+v, expected %+v", firewallRule, expected)
+	rule := &FirewallRuleReq{
+		IPType:     "v4",
+		Protocol:   "tcp",
+		Subnet:     "127.0.0.1",
+		SubnetSize: 30,
+		Port:       "80",
+		Notes:      "thisisanote",
 	}
 
-	firewallRule, err = client.FirewallRule.Create(ctx, "123456", "tcp", "8080", "::/0", "note")
-
+	firewallRule, err := client.FirewallRule.Create(ctx, "abc123", rule)
 	if err != nil {
 		t.Errorf("FirewallRule.Create returned error: %v", err)
 	}
 
-	expected = &FirewallRule{RuleNumber: 2}
+	expected := &FirewallRule{
+		ID:         1,
+		Action:     "accept",
+		Type:       "v4",
+		Protocol:   "tcp",
+		Port:       "80",
+		Subnet:     "127.0.0.1",
+		SubnetSize: 32,
+		Source:     "",
+		Notes:      "thisisanote",
+	}
 
 	if !reflect.DeepEqual(firewallRule, expected) {
 		t.Errorf("FirewallRule.Create returned %+v, expected %+v", firewallRule, expected)
@@ -47,90 +51,86 @@ func TestFireWallRuleServiceHandler_Delete(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/firewall/rule_delete", func(writer http.ResponseWriter, request *http.Request) {
+	mux.HandleFunc("/v2/firewalls/abc123/rules/1", func(writer http.ResponseWriter, request *http.Request) {
 		fmt.Fprint(writer)
 	})
 
-	err := client.FirewallRule.Delete(ctx, "123456", "123")
+	err := client.FirewallRule.Delete(ctx, "abc123", 1)
 
 	if err != nil {
 		t.Errorf("FirewallRule.Delete returned error: %v", err)
 	}
-
 }
 
-func TestFireWallRuleServiceHandler_GetAll(t *testing.T) {
+func TestFireWallRuleServiceHandler_List(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/firewall/rule_list", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{ "1": {"rulenumber": 1,"action": "accept","protocol": "icmp","port": "","subnet": "","subnet_size": 0,"notes": ""}}`
+	mux.HandleFunc("/v2/firewalls/abc123/rules", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"firewall_rules":[{"id":1,"type":"v4","action":"accept","protocol":"tcp","port":"22","subnet":"0.0.0.0","subnet_size":0,"source":"","notes":""}],"meta":{"total":5,"links":{"next":"","prev":""}}}`
 		fmt.Fprint(writer, response)
 	})
 
-	firewallRule, err := client.FirewallRule.ListByIPType(ctx, "12345", "v4")
+	firewallRule, meta, err := client.FirewallRule.List(ctx, "abc123", nil)
 	if err != nil {
-		t.Errorf("FirewallRule.ListByIPType returned error: %v", err)
+		t.Errorf("FirewallRule.List returned error: %v", err)
 	}
 
-	expected := []FirewallRule{
+	expectedRule := []FirewallRule{
 		{
-			RuleNumber: 1,
+			ID:         1,
 			Action:     "accept",
-			Protocol:   "icmp",
-			Network:    nil,
+			Type:       "v4",
+			Protocol:   "tcp",
+			Port:       "22",
+			Subnet:     "0.0.0.0",
+			SubnetSize: 0,
+			Source:     "",
+			Notes:      "",
 		},
 	}
 
-	if !reflect.DeepEqual(firewallRule, expected) {
-		t.Errorf("FirewallRule.ListByIPType returned %+v, expected %+v", firewallRule, expected)
-	}
-
-	firewallRule, err = client.FirewallRule.ListByIPType(ctx, "12345", "v6")
-	if err != nil {
-		t.Errorf("FirewallRule.ListByIPType returned error: %v", err)
+	expectedMeta := &Meta{
+		Total: 5,
+		Links: &Links{},
 	}
 
-	expected = []FirewallRule{
-		{
-			RuleNumber: 1,
-			Action:     "accept",
-			Protocol:   "icmp",
-			Network:    nil,
-		},
+	if !reflect.DeepEqual(firewallRule, expectedRule) {
+		t.Errorf("FirewallRule.List rules returned %+v, expected %+v", firewallRule, expectedRule)
 	}
 
-	if !reflect.DeepEqual(firewallRule, expected) {
-		t.Errorf("FirewallRule.ListByIPType returned %+v, expected %+v", firewallRule, expected)
+	if !reflect.DeepEqual(meta, expectedMeta) {
+		t.Errorf("FirewallRule.List meta returned %+v, expected %+v", meta, expectedMeta)
 	}
 }
 
-func TestFireWallRuleServiceHandler_List(t *testing.T) {
+func TestFireWallRuleServiceHandler_Get(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/firewall/rule_list", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{ "1": {"rulenumber": 1,"action": "accept","protocol": "icmp","port": "8080","subnet": "10.0.0.0","subnet_size": 32,"notes": ""}}`
+	mux.HandleFunc("/v2/firewalls/abc123/rules/1", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"firewall_rule":{"id":1,"type":"v4","action":"accept","protocol":"tcp","port":"22","subnet":"0.0.0.0","subnet_size":0,"source":"","notes":""}}`
 		fmt.Fprint(writer, response)
 	})
 
-	firewallRule, err := client.FirewallRule.List(ctx, "12345")
+	firewallRule, err := client.FirewallRule.Get(ctx, "abc123", 1)
 	if err != nil {
-		t.Errorf("FirewallRule.List returned error: %v", err)
+		t.Errorf("FirewallRule.Get returned error: %v", err)
 	}
 
-	_, ip, _ := net.ParseCIDR("10.0.0.0/32")
-	expected := []FirewallRule{
-		{
-			RuleNumber: 1,
-			Action:     "accept",
-			Protocol:   "icmp",
-			Port:       "8080",
-			Network:    ip,
-		},
+	expectedRule := &FirewallRule{
+		ID:         1,
+		Action:     "accept",
+		Type:       "v4",
+		Protocol:   "tcp",
+		Port:       "22",
+		Subnet:     "0.0.0.0",
+		SubnetSize: 0,
+		Source:     "",
+		Notes:      "",
 	}
 
-	if !reflect.DeepEqual(firewallRule, expected) {
-		t.Errorf("FirewallRule.List returned %+v, expected %+v", firewallRule, expected)
+	if !reflect.DeepEqual(firewallRule, expectedRule) {
+		t.Errorf("FirewallRule.Get returned %+v, expected %+v", firewallRule, expectedRule)
 	}
 }
diff --git a/go.mod b/go.mod
index d0abdb4..36add09 100644
--- a/go.mod
+++ b/go.mod
@@ -1,5 +1,8 @@
-module github.com/vultr/govultr
+module github.com/vultr/govultr/v2
 
-go 1.12
+go 1.16
 
-require github.com/hashicorp/go-retryablehttp v0.6.6
+require (
+	github.com/google/go-querystring v1.1.0
+	github.com/hashicorp/go-retryablehttp v0.7.0
+)
diff --git a/go.sum b/go.sum
index 5142c55..ea425ca 100644
--- a/go.sum
+++ b/go.sum
@@ -1,16 +1,14 @@
-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/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
+github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
+github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
 github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
 github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
 github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
 github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
-github.com/hashicorp/go-retryablehttp v0.6.3 h1:tuulM+WnToeqa05z83YLmKabZxrySOmJAd4mJ+s2Nfg=
-github.com/hashicorp/go-retryablehttp v0.6.3/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
-github.com/hashicorp/go-retryablehttp v0.6.4 h1:BbgctKO892xEyOXnGiaAwIoSq1QZ/SS4AhjoAh9DnfY=
-github.com/hashicorp/go-retryablehttp v0.6.4/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
-github.com/hashicorp/go-retryablehttp v0.6.6 h1:HJunrbHTDDbBb/ay4kxa1n+dLmttUlnP3V9oNE4hmsM=
-github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/hashicorp/go-retryablehttp v0.7.0 h1:eu1EI/mbirUgP5C8hVsTNaGZreBDlYiwC1FZWkvQPQ4=
+github.com/hashicorp/go-retryablehttp v0.7.0/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/govultr.go b/govultr.go
index 639ffa5..f1846ac 100644
--- a/govultr.go
+++ b/govultr.go
@@ -1,11 +1,11 @@
 package govultr
 
 import (
+	"bytes"
 	"context"
 	"encoding/json"
 	"errors"
 	"fmt"
-	"io"
 	"io/ioutil"
 	"net/http"
 	"net/url"
@@ -16,36 +16,22 @@ import (
 )
 
 const (
-	version     = "0.4.2"
+	version     = "2.14.2"
 	defaultBase = "https://api.vultr.com"
 	userAgent   = "govultr/" + version
-	rateLimit   = 600 * time.Millisecond
+	rateLimit   = 500 * time.Millisecond
 	retryLimit  = 3
 )
 
-// whiteListURI is an array of endpoints that should not have the API Key passed to them
-var whiteListURI = [13]string{
-	"/v1/regions/availability",
-	"/v1/app/list",
-	"/v1/objectstorage/list_cluster",
-	"/v1/os/list",
-	"/v1/plans/list",
-	"/v1/plans/list_baremetal",
-	"/v1/plans/list_vc2",
-	"/v1/plans/list_vc2z",
-	"/v1/plans/list_vdc2",
-	"/v1/regions/list",
-	"/v1/regions/availability_vc2",
-	"/v1/regions/availability_vdc2",
-	"/v1/regions/availability_baremetal",
-}
-
 // APIKey contains a users API Key for interacting with the API
 type APIKey struct {
 	// API Key
 	key string
 }
 
+// RequestBody is used to create JSON bodies for one off calls
+type RequestBody map[string]interface{}
+
 // Client manages interaction with the Vultr V1 API
 type Client struct {
 	// Http Client used to interact with the Vultr V1 API
@@ -57,21 +43,20 @@ type Client struct {
 	// User Agent for the client
 	UserAgent string
 
-	// API Key
-	APIKey APIKey
-
 	// Services used to interact with the API
 	Account         AccountService
-	API             APIService
 	Application     ApplicationService
 	Backup          BackupService
 	BareMetalServer BareMetalServerService
+	Billing         BillingService
 	BlockStorage    BlockStorageService
-	DNSDomain       DNSDomainService
-	DNSRecord       DNSRecordService
+	Domain          DomainService
+	DomainRecord    DomainRecordService
 	FirewallGroup   FirewallGroupService
 	FirewallRule    FireWallRuleService
+	Instance        InstanceService
 	ISO             ISOService
+	Kubernetes      KubernetesService
 	LoadBalancer    LoadBalancerService
 	Network         NetworkService
 	ObjectStorage   ObjectStorageService
@@ -79,7 +64,6 @@ type Client struct {
 	Plan            PlanService
 	Region          RegionService
 	ReservedIP      ReservedIPService
-	Server          ServerService
 	Snapshot        SnapshotService
 	SSHKey          SSHKeyService
 	StartupScript   StartupScriptService
@@ -93,7 +77,7 @@ type Client struct {
 type RequestCompletionCallback func(*http.Request, *http.Response)
 
 // NewClient returns a Vultr API Client
-func NewClient(httpClient *http.Client, key string) *Client {
+func NewClient(httpClient *http.Client) *Client {
 
 	if httpClient == nil {
 		httpClient = http.DefaultClient
@@ -114,73 +98,55 @@ func NewClient(httpClient *http.Client, key string) *Client {
 	client.SetRateLimit(rateLimit)
 
 	client.Account = &AccountServiceHandler{client}
-	client.API = &APIServiceHandler{client}
 	client.Application = &ApplicationServiceHandler{client}
 	client.Backup = &BackupServiceHandler{client}
 	client.BareMetalServer = &BareMetalServerServiceHandler{client}
+	client.Billing = &BillingServiceHandler{client}
 	client.BlockStorage = &BlockStorageServiceHandler{client}
-	client.DNSDomain = &DNSDomainServiceHandler{client}
-	client.DNSRecord = &DNSRecordsServiceHandler{client}
+	client.Domain = &DomainServiceHandler{client}
+	client.DomainRecord = &DomainRecordsServiceHandler{client}
 	client.FirewallGroup = &FireWallGroupServiceHandler{client}
 	client.FirewallRule = &FireWallRuleServiceHandler{client}
+	client.Instance = &InstanceServiceHandler{client}
 	client.ISO = &ISOServiceHandler{client}
+	client.Kubernetes = &KubernetesHandler{client}
 	client.LoadBalancer = &LoadBalancerHandler{client}
 	client.Network = &NetworkServiceHandler{client}
 	client.ObjectStorage = &ObjectStorageServiceHandler{client}
 	client.OS = &OSServiceHandler{client}
 	client.Plan = &PlanServiceHandler{client}
 	client.Region = &RegionServiceHandler{client}
-	client.Server = &ServerServiceHandler{client}
 	client.ReservedIP = &ReservedIPServiceHandler{client}
 	client.Snapshot = &SnapshotServiceHandler{client}
 	client.SSHKey = &SSHKeyServiceHandler{client}
 	client.StartupScript = &StartupScriptServiceHandler{client}
 	client.User = &UserServiceHandler{client}
 
-	apiKey := APIKey{key: key}
-	client.APIKey = apiKey
-
 	return client
 }
 
 // NewRequest creates an API Request
-func (c *Client) NewRequest(ctx context.Context, method, uri string, body url.Values) (*http.Request, error) {
-
-	path, err := url.Parse(uri)
-	resolvedURL := c.BaseURL.ResolveReference(path)
-
+func (c *Client) NewRequest(ctx context.Context, method, uri string, body interface{}) (*http.Request, error) {
+	resolvedURL, err := c.BaseURL.Parse(uri)
 	if err != nil {
 		return nil, err
 	}
 
-	var reqBody io.Reader
-
+	buf := new(bytes.Buffer)
 	if body != nil {
-		reqBody = strings.NewReader(body.Encode())
-	} else {
-		reqBody = nil
+		if err = json.NewEncoder(buf).Encode(body); err != nil {
+			return nil, err
+		}
 	}
 
-	req, err := http.NewRequest(method, resolvedURL.String(), reqBody)
-
+	req, err := http.NewRequest(method, resolvedURL.String(), buf)
 	if err != nil {
 		return nil, err
 	}
 
-	req.Header.Add("API-key", c.APIKey.key)
-	for _, v := range whiteListURI {
-		if v == uri {
-			req.Header.Del("API-key")
-			break
-		}
-	}
-
 	req.Header.Add("User-Agent", c.UserAgent)
 	req.Header.Add("Accept", "application/json")
-
-	if req.Method == "POST" {
-		req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
-	}
+	req.Header.Add("Content-Type", "application/json")
 
 	return req, nil
 }
@@ -189,9 +155,7 @@ func (c *Client) NewRequest(ctx context.Context, method, uri string, body url.Va
 // a successful call. A successful call is then checked to see if we need to unmarshal since some resources
 // have their own implements of unmarshal.
 func (c *Client) DoWithContext(ctx context.Context, r *http.Request, data interface{}) error {
-
 	rreq, err := retryablehttp.FromRequest(r)
-
 	if err != nil {
 		return err
 	}
@@ -211,19 +175,14 @@ func (c *Client) DoWithContext(ctx context.Context, r *http.Request, data interf
 	defer res.Body.Close()
 
 	body, err := ioutil.ReadAll(res.Body)
-
 	if err != nil {
 		return err
 	}
 
-	if res.StatusCode == http.StatusOK {
+	if res.StatusCode >= http.StatusOK && res.StatusCode <= http.StatusNoContent {
 		if data != nil {
-			if string(body) == "[]" {
-				data = nil
-			} else {
-				if err := json.Unmarshal(body, data); err != nil {
-					return err
-				}
+			if err := json.Unmarshal(body, data); err != nil {
+				return err
 			}
 		}
 		return nil
@@ -268,12 +227,30 @@ func (c *Client) SetRetryLimit(n int) {
 
 func (c *Client) vultrErrorHandler(resp *http.Response, err error, numTries int) (*http.Response, error) {
 	if resp == nil {
-		return nil, fmt.Errorf("gave up after %d attempts, last error unavailable (resp == nil)", c.client.RetryMax+1)
+		if err != nil {
+			return nil, fmt.Errorf("gave up after %d attempts, last error : %s", numTries, err.Error())
+		}
+		return nil, fmt.Errorf("gave up after %d attempts, last error unavailable (resp == nil)", numTries)
 	}
 
 	buf, err := ioutil.ReadAll(resp.Body)
 	if err != nil {
-		return nil, fmt.Errorf("gave up after %d attempts, last error unavailable (error reading response body: %v)", c.client.RetryMax+1, err)
+		return nil, fmt.Errorf("gave up after %d attempts, last error unavailable (error reading response body: %v)", numTries, err)
 	}
-	return nil, fmt.Errorf("gave up after %d attempts, last error: %#v", c.client.RetryMax+1, strings.TrimSpace(string(buf)))
+	return nil, fmt.Errorf("gave up after %d attempts, last error: %#v", numTries, strings.TrimSpace(string(buf)))
+}
+
+// BoolToBoolPtr helper function that returns a pointer from your bool value
+func BoolToBoolPtr(value bool) *bool {
+	return &value
+}
+
+// StringToStringPtr helper function that returns a pointer from your string value
+func StringToStringPtr(value string) *string {
+	return &value
+}
+
+// IntToIntPtr helper function that returns a pointer from your string value
+func IntToIntPtr(value int) *int {
+	return &value
 }
diff --git a/govultr_test.go b/govultr_test.go
index 02f56db..ca6f687 100644
--- a/govultr_test.go
+++ b/govultr_test.go
@@ -26,7 +26,7 @@ func setup() {
 	mux = http.NewServeMux()
 	server = httptest.NewServer(mux)
 
-	client = NewClient(nil, "dummy-key")
+	client = NewClient(nil)
 	url, _ := url.Parse(server.URL)
 	client.BaseURL = url
 }
@@ -43,9 +43,9 @@ func TestNewClient(t *testing.T) {
 		t.Errorf("NewClient BaseURL = %v, expected %v", client.BaseURL, server.URL)
 	}
 
-	if client.APIKey.key != "dummy-key" {
-		t.Errorf("NewClient ApiKey = %v, expected %v", client.APIKey.key, "dummy-key")
-	}
+	//if client != "dummy-key" {
+	//	t.Errorf("NewClient ApiKey = %v, expected %v", client.APIKey.key, "dummy-key")
+	//}
 
 	if client.UserAgent != userAgent {
 		t.Errorf("NewClient UserAgent = %v, expected %v", client.UserAgent, userAgent)
@@ -130,7 +130,7 @@ func TestClient_DoWithContextError(t *testing.T) {
 
 	client = NewClient(&http.Client{
 		Transport: errRoundTripper{},
-	}, "dummy-key")
+	})
 
 	req, _ := client.NewRequest(ctx, http.MethodGet, "/", nil)
 
@@ -149,18 +149,15 @@ func TestClient_DoWithContextError(t *testing.T) {
 }
 
 func TestClient_NewRequest(t *testing.T) {
-	c := NewClient(nil, "dum-dum")
+	c := NewClient(nil)
 
 	in := "/unit"
 	out := defaultBase + "/unit"
 
-	inRequest := url.Values{
-		"balance": {"500"},
-	}
-	outRequest := `balance=500`
+	inRequest := RequestBody{"balance": 500}
+	outRequest := `{"balance":500}` + "\n"
 
 	req, _ := c.NewRequest(ctx, http.MethodPost, in, inRequest)
-
 	if req.URL.String() != out {
 		t.Errorf("NewRequest(%v) URL = %v, expected %v", in, req.URL, out)
 	}
@@ -176,12 +173,8 @@ func TestClient_NewRequest(t *testing.T) {
 		t.Errorf("NewRequest() User-Agent = %v, expected %v", userAgent, c.UserAgent)
 	}
 
-	if c.APIKey.key != "dum-dum" {
-		t.Errorf("NewRequest() API-Key = %v, expected %v", c.APIKey.key, "dum-dum")
-	}
-
 	contentType := req.Header.Get("Content-Type")
-	if contentType != "application/x-www-form-urlencoded" {
+	if contentType != "application/json" {
 		t.Errorf("NewRequest() Header Content Type = %v, expected %v", contentType, "application/x-www-form-urlencoded")
 	}
 
@@ -201,6 +194,10 @@ func TestClient_SetBaseUrl(t *testing.T) {
 	if client.BaseURL.String() != base {
 		t.Errorf("NewClient BaseUrl = %v, expected %v", client.BaseURL, base)
 	}
+
+	if err := client.SetBaseURL(":"); err == nil {
+		t.Error("Expected invalid BaseURL to fail")
+	}
 }
 
 func TestClient_SetUserAgent(t *testing.T) {
@@ -280,3 +277,49 @@ func TestClient_SetRetryLimit(t *testing.T) {
 		t.Errorf("NewClient RateLimit = %v, expected %v", client.client.RetryMax, 4)
 	}
 }
+
+func TestNewRequest_badURI(t *testing.T) {
+	c := NewClient(nil)
+	_, err := c.NewRequest(ctx, http.MethodGet, ":/1.", nil)
+	if err == nil {
+		t.Error("expected invalid URI to fail")
+	}
+}
+
+func TestNewRequest_badBody(t *testing.T) {
+	c := NewClient(nil)
+	_, err := c.NewRequest(ctx, http.MethodGet, "/", make(chan int))
+	if err == nil {
+		t.Error("expected invalid Body to fail")
+	}
+}
+
+func TestRequest_InvalidCall(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/wrong", func(writer http.ResponseWriter, request *http.Request) {
+		writer.WriteHeader(http.StatusBadRequest)
+		fmt.Fprint(writer, nil)
+	})
+
+	req, _ := client.NewRequest(ctx, http.MethodGet, "/wrong", nil)
+	if err := client.DoWithContext(ctx, req, nil); err == nil {
+		t.Error("Expected invalid status code to bad request")
+	}
+}
+
+func TestRequest_InvalidResponseBody(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/wrong", func(writer http.ResponseWriter, request *http.Request) {
+		writer.WriteHeader(http.StatusOK)
+		fmt.Fprint(writer, `{`)
+	})
+
+	req, _ := client.NewRequest(ctx, http.MethodGet, "/wrong", nil)
+	if err := client.DoWithContext(ctx, req, struct{}{}); err == nil {
+		t.Error("Expected response body to be invalid")
+	}
+}
diff --git a/instance.go b/instance.go
new file mode 100644
index 0000000..3312d47
--- /dev/null
+++ b/instance.go
@@ -0,0 +1,762 @@
+package govultr
+
+import (
+	"context"
+	"fmt"
+	"net/http"
+
+	"github.com/google/go-querystring/query"
+)
+
+const instancePath = "/v2/instances"
+
+// InstanceService is the interface to interact with the instance endpoints on the Vultr API
+// Link: https://www.vultr.com/api/#tag/instances
+type InstanceService interface {
+	Create(ctx context.Context, instanceReq *InstanceCreateReq) (*Instance, error)
+	Get(ctx context.Context, instanceID string) (*Instance, error)
+	Update(ctx context.Context, instanceID string, instanceReq *InstanceUpdateReq) (*Instance, error)
+	Delete(ctx context.Context, instanceID string) error
+	List(ctx context.Context, options *ListOptions) ([]Instance, *Meta, error)
+
+	Start(ctx context.Context, instanceID string) error
+	Halt(ctx context.Context, instanceID string) error
+	Reboot(ctx context.Context, instanceID string) error
+	Reinstall(ctx context.Context, instanceID string, reinstallReq *ReinstallReq) (*Instance, error)
+
+	MassStart(ctx context.Context, instanceList []string) error
+	MassHalt(ctx context.Context, instanceList []string) error
+	MassReboot(ctx context.Context, instanceList []string) error
+
+	Restore(ctx context.Context, instanceID string, restoreReq *RestoreReq) error
+
+	GetBandwidth(ctx context.Context, instanceID string) (*Bandwidth, error)
+	GetNeighbors(ctx context.Context, instanceID string) (*Neighbors, error)
+
+	ListPrivateNetworks(ctx context.Context, instanceID string, options *ListOptions) ([]PrivateNetwork, *Meta, error)
+	AttachPrivateNetwork(ctx context.Context, instanceID, networkID string) error
+	DetachPrivateNetwork(ctx context.Context, instanceID, networkID string) error
+
+	ISOStatus(ctx context.Context, instanceID string) (*Iso, error)
+	AttachISO(ctx context.Context, instanceID, isoID string) error
+	DetachISO(ctx context.Context, instanceID string) error
+
+	GetBackupSchedule(ctx context.Context, instanceID string) (*BackupSchedule, error)
+	SetBackupSchedule(ctx context.Context, instanceID string, backup *BackupScheduleReq) error
+
+	CreateIPv4(ctx context.Context, instanceID string, reboot *bool) (*IPv4, error)
+	ListIPv4(ctx context.Context, instanceID string, option *ListOptions) ([]IPv4, *Meta, error)
+	DeleteIPv4(ctx context.Context, instanceID, ip string) error
+	ListIPv6(ctx context.Context, instanceID string, option *ListOptions) ([]IPv6, *Meta, error)
+
+	CreateReverseIPv6(ctx context.Context, instanceID string, reverseReq *ReverseIP) error
+	ListReverseIPv6(ctx context.Context, instanceID string) ([]ReverseIP, error)
+	DeleteReverseIPv6(ctx context.Context, instanceID, ip string) error
+
+	CreateReverseIPv4(ctx context.Context, instanceID string, reverseReq *ReverseIP) error
+	DefaultReverseIPv4(ctx context.Context, instanceID, ip string) error
+
+	GetUserData(ctx context.Context, instanceID string) (*UserData, error)
+
+	GetUpgrades(ctx context.Context, instanceID string) (*Upgrades, error)
+}
+
+// InstanceServiceHandler handles interaction with the server methods for the Vultr API
+type InstanceServiceHandler struct {
+	client *Client
+}
+
+// Instance represents a VPS
+type Instance struct {
+	ID               string   `json:"id"`
+	Os               string   `json:"os"`
+	RAM              int      `json:"ram"`
+	Disk             int      `json:"disk"`
+	Plan             string   `json:"plan"`
+	MainIP           string   `json:"main_ip"`
+	VCPUCount        int      `json:"vcpu_count"`
+	Region           string   `json:"region"`
+	DefaultPassword  string   `json:"default_password,omitempty"`
+	DateCreated      string   `json:"date_created"`
+	Status           string   `json:"status"`
+	AllowedBandwidth int      `json:"allowed_bandwidth"`
+	NetmaskV4        string   `json:"netmask_v4"`
+	GatewayV4        string   `json:"gateway_v4"`
+	PowerStatus      string   `json:"power_status"`
+	ServerStatus     string   `json:"server_status"`
+	V6Network        string   `json:"v6_network"`
+	V6MainIP         string   `json:"v6_main_ip"`
+	V6NetworkSize    int      `json:"v6_network_size"`
+	Label            string   `json:"label"`
+	InternalIP       string   `json:"internal_ip"`
+	KVM              string   `json:"kvm"`
+	Tag              string   `json:"tag"`
+	OsID             int      `json:"os_id"`
+	AppID            int      `json:"app_id"`
+	ImageID          string   `json:"image_id"`
+	FirewallGroupID  string   `json:"firewall_group_id"`
+	Features         []string `json:"features"`
+	Hostname         string   `json:"hostname"`
+}
+
+type instanceBase struct {
+	Instance *Instance `json:"instance"`
+}
+
+type ipv4Base struct {
+	IPv4 *IPv4 `json:"ipv4"`
+}
+
+type instancesBase struct {
+	Instances []Instance `json:"instances"`
+	Meta      *Meta      `json:"meta"`
+}
+
+// Neighbors that might exist on the same host.
+type Neighbors struct {
+	Neighbors []string `json:"neighbors"`
+}
+
+// Bandwidth used on a given instance.
+type Bandwidth struct {
+	Bandwidth map[string]struct {
+		IncomingBytes int `json:"incoming_bytes"`
+		OutgoingBytes int `json:"outgoing_bytes"`
+	} `json:"bandwidth"`
+}
+
+type privateNetworksBase struct {
+	PrivateNetworks []PrivateNetwork `json:"private_networks"`
+	Meta            *Meta            `json:"meta"`
+}
+
+// PrivateNetwork information for a given instance.
+type PrivateNetwork struct {
+	NetworkID  string `json:"network_id"`
+	MacAddress string `json:"mac_address"`
+	IPAddress  string `json:"ip_address"`
+}
+
+type isoStatusBase struct {
+	IsoStatus *Iso `json:"iso_status"`
+}
+
+// Iso information for a given instance.
+type Iso struct {
+	State string `json:"state"`
+	IsoID string `json:"iso_id"`
+}
+
+type backupScheduleBase struct {
+	BackupSchedule *BackupSchedule `json:"backup_schedule"`
+}
+
+// BackupSchedule information for a given instance.
+type BackupSchedule struct {
+	Enabled             *bool  `json:"enabled,omitempty"`
+	Type                string `json:"type,omitempty"`
+	NextScheduleTimeUTC string `json:"next_scheduled_time_utc,omitempty"`
+	Hour                int    `json:"hour,omitempty"`
+	Dow                 int    `json:"dow,omitempty"`
+	Dom                 int    `json:"dom,omitempty"`
+}
+
+// BackupScheduleReq struct used to create a backup schedule for an instance.
+type BackupScheduleReq struct {
+	Type string `json:"type"`
+	Hour *int   `json:"hour,omitempty"`
+	Dow  *int   `json:"dow,omitempty"`
+	Dom  int    `json:"dom,omitempty"`
+}
+
+// RestoreReq struct used to supply whether a restore should be from a backup or snapshot.
+type RestoreReq struct {
+	BackupID   string `json:"backup_id,omitempty"`
+	SnapshotID string `json:"snapshot_id,omitempty"`
+}
+
+// todo can we remove this list and return this data back in the list?
+type reverseIPv6sBase struct {
+	ReverseIPv6s []ReverseIP `json:"reverse_ipv6s"`
+	// no meta?
+}
+
+// ReverseIP information for a given instance.
+type ReverseIP struct {
+	IP      string `json:"ip"`
+	Reverse string `json:"reverse"`
+}
+
+type userDataBase struct {
+	UserData *UserData `json:"user_data"`
+}
+
+// UserData information for a given struct.
+type UserData struct {
+	Data string `json:"data"`
+}
+
+type upgradeBase struct {
+	Upgrades *Upgrades `json:"upgrades"`
+}
+
+// Upgrades that are available for a given Instance.
+type Upgrades struct {
+	Applications []Application `json:"applications,omitempty"`
+	OS           []OS          `json:"os,omitempty"`
+	Plans        []string      `json:"plans,omitempty"`
+}
+
+// InstanceCreateReq struct used to create an instance.
+type InstanceCreateReq struct {
+	Region               string   `json:"region,omitempty"`
+	Plan                 string   `json:"plan,omitempty"`
+	Label                string   `json:"label,omitempty"`
+	Tag                  string   `json:"tag,omitempty"`
+	OsID                 int      `json:"os_id,omitempty"`
+	ISOID                string   `json:"iso_id,omitempty"`
+	AppID                int      `json:"app_id,omitempty"`
+	ImageID              string   `json:"image_id,omitempty"`
+	FirewallGroupID      string   `json:"firewall_group_id,omitempty"`
+	Hostname             string   `json:"hostname,omitempty"`
+	IPXEChainURL         string   `json:"ipxe_chain_url,omitempty"`
+	ScriptID             string   `json:"script_id,omitempty"`
+	SnapshotID           string   `json:"snapshot_id,omitempty"`
+	EnableIPv6           *bool    `json:"enable_ipv6,omitempty"`
+	EnablePrivateNetwork *bool    `json:"enable_private_network,omitempty"`
+	AttachPrivateNetwork []string `json:"attach_private_network,omitempty"`
+	SSHKeys              []string `json:"sshkey_id,omitempty"`
+	Backups              string   `json:"backups,omitempty"`
+	DDOSProtection       *bool    `json:"ddos_protection,omitempty"`
+	UserData             string   `json:"user_data,omitempty"`
+	ReservedIPv4         string   `json:"reserved_ipv4,omitempty"`
+	ActivationEmail      *bool    `json:"activation_email,omitempty"`
+}
+
+// InstanceUpdateReq struct used to update an instance.
+type InstanceUpdateReq struct {
+	Plan                 string   `json:"plan,omitempty"`
+	Label                string   `json:"label,omitempty"`
+	Tag                  string   `json:"tag,omitempty"`
+	OsID                 int      `json:"os_id,omitempty"`
+	AppID                int      `json:"app_id,omitempty"`
+	ImageID              string   `json:"image_id,omitempty"`
+	EnableIPv6           *bool    `json:"enable_ipv6,omitempty"`
+	EnablePrivateNetwork *bool    `json:"enable_private_network,omitempty"`
+	AttachPrivateNetwork []string `json:"attach_private_network,omitempty"`
+	DetachPrivateNetwork []string `json:"detach_private_network,omitempty"`
+	Backups              string   `json:"backups,omitempty"`
+	DDOSProtection       *bool    `json:"ddos_protection"`
+	UserData             string   `json:"user_data,omitempty"`
+	FirewallGroupID      string   `json:"firewall_group_id,omitempty"`
+}
+
+// ReinstallReq struct used to allow changes during a reinstall
+type ReinstallReq struct {
+	Hostname string `json:"hostname,omitempty"`
+}
+
+// Create will create the server with the given parameters
+func (i *InstanceServiceHandler) Create(ctx context.Context, instanceReq *InstanceCreateReq) (*Instance, error) {
+	uri := fmt.Sprintf("%s", instancePath)
+
+	req, err := i.client.NewRequest(ctx, http.MethodPost, uri, instanceReq)
+	if err != nil {
+		return nil, err
+	}
+
+	instance := new(instanceBase)
+	if err = i.client.DoWithContext(ctx, req, instance); err != nil {
+		return nil, err
+	}
+
+	return instance.Instance, nil
+}
+
+// Get will get the server with the given instanceID
+func (i *InstanceServiceHandler) Get(ctx context.Context, instanceID string) (*Instance, error) {
+	uri := fmt.Sprintf("%s/%s", instancePath, instanceID)
+
+	req, err := i.client.NewRequest(ctx, http.MethodGet, uri, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	instance := new(instanceBase)
+	if err = i.client.DoWithContext(ctx, req, instance); err != nil {
+		return nil, err
+	}
+
+	return instance.Instance, nil
+}
+
+// Update will update the server with the given parameters
+func (i *InstanceServiceHandler) Update(ctx context.Context, instanceID string, instanceReq *InstanceUpdateReq) (*Instance, error) {
+	uri := fmt.Sprintf("%s/%s", instancePath, instanceID)
+
+	req, err := i.client.NewRequest(ctx, http.MethodPatch, uri, instanceReq)
+	if err != nil {
+		return nil, err
+	}
+
+	instance := new(instanceBase)
+	if err := i.client.DoWithContext(ctx, req, instance); err != nil {
+		return nil, err
+	}
+
+	return instance.Instance, nil
+}
+
+// Delete an instance. All data will be permanently lost, and the IP address will be released
+func (i *InstanceServiceHandler) Delete(ctx context.Context, instanceID string) error {
+	uri := fmt.Sprintf("%s/%s", instancePath, instanceID)
+
+	req, err := i.client.NewRequest(ctx, http.MethodDelete, uri, nil)
+	if err != nil {
+		return err
+	}
+
+	return i.client.DoWithContext(ctx, req, nil)
+}
+
+// List all instances on your account.
+func (i *InstanceServiceHandler) List(ctx context.Context, options *ListOptions) ([]Instance, *Meta, error) {
+	req, err := i.client.NewRequest(ctx, http.MethodGet, instancePath, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	newValues, err := query.Values(options)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	req.URL.RawQuery = newValues.Encode()
+
+	instances := new(instancesBase)
+	if err = i.client.DoWithContext(ctx, req, instances); err != nil {
+		return nil, nil, err
+	}
+
+	return instances.Instances, instances.Meta, nil
+}
+
+// Start will start a vps instance the machine is already running, it will be restarted.
+func (i *InstanceServiceHandler) Start(ctx context.Context, instanceID string) error {
+	uri := fmt.Sprintf("%s/%s/start", instancePath, instanceID)
+
+	req, err := i.client.NewRequest(ctx, http.MethodPost, uri, nil)
+	if err != nil {
+		return err
+	}
+
+	return i.client.DoWithContext(ctx, req, nil)
+}
+
+// Halt will pause an instance.
+func (i *InstanceServiceHandler) Halt(ctx context.Context, instanceID string) error {
+	uri := fmt.Sprintf("%s/%s/halt", instancePath, instanceID)
+
+	req, err := i.client.NewRequest(ctx, http.MethodPost, uri, nil)
+	if err != nil {
+		return err
+	}
+
+	return i.client.DoWithContext(ctx, req, nil)
+}
+
+// Reboot an instance.
+func (i *InstanceServiceHandler) Reboot(ctx context.Context, instanceID string) error {
+	uri := fmt.Sprintf("%s/%s/reboot", instancePath, instanceID)
+
+	req, err := i.client.NewRequest(ctx, http.MethodPost, uri, nil)
+	if err != nil {
+		return err
+	}
+
+	return i.client.DoWithContext(ctx, req, nil)
+}
+
+// Reinstall an instance.
+func (i *InstanceServiceHandler) Reinstall(ctx context.Context, instanceID string, reinstallReq *ReinstallReq) (*Instance, error) {
+	uri := fmt.Sprintf("%s/%s/reinstall", instancePath, instanceID)
+
+	req, err := i.client.NewRequest(ctx, http.MethodPost, uri, reinstallReq)
+	if err != nil {
+		return nil, err
+	}
+
+	instance := new(instanceBase)
+	if err := i.client.DoWithContext(ctx, req, instance); err != nil {
+		return nil, err
+	}
+	return instance.Instance, nil
+}
+
+// MassStart will start a list of instances the machine is already running, it will be restarted.
+func (i *InstanceServiceHandler) MassStart(ctx context.Context, instanceList []string) error {
+	uri := fmt.Sprintf("%s/start", instancePath)
+
+	reqBody := RequestBody{"instance_ids": instanceList}
+	req, err := i.client.NewRequest(ctx, http.MethodPost, uri, reqBody)
+	if err != nil {
+		return err
+	}
+
+	return i.client.DoWithContext(ctx, req, nil)
+}
+
+// MassHalt will pause a list of instances.
+func (i *InstanceServiceHandler) MassHalt(ctx context.Context, instanceList []string) error {
+	uri := fmt.Sprintf("%s/halt", instancePath)
+
+	reqBody := RequestBody{"instance_ids": instanceList}
+	req, err := i.client.NewRequest(ctx, http.MethodPost, uri, reqBody)
+	if err != nil {
+		return err
+	}
+
+	return i.client.DoWithContext(ctx, req, nil)
+}
+
+// MassReboot reboots a list of instances.
+func (i *InstanceServiceHandler) MassReboot(ctx context.Context, instanceList []string) error {
+	uri := fmt.Sprintf("%s/reboot", instancePath)
+
+	reqBody := RequestBody{"instance_ids": instanceList}
+	req, err := i.client.NewRequest(ctx, http.MethodPost, uri, reqBody)
+	if err != nil {
+		return err
+	}
+
+	return i.client.DoWithContext(ctx, req, nil)
+}
+
+// Restore an instance.
+func (i *InstanceServiceHandler) Restore(ctx context.Context, instanceID string, restoreReq *RestoreReq) error {
+	uri := fmt.Sprintf("%s/%s/restore", instancePath, instanceID)
+
+	req, err := i.client.NewRequest(ctx, http.MethodPost, uri, restoreReq)
+	if err != nil {
+		return err
+	}
+
+	return i.client.DoWithContext(ctx, req, nil)
+}
+
+// GetBandwidth for a given instance.
+func (i *InstanceServiceHandler) GetBandwidth(ctx context.Context, instanceID string) (*Bandwidth, error) {
+	uri := fmt.Sprintf("%s/%s/bandwidth", instancePath, instanceID)
+	req, err := i.client.NewRequest(ctx, http.MethodGet, uri, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	bandwidth := new(Bandwidth)
+	if err = i.client.DoWithContext(ctx, req, bandwidth); err != nil {
+		return nil, err
+	}
+
+	return bandwidth, nil
+}
+
+// GetNeighbors gets a list of other instances in the same location as this Instance.
+func (i *InstanceServiceHandler) GetNeighbors(ctx context.Context, instanceID string) (*Neighbors, error) {
+	uri := fmt.Sprintf("%s/%s/neighbors", instancePath, instanceID)
+	req, err := i.client.NewRequest(ctx, http.MethodGet, uri, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	neighbors := new(Neighbors)
+	if err = i.client.DoWithContext(ctx, req, neighbors); err != nil {
+		return nil, err
+	}
+
+	return neighbors, nil
+}
+
+// ListPrivateNetworks currently attached to an instance.
+func (i *InstanceServiceHandler) ListPrivateNetworks(ctx context.Context, instanceID string, options *ListOptions) ([]PrivateNetwork, *Meta, error) {
+	uri := fmt.Sprintf("%s/%s/private-networks", instancePath, instanceID)
+	req, err := i.client.NewRequest(ctx, http.MethodGet, uri, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	newValues, err := query.Values(options)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	req.URL.RawQuery = newValues.Encode()
+
+	networks := new(privateNetworksBase)
+	if err = i.client.DoWithContext(ctx, req, networks); err != nil {
+		return nil, nil, err
+	}
+
+	return networks.PrivateNetworks, networks.Meta, nil
+}
+
+// AttachPrivateNetwork to an instance
+func (i *InstanceServiceHandler) AttachPrivateNetwork(ctx context.Context, instanceID, networkID string) error {
+	uri := fmt.Sprintf("%s/%s/private-networks/attach", instancePath, instanceID)
+	body := RequestBody{"network_id": networkID}
+
+	req, err := i.client.NewRequest(ctx, http.MethodPost, uri, body)
+	if err != nil {
+		return err
+	}
+
+	return i.client.DoWithContext(ctx, req, nil)
+}
+
+// DetachPrivateNetwork from an instance.
+func (i *InstanceServiceHandler) DetachPrivateNetwork(ctx context.Context, instanceID, networkID string) error {
+	uri := fmt.Sprintf("%s/%s/private-networks/detach", instancePath, instanceID)
+	body := RequestBody{"network_id": networkID}
+
+	req, err := i.client.NewRequest(ctx, http.MethodPost, uri, body)
+	if err != nil {
+		return err
+	}
+
+	return i.client.DoWithContext(ctx, req, nil)
+}
+
+// ISOStatus retrieves the current ISO state for a given VPS.
+// The returned state may be one of: ready | isomounting | isomounted.
+func (i *InstanceServiceHandler) ISOStatus(ctx context.Context, instanceID string) (*Iso, error) {
+	uri := fmt.Sprintf("%s/%s/iso", instancePath, instanceID)
+	req, err := i.client.NewRequest(ctx, http.MethodGet, uri, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	iso := new(isoStatusBase)
+	if err = i.client.DoWithContext(ctx, req, iso); err != nil {
+		return nil, err
+	}
+	return iso.IsoStatus, nil
+}
+
+// AttachISO will attach an ISO to the given instance and reboot it
+func (i *InstanceServiceHandler) AttachISO(ctx context.Context, instanceID, isoID string) error {
+	uri := fmt.Sprintf("%s/%s/iso/attach", instancePath, instanceID)
+	body := RequestBody{"iso_id": isoID}
+
+	req, err := i.client.NewRequest(ctx, http.MethodPost, uri, body)
+	if err != nil {
+		return err
+	}
+
+	return i.client.DoWithContext(ctx, req, nil)
+}
+
+// DetachISO will detach the currently mounted ISO and reboot the instance.
+func (i *InstanceServiceHandler) DetachISO(ctx context.Context, instanceID string) error {
+	uri := fmt.Sprintf("%s/%s/iso/detach", instancePath, instanceID)
+
+	req, err := i.client.NewRequest(ctx, http.MethodPost, uri, nil)
+	if err != nil {
+		return err
+	}
+
+	return i.client.DoWithContext(ctx, req, nil)
+}
+
+// GetBackupSchedule retrieves the backup schedule for a given instance - all time values are in UTC
+func (i *InstanceServiceHandler) GetBackupSchedule(ctx context.Context, instanceID string) (*BackupSchedule, error) {
+	uri := fmt.Sprintf("%s/%s/backup-schedule", instancePath, instanceID)
+	req, err := i.client.NewRequest(ctx, http.MethodGet, uri, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	backup := new(backupScheduleBase)
+	if err = i.client.DoWithContext(ctx, req, backup); err != nil {
+		return nil, err
+	}
+
+	return backup.BackupSchedule, nil
+}
+
+// SetBackupSchedule sets the backup schedule for a given instance - all time values are in UTC.
+func (i *InstanceServiceHandler) SetBackupSchedule(ctx context.Context, instanceID string, backup *BackupScheduleReq) error {
+	uri := fmt.Sprintf("%s/%s/backup-schedule", instancePath, instanceID)
+	req, err := i.client.NewRequest(ctx, http.MethodPost, uri, backup)
+	if err != nil {
+		return err
+	}
+
+	return i.client.DoWithContext(ctx, req, nil)
+}
+
+// CreateIPv4 an additional IPv4 address for given instance.
+func (i *InstanceServiceHandler) CreateIPv4(ctx context.Context, instanceID string, reboot *bool) (*IPv4, error) {
+	uri := fmt.Sprintf("%s/%s/ipv4", instancePath, instanceID)
+
+	body := RequestBody{"reboot": reboot}
+
+	req, err := i.client.NewRequest(ctx, http.MethodPost, uri, body)
+	if err != nil {
+		return nil, err
+	}
+
+	ip := new(ipv4Base)
+	if err = i.client.DoWithContext(ctx, req, ip); err != nil {
+		return nil, err
+	}
+
+	return ip.IPv4, nil
+}
+
+// ListIPv4 addresses that are currently assigned to a given instance.
+func (i *InstanceServiceHandler) ListIPv4(ctx context.Context, instanceID string, options *ListOptions) ([]IPv4, *Meta, error) {
+	uri := fmt.Sprintf("%s/%s/ipv4", instancePath, instanceID)
+	req, err := i.client.NewRequest(ctx, http.MethodGet, uri, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	newValues, err := query.Values(options)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	req.URL.RawQuery = newValues.Encode()
+	ips := new(ipBase)
+	if err = i.client.DoWithContext(ctx, req, ips); err != nil {
+		return nil, nil, err
+	}
+
+	return ips.IPv4s, ips.Meta, nil
+}
+
+// DeleteIPv4 address from a given instance.
+func (i *InstanceServiceHandler) DeleteIPv4(ctx context.Context, instanceID, ip string) error {
+	uri := fmt.Sprintf("%s/%s/ipv4/%s", instancePath, instanceID, ip)
+	req, err := i.client.NewRequest(ctx, http.MethodDelete, uri, nil)
+	if err != nil {
+		return err
+	}
+
+	return i.client.DoWithContext(ctx, req, nil)
+}
+
+// ListIPv6 addresses that are currently assigned to a given instance.
+func (i *InstanceServiceHandler) ListIPv6(ctx context.Context, instanceID string, options *ListOptions) ([]IPv6, *Meta, error) {
+	uri := fmt.Sprintf("%s/%s/ipv6", instancePath, instanceID)
+	req, err := i.client.NewRequest(ctx, http.MethodGet, uri, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	newValues, err := query.Values(options)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	req.URL.RawQuery = newValues.Encode()
+	ips := new(ipBase)
+	if err = i.client.DoWithContext(ctx, req, ips); err != nil {
+		return nil, nil, err
+	}
+
+	return ips.IPv6s, ips.Meta, nil
+}
+
+// CreateReverseIPv6 for a given instance.
+func (i *InstanceServiceHandler) CreateReverseIPv6(ctx context.Context, instanceID string, reverseReq *ReverseIP) error {
+	uri := fmt.Sprintf("%s/%s/ipv6/reverse", instancePath, instanceID)
+	req, err := i.client.NewRequest(ctx, http.MethodPost, uri, reverseReq)
+	if err != nil {
+		return err
+	}
+
+	return i.client.DoWithContext(ctx, req, nil)
+}
+
+// ListReverseIPv6 currently assigned to a given instance.
+func (i *InstanceServiceHandler) ListReverseIPv6(ctx context.Context, instanceID string) ([]ReverseIP, error) {
+	uri := fmt.Sprintf("%s/%s/ipv6/reverse", instancePath, instanceID)
+	req, err := i.client.NewRequest(ctx, http.MethodGet, uri, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	reverse := new(reverseIPv6sBase)
+	if err = i.client.DoWithContext(ctx, req, reverse); err != nil {
+		return nil, err
+	}
+
+	return reverse.ReverseIPv6s, nil
+}
+
+// DeleteReverseIPv6 a given reverse IPv6.
+func (i *InstanceServiceHandler) DeleteReverseIPv6(ctx context.Context, instanceID, ip string) error {
+	uri := fmt.Sprintf("%s/%s/ipv6/reverse/%s", instancePath, instanceID, ip)
+	req, err := i.client.NewRequest(ctx, http.MethodDelete, uri, nil)
+	if err != nil {
+		return err
+	}
+
+	return i.client.DoWithContext(ctx, req, nil)
+}
+
+// CreateReverseIPv4 for a given IP on a given instance.
+func (i *InstanceServiceHandler) CreateReverseIPv4(ctx context.Context, instanceID string, reverseReq *ReverseIP) error {
+	uri := fmt.Sprintf("%s/%s/ipv4/reverse", instancePath, instanceID)
+	req, err := i.client.NewRequest(ctx, http.MethodPost, uri, reverseReq)
+	if err != nil {
+		return err
+	}
+
+	return i.client.DoWithContext(ctx, req, nil)
+}
+
+// DefaultReverseIPv4 will set the IPs reverse setting back to the original one supplied by Vultr.
+func (i *InstanceServiceHandler) DefaultReverseIPv4(ctx context.Context, instanceID, ip string) error {
+	uri := fmt.Sprintf("%s/%s/ipv4/reverse/default", instancePath, instanceID)
+	reqBody := RequestBody{"ip": ip}
+
+	req, err := i.client.NewRequest(ctx, http.MethodPost, uri, reqBody)
+	if err != nil {
+		return err
+	}
+
+	return i.client.DoWithContext(ctx, req, nil)
+}
+
+// GetUserData from given instance. The userdata returned will be in base64 encoding.
+func (i *InstanceServiceHandler) GetUserData(ctx context.Context, instanceID string) (*UserData, error) {
+	uri := fmt.Sprintf("%s/%s/user-data", instancePath, instanceID)
+	req, err := i.client.NewRequest(ctx, http.MethodGet, uri, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	userData := new(userDataBase)
+	if err = i.client.DoWithContext(ctx, req, userData); err != nil {
+		return nil, err
+	}
+
+	return userData.UserData, nil
+}
+
+// GetUpgrades that are available for a given instance.
+func (i *InstanceServiceHandler) GetUpgrades(ctx context.Context, instanceID string) (*Upgrades, error) {
+	uri := fmt.Sprintf("%s/%s/upgrades", instancePath, instanceID)
+	req, err := i.client.NewRequest(ctx, http.MethodGet, uri, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	upgrades := new(upgradeBase)
+	if err = i.client.DoWithContext(ctx, req, upgrades); err != nil {
+		return nil, err
+	}
+
+	return upgrades.Upgrades, nil
+}
diff --git a/instance_test.go b/instance_test.go
new file mode 100644
index 0000000..09f769b
--- /dev/null
+++ b/instance_test.go
@@ -0,0 +1,1233 @@
+package govultr
+
+import (
+	"fmt"
+	"io/ioutil"
+	"net/http"
+	"reflect"
+	"testing"
+)
+
+func TestServerServiceHandler_GetBackupSchedule(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/instances/14b3e7d6-ffb5-4994-8502-57fcd9db3b33/backup-schedule", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"backup_schedule":{"enabled": true,"type": "weekly","next_scheduled_time_utc": "2016-05-07 08:00:00","hour": 8,"dow": 6,"dom": 0}}`
+		fmt.Fprint(writer, response)
+	})
+
+	backup, err := client.Instance.GetBackupSchedule(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33")
+	if err != nil {
+		t.Errorf("Instance.GetBackupSchedule returned %+v, ", err)
+	}
+
+	expected := &BackupSchedule{
+		Enabled:             BoolToBoolPtr(true),
+		Type:                "weekly",
+		NextScheduleTimeUTC: "2016-05-07 08:00:00",
+		Hour:                8,
+		Dow:                 6,
+		Dom:                 0,
+	}
+
+	if !reflect.DeepEqual(backup, expected) {
+		t.Errorf("Instance.GetBackupSchedule returned %+v, expected %+v", backup, expected)
+	}
+}
+
+func TestServerServiceHandler_SetBackupSchedule(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/instances/14b3e7d6-ffb5-4994-8502-57fcd9db3b33/backup-schedule", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"backup_schedule":{"enabled": true,"type": "weekly","next_scheduled_time_utc": "2016-05-07 08:00:00","hour": 22,"dow": 2,"dom": 3}}`
+		fmt.Fprint(writer, response)
+	})
+
+	bs := &BackupScheduleReq{
+		Type: "weekly",
+		Hour: IntToIntPtr(22),
+		Dow:  IntToIntPtr(2),
+		Dom:  3,
+	}
+
+	if err := client.Instance.SetBackupSchedule(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33", bs); err != nil {
+		t.Errorf("Instance.SetBackupSchedule returned %+v, ", err)
+	}
+}
+
+func TestServerServiceHandler_RestoreBackup(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/instances/14b3e7d6-ffb5-4994-8502-57fcd9db3b33/restore", func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
+	})
+
+	restoreReq := &RestoreReq{
+		BackupID: "14b3e7d6-ffb5-4994-8502-57fcd9db3b33",
+	}
+
+	if err := client.Instance.Restore(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33", restoreReq); err != nil {
+		t.Errorf("Instance.Restore returned %+v, ", err)
+	}
+}
+
+func TestServerServiceHandler_RestoreSnapshot(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/instances/14b3e7d6-ffb5-4994-8502-57fcd9db3b33/restore", func(writer http.ResponseWriter, request *http.Request) {
+		body, err := ioutil.ReadAll(request.Body)
+		if err != nil || len(body) == 0 {
+			http.Error(writer, "can't read body", http.StatusBadRequest)
+			return
+		}
+		fmt.Fprint(writer)
+	})
+
+	restoreReq := &RestoreReq{
+		SnapshotID: "14b3e7d6-ffb5-4994-8502-57fcd9db3b33",
+	}
+
+	if err := client.Instance.Restore(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33", restoreReq); err != nil {
+		t.Errorf("Instance.Restore returned %+v, ", err)
+	}
+}
+
+func TestServerServiceHandler_Neighbors(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/instances/14b3e7d6-ffb5-4994-8502-57fcd9db3b33/neighbors", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"neighbors":["14b3e7d6-ffb5-4994-8502-57fcd9db3b33","14b3e7d6-ffb5-4994-8502-57fcd9db3b33"]}`
+		fmt.Fprint(writer, response)
+	})
+
+	neighbors, err := client.Instance.GetNeighbors(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33")
+	if err != nil {
+		t.Errorf("Instance.Neighbors returned %+v, ", err)
+	}
+
+	expected := &Neighbors{
+		Neighbors: []string{"14b3e7d6-ffb5-4994-8502-57fcd9db3b33", "14b3e7d6-ffb5-4994-8502-57fcd9db3b33"},
+	}
+
+	if !reflect.DeepEqual(neighbors, expected) {
+		t.Errorf("Instance.Neighbors returned %+v, expected %+v", neighbors, expected)
+	}
+}
+
+func TestServerServiceHandler_ListPrivateNetworks(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/instances/14b3e7d6-ffb5-4994-8502-57fcd9db3b33/private-networks", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"private_networks": [{"network_id": "v1-net539626f0798d7","mac_address": "5a:02:00:00:24:e9","ip_address": "10.99.0.3"}],"meta":{"total":1,"links":{"next":"thisismycusror","prev":""}}}`
+		fmt.Fprint(writer, response)
+	})
+
+	options := &ListOptions{
+		PerPage: 1,
+		Cursor:  "",
+	}
+	privateNetwork, meta, err := client.Instance.ListPrivateNetworks(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33", options)
+	if err != nil {
+		t.Errorf("Instance.ListPrivateNetworks return %+v, ", err)
+	}
+
+	expected := []PrivateNetwork{
+		{
+			NetworkID:  "v1-net539626f0798d7",
+			MacAddress: "5a:02:00:00:24:e9",
+			IPAddress:  "10.99.0.3",
+		},
+	}
+
+	if !reflect.DeepEqual(privateNetwork, expected) {
+		t.Errorf("Instance.ListPrivateNetworks returned %+v, expected %+v", privateNetwork, expected)
+	}
+
+	expectedMeta := &Meta{
+		Total: 1,
+		Links: &Links{
+			Next: "thisismycusror",
+			Prev: "",
+		},
+	}
+
+	if !reflect.DeepEqual(meta, expectedMeta) {
+		t.Errorf("Instance.ListPrivateNetworks meta returned %+v, expected %+v", meta, expectedMeta)
+	}
+}
+
+func TestServerServiceHandler_GetUserData(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/instances/14b3e7d6-ffb5-4994-8502-57fcd9db3b33/user-data", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"user_data": {"data" : "ZWNobyBIZWxsbyBXb3JsZA=="}}`
+		fmt.Fprint(writer, response)
+	})
+
+	userData, err := client.Instance.GetUserData(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33")
+	if err != nil {
+		t.Errorf("Instance.GetUserData return %+v ", err)
+	}
+
+	expected := &UserData{Data: "ZWNobyBIZWxsbyBXb3JsZA=="}
+
+	if !reflect.DeepEqual(userData, expected) {
+		t.Errorf("Instance.GetUserData returned %+v, expected %+v", userData, expected)
+	}
+}
+
+func TestServerServiceHandler_ListIPv4(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/instances/14b3e7d6-ffb5-4994-8502-57fcd9db3b33/ipv4", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{ "ipv4s": [{"ip": "123.123.123.123","netmask": "255.255.255.248","gateway": "123.123.123.1","type": "main_ip","reverse": "host1.example.com"}],"meta":{"total":1,"links":{"next":"thisismycusror","prev":""}}}`
+		fmt.Fprint(writer, response)
+	})
+
+	ipv4, meta, err := client.Instance.ListIPv4(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33", nil)
+
+	if err != nil {
+		t.Errorf("Instance.ListIPv4 returned %+v", err)
+	}
+
+	expected := []IPv4{
+		{
+			IP:      "123.123.123.123",
+			Netmask: "255.255.255.248",
+			Gateway: "123.123.123.1",
+			Type:    "main_ip",
+			Reverse: "host1.example.com",
+		},
+	}
+
+	if !reflect.DeepEqual(ipv4, expected) {
+		t.Errorf("Instance.ListIPv4 returned %+v, expected %+v", ipv4, expected)
+	}
+
+	expectedMeta := &Meta{
+		Total: 1,
+		Links: &Links{
+			Next: "thisismycusror",
+			Prev: "",
+		},
+	}
+
+	if !reflect.DeepEqual(meta, expectedMeta) {
+		t.Errorf("Instance.ListIPv4 meta returned %+v, expected %+v", meta, expectedMeta)
+	}
+}
+
+func TestServerServiceHandler_ListIPv6(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/instances/14b3e7d6-ffb5-4994-8502-57fcd9db3b33/ipv6", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"ipv6s": [{"ip": "2001:DB8:1000::100","network": "2001:DB8:1000::","network_size": 64,"type": "main_ip"}],"meta":{"total":1,"links":{"next":"thisismycusror","prev":""}}}`
+		fmt.Fprint(writer, response)
+	})
+
+	ipv6, meta, err := client.Instance.ListIPv6(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33", nil)
+	if err != nil {
+		t.Errorf("Instance.ListIPv6 returned %+v", err)
+	}
+
+	expected := []IPv6{
+		{
+			IP:          "2001:DB8:1000::100",
+			Network:     "2001:DB8:1000::",
+			NetworkSize: 64,
+			Type:        "main_ip",
+		},
+	}
+
+	if !reflect.DeepEqual(ipv6, expected) {
+		t.Errorf("Instance.ListIPv6 returned %+v, expected %+v", ipv6, expected)
+	}
+
+	expectedMeta := &Meta{
+		Total: 1,
+		Links: &Links{
+			Next: "thisismycusror",
+			Prev: "",
+		},
+	}
+
+	if !reflect.DeepEqual(meta, expectedMeta) {
+		t.Errorf("Instance.ListIPV6 meta returned %+v, expected %+v", meta, expectedMeta)
+	}
+}
+
+func TestServerServiceHandler_CreateIPv4(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/instances/14b3e7d6-ffb5-4994-8502-57fcd9db3b33/ipv4", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{ "ipv4": {"ip": "123.123.123.123","netmask": "255.255.255.248","gateway": "123.123.123.1","type": "main_ip","reverse": "host1.example.com"}}`
+		fmt.Fprint(writer, response)
+	})
+
+	ipv4, err := client.Instance.CreateIPv4(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33", BoolToBoolPtr(false))
+	if err != nil {
+		t.Errorf("Instance.CreateIPv4 returned %+v", err)
+	}
+
+	expected := &IPv4{
+		IP:      "123.123.123.123",
+		Netmask: "255.255.255.248",
+		Gateway: "123.123.123.1",
+		Type:    "main_ip",
+		Reverse: "host1.example.com",
+	}
+
+	if !reflect.DeepEqual(ipv4, expected) {
+		t.Errorf("Instance.CreateIPv4 returned %+v, expected %+v", ipv4, expected)
+	}
+}
+
+func TestServerServiceHandler_DestroyIPV4(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/instances/14b3e7d6-ffb5-4994-8502-57fcd9db3b33/ipv4/192.168.0.1", func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
+	})
+
+	err := client.Instance.DeleteIPv4(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33", "192.168.0.1")
+
+	if err != nil {
+		t.Errorf("Instance.DestroyIPV4 returned %+v", err)
+	}
+}
+
+func TestServerServiceHandler_GetBandwidth(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/instances/14b3e7d6-ffb5-4994-8502-57fcd9db3b33/bandwidth", func(writer http.ResponseWriter, request *http.Request) {
+		response := `
+		{
+			"bandwidth": {
+				"2017-04-01": {
+					"incoming_bytes": 91571055,
+					"outgoing_bytes": 3084731
+				}
+			}
+		}		
+		`
+		fmt.Fprint(writer, response)
+	})
+
+	bandwidth, err := client.Instance.GetBandwidth(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33")
+	if err != nil {
+		t.Errorf("Instance.GetBandwidth returned %+v", err)
+	}
+
+	expected := &Bandwidth{
+		Bandwidth: map[string]struct {
+			IncomingBytes int `json:"incoming_bytes"`
+			OutgoingBytes int `json:"outgoing_bytes"`
+		}{
+			"2017-04-01": {
+				IncomingBytes: 91571055,
+				OutgoingBytes: 3084731,
+			},
+		},
+	}
+
+	if !reflect.DeepEqual(bandwidth, expected) {
+		t.Errorf("Instance.GetBandwidth returned %+v, expected %+v", bandwidth, expected)
+	}
+}
+
+func TestServerServiceHandler_ListReverseIPv6(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/instances/14b3e7d6-ffb5-4994-8502-57fcd9db3b33/ipv6/reverse", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"reverse_ipv6s": [{"ip": "2001:DB8:1000::101","reverse": "host1.example.com"}]}`
+		fmt.Fprint(writer, response)
+	})
+
+	reverseIPV6, err := client.Instance.ListReverseIPv6(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33")
+
+	if err != nil {
+		t.Errorf("Instance.ListReverseIPv6 returned error: %v", err)
+	}
+
+	expected := []ReverseIP{
+		{IP: "2001:DB8:1000::101", Reverse: "host1.example.com"},
+	}
+
+	if !reflect.DeepEqual(reverseIPV6, expected) {
+		t.Errorf("Instance.ListReverseIPv6 returned %+v, expected %+v", reverseIPV6, expected)
+	}
+}
+
+func TestServerServiceHandler_DefaultReverseIPv4(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/instances/14b3e7d6-ffb5-4994-8502-57fcd9db3b33/ipv4/reverse/default", func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
+	})
+
+	if err := client.Instance.DefaultReverseIPv4(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33", "129.123.123.1"); err != nil {
+		t.Errorf("Instance.DefaultReverseIPv4 returned %+v", err)
+	}
+}
+
+func TestServerServiceHandler_DeleteReverseIPv6(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/instances/14b3e7d6-ffb5-4994-8502-57fcd9db3b33/ipv6/reverse/2001:19f0:8001:1480:5400:2ff:fe00:8228", func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
+	})
+
+	if err := client.Instance.DeleteReverseIPv6(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33", "2001:19f0:8001:1480:5400:2ff:fe00:8228"); err != nil {
+		t.Errorf("Instance.DeleteReverseIPv6 returned %+v", err)
+	}
+}
+
+func TestServerServiceHandler_CreateReverseIPv4(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/instances/14b3e7d6-ffb5-4994-8502-57fcd9db3b33/ipv4/reverse", func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
+	})
+
+	reverseReq := &ReverseIP{
+		IP:      "192.168.0.1",
+		Reverse: "test.com",
+	}
+
+	if err := client.Instance.CreateReverseIPv4(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33", reverseReq); err != nil {
+		t.Errorf("Instance.CreateReverseIPv4 returned %+v", err)
+	}
+}
+
+func TestServerServiceHandler_CreateReverseIPv6(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/instances/14b3e7d6-ffb5-4994-8502-57fcd9db3b33/ipv6/reverse", func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
+	})
+
+	reverseReq := &ReverseIP{
+		IP:      "192.168.0.1",
+		Reverse: "test.com",
+	}
+
+	if err := client.Instance.CreateReverseIPv6(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33", reverseReq); err != nil {
+		t.Errorf("Instance.CreateReverseIPv6 returned %+v", err)
+	}
+}
+
+func TestServerServiceHandler_Halt(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/instances/14b3e7d6-ffb5-4994-8502-57fcd9db3b33/halt", func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
+	})
+
+	if err := client.Instance.Halt(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33"); err != nil {
+		t.Errorf("Instance.Halt returned %+v", err)
+	}
+}
+
+func TestServerServiceHandler_Start(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/instances/14b3e7d6-ffb5-4994-8502-57fcd9db3b33/start", func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
+	})
+
+	if err := client.Instance.Start(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33"); err != nil {
+		t.Errorf("Instance.Start returned %+v", err)
+	}
+}
+
+func TestServerServiceHandler_Reboot(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/instances/14b3e7d6-ffb5-4994-8502-57fcd9db3b33/reboot", func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
+	})
+
+	err := client.Instance.Reboot(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33")
+
+	if err != nil {
+		t.Errorf("Instance.Reboot returned %+v", err)
+	}
+}
+
+func TestServerServiceHandler_Reinstall(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/instances/14b3e7d6-ffb5-4994-8502-57fcd9db3b33/reinstall", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{
+			"instance": {
+				"id": "14b3e7d6-ffb5-4994-8502-57fcd9db3b33",
+				"os": "CentOS SELinux 8 x64",
+				"ram": 2048,
+				"disk": 60,
+				"main_ip": "123.123.123.123",
+				"vcpu_count": 2,
+				"region": "ewr",
+				"plan": "vc2-1c-2gb",
+				"date_created": "2013-12-19 14:45:41",
+				"status": "active",
+				"allowed_bandwidth": 2000,
+				"netmask_v4": "255.255.255.248",
+				"gateway_v4": "123.123.123.1",
+				"power_status": "running",
+				"server_status": "ok",
+				"v6_network": "2001:DB8:1000::",
+				"v6_main_ip": "fd11:1111:1112:1c02:0200:00ff:fe00:0000",
+				"v6_network_size": 64,
+				"label": "my new server",
+				"internal_ip": "10.99.0.10",
+				"kvm": "https://my.vultr.com/subs/novnc/api.php?data=eawxFVZw2mXnhGUV",
+				"default_password" : "nreqnusibni",
+				"tag": "tagger",
+				"os_id": 362,
+				"app_id": 0,
+				"firewall_group_id": "1234",
+				"features": [
+					"auto_backups", "ipv6"
+				]
+			}
+		}`
+		fmt.Fprint(writer, response)
+	})
+
+	instanceRes, err := client.Instance.Reinstall(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33", nil)
+	if err != nil {
+		t.Errorf("Instance.Reinstall returned %+v", err)
+	}
+
+	expected := &Instance{
+		ID:               "14b3e7d6-ffb5-4994-8502-57fcd9db3b33",
+		Os:               "CentOS SELinux 8 x64",
+		OsID:             362,
+		RAM:              2048,
+		Disk:             60,
+		MainIP:           "123.123.123.123",
+		VCPUCount:        2,
+		Region:           "ewr",
+		DefaultPassword:  "nreqnusibni",
+		DateCreated:      "2013-12-19 14:45:41",
+		Status:           "active",
+		AllowedBandwidth: 2000,
+		NetmaskV4:        "255.255.255.248",
+		GatewayV4:        "123.123.123.1",
+		PowerStatus:      "running",
+		ServerStatus:     "ok",
+		Plan:             "vc2-1c-2gb",
+		V6Network:        "2001:DB8:1000::",
+		V6MainIP:         "fd11:1111:1112:1c02:0200:00ff:fe00:0000",
+		V6NetworkSize:    64,
+		Label:            "my new server",
+		InternalIP:       "10.99.0.10",
+		KVM:              "https://my.vultr.com/subs/novnc/api.php?data=eawxFVZw2mXnhGUV",
+		Tag:              "tagger",
+		AppID:            0,
+		FirewallGroupID:  "1234",
+		Features:         []string{"auto_backups", "ipv6"},
+	}
+
+	if !reflect.DeepEqual(instanceRes, expected) {
+		t.Errorf("Instance.Create returned %+v, expected %+v", server, expected)
+	}
+}
+
+func TestServerServiceHandler_Delete(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/instances/14b3e7d6-ffb5-4994-8502-57fcd9db3b33", func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
+	})
+
+	err := client.Instance.Delete(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33")
+
+	if err != nil {
+		t.Errorf("Instance.Delete returned %+v", err)
+	}
+}
+
+func TestServerServiceHandler_Create(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/instances", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{
+			"instance": {
+				"id": "14b3e7d6-ffb5-4994-8502-57fcd9db3b33",
+				"os": "CentOS SELinux 8 x64",
+				"ram": 2048,
+				"disk": 60,
+				"main_ip": "123.123.123.123",
+				"vcpu_count": 2,
+				"region": "ewr",
+				"plan": "vc2-1c-2gb",
+				"date_created": "2013-12-19 14:45:41",
+				"status": "active",
+				"allowed_bandwidth": 2000,
+				"netmask_v4": "255.255.255.248",
+				"gateway_v4": "123.123.123.1",
+				"power_status": "running",
+				"server_status": "ok",
+				"v6_network": "2001:DB8:1000::",
+				"v6_main_ip": "fd11:1111:1112:1c02:0200:00ff:fe00:0000",
+				"v6_network_size": 64,
+				"label": "my new server",
+				"internal_ip": "10.99.0.10",
+				"kvm": "https://my.vultr.com/subs/novnc/api.php?data=eawxFVZw2mXnhGUV",
+				"default_password" : "nreqnusibni",
+				"tag": "tagger",
+				"os_id": 362,
+				"app_id": 0,
+				"firewall_group_id": "1234",
+				"features": [
+					"auto_backups", "ipv6"
+				]
+			}
+		}`
+		fmt.Fprint(writer, response)
+	})
+
+	options := &InstanceCreateReq{
+		IPXEChainURL:    "test.org",
+		ISOID:           "14b3e7d6-ffb5-4994-8502-57fcd9db3b33",
+		ScriptID:        "213",
+		EnableIPv6:      BoolToBoolPtr(true),
+		Backups:         "enabled",
+		UserData:        "dW5vLWRvcy10cmVz",
+		ActivationEmail: BoolToBoolPtr(true),
+		DDOSProtection:  BoolToBoolPtr(true),
+		SnapshotID:      "12ab",
+		Hostname:        "hostname-3000",
+		Tag:             "tagger",
+		Label:           "label-extreme",
+		SSHKeys:         []string{"14b3e7d6-ffb5-4994-8502-57fcd9db3b33", "dev-preview-abc124"},
+		ReservedIPv4:    "63.209.35.79",
+		FirewallGroupID: "1234",
+		AppID:           1,
+	}
+
+	server, err := client.Instance.Create(ctx, options)
+	if err != nil {
+		t.Errorf("Instance.Create returned %+v", err)
+	}
+
+	features := []string{"auto_backups", "ipv6"}
+
+	expected := &Instance{
+		ID:               "14b3e7d6-ffb5-4994-8502-57fcd9db3b33",
+		Os:               "CentOS SELinux 8 x64",
+		OsID:             362,
+		RAM:              2048,
+		Disk:             60,
+		MainIP:           "123.123.123.123",
+		VCPUCount:        2,
+		Region:           "ewr",
+		DefaultPassword:  "nreqnusibni",
+		DateCreated:      "2013-12-19 14:45:41",
+		Status:           "active",
+		AllowedBandwidth: 2000,
+		NetmaskV4:        "255.255.255.248",
+		GatewayV4:        "123.123.123.1",
+		PowerStatus:      "running",
+		ServerStatus:     "ok",
+		Plan:             "vc2-1c-2gb",
+		V6Network:        "2001:DB8:1000::",
+		V6MainIP:         "fd11:1111:1112:1c02:0200:00ff:fe00:0000",
+		V6NetworkSize:    64,
+		Label:            "my new server",
+		InternalIP:       "10.99.0.10",
+		KVM:              "https://my.vultr.com/subs/novnc/api.php?data=eawxFVZw2mXnhGUV",
+		Tag:              "tagger",
+		AppID:            0,
+		FirewallGroupID:  "1234",
+		Features:         features,
+	}
+
+	if !reflect.DeepEqual(server, expected) {
+		t.Errorf("Instance.Create returned %+v, expected %+v", server, expected)
+	}
+}
+
+func TestServerServiceHandler_List(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/instances", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{
+			"instances": [{
+				"id": "14b3e7d6-ffb5-4994-8502-57fcd9db3b33",
+				"os": "CentOS SELinux 8 x64",
+				"ram": 2048,
+				"disk": 60,
+				"main_ip": "123.123.123.123",
+				"vcpu_count": 2,
+				"region": "ewr",
+				"plan": "vc2-1c-2gb",
+				"date_created": "2013-12-19 14:45:41",
+				"status": "active",
+				"allowed_bandwidth": 2000,
+				"netmask_v4": "255.255.255.248",
+				"gateway_v4": "123.123.123.1",
+				"power_status": "running",
+				"server_status": "ok",
+				"v6_network": "2001:DB8:1000::",
+				"v6_main_ip": "fd11:1111:1112:1c02:0200:00ff:fe00:0000",
+				"v6_network_size": 64,
+				"label": "my new server",
+				"internal_ip": "10.99.0.10",
+				"kvm": "https://my.vultr.com/subs/novnc/api.php?data=eawxFVZw2mXnhGUV",
+				"default_password" : "nreqnusibni",
+				"tag": "mytag",
+				"os_id": 362,
+				"app_id": 0,
+				"firewall_group_id": "",
+				"features": [
+					"auto_backups"
+				]
+			}],
+			"meta":{
+				"total":1,
+				"links":{
+					"next":"thisismycusror",
+					"prev":""
+				}
+			}			
+		}`
+		fmt.Fprint(writer, response)
+	})
+
+	server, meta, err := client.Instance.List(ctx, nil)
+	if err != nil {
+		t.Errorf("Instance.List returned %+v", err)
+	}
+
+	features := []string{"auto_backups"}
+
+	expected := []Instance{
+		{
+			ID:               "14b3e7d6-ffb5-4994-8502-57fcd9db3b33",
+			Os:               "CentOS SELinux 8 x64",
+			OsID:             362,
+			RAM:              2048,
+			Disk:             60,
+			MainIP:           "123.123.123.123",
+			VCPUCount:        2,
+			Region:           "ewr",
+			DefaultPassword:  "nreqnusibni",
+			DateCreated:      "2013-12-19 14:45:41",
+			Status:           "active",
+			AllowedBandwidth: 2000,
+			NetmaskV4:        "255.255.255.248",
+			GatewayV4:        "123.123.123.1",
+			PowerStatus:      "running",
+			ServerStatus:     "ok",
+			Plan:             "vc2-1c-2gb",
+			V6Network:        "2001:DB8:1000::",
+			V6MainIP:         "fd11:1111:1112:1c02:0200:00ff:fe00:0000",
+			V6NetworkSize:    64,
+			Label:            "my new server",
+			InternalIP:       "10.99.0.10",
+			KVM:              "https://my.vultr.com/subs/novnc/api.php?data=eawxFVZw2mXnhGUV",
+			Tag:              "mytag",
+			AppID:            0,
+			FirewallGroupID:  "",
+			Features:         features,
+		},
+	}
+
+	if !reflect.DeepEqual(server, expected) {
+		t.Errorf("Instance.List returned %+v, expected %+v", server, expected)
+	}
+
+	expectedMeta := &Meta{
+		Total: 1,
+		Links: &Links{
+			Next: "thisismycusror",
+			Prev: "",
+		},
+	}
+
+	if !reflect.DeepEqual(meta, expectedMeta) {
+		t.Errorf("Instance.List meta returned %+v, expected %+v", meta, expectedMeta)
+	}
+}
+
+func TestServerServiceHandler_GetServer(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/instances/14b3e7d6-ffb5-4994-8502-57fcd9db3b33", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{
+			"instance": {
+				"id": "14b3e7d6-ffb5-4994-8502-57fcd9db3b33",
+				"os": "CentOS SELinux 8 x64",
+				"ram": 2048,
+				"disk": 60,
+				"main_ip": "123.123.123.123",
+				"vcpu_count": 2,
+				"region": "ewr",
+				"plan": "vc2-1c-2gb",
+				"date_created": "2013-12-19 14:45:41",
+				"status": "active",
+				"allowed_bandwidth": 2000,
+				"netmask_v4": "255.255.255.248",
+				"gateway_v4": "123.123.123.1",
+				"power_status": "running",
+				"server_status": "ok",
+				"v6_network": "2001:DB8:1000::",
+				"v6_main_ip": "fd11:1111:1112:1c02:0200:00ff:fe00:0000",
+				"v6_network_size": 64,
+				"label": "my new server",
+				"internal_ip": "10.99.0.10",
+				"kvm": "https://my.vultr.com/subs/novnc/api.php?data=eawxFVZw2mXnhGUV",
+				"default_password" : "nreqnusibni",
+				"tag": "mytag",
+				"os_id": 362,
+				"app_id": 0,
+				"firewall_group_id": "",
+				"features": [
+					"auto_backups"
+				]
+			}
+		}`
+		fmt.Fprint(writer, response)
+	})
+
+	server, err := client.Instance.Get(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33")
+	if err != nil {
+		t.Errorf("Instance.GetServer returned %+v", err)
+	}
+
+	features := []string{"auto_backups"}
+
+	expected := &Instance{
+		ID:               "14b3e7d6-ffb5-4994-8502-57fcd9db3b33",
+		Os:               "CentOS SELinux 8 x64",
+		OsID:             362,
+		RAM:              2048,
+		Disk:             60,
+		MainIP:           "123.123.123.123",
+		VCPUCount:        2,
+		Region:           "ewr",
+		DefaultPassword:  "nreqnusibni",
+		DateCreated:      "2013-12-19 14:45:41",
+		Status:           "active",
+		AllowedBandwidth: 2000,
+		NetmaskV4:        "255.255.255.248",
+		GatewayV4:        "123.123.123.1",
+		PowerStatus:      "running",
+		ServerStatus:     "ok",
+		Plan:             "vc2-1c-2gb",
+		V6Network:        "2001:DB8:1000::",
+		V6MainIP:         "fd11:1111:1112:1c02:0200:00ff:fe00:0000",
+		V6NetworkSize:    64,
+		Label:            "my new server",
+		InternalIP:       "10.99.0.10",
+		KVM:              "https://my.vultr.com/subs/novnc/api.php?data=eawxFVZw2mXnhGUV",
+		Tag:              "mytag",
+		AppID:            0,
+		FirewallGroupID:  "",
+		Features:         features,
+	}
+
+	if !reflect.DeepEqual(server, expected) {
+		t.Errorf("Instance.GetServer returned %+v, expected %+v", server, expected)
+	}
+}
+
+func TestInstanceServiceHandler_GetUpgrades(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/instances/14b3e7d6-ffb5-4994-8502-57fcd9db3b33/upgrades", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{
+   "upgrades":{
+      "os":[
+         {
+            "id":127,
+            "name":"CentOS 6 x64",
+            "arch":"x64",
+            "family":"centos"
+         }
+      ],
+      "applications":[
+         {
+            "id":1,
+            "name":"LEMP",
+            "short_name":"lemp",
+            "deploy_name":"LEMP on CentOS 6"
+         }
+      ],
+      "plans":[
+         "vc2-2c-4gb"
+      ]
+   }
+}`
+		fmt.Fprint(writer, response)
+	})
+
+	server, err := client.Instance.GetUpgrades(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33")
+	if err != nil {
+		t.Errorf("Instance.GetUpgrades returned %+v", err)
+	}
+
+	expected := &Upgrades{
+		Applications: []Application{
+			{
+				ID:         1,
+				Name:       "LEMP",
+				ShortName:  "lemp",
+				DeployName: "LEMP on CentOS 6",
+			},
+		},
+		OS: []OS{
+			{
+				ID:     127,
+				Name:   "CentOS 6 x64",
+				Arch:   "x64",
+				Family: "centos",
+			},
+		},
+		Plans: []string{
+			"vc2-2c-4gb",
+		},
+	}
+
+	if !reflect.DeepEqual(server, expected) {
+		t.Errorf("Instance.GetUpgrades returned %+v, expected %+v", server, expected)
+	}
+}
+
+func TestServerServiceHandler_MassStart(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/instances/start", func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
+	})
+
+	if err := client.Instance.MassStart(ctx, []string{"14b3e7d6-ffb5-4994-8502-57fcd9db3b33"}); err != nil {
+		t.Errorf("Instance.MassStart returned %+v", err)
+	}
+}
+
+func TestServerServiceHandler_MassReboot(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/instances/reboot", func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
+	})
+
+	if err := client.Instance.MassReboot(ctx, []string{"14b3e7d6-ffb5-4994-8502-57fcd9db3b33"}); err != nil {
+		t.Errorf("Instance.MassReboot returned %+v", err)
+	}
+}
+
+func TestServerServiceHandler_MassHalt(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/instances/halt", func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
+	})
+
+	if err := client.Instance.MassHalt(ctx, []string{"14b3e7d6-ffb5-4994-8502-57fcd9db3b33"}); err != nil {
+		t.Errorf("Instance.MassHalt returned %+v", err)
+	}
+}
+
+func TestServerServiceHandler_AttachPrivateNetwork(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/instances/14b3e7d6-ffb5-4994-8502-57fcd9db3b33/private-networks/attach", func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
+	})
+
+	if err := client.Instance.AttachPrivateNetwork(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33", "14b3e7d6-ffb5-4994-8502-57fcd9db3b33"); err != nil {
+		t.Errorf("Instance.AttachPrivateNetwork returned %+v", err)
+	}
+}
+
+func TestServerServiceHandler_DetachPrivateNetwork(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/instances/14b3e7d6-ffb5-4994-8502-57fcd9db3b33/private-networks/detach", func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
+	})
+
+	if err := client.Instance.DetachPrivateNetwork(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33", "14b3e7d6-ffb5-4994-8502-57fcd9db3b33"); err != nil {
+		t.Errorf("Instance.DetachPrivateNetwork returned %+v", err)
+	}
+}
+
+func TestServerServiceHandler_ISOAttach(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/instances/14b3e7d6-ffb5-4994-8502-57fcd9db3b33/iso/attach", func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
+	})
+
+	if err := client.Instance.AttachISO(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33", "14b3e7d6-ffb5-4994-8502-57fcd9db3b33"); err != nil {
+		t.Errorf("Instance.AttachISO returned %+v", err)
+	}
+}
+
+func TestServerServiceHandler_ISODetach(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/instances/14b3e7d6-ffb5-4994-8502-57fcd9db3b33/iso/detach", func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
+	})
+
+	if err := client.Instance.DetachISO(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33"); err != nil {
+		t.Errorf("Instance.DetachISO returned %+v", err)
+	}
+}
+
+func TestServerServiceHandler_ISO(t *testing.T) {
+	setup()
+	defer teardown()
+	ret := `{"iso_status": {"state": "ready","iso_id": "0532a75b-14e8-48b8-b27e-1ebcf382a804"}}`
+	mux.HandleFunc("/v2/instances/14b3e7d6-ffb5-4994-8502-57fcd9db3b33/iso", func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer, ret)
+	})
+
+	iso, err := client.Instance.ISOStatus(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33")
+	if err != nil {
+		t.Errorf("Instance.ISOStatus returned %+v", err)
+	}
+
+	expected := &Iso{
+		State: "ready",
+		IsoID: "0532a75b-14e8-48b8-b27e-1ebcf382a804",
+	}
+
+	if !reflect.DeepEqual(iso, expected) {
+		t.Errorf("Instance.ISOStatus returned %+v, expected %+v", iso, expected)
+	}
+}
+
+func TestServerServiceHandler_Update(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/instances/14b3e7d6-ffb5-4994-8502-57fcd9db3b33", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{
+			"instance": {
+				"id": "14b3e7d6-ffb5-4994-8502-57fcd9db3b33",
+				"os": "CentOS SELinux 8 x64",
+				"ram": 2048,
+				"disk": 60,
+				"main_ip": "123.123.123.123",
+				"vcpu_count": 2,
+				"region": "ewr",
+				"plan": "vc2-1c-2gb",
+				"date_created": "2013-12-19 14:45:41",
+				"status": "active",
+				"allowed_bandwidth": 2000,
+				"netmask_v4": "255.255.255.248",
+				"gateway_v4": "123.123.123.1",
+				"power_status": "running",
+				"server_status": "ok",
+				"v6_network": "2001:DB8:1000::",
+				"v6_main_ip": "fd11:1111:1112:1c02:0200:00ff:fe00:0000",
+				"v6_network_size": 64,
+				"label": "my new server",
+				"internal_ip": "10.99.0.10",
+				"kvm": "https://my.vultr.com/subs/novnc/api.php?data=eawxFVZw2mXnhGUV",
+				"default_password" : "nreqnusibni",
+				"tag": "tagger",
+				"os_id": 362,
+				"app_id": 0,
+				"firewall_group_id": "1234",
+				"features": [
+					"auto_backups", "ipv6"
+				]
+			}
+		}`
+		fmt.Fprint(writer, response)
+	})
+
+	options := &InstanceUpdateReq{
+		EnableIPv6:      BoolToBoolPtr(true),
+		Backups:         "enabled",
+		UserData:        "dW5vLWRvcy10cmVz",
+		DDOSProtection:  BoolToBoolPtr(true),
+		Tag:             "tagger",
+		Label:           "label-extreme",
+		FirewallGroupID: "1234",
+		AppID:           1,
+	}
+
+	server, err := client.Instance.Update(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33", options)
+	if err != nil {
+		t.Errorf("Instance.Update returned %+v", err)
+	}
+
+	expected := &Instance{
+		ID:               "14b3e7d6-ffb5-4994-8502-57fcd9db3b33",
+		Os:               "CentOS SELinux 8 x64",
+		OsID:             362,
+		RAM:              2048,
+		Disk:             60,
+		MainIP:           "123.123.123.123",
+		VCPUCount:        2,
+		Region:           "ewr",
+		DefaultPassword:  "nreqnusibni",
+		DateCreated:      "2013-12-19 14:45:41",
+		Status:           "active",
+		AllowedBandwidth: 2000,
+		NetmaskV4:        "255.255.255.248",
+		GatewayV4:        "123.123.123.1",
+		PowerStatus:      "running",
+		ServerStatus:     "ok",
+		Plan:             "vc2-1c-2gb",
+		V6Network:        "2001:DB8:1000::",
+		V6MainIP:         "fd11:1111:1112:1c02:0200:00ff:fe00:0000",
+		V6NetworkSize:    64,
+		Label:            "my new server",
+		InternalIP:       "10.99.0.10",
+		KVM:              "https://my.vultr.com/subs/novnc/api.php?data=eawxFVZw2mXnhGUV",
+		Tag:              "tagger",
+		AppID:            0,
+		FirewallGroupID:  "1234",
+		Features:         []string{"auto_backups", "ipv6"},
+	}
+
+	if !reflect.DeepEqual(server, expected) {
+		t.Errorf("Instance.Update returned %+v, expected %+v", server, expected)
+	}
+}
+
+func TestServerServiceHandler_CreateMarketplace(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/instances", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{
+			"instance": {
+				"id": "14b3e7d6-ffb5-4994-8502-57fcd9db3b33",
+				"os": "CentOS SELinux 8 x64",
+				"ram": 2048,
+				"disk": 60,
+				"main_ip": "123.123.123.123",
+				"vcpu_count": 2,
+				"region": "ewr",
+				"plan": "vc2-1c-2gb",
+				"date_created": "2013-12-19 14:45:41",
+				"status": "active",
+				"allowed_bandwidth": 2000,
+				"netmask_v4": "255.255.255.248",
+				"gateway_v4": "123.123.123.1",
+				"power_status": "running",
+				"server_status": "ok",
+				"v6_network": "2001:DB8:1000::",
+				"v6_main_ip": "fd11:1111:1112:1c02:0200:00ff:fe00:0000",
+				"v6_network_size": 64,
+				"label": "my new server",
+				"internal_ip": "10.99.0.10",
+				"kvm": "https://my.vultr.com/subs/novnc/api.php?data=eawxFVZw2mXnhGUV",
+				"default_password" : "nreqnusibni",
+				"tag": "tagger",
+				"os_id": 362,
+				"image_id": "test",
+				"app_id": 0,
+				"firewall_group_id": "1234",
+				"features": [
+					"auto_backups", "ipv6"
+				]
+			}
+		}`
+		fmt.Fprint(writer, response)
+	})
+
+	options := &InstanceCreateReq{
+		IPXEChainURL:    "test.org",
+		ISOID:           "14b3e7d6-ffb5-4994-8502-57fcd9db3b33",
+		ScriptID:        "213",
+		EnableIPv6:      BoolToBoolPtr(true),
+		Backups:         "enabled",
+		UserData:        "dW5vLWRvcy10cmVz",
+		ActivationEmail: BoolToBoolPtr(true),
+		DDOSProtection:  BoolToBoolPtr(true),
+		SnapshotID:      "12ab",
+		Hostname:        "hostname-3000",
+		Tag:             "tagger",
+		Label:           "label-extreme",
+		SSHKeys:         []string{"14b3e7d6-ffb5-4994-8502-57fcd9db3b33", "dev-preview-abc124"},
+		ReservedIPv4:    "63.209.35.79",
+		FirewallGroupID: "1234",
+		ImageID:         "test",
+	}
+
+	server, err := client.Instance.Create(ctx, options)
+	if err != nil {
+		t.Errorf("Instance.Create returned %+v", err)
+	}
+
+	features := []string{"auto_backups", "ipv6"}
+
+	expected := &Instance{
+		ID:               "14b3e7d6-ffb5-4994-8502-57fcd9db3b33",
+		Os:               "CentOS SELinux 8 x64",
+		OsID:             362,
+		RAM:              2048,
+		Disk:             60,
+		MainIP:           "123.123.123.123",
+		VCPUCount:        2,
+		Region:           "ewr",
+		DefaultPassword:  "nreqnusibni",
+		DateCreated:      "2013-12-19 14:45:41",
+		Status:           "active",
+		AllowedBandwidth: 2000,
+		NetmaskV4:        "255.255.255.248",
+		GatewayV4:        "123.123.123.1",
+		PowerStatus:      "running",
+		ServerStatus:     "ok",
+		Plan:             "vc2-1c-2gb",
+		V6Network:        "2001:DB8:1000::",
+		V6MainIP:         "fd11:1111:1112:1c02:0200:00ff:fe00:0000",
+		V6NetworkSize:    64,
+		Label:            "my new server",
+		InternalIP:       "10.99.0.10",
+		KVM:              "https://my.vultr.com/subs/novnc/api.php?data=eawxFVZw2mXnhGUV",
+		Tag:              "tagger",
+		AppID:            0,
+		ImageID:          "test",
+		FirewallGroupID:  "1234",
+		Features:         features,
+	}
+
+	if !reflect.DeepEqual(server, expected) {
+		t.Errorf("Instance.Create returned %+v, expected %+v", server, expected)
+	}
+}
diff --git a/ip.go b/ip.go
new file mode 100644
index 0000000..6c1429b
--- /dev/null
+++ b/ip.go
@@ -0,0 +1,24 @@
+package govultr
+
+// IPv4 struct
+type IPv4 struct {
+	IP      string `json:"ip,omitempty"`
+	Netmask string `json:"netmask,omitempty"`
+	Gateway string `json:"gateway,omitempty"`
+	Type    string `json:"type,omitempty"`
+	Reverse string `json:"reverse,omitempty"`
+}
+
+// IPv6 struct
+type IPv6 struct {
+	IP          string `json:"ip,omitempty"`
+	Network     string `json:"network,omitempty"`
+	NetworkSize int    `json:"network_size,omitempty"`
+	Type        string `json:"type,omitempty"`
+}
+
+type ipBase struct {
+	IPv4s []IPv4 `json:"ipv4s,omitempty"`
+	IPv6s []IPv6 `json:"ipv6s,omitempty"`
+	Meta  *Meta  `json:"meta"`
+}
diff --git a/iso.go b/iso.go
index 8cedd34..4d24823 100644
--- a/iso.go
+++ b/iso.go
@@ -2,141 +2,154 @@ package govultr
 
 import (
 	"context"
+	"fmt"
 	"net/http"
-	"net/url"
-	"strconv"
+
+	"github.com/google/go-querystring/query"
 )
 
 // ISOService is the interface to interact with the ISO endpoints on the Vultr API
-// Link: https://www.vultr.com/api/#ISO
+// Link : https://www.vultr.com/api/#tag/iso
 type ISOService interface {
-	CreateFromURL(ctx context.Context, ISOURL string) (*ISO, error)
-	Delete(ctx context.Context, ISOID int) error
-	List(ctx context.Context) ([]ISO, error)
-	GetPublicList(ctx context.Context) ([]PublicISO, error)
+	Create(ctx context.Context, isoReq *ISOReq) (*ISO, error)
+	Get(ctx context.Context, isoID string) (*ISO, error)
+	Delete(ctx context.Context, isoID string) error
+	List(ctx context.Context, options *ListOptions) ([]ISO, *Meta, error)
+	ListPublic(ctx context.Context, options *ListOptions) ([]PublicISO, *Meta, error)
 }
 
 // ISOServiceHandler handles interaction with the ISO methods for the Vultr API
 type ISOServiceHandler struct {
-	Client *Client
+	client *Client
 }
 
 // ISO represents ISOs currently available on this account.
 type ISO struct {
-	ISOID       int    `json:"ISOID"`
+	ID          string `json:"id"`
 	DateCreated string `json:"date_created"`
 	FileName    string `json:"filename"`
-	Size        int    `json:"size"`
-	MD5Sum      string `json:"md5sum"`
-	SHA512Sum   string `json:"sha512sum"`
+	Size        int    `json:"size,omitempty"`
+	MD5Sum      string `json:"md5sum,omitempty"`
+	SHA512Sum   string `json:"sha512sum,omitempty"`
 	Status      string `json:"status"`
 }
 
 // PublicISO represents public ISOs offered in the Vultr ISO library.
 type PublicISO struct {
-	ISOID       int    `json:"ISOID"`
+	ID          string `json:"id"`
 	Name        string `json:"name"`
 	Description string `json:"description"`
+	MD5Sum      string `json:"md5sum,omitempty"`
 }
 
-// CreateFromURL will create a new ISO image on your account
-func (i *ISOServiceHandler) CreateFromURL(ctx context.Context, ISOURL string) (*ISO, error) {
+// ISOReq is used for creating ISOs.
+type ISOReq struct {
+	URL string `json:"url"`
+}
 
-	uri := "/v1/iso/create_from_url"
+type isosBase struct {
+	ISOs []ISO `json:"isos"`
+	Meta *Meta `json:"meta"`
+}
 
-	values := url.Values{
-		"url": {ISOURL},
-	}
+type isoBase struct {
+	ISO *ISO `json:"iso"`
+}
+
+type publicIsosBase struct {
+	PublicIsos []PublicISO `json:"public_isos"`
+	Meta       *Meta       `json:"meta"`
+}
 
-	req, err := i.Client.NewRequest(ctx, http.MethodPost, uri, values)
+// Create will create a new ISO image on your account
+func (i *ISOServiceHandler) Create(ctx context.Context, isoReq *ISOReq) (*ISO, error) {
+	uri := "/v2/iso"
 
+	req, err := i.client.NewRequest(ctx, http.MethodPost, uri, isoReq)
 	if err != nil {
 		return nil, err
 	}
 
-	iso := new(ISO)
-	err = i.Client.DoWithContext(ctx, req, iso)
-
-	if err != nil {
+	iso := new(isoBase)
+	if err = i.client.DoWithContext(ctx, req, iso); err != nil {
 		return nil, err
 	}
 
-	return iso, nil
+	return iso.ISO, nil
 }
 
-// Delete will delete an ISO image from your account
-func (i *ISOServiceHandler) Delete(ctx context.Context, isoID int) error {
-
-	uri := "/v1/iso/destroy"
+// Get an ISO
+func (i *ISOServiceHandler) Get(ctx context.Context, isoID string) (*ISO, error) {
+	uri := fmt.Sprintf("/v2/iso/%s", isoID)
 
-	values := url.Values{
-		"ISOID": {strconv.Itoa(isoID)},
+	req, err := i.client.NewRequest(ctx, http.MethodGet, uri, nil)
+	if err != nil {
+		return nil, err
 	}
 
-	req, err := i.Client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
+	iso := new(isoBase)
+	if err := i.client.DoWithContext(ctx, req, iso); err != nil {
+		return nil, err
 	}
+	return iso.ISO, nil
+}
 
-	err = i.Client.DoWithContext(ctx, req, nil)
+// Delete will delete an ISO image from your account
+func (i *ISOServiceHandler) Delete(ctx context.Context, isoID string) error {
+	uri := fmt.Sprintf("/v2/iso/%s", isoID)
 
+	req, err := i.client.NewRequest(ctx, http.MethodDelete, uri, nil)
 	if err != nil {
 		return err
 	}
 
-	return nil
+	return i.client.DoWithContext(ctx, req, nil)
 }
 
 // List will list all ISOs currently available on your account
-func (i *ISOServiceHandler) List(ctx context.Context) ([]ISO, error) {
-
-	uri := "/v1/iso/list"
-
-	req, err := i.Client.NewRequest(ctx, http.MethodGet, uri, nil)
+func (i *ISOServiceHandler) List(ctx context.Context, options *ListOptions) ([]ISO, *Meta, error) {
+	uri := "/v2/iso"
 
+	req, err := i.client.NewRequest(ctx, http.MethodGet, uri, nil)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	var ISOMap map[string]ISO
-	err = i.Client.DoWithContext(ctx, req, &ISOMap)
-
+	newValues, err := query.Values(options)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	var iso []ISO
-	for _, i := range ISOMap {
-		iso = append(iso, i)
+	req.URL.RawQuery = newValues.Encode()
+
+	iso := new(isosBase)
+	if err = i.client.DoWithContext(ctx, req, iso); err != nil {
+		return nil, nil, err
 	}
 
-	return iso, nil
+	return iso.ISOs, iso.Meta, nil
 }
 
-// GetPublicList will list public ISOs offered in the Vultr ISO library.
-func (i *ISOServiceHandler) GetPublicList(ctx context.Context) ([]PublicISO, error) {
-
-	uri := "/v1/iso/list_public"
-
-	req, err := i.Client.NewRequest(ctx, http.MethodGet, uri, nil)
+// ListPublic will list public ISOs offered in the Vultr ISO library.
+func (i *ISOServiceHandler) ListPublic(ctx context.Context, options *ListOptions) ([]PublicISO, *Meta, error) {
+	uri := "/v2/iso-public"
 
+	req, err := i.client.NewRequest(ctx, http.MethodGet, uri, nil)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	var ISOMap map[string]PublicISO
-	err = i.Client.DoWithContext(ctx, req, &ISOMap)
-
+	newValues, err := query.Values(options)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	var publicISO []PublicISO
+	req.URL.RawQuery = newValues.Encode()
 
-	for _, p := range ISOMap {
-		publicISO = append(publicISO, p)
+	iso := new(publicIsosBase)
+	if err = i.client.DoWithContext(ctx, req, iso); err != nil {
+		return nil, nil, err
 	}
 
-	return publicISO, nil
+	return iso.PublicIsos, iso.Meta, nil
 }
diff --git a/iso_test.go b/iso_test.go
index f112b9d..a57b4c0 100644
--- a/iso_test.go
+++ b/iso_test.go
@@ -7,25 +7,62 @@ import (
 	"testing"
 )
 
-func TestIsoServiceHandler_CreateFromURL(t *testing.T) {
+func TestIsoServiceHandler_Create(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/iso/create_from_url", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"ISOID": 24}`
+	mux.HandleFunc("/v2/iso", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"iso":{"id":"9931","date_created":"2020-07-0917:15:27","filename":"CentOS-8.1.1911-x86_64-dvd1.iso","status":"pending"}}`
+		fmt.Fprint(writer, response)
+	})
+
+	isoReq := &ISOReq{URL: "http://centos.com/CentOS-8.1.1911-x86_64-dvd1.iso"}
+	iso, err := client.ISO.Create(ctx, isoReq)
+	if err != nil {
+		t.Errorf("Iso.Create returned %+v, expected %+v", err, nil)
+	}
+
+	expected := &ISO{
+		ID:          "9931",
+		DateCreated: "2020-07-0917:15:27",
+		FileName:    "CentOS-8.1.1911-x86_64-dvd1.iso",
+		Size:        0,
+		MD5Sum:      "",
+		SHA512Sum:   "",
+		Status:      "pending",
+	}
+
+	if !reflect.DeepEqual(iso, expected) {
+		t.Errorf("Iso.Create returned %+v, expected %+v", iso, expected)
+	}
+}
+
+func TestIsoServiceHandler_Get(t *testing.T) {
+	setup()
+	defer teardown()
 
+	mux.HandleFunc("/v2/iso/9931", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"iso":{"id":"9931","date_created":"2020-07-0917:15:27","filename":"CentOS-8.1.1911-x86_64-dvd1.iso","status":"pending"}}`
 		fmt.Fprint(writer, response)
 	})
 
-	iso, err := client.ISO.CreateFromURL(ctx, "domain.com/coolest-iso-ever.iso")
+	iso, err := client.ISO.Get(ctx, "9931")
 	if err != nil {
-		t.Errorf("Iso.CreateFromURL returned %+v, expected %+v", err, nil)
+		t.Errorf("Iso.Get returned %+v, expected %+v", err, nil)
 	}
 
-	expected := &ISO{ISOID: 24}
+	expected := &ISO{
+		ID:          "9931",
+		DateCreated: "2020-07-0917:15:27",
+		FileName:    "CentOS-8.1.1911-x86_64-dvd1.iso",
+		Size:        0,
+		MD5Sum:      "",
+		SHA512Sum:   "",
+		Status:      "pending",
+	}
 
 	if !reflect.DeepEqual(iso, expected) {
-		t.Errorf("Iso.CreateFromURL returned %+v, expected %+v", iso, expected)
+		t.Errorf("Iso.Get returned %+v, expected %+v", iso, expected)
 	}
 }
 
@@ -33,11 +70,11 @@ func TestIsoServiceHandler_Delete(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/iso/destroy", func(writer http.ResponseWriter, request *http.Request) {
+	mux.HandleFunc("/v2/iso/24", func(writer http.ResponseWriter, request *http.Request) {
 		fmt.Fprint(writer)
 	})
 
-	err := client.ISO.Delete(ctx, 24)
+	err := client.ISO.Delete(ctx, "24")
 
 	if err != nil {
 		t.Errorf("Iso.Delete returned %+v, expected %+v", err, nil)
@@ -48,46 +85,67 @@ func TestIsoServiceHandler_List(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/iso/list", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{ "24": { "ISOID": 24,"date_created": "2014-04-01 14:10:09","filename": "CentOS-6.5-x86_64-minimal.iso","size": 9342976,"md5sum": "ec066","sha512sum": "1741f890bce04613f60b0","status": "complete"}}`
+	mux.HandleFunc("/v2/iso", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"isos":[{"id":"9931","date_created":"2020-07-0917:15:27","filename":"CentOS-8.1.1911-x86_64-dvd1.iso","status":"pending"}],"meta":{"total":8,"links":{"next":"","prev":""}}}`
 		fmt.Fprint(writer, response)
 	})
 
-	iso, err := client.ISO.List(ctx)
-
+	iso, meta, err := client.ISO.List(ctx, nil)
 	if err != nil {
 		t.Errorf("Iso.List returned %+v, expected %+v", err, nil)
 	}
 
-	expected := []ISO{
-		{ISOID: 24, DateCreated: "2014-04-01 14:10:09", FileName: "CentOS-6.5-x86_64-minimal.iso", Size: 9342976, MD5Sum: "ec066", SHA512Sum: "1741f890bce04613f60b0", Status: "complete"},
+	expectedIso := []ISO{
+		{
+			ID:          "9931",
+			DateCreated: "2020-07-0917:15:27",
+			FileName:    "CentOS-8.1.1911-x86_64-dvd1.iso",
+			Size:        0,
+			MD5Sum:      "",
+			SHA512Sum:   "",
+			Status:      "pending",
+		},
 	}
 
-	if !reflect.DeepEqual(iso, expected) {
-		t.Errorf("Iso.List returned %+v, expected %+v", iso, expected)
+	expectedMeta := &Meta{
+		Total: 8,
+		Links: &Links{},
+	}
+	if !reflect.DeepEqual(iso, expectedIso) {
+		t.Errorf("Iso.List iso returned %+v, expected %+v", iso, expectedIso)
+	}
+
+	if !reflect.DeepEqual(meta, expectedMeta) {
+		t.Errorf("Iso.List returned %+v, expected %+v", meta, expectedMeta)
 	}
 }
 
-func TestIsoServiceHandler_GetPublicList(t *testing.T) {
+func TestIsoServiceHandler_ListPublic(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/iso/list_public", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"204515": {"ISOID": 204515,"name": "CentOS 7","description": "7 x86_64 Minimal"}}`
+	mux.HandleFunc("/v2/iso-public", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"public_isos": [{"id": "204515","name": "CentOS 7","description": "7 x86_64 Minimal"}],"meta":{"total":8,"links":{"next":"","prev":""}}}`
 		fmt.Fprint(writer, response)
 	})
 
-	iso, err := client.ISO.GetPublicList(ctx)
-
+	iso, meta, err := client.ISO.ListPublic(ctx, nil)
 	if err != nil {
-		t.Errorf("Iso.GetPublicList returned %+v, expected %+v", err, nil)
+		t.Errorf("Iso.ListPublic returned %+v, expected %+v", err, nil)
 	}
 
-	expected := []PublicISO{
-		{ISOID: 204515, Name: "CentOS 7", Description: "7 x86_64 Minimal"},
+	expectedIso := []PublicISO{
+		{ID: "204515", Name: "CentOS 7", Description: "7 x86_64 Minimal"},
 	}
 
-	if !reflect.DeepEqual(iso, expected) {
-		t.Errorf("Iso.GetPublicList returned %+v, expected %+v", iso, expected)
+	expectedMeta := &Meta{
+		Total: 8,
+		Links: &Links{},
+	}
+	if !reflect.DeepEqual(iso, expectedIso) {
+		t.Errorf("Iso.ListPublic  iso returned %+v, expected %+v", iso, expectedIso)
+	}
+	if !reflect.DeepEqual(meta, expectedMeta) {
+		t.Errorf("Iso.ListPublic meta returned %+v, expected %+v", meta, expectedMeta)
 	}
 }
diff --git a/kubernetes.go b/kubernetes.go
new file mode 100644
index 0000000..9fdc800
--- /dev/null
+++ b/kubernetes.go
@@ -0,0 +1,341 @@
+package govultr
+
+import (
+	"context"
+	"fmt"
+	"net/http"
+
+	"github.com/google/go-querystring/query"
+)
+
+const vkePath = "/v2/kubernetes/clusters"
+
+// KubernetesService is the interface to interact with kubernetes endpoint on the Vultr API
+// Link : https://www.vultr.com/api/#tag/kubernetes
+type KubernetesService interface {
+	CreateCluster(ctx context.Context, createReq *ClusterReq) (*Cluster, error)
+	GetCluster(ctx context.Context, id string) (*Cluster, error)
+	ListClusters(ctx context.Context, options *ListOptions) ([]Cluster, *Meta, error)
+	UpdateCluster(ctx context.Context, vkeID string, updateReq *ClusterReqUpdate) error
+	DeleteCluster(ctx context.Context, id string) error
+	DeleteClusterWithResources(ctx context.Context, id string) error
+
+	CreateNodePool(ctx context.Context, vkeID string, nodePoolReq *NodePoolReq) (*NodePool, error)
+	ListNodePools(ctx context.Context, vkeID string, options *ListOptions) ([]NodePool, *Meta, error)
+	GetNodePool(ctx context.Context, vkeID, nodePoolID string) (*NodePool, error)
+	UpdateNodePool(ctx context.Context, vkeID, nodePoolID string, updateReq *NodePoolReqUpdate) (*NodePool, error)
+	DeleteNodePool(ctx context.Context, vkeID, nodePoolID string) error
+
+	DeleteNodePoolInstance(ctx context.Context, vkeID, nodePoolID, nodeID string) error
+	RecycleNodePoolInstance(ctx context.Context, vkeID, nodePoolID, nodeID string) error
+
+	GetKubeConfig(ctx context.Context, vkeID string) (*KubeConfig, error)
+	GetVersions(ctx context.Context) (*Versions, error)
+}
+
+// KubernetesHandler handles interaction with the kubernetes methods for the Vultr API
+type KubernetesHandler struct {
+	client *Client
+}
+
+// Cluster represents a full VKE cluster
+type Cluster struct {
+	ID            string     `json:"id"`
+	Label         string     `json:"label"`
+	DateCreated   string     `json:"date_created"`
+	ClusterSubnet string     `json:"cluster_subnet"`
+	ServiceSubnet string     `json:"service_subnet"`
+	IP            string     `json:"ip"`
+	Endpoint      string     `json:"endpoint"`
+	Version       string     `json:"version"`
+	Region        string     `json:"region"`
+	Status        string     `json:"status"`
+	NodePools     []NodePool `json:"node_pools"`
+}
+
+// NodePool represents a pool of nodes that are grouped by their label and plan type
+type NodePool struct {
+	ID           string `json:"id"`
+	DateCreated  string `json:"date_created"`
+	DateUpdated  string `json:"date_updated"`
+	Label        string `json:"label"`
+	Plan         string `json:"plan"`
+	Status       string `json:"status"`
+	NodeQuantity int    `json:"node_quantity"`
+	Tag          string `json:"tag"`
+	Nodes        []Node `json:"nodes"`
+}
+
+// Node represents a node that will live within a nodepool
+type Node struct {
+	ID          string `json:"id"`
+	DateCreated string `json:"date_created"`
+	Label       string `json:"label"`
+	Status      string `json:"status"`
+}
+
+// KubeConfig will contain the kubeconfig b64 encoded
+type KubeConfig struct {
+	KubeConfig string `json:"kube_config"`
+}
+
+// ClusterReq struct used to create a cluster
+type ClusterReq struct {
+	Label     string        `json:"label"`
+	Region    string        `json:"region"`
+	Version   string        `json:"version"`
+	NodePools []NodePoolReq `json:"node_pools"`
+}
+
+// ClusterReqUpdate struct used to update update a cluster
+type ClusterReqUpdate struct {
+	Label string `json:"label"`
+}
+
+// NodePoolReq struct used to create a node pool
+type NodePoolReq struct {
+	NodeQuantity int    `json:"node_quantity"`
+	Label        string `json:"label"`
+	Plan         string `json:"plan"`
+	Tag          string `json:"tag"`
+}
+
+// NodePoolReqUpdate struct used to update a node pool
+type NodePoolReqUpdate struct {
+	NodeQuantity int    `json:"node_quantity,omitempty"`
+	Tag          string `json:"tag,omitempty"`
+}
+
+type vkeClustersBase struct {
+	VKEClusters []Cluster `json:"vke_clusters"`
+	Meta        *Meta     `json:"meta"`
+}
+
+type vkeClusterBase struct {
+	VKECluster *Cluster `json:"vke_cluster"`
+}
+
+type vkeNodePoolsBase struct {
+	NodePools []NodePool `json:"node_pools"`
+	Meta      *Meta      `json:"meta"`
+}
+
+type vkeNodePoolBase struct {
+	NodePool *NodePool `json:"node_pool"`
+}
+
+// Versions that are supported for VKE
+type Versions struct {
+	Versions []string `json:"versions"`
+}
+
+// CreateCluster will create a Kubernetes cluster.
+func (k *KubernetesHandler) CreateCluster(ctx context.Context, createReq *ClusterReq) (*Cluster, error) {
+	req, err := k.client.NewRequest(ctx, http.MethodPost, vkePath, createReq)
+	if err != nil {
+		return nil, err
+	}
+
+	var k8 = new(vkeClusterBase)
+	if err = k.client.DoWithContext(ctx, req, &k8); err != nil {
+		return nil, err
+	}
+
+	return k8.VKECluster, nil
+}
+
+// GetCluster will return a Kubernetes cluster.
+func (k *KubernetesHandler) GetCluster(ctx context.Context, id string) (*Cluster, error) {
+	req, err := k.client.NewRequest(ctx, http.MethodGet, fmt.Sprintf("%s/%s", vkePath, id), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	k8 := new(vkeClusterBase)
+	if err = k.client.DoWithContext(ctx, req, &k8); err != nil {
+		return nil, err
+	}
+
+	return k8.VKECluster, nil
+}
+
+// ListClusters will return all kubernetes clusters.
+func (k *KubernetesHandler) ListClusters(ctx context.Context, options *ListOptions) ([]Cluster, *Meta, error) {
+	req, err := k.client.NewRequest(ctx, http.MethodGet, vkePath, nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	newValues, err := query.Values(options)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	req.URL.RawQuery = newValues.Encode()
+
+	k8s := new(vkeClustersBase)
+	if err = k.client.DoWithContext(ctx, req, &k8s); err != nil {
+		return nil, nil, err
+	}
+
+	return k8s.VKEClusters, k8s.Meta, nil
+}
+
+// UpdateCluster updates label on VKE cluster
+func (k *KubernetesHandler) UpdateCluster(ctx context.Context, vkeID string, updateReq *ClusterReqUpdate) error {
+	req, err := k.client.NewRequest(ctx, http.MethodPut, fmt.Sprintf("%s/%s", vkePath, vkeID), updateReq)
+	if err != nil {
+		return err
+	}
+
+	return k.client.DoWithContext(ctx, req, nil)
+}
+
+// DeleteCluster will delete a Kubernetes cluster.
+func (k *KubernetesHandler) DeleteCluster(ctx context.Context, id string) error {
+	req, err := k.client.NewRequest(ctx, http.MethodDelete, fmt.Sprintf("%s/%s", vkePath, id), nil)
+	if err != nil {
+		return err
+	}
+
+	return k.client.DoWithContext(ctx, req, nil)
+}
+
+// DeleteClusterWithResources will delete a Kubernetes cluster and all related resources.
+func (k *KubernetesHandler) DeleteClusterWithResources(ctx context.Context, id string) error {
+	req, err := k.client.NewRequest(ctx, http.MethodDelete, fmt.Sprintf("%s/%s/delete-with-linked-resources", vkePath, id), nil)
+	if err != nil {
+		return err
+	}
+
+	return k.client.DoWithContext(ctx, req, nil)
+}
+
+// CreateNodePool creates a nodepool on a VKE cluster
+func (k *KubernetesHandler) CreateNodePool(ctx context.Context, vkeID string, nodePoolReq *NodePoolReq) (*NodePool, error) {
+	req, err := k.client.NewRequest(ctx, http.MethodPost, fmt.Sprintf("%s/%s/node-pools", vkePath, vkeID), nodePoolReq)
+	if err != nil {
+		return nil, err
+	}
+
+	n := new(vkeNodePoolBase)
+	err = k.client.DoWithContext(ctx, req, n)
+	if err != nil {
+		return nil, err
+	}
+
+	return n.NodePool, nil
+}
+
+// ListNodePools will return all nodepools for a given VKE cluster
+func (k *KubernetesHandler) ListNodePools(ctx context.Context, vkeID string, options *ListOptions) ([]NodePool, *Meta, error) {
+	req, err := k.client.NewRequest(ctx, http.MethodGet, fmt.Sprintf("%s/%s/node-pools", vkePath, vkeID), nil)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	newValues, err := query.Values(options)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	req.URL.RawQuery = newValues.Encode()
+
+	n := new(vkeNodePoolsBase)
+	if err = k.client.DoWithContext(ctx, req, &n); err != nil {
+		return nil, nil, err
+	}
+
+	return n.NodePools, n.Meta, nil
+}
+
+// GetNodePool will return a single nodepool
+func (k *KubernetesHandler) GetNodePool(ctx context.Context, vkeID, nodePoolID string) (*NodePool, error) {
+	req, err := k.client.NewRequest(ctx, http.MethodGet, fmt.Sprintf("%s/%s/node-pools/%s", vkePath, vkeID, nodePoolID), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	n := new(vkeNodePoolBase)
+	if err = k.client.DoWithContext(ctx, req, &n); err != nil {
+		return nil, err
+	}
+
+	return n.NodePool, nil
+}
+
+// UpdateNodePool will allow you change the quantity of nodes within a nodepool
+func (k *KubernetesHandler) UpdateNodePool(ctx context.Context, vkeID, nodePoolID string, updateReq *NodePoolReqUpdate) (*NodePool, error) {
+	req, err := k.client.NewRequest(ctx, http.MethodPatch, fmt.Sprintf("%s/%s/node-pools/%s", vkePath, vkeID, nodePoolID), updateReq)
+	if err != nil {
+		return nil, err
+	}
+
+	np := new(vkeNodePoolBase)
+	if err = k.client.DoWithContext(ctx, req, np); err != nil {
+		return nil, err
+	}
+
+	return np.NodePool, nil
+}
+
+// DeleteNodePool will remove a nodepool from a VKE cluster
+func (k *KubernetesHandler) DeleteNodePool(ctx context.Context, vkeID, nodePoolID string) error {
+	req, err := k.client.NewRequest(ctx, http.MethodDelete, fmt.Sprintf("%s/%s/node-pools/%s", vkePath, vkeID, nodePoolID), nil)
+	if err != nil {
+		return err
+	}
+
+	return k.client.DoWithContext(ctx, req, nil)
+}
+
+// DeleteNodePoolInstance will remove a specified node from a nodepool
+func (k *KubernetesHandler) DeleteNodePoolInstance(ctx context.Context, vkeID, nodePoolID, nodeID string) error {
+	req, err := k.client.NewRequest(ctx, http.MethodDelete, fmt.Sprintf("%s/%s/node-pools/%s/nodes/%s", vkePath, vkeID, nodePoolID, nodeID), nil)
+	if err != nil {
+		return err
+	}
+
+	return k.client.DoWithContext(ctx, req, nil)
+}
+
+// RecycleNodePoolInstance will recycle (destroy + redeploy) a given node on a nodepool
+func (k *KubernetesHandler) RecycleNodePoolInstance(ctx context.Context, vkeID, nodePoolID, nodeID string) error {
+	req, err := k.client.NewRequest(ctx, http.MethodPost, fmt.Sprintf("%s/%s/node-pools/%s/nodes/%s/recycle", vkePath, vkeID, nodePoolID, nodeID), nil)
+	if err != nil {
+		return err
+	}
+
+	return k.client.DoWithContext(ctx, req, nil)
+}
+
+// GetKubeConfig returns the kubeconfig for the specified VKE cluster
+func (k *KubernetesHandler) GetKubeConfig(ctx context.Context, vkeID string) (*KubeConfig, error) {
+	req, err := k.client.NewRequest(ctx, http.MethodGet, fmt.Sprintf("%s/%s/config", vkePath, vkeID), nil)
+	if err != nil {
+		return nil, err
+	}
+
+	kc := new(KubeConfig)
+	if err = k.client.DoWithContext(ctx, req, &kc); err != nil {
+		return nil, err
+	}
+
+	return kc, nil
+}
+
+// GetVersions returns the supported kubernetes versions
+func (k *KubernetesHandler) GetVersions(ctx context.Context) (*Versions, error) {
+	uri := "/v2/kubernetes/versions"
+	req, err := k.client.NewRequest(ctx, http.MethodGet, uri, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	versions := new(Versions)
+	if err = k.client.DoWithContext(ctx, req, &versions); err != nil {
+		return nil, err
+	}
+
+	return versions, nil
+}
diff --git a/kubernetes_test.go b/kubernetes_test.go
new file mode 100644
index 0000000..68f83b8
--- /dev/null
+++ b/kubernetes_test.go
@@ -0,0 +1,718 @@
+package govultr
+
+import (
+	"context"
+	"fmt"
+	"net/http"
+	"reflect"
+	"testing"
+	"time"
+)
+
+func TestKubernetesHandler_CreateCluster(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc(vkePath, func(writer http.ResponseWriter, request *http.Request) {
+		response := `{
+    "vke_cluster": {
+        "id": "014da059-21e3-47eb-acb5-91bf697c31aa",
+        "label": "vke",
+        "date_created": "2021-07-13T14:20:16+00:00",
+        "cluster_subnet": "10.244.0.0/16",
+        "service_subnet": "10.96.0.0/12",
+        "ip": "0.0.0.0",
+        "endpoint": "014da059-21e3-47eb-acb5-91bf697c31aa.vultr-k8s.com",
+        "version": "1.20",
+        "region": "lax",
+        "status": "pending",
+        "node_pools": [
+            {
+                "id": "e1c7a313-e42d-43bb-82ef-4f287639b303",
+                "date_created": "2021-07-13T14:20:16+00:00",
+                "label": "my-label-48957292",
+                "plan": "vc2-1c-2gb",
+                "status": "pending",
+                "node_quantity": 1,
+                "nodes": [
+                    {
+                        "id": "38364f79-17e3-4f1f-b7df-d9494bce0e4a",
+                        "label": "my-label-48957292-fef60eda12071",
+                        "date_created": "2021-07-13T14:20:16+00:00",
+                        "status": "pending"
+                    }
+                ]
+            }
+        ]
+    }
+}`
+		fmt.Fprintf(writer, response)
+	})
+
+	createReq := &ClusterReq{
+		Label:     "vke",
+		Region:    "lax",
+		Version:   "1.20",
+		NodePools: nil,
+	}
+	vke, err := client.Kubernetes.CreateCluster(ctx, createReq)
+	if err != nil {
+		t.Errorf("Kubernetes.CreateCluster returned %v", err)
+	}
+
+	expected := &Cluster{
+		ID:            "014da059-21e3-47eb-acb5-91bf697c31aa",
+		Label:         "vke",
+		DateCreated:   "2021-07-13T14:20:16+00:00",
+		ClusterSubnet: "10.244.0.0/16",
+		ServiceSubnet: "10.96.0.0/12",
+		IP:            "0.0.0.0",
+		Endpoint:      "014da059-21e3-47eb-acb5-91bf697c31aa.vultr-k8s.com",
+		Version:       "1.20",
+		Region:        "lax",
+		Status:        "pending",
+		NodePools: []NodePool{
+			{
+				ID:           "e1c7a313-e42d-43bb-82ef-4f287639b303",
+				DateCreated:  "2021-07-13T14:20:16+00:00",
+				Label:        "my-label-48957292",
+				Plan:         "vc2-1c-2gb",
+				Status:       "pending",
+				NodeQuantity: 1,
+				Nodes: []Node{
+					{
+						ID:          "38364f79-17e3-4f1f-b7df-d9494bce0e4a",
+						DateCreated: "2021-07-13T14:20:16+00:00",
+						Label:       "my-label-48957292-fef60eda12071",
+						Status:      "pending",
+					},
+				},
+			},
+		},
+	}
+
+	if !reflect.DeepEqual(vke, expected) {
+		t.Errorf("Kubernetes.CreateCluster returned %+v, expected %+v", vke, expected)
+	}
+
+	c, can := context.WithTimeout(ctx, 1*time.Microsecond)
+	defer can()
+	_, err = client.Kubernetes.CreateCluster(c, createReq)
+	if err == nil {
+		t.Error("Kubernetes.CreateCluster returned nil")
+	}
+}
+
+func TestKubernetesHandler_GetCluster(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc(fmt.Sprintf("%s/%s", vkePath, "014da059-21e3-47eb-acb5-91bf697c31aa"), func(writer http.ResponseWriter, request *http.Request) {
+		response := `{
+    "vke_cluster": {
+        "id": "014da059-21e3-47eb-acb5-91bf697c31aa",
+        "label": "vke",
+        "date_created": "2021-07-13T14:20:16+00:00",
+        "cluster_subnet": "10.244.0.0/16",
+        "service_subnet": "10.96.0.0/12",
+        "ip": "0.0.0.0",
+        "endpoint": "014da059-21e3-47eb-acb5-91bf697c31aa.vultr-k8s.com",
+        "version": "1.20",
+        "region": "lax",
+        "status": "pending",
+        "node_pools": [
+            {
+                "id": "e1c7a313-e42d-43bb-82ef-4f287639b303",
+                "date_created": "2021-07-13T14:20:16+00:00",
+                "label": "my-label-48957292",
+                "plan": "vc2-1c-2gb",
+                "status": "pending",
+                "node_quantity": 1,
+                "nodes": [
+                    {
+                        "id": "38364f79-17e3-4f1f-b7df-d9494bce0e4a",
+                        "label": "my-label-48957292-fef60eda12071",
+                        "date_created": "2021-07-13T14:20:16+00:00",
+                        "status": "pending"
+                    }
+                ]
+            }
+        ]
+    }
+}`
+		fmt.Fprintf(writer, response)
+	})
+
+	vke, err := client.Kubernetes.GetCluster(ctx, "014da059-21e3-47eb-acb5-91bf697c31aa")
+	if err != nil {
+		t.Errorf("Kubernetes.GetCluster returned %v", err)
+	}
+
+	expected := &Cluster{
+		ID:            "014da059-21e3-47eb-acb5-91bf697c31aa",
+		Label:         "vke",
+		DateCreated:   "2021-07-13T14:20:16+00:00",
+		ClusterSubnet: "10.244.0.0/16",
+		ServiceSubnet: "10.96.0.0/12",
+		IP:            "0.0.0.0",
+		Endpoint:      "014da059-21e3-47eb-acb5-91bf697c31aa.vultr-k8s.com",
+		Version:       "1.20",
+		Region:        "lax",
+		Status:        "pending",
+		NodePools: []NodePool{
+			{
+				ID:           "e1c7a313-e42d-43bb-82ef-4f287639b303",
+				DateCreated:  "2021-07-13T14:20:16+00:00",
+				Label:        "my-label-48957292",
+				Plan:         "vc2-1c-2gb",
+				Status:       "pending",
+				NodeQuantity: 1,
+				Nodes: []Node{
+					{
+						ID:          "38364f79-17e3-4f1f-b7df-d9494bce0e4a",
+						DateCreated: "2021-07-13T14:20:16+00:00",
+						Label:       "my-label-48957292-fef60eda12071",
+						Status:      "pending",
+					},
+				},
+			},
+		},
+	}
+
+	if !reflect.DeepEqual(vke, expected) {
+		t.Errorf("Kubernetes.GetCluster returned %+v, expected %+v", vke, expected)
+	}
+
+	c, can := context.WithTimeout(ctx, 1*time.Microsecond)
+	defer can()
+	_, err = client.Kubernetes.GetCluster(c, "014da059-21e3-47eb-acb5-91bf697c31aa")
+	if err == nil {
+		t.Error("Kubernetes.GetCluster returned nil")
+	}
+}
+
+func TestKubernetesHandler_ListClusters(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc(fmt.Sprintf("%s", vkePath), func(writer http.ResponseWriter, request *http.Request) {
+		response := `{
+    "vke_clusters": [{
+        "id": "014da059-21e3-47eb-acb5-91bf697c31aa",
+        "label": "vke",
+        "date_created": "2021-07-13T14:20:16+00:00",
+        "cluster_subnet": "10.244.0.0/16",
+        "service_subnet": "10.96.0.0/12",
+        "ip": "0.0.0.0",
+        "endpoint": "014da059-21e3-47eb-acb5-91bf697c31aa.vultr-k8s.com",
+        "version": "1.20",
+        "region": "lax",
+        "status": "pending",
+        "node_pools": [
+            {
+                "id": "e1c7a313-e42d-43bb-82ef-4f287639b303",
+                "date_created": "2021-07-13T14:20:16+00:00",
+                "label": "my-label-48957292",
+                "plan": "vc2-1c-2gb",
+                "status": "pending",
+				"tag": "mytag",
+                "node_quantity": 1,
+                "nodes": [
+                    {
+                        "id": "38364f79-17e3-4f1f-b7df-d9494bce0e4a",
+                        "label": "my-label-48957292-fef60eda12071",
+                        "date_created": "2021-07-13T14:20:16+00:00",
+                        "status": "pending"
+                    }
+                ]
+            }
+        ]
+    }
+],
+    "meta": {
+        "total": 1,
+        "links": {
+            "next": "thisismycusror",
+            "prev": ""
+        }
+    }
+}`
+		fmt.Fprintf(writer, response)
+	})
+
+	vke, meta, err := client.Kubernetes.ListClusters(ctx, nil)
+	if err != nil {
+		t.Errorf("Kubernetes.ListClusters returned %v", err)
+	}
+
+	expected := []Cluster{
+		{
+			ID:            "014da059-21e3-47eb-acb5-91bf697c31aa",
+			Label:         "vke",
+			DateCreated:   "2021-07-13T14:20:16+00:00",
+			ClusterSubnet: "10.244.0.0/16",
+			ServiceSubnet: "10.96.0.0/12",
+			IP:            "0.0.0.0",
+			Endpoint:      "014da059-21e3-47eb-acb5-91bf697c31aa.vultr-k8s.com",
+			Version:       "1.20",
+			Region:        "lax",
+			Status:        "pending",
+			NodePools: []NodePool{
+				{
+					ID:           "e1c7a313-e42d-43bb-82ef-4f287639b303",
+					DateCreated:  "2021-07-13T14:20:16+00:00",
+					Label:        "my-label-48957292",
+					Plan:         "vc2-1c-2gb",
+					Status:       "pending",
+					Tag:          "mytag",
+					NodeQuantity: 1,
+					Nodes: []Node{
+						{
+							ID:          "38364f79-17e3-4f1f-b7df-d9494bce0e4a",
+							DateCreated: "2021-07-13T14:20:16+00:00",
+							Label:       "my-label-48957292-fef60eda12071",
+							Status:      "pending",
+						},
+					},
+				},
+			},
+		},
+	}
+	expectedMeta := &Meta{
+		Total: 1,
+		Links: &Links{
+			Next: "thisismycusror",
+			Prev: "",
+		},
+	}
+	if !reflect.DeepEqual(vke, expected) {
+		t.Errorf("Kubernetes.List returned %+v, expected %+v", vke, expected)
+	}
+
+	if !reflect.DeepEqual(meta, expectedMeta) {
+		t.Errorf("Kubernetes.List meta returned %+v, expected %+v", vke, expected)
+	}
+
+	c, can := context.WithTimeout(ctx, 1*time.Microsecond)
+	defer can()
+	_, _, err = client.Kubernetes.ListClusters(c, nil)
+	if err == nil {
+		t.Error("Kubernetes.ListClusters returned nil")
+	}
+}
+
+func TestKubernetesHandler_UpdateCluster(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc(fmt.Sprintf("%s/%s", vkePath, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33"), func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
+	})
+	update := ClusterReqUpdate{Label: "new label"}
+	err := client.Kubernetes.UpdateCluster(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33", &update)
+
+	if err != nil {
+		t.Errorf("Kubernetes.UpdateCluster returned %+v", err)
+	}
+}
+
+func TestKubernetesHandler_DeleteCluster(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc(fmt.Sprintf("%s/%s", vkePath, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33"), func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
+	})
+
+	err := client.Kubernetes.DeleteCluster(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33")
+	if err != nil {
+		t.Errorf("Kubernetes.DeleteCluster returned %+v", err)
+	}
+}
+
+func TestKubernetesHandler_DeleteClusterWithResources(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc(fmt.Sprintf("%s/%s/delete-with-linked-resources", vkePath, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33"), func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
+	})
+
+	err := client.Kubernetes.DeleteClusterWithResources(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33")
+	if err != nil {
+		t.Errorf("Kubernetes.DeleteClusterWithResources returned %+v", err)
+	}
+}
+
+func TestKubernetesHandler_CreateNodePool(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc(fmt.Sprintf("%s/%s/node-pools", vkePath, "1"), func(writer http.ResponseWriter, request *http.Request) {
+		response := `{
+    "node_pool": {
+        "id": "554e7248-705a-5862-516f-4f4a6735346a",
+        "date_created": "2021-07-13T15:42:21+00:00",
+        "label": "nodepool-48959140",
+        "plan": "vc2-1c-2gb",
+        "status": "pending",
+        "node_quantity": 1,
+		"tag": "mytag",
+        "nodes": [
+            {
+                "id": "3e1ca1e0-25be-4977-907a-3dee42b9bb15",
+                "label": "nodepool-48959140-74a60edb45de0",
+                "date_created": "2021-07-13T15:42:21+00:00",
+                "status": "pending"
+            }
+        ]
+    }
+}`
+		fmt.Fprintf(writer, response)
+	})
+
+	createReq := &NodePoolReq{
+		NodeQuantity: 1,
+		Label:        "nodepool-48959140",
+		Plan:         "vc2-1c-2gb",
+		Tag:          "mytag",
+	}
+	np, err := client.Kubernetes.CreateNodePool(ctx, "1", createReq)
+	if err != nil {
+		t.Errorf("Kubernetes.CreateNodePool returned %v", err)
+	}
+
+	expected := &NodePool{
+		ID:           "554e7248-705a-5862-516f-4f4a6735346a",
+		DateCreated:  "2021-07-13T15:42:21+00:00",
+		Label:        "nodepool-48959140",
+		Plan:         "vc2-1c-2gb",
+		Status:       "pending",
+		NodeQuantity: 1,
+		Tag:          "mytag",
+		Nodes: []Node{
+			{
+				ID:          "3e1ca1e0-25be-4977-907a-3dee42b9bb15",
+				Label:       "nodepool-48959140-74a60edb45de0",
+				DateCreated: "2021-07-13T15:42:21+00:00",
+				Status:      "pending",
+			},
+		},
+	}
+
+	if !reflect.DeepEqual(np, expected) {
+		t.Errorf("Kubernetes.CreateNodePool returned %+v, expected %+v", np, expected)
+	}
+
+	c, can := context.WithTimeout(ctx, 1*time.Microsecond)
+	defer can()
+	_, err = client.Kubernetes.CreateNodePool(c, "1", createReq)
+	if err == nil {
+		t.Error("Kubernetes.CreateNodePool returned nil")
+	}
+}
+
+func TestKubernetesHandler_GetNodePool(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc(fmt.Sprintf("%s/%s/node-pools/%s", vkePath, "1", "2"), func(writer http.ResponseWriter, request *http.Request) {
+		response := `{
+    "node_pool": {
+        "id": "554e7248-705a-5862-516f-4f4a6735346a",
+        "date_created": "2021-07-13T15:42:21+00:00",
+        "label": "nodepool-48959140",
+        "plan": "vc2-1c-2gb",
+        "status": "pending",
+        "node_quantity": 1,
+		"tag": "mytag",
+        "nodes": [
+            {
+                "id": "3e1ca1e0-25be-4977-907a-3dee42b9bb15",
+                "label": "nodepool-48959140-74a60edb45de0",
+                "date_created": "2021-07-13T15:42:21+00:00",
+                "status": "pending"
+            }
+        ]
+    }
+}`
+		fmt.Fprintf(writer, response)
+	})
+
+	np, err := client.Kubernetes.GetNodePool(ctx, "1", "2")
+	if err != nil {
+		t.Errorf("Kubernetes.GetNodePool returned %v", err)
+	}
+
+	expected := &NodePool{
+		ID:           "554e7248-705a-5862-516f-4f4a6735346a",
+		DateCreated:  "2021-07-13T15:42:21+00:00",
+		Label:        "nodepool-48959140",
+		Plan:         "vc2-1c-2gb",
+		Status:       "pending",
+		Tag:          "mytag",
+		NodeQuantity: 1,
+		Nodes: []Node{
+			{
+				ID:          "3e1ca1e0-25be-4977-907a-3dee42b9bb15",
+				Label:       "nodepool-48959140-74a60edb45de0",
+				DateCreated: "2021-07-13T15:42:21+00:00",
+				Status:      "pending",
+			},
+		},
+	}
+
+	if !reflect.DeepEqual(np, expected) {
+		t.Errorf("Kubernetes.GetNodePool returned %+v, expected %+v", np, expected)
+	}
+
+	c, can := context.WithTimeout(ctx, 1*time.Microsecond)
+	defer can()
+	_, err = client.Kubernetes.GetNodePool(c, "1", "2")
+	if err == nil {
+		t.Error("Kubernetes.GetNodePool returned nil")
+	}
+}
+
+func TestKubernetesHandler_ListNodePools(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc(fmt.Sprintf("%s/%s/node-pools", vkePath, "1"), func(writer http.ResponseWriter, request *http.Request) {
+		response := `{
+    "node_pools": [{
+        "id": "554e7248-705a-5862-516f-4f4a6735346a",
+        "date_created": "2021-07-13T15:42:21+00:00",
+        "label": "nodepool-48959140",
+        "plan": "vc2-1c-2gb",
+        "status": "pending",
+        "node_quantity": 1,
+		"tag": "mytag",
+        "nodes": [
+            {
+                "id": "3e1ca1e0-25be-4977-907a-3dee42b9bb15",
+                "label": "nodepool-48959140-74a60edb45de0",
+                "date_created": "2021-07-13T15:42:21+00:00",
+                "status": "pending"
+            }
+        ]
+    }],
+    "meta": {
+        "total": 1,
+        "links": {
+            "next": "thisismycusror",
+            "prev": ""
+        }
+    }
+}`
+		fmt.Fprintf(writer, response)
+	})
+
+	np, meta, err := client.Kubernetes.ListNodePools(ctx, "1", nil)
+	if err != nil {
+		t.Errorf("Kubernetes.ListNodePools returned %v", err)
+	}
+
+	expected := []NodePool{
+		{
+			ID:           "554e7248-705a-5862-516f-4f4a6735346a",
+			DateCreated:  "2021-07-13T15:42:21+00:00",
+			Label:        "nodepool-48959140",
+			Plan:         "vc2-1c-2gb",
+			Status:       "pending",
+			Tag:          "mytag",
+			NodeQuantity: 1,
+			Nodes: []Node{
+				{
+					ID:          "3e1ca1e0-25be-4977-907a-3dee42b9bb15",
+					Label:       "nodepool-48959140-74a60edb45de0",
+					DateCreated: "2021-07-13T15:42:21+00:00",
+					Status:      "pending",
+				},
+			},
+		},
+	}
+
+	if !reflect.DeepEqual(np, expected) {
+		t.Errorf("Kubernetes.ListNodePools returned %+v, expected %+v", np, expected)
+	}
+
+	expectedMeta := &Meta{
+		Total: 1,
+		Links: &Links{
+			Next: "thisismycusror",
+			Prev: "",
+		},
+	}
+
+	if !reflect.DeepEqual(meta, expectedMeta) {
+		t.Errorf("Kubernetes.ListNodePools meta returned %+v, expected %+v", meta, expected)
+	}
+
+	c, can := context.WithTimeout(ctx, 1*time.Microsecond)
+	defer can()
+	_, _, err = client.Kubernetes.ListNodePools(c, "1", nil)
+	if err == nil {
+		t.Error("Kubernetes.ListNodePools returned nil")
+	}
+}
+
+func TestKubernetesHandler_UpdateNodePool(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc(fmt.Sprintf("%s/%s/node-pools/%s", vkePath, "1", "2"), func(writer http.ResponseWriter, request *http.Request) {
+		response := `{
+  "node_pool": {
+    "id": "e97bdee9-2781-4f31-be03-60fc75f399ae",
+    "date_created": "2021-07-07T23:27:08+00:00",
+    "date_updated": "2021-07-08T12:12:44+00:00",
+    "label": "my-label-48770703",
+    "plan": "vc2-1c-2gb",
+    "status": "active",
+    "node_quantity": 1,
+	"tag": "mytag",
+    "nodes": [
+      {
+        "id": "f2e11430-76e5-4dc6-a1c9-ef5682c21ddf",
+        "label": "my-label-48770703-44060e6384c45",
+        "date_created": "2021-07-07T23:27:08+00:00",
+        "status": "active"
+      }
+    ]
+  }
+}`
+		fmt.Fprintf(writer, response)
+	})
+	update := NodePoolReqUpdate{NodeQuantity: 1}
+	response, err := client.Kubernetes.UpdateNodePool(ctx, "1", "2", &update)
+	if err != nil {
+		t.Errorf("Kubernetes.UpdateNodePool returned %+v", err)
+	}
+
+	expected := &NodePool{
+		ID:           "e97bdee9-2781-4f31-be03-60fc75f399ae",
+		DateCreated:  "2021-07-07T23:27:08+00:00",
+		DateUpdated:  "2021-07-08T12:12:44+00:00",
+		Label:        "my-label-48770703",
+		Plan:         "vc2-1c-2gb",
+		Status:       "active",
+		NodeQuantity: 1,
+		Tag:          "mytag",
+		Nodes: []Node{
+			{
+				ID:          "f2e11430-76e5-4dc6-a1c9-ef5682c21ddf",
+				DateCreated: "2021-07-07T23:27:08+00:00",
+				Label:       "my-label-48770703-44060e6384c45",
+				Status:      "active",
+			},
+		},
+	}
+
+	if !reflect.DeepEqual(response, expected) {
+		t.Errorf("Kubernetes.UpdateNodePool meta returned %+v, expected %+v", response, expected)
+	}
+
+	c, can := context.WithTimeout(ctx, 1*time.Microsecond)
+	defer can()
+	_, err = client.Kubernetes.UpdateNodePool(c, "1", "2", &update)
+	if err == nil {
+		t.Error("Kubernetes.UpdateNodePool returned nil")
+	}
+}
+
+func TestKubernetesHandler_DeleteNodePool(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc(fmt.Sprintf("%s/%s/node-pools/%s", vkePath, "1", "2"), func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
+	})
+
+	err := client.Kubernetes.DeleteNodePool(ctx, "1", "2")
+	if err != nil {
+		t.Errorf("Kubernetes.DeleteNodePool returned %+v", err)
+	}
+}
+
+func TestKubernetesHandler_DeleteNodePoolInstance(t *testing.T) {
+	setup()
+	defer teardown()
+	path := fmt.Sprintf("%s/%s/node-pools/%s/nodes/%s", vkePath, "1", "2", "3")
+	mux.HandleFunc(fmt.Sprintf(path), func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
+	})
+
+	err := client.Kubernetes.DeleteNodePoolInstance(ctx, "1", "2", "3")
+	if err != nil {
+		t.Errorf("Kubernetes.DeleteNodePoolInstance returned %+v", err)
+	}
+}
+
+func TestKubernetesHandler_RecycleNodePoolInstance(t *testing.T) {
+	setup()
+	defer teardown()
+	path := fmt.Sprintf("%s/%s/node-pools/%s/nodes/%s/recycle", vkePath, "1", "2", "3")
+	mux.HandleFunc(fmt.Sprintf(path), func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
+	})
+
+	err := client.Kubernetes.RecycleNodePoolInstance(ctx, "1", "2", "3")
+	if err != nil {
+		t.Errorf("Kubernetes.RecycleNodePoolInstance returned %+v", err)
+	}
+}
+
+func TestKubernetesHandler_GetKubeConfig(t *testing.T) {
+	setup()
+	defer teardown()
+	path := fmt.Sprintf("%s/%s/config", vkePath, "1")
+	mux.HandleFunc(fmt.Sprintf(path), func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"kube_config": "config="}`
+		fmt.Fprint(writer, response)
+	})
+
+	config, err := client.Kubernetes.GetKubeConfig(ctx, "1")
+	if err != nil {
+		t.Errorf("Kubernetes.GetKubeConfig returned %+v", err)
+	}
+
+	expected := &KubeConfig{KubeConfig: "config="}
+	if !reflect.DeepEqual(config, expected) {
+		t.Errorf("Kubernetes.GetKubeConfig  returned %+v, expected %+v", config, expected)
+	}
+
+	c, can := context.WithTimeout(ctx, 1*time.Microsecond)
+	defer can()
+	_, err = client.Kubernetes.GetKubeConfig(c, "1")
+	if err == nil {
+		t.Error("Kubernetes.GetKubeConfig returned nil")
+	}
+}
+
+func TestKubernetesHandler_GetVersions(t *testing.T) {
+	setup()
+	defer teardown()
+	path := "/v2/kubernetes/versions"
+	mux.HandleFunc(fmt.Sprintf(path), func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"versions": ["v1.20.0+1"]}`
+		fmt.Fprint(writer, response)
+	})
+
+	config, err := client.Kubernetes.GetVersions(ctx)
+	if err != nil {
+		t.Errorf("Kubernetes.GetVersions returned %+v", err)
+	}
+
+	expected := &Versions{Versions: []string{"v1.20.0+1"}}
+	if !reflect.DeepEqual(config, expected) {
+		t.Errorf("Kubernetes.GetVersions returned %+v, expected %+v", config, expected)
+	}
+
+	c, can := context.WithTimeout(ctx, 1*time.Microsecond)
+	defer can()
+	_, err = client.Kubernetes.GetVersions(c)
+	if err == nil {
+		t.Error("Kubernetes.GetVersions returned nil")
+	}
+}
diff --git a/listOptions.go b/listOptions.go
new file mode 100644
index 0000000..0b70ec5
--- /dev/null
+++ b/listOptions.go
@@ -0,0 +1,20 @@
+package govultr
+
+// ListOptions are the available query params
+type ListOptions struct {
+	// These query params are used for all list calls that support pagination
+	PerPage int    `url:"per_page,omitempty"`
+	Cursor  string `url:"cursor,omitempty"`
+
+	// These three query params are currently used for the list instance call
+	// These may be extended to other list calls
+	// https://www.vultr.com/api/#operation/list-instances
+	MainIP string `url:"main_ip,omitempty"`
+	Label  string `url:"label,omitempty"`
+	Tag    string `url:"tag,omitempty"`
+	Region string `url:"region,omitempty"`
+
+	// Query params that can be used on the list snapshots call
+	// https://www.vultr.com/api/#operation/list-snapshots
+	Description string `url:"description,omitempty"`
+}
diff --git a/load_balancer.go b/load_balancer.go
index b137c19..a7e1f87 100644
--- a/load_balancer.go
+++ b/load_balancer.go
@@ -2,35 +2,28 @@ package govultr
 
 import (
 	"context"
-	"encoding/json"
+	"fmt"
 	"net/http"
-	"net/url"
-	"strconv"
+
+	"github.com/google/go-querystring/query"
 )
 
+const lbPath = "/v2/load-balancers"
+
 // LoadBalancerService is the interface to interact with the server endpoints on the Vultr API
-// Link: https://www.vultr.com/api/#loadbalancer
+// Link : https://www.vultr.com/api/#tag/load-balancer
 type LoadBalancerService interface {
-	List(ctx context.Context) ([]LoadBalancers, error)
-	Delete(ctx context.Context, ID int) error
-	SetLabel(ctx context.Context, ID int, label string) error
-	AttachedInstances(ctx context.Context, ID int) (*InstanceList, error)
-	AttachInstance(ctx context.Context, ID, backendNode int) error
-	DetachInstance(ctx context.Context, ID, backendNode int) error
-	GetHealthCheck(ctx context.Context, ID int) (*HealthCheck, error)
-	SetHealthCheck(ctx context.Context, ID int, healthConfig *HealthCheck) error
-	GetGenericInfo(ctx context.Context, ID int) (*GenericInfo, error)
-	ListForwardingRules(ctx context.Context, ID int) (*ForwardingRules, error)
-	DeleteForwardingRule(ctx context.Context, ID int, RuleID string) error
-	CreateForwardingRule(ctx context.Context, ID int, rule *ForwardingRule) (*ForwardingRule, error)
-	GetFullConfig(ctx context.Context, ID int) (*LBConfig, error)
-	HasSSL(ctx context.Context, ID int) (*struct {
-		SSLInfo bool `json:"has_ssl"`
-	}, error)
-	Create(ctx context.Context, region int, label string, genericInfo *GenericInfo, healthCheck *HealthCheck, rules []ForwardingRule, ssl *SSL, instances *InstanceList) (*LoadBalancers, error)
-	UpdateGenericInfo(ctx context.Context, ID int, label string, genericInfo *GenericInfo) error
-	AddSSL(ctx context.Context, ID int, ssl *SSL) error
-	RemoveSSL(ctx context.Context, ID int) error
+	Create(ctx context.Context, createReq *LoadBalancerReq) (*LoadBalancer, error)
+	Get(ctx context.Context, ID string) (*LoadBalancer, error)
+	Update(ctx context.Context, ID string, updateReq *LoadBalancerReq) error
+	Delete(ctx context.Context, ID string) error
+	List(ctx context.Context, options *ListOptions) ([]LoadBalancer, *Meta, error)
+	CreateForwardingRule(ctx context.Context, ID string, rule *ForwardingRule) (*ForwardingRule, error)
+	GetForwardingRule(ctx context.Context, ID string, ruleID string) (*ForwardingRule, error)
+	DeleteForwardingRule(ctx context.Context, ID string, RuleID string) error
+	ListForwardingRules(ctx context.Context, ID string, options *ListOptions) ([]ForwardingRule, *Meta, error)
+	ListFirewallRules(ctx context.Context, ID string, options *ListOptions) ([]LBFirewallRule, *Meta, error)
+	GetFirewallRule(ctx context.Context, ID string, ruleID string) (*LBFirewallRule, error)
 }
 
 // LoadBalancerHandler handles interaction with the server methods for the Vultr API
@@ -38,21 +31,42 @@ type LoadBalancerHandler struct {
 	client *Client
 }
 
-// LoadBalancers represent a basic structure of a load balancer
-type LoadBalancers struct {
-	ID          int    `json:"SUBID,omitempty"`
-	DateCreated string `json:"date_created,omitempty"`
-	RegionID    int    `json:"DCID,omitempty"`
-	Location    string `json:"location,omitempty"`
-	Label       string `json:"label,omitempty"`
-	Status      string `json:"status,omitempty"`
-	IPV4        string `json:"ipv4,omitempty"`
-	IPV6        string `json:"ipv6,omitempty"`
+// LoadBalancer represent the structure of a load balancer
+type LoadBalancer struct {
+	ID              string           `json:"id,omitempty"`
+	DateCreated     string           `json:"date_created,omitempty"`
+	Region          string           `json:"region,omitempty"`
+	Label           string           `json:"label,omitempty"`
+	Status          string           `json:"status,omitempty"`
+	IPV4            string           `json:"ipv4,omitempty"`
+	IPV6            string           `json:"ipv6,omitempty"`
+	Instances       []string         `json:"instances,omitempty"`
+	HealthCheck     *HealthCheck     `json:"health_check,omitempty"`
+	GenericInfo     *GenericInfo     `json:"generic_info,omitempty"`
+	SSLInfo         *bool            `json:"has_ssl,omitempty"`
+	ForwardingRules []ForwardingRule `json:"forwarding_rules,omitempty"`
+	FirewallRules   []LBFirewallRule `json:"firewall_rules,omitempty"`
+}
+
+// LoadBalancerReq gives options for creating or updating a load balancer
+type LoadBalancerReq struct {
+	Region             string           `json:"region,omitempty"`
+	Label              string           `json:"label,omitempty"`
+	Instances          []string         `json:"instances"`
+	HealthCheck        *HealthCheck     `json:"health_check,omitempty"`
+	StickySessions     *StickySessions  `json:"sticky_session,omitempty"`
+	ForwardingRules    []ForwardingRule `json:"forwarding_rules,omitempty"`
+	SSL                *SSL             `json:"ssl,omitempty"`
+	SSLRedirect        *bool            `json:"ssl_redirect,omitempty"`
+	ProxyProtocol      *bool            `json:"proxy_protocol,omitempty"`
+	BalancingAlgorithm string           `json:"balancing_algorithm,omitempty"`
+	FirewallRules      []LBFirewallRule `json:"firewall_rules"`
+	PrivateNetwork     *string          `json:"private_network,omitempty"`
 }
 
-// InstanceList represents instances that attached to your load balancer
+// InstanceList represents instances that are attached to your load balancer
 type InstanceList struct {
-	InstanceList []int `json:"instance_list"`
+	InstanceList []string
 }
 
 // HealthCheck represents your health check configuration for your load balancer.
@@ -68,568 +82,251 @@ type HealthCheck struct {
 
 // GenericInfo represents generic configuration of your load balancer
 type GenericInfo struct {
-	BalancingAlgorithm string          `json:"balancing_algorithm"`
+	BalancingAlgorithm string          `json:"balancing_algorithm,omitempty"`
 	SSLRedirect        *bool           `json:"ssl_redirect,omitempty"`
-	StickySessions     *StickySessions `json:"sticky_sessions"`
-	ProxyProtocol      *bool           `json:"proxy_protocol"`
+	StickySessions     *StickySessions `json:"sticky_sessions,omitempty"`
+	ProxyProtocol      *bool           `json:"proxy_protocol,omitempty"`
+	PrivateNetwork     string          `json:"private_network,omitempty"`
 }
 
-// CookieName represents cookie for your load balancer
+// StickySessions represents cookie for your load balancer
 type StickySessions struct {
-	StickySessionsEnabled string `json:"sticky_sessions"`
-	CookieName            string `json:"cookie_name"`
+	CookieName string `json:"cookie_name,omitempty"`
 }
 
 // ForwardingRules represent a list of forwarding rules
 type ForwardingRules struct {
-	ForwardRuleList []ForwardingRule `json:"forward_rule_list"`
+	ForwardRuleList []ForwardingRule `json:"forwarding_rules,omitempty"`
 }
 
 // ForwardingRule represent a single forwarding rule
 type ForwardingRule struct {
-	RuleID           string `json:"RULEID,omitempty"`
+	RuleID           string `json:"id,omitempty"`
 	FrontendProtocol string `json:"frontend_protocol,omitempty"`
 	FrontendPort     int    `json:"frontend_port,omitempty"`
 	BackendProtocol  string `json:"backend_protocol,omitempty"`
 	BackendPort      int    `json:"backend_port,omitempty"`
 }
 
-// LBConfig represents the full config with all components of a load balancer
-type LBConfig struct {
-	GenericInfo `json:"generic_info"`
-	HealthCheck `json:"health_checks_info"`
-	SSLInfo     bool `json:"has_ssl"`
-	ForwardingRules
-	InstanceList
+// LBFirewallRule represent a single firewall rule
+type LBFirewallRule struct {
+	RuleID string `json:"id,omitempty"`
+	Port   int    `json:"port,omitempty"`
+	IPType string `json:"ip_type,omitempty"`
+	Source string `json:"source,omitempty"`
 }
 
 // SSL represents valid SSL config
 type SSL struct {
-	PrivateKey  string `json:"ssl_private_key"`
-	Certificate string `json:"ssl_certificate"`
+	PrivateKey  string `json:"private_key,omitempty"`
+	Certificate string `json:"certificate,omitempty"`
 	Chain       string `json:"chain,omitempty"`
 }
 
-// List all load balancer subscriptions on the current account.
-func (l *LoadBalancerHandler) List(ctx context.Context) ([]LoadBalancers, error) {
-	uri := "/v1/loadbalancer/list"
-
-	req, err := l.client.NewRequest(ctx, http.MethodGet, uri, nil)
-	if err != nil {
-		return nil, err
-	}
-
-	var lbList []LoadBalancers
-
-	err = l.client.DoWithContext(ctx, req, &lbList)
-	if err != nil {
-		return nil, err
-	}
-
-	return lbList, nil
+type lbsBase struct {
+	LoadBalancers []LoadBalancer `json:"load_balancers"`
+	Meta          *Meta          `json:"meta"`
 }
 
-// Delete a load balancer subscription.
-func (l *LoadBalancerHandler) Delete(ctx context.Context, ID int) error {
-	uri := "/v1/loadbalancer/destroy"
-
-	values := url.Values{
-		"SUBID": {strconv.Itoa(ID)},
-	}
-
-	req, err := l.client.NewRequest(ctx, http.MethodPost, uri, values)
-	if err != nil {
-		return err
-	}
-
-	err = l.client.DoWithContext(ctx, req, nil)
-	if err != nil {
-		return err
-	}
-
-	return nil
+type lbBase struct {
+	LoadBalancer *LoadBalancer `json:"load_balancer"`
 }
 
-// SetLabel sets the label for your load balancer subscription.
-func (l *LoadBalancerHandler) SetLabel(ctx context.Context, ID int, label string) error {
-	uri := "/v1/loadbalancer/label_set"
-
-	values := url.Values{
-		"SUBID": {strconv.Itoa(ID)},
-		"label": {label},
-	}
-
-	req, err := l.client.NewRequest(ctx, http.MethodPost, uri, values)
-	if err != nil {
-		return err
-	}
-
-	err = l.client.DoWithContext(ctx, req, nil)
-	if err != nil {
-		return nil
-	}
-
-	return nil
+type lbRulesBase struct {
+	ForwardingRules []ForwardingRule `json:"forwarding_rules"`
+	Meta            *Meta            `json:"meta"`
 }
 
-// AttachedInstances lists the instances that are currently attached to a load balancer subscription.
-func (l *LoadBalancerHandler) AttachedInstances(ctx context.Context, ID int) (*InstanceList, error) {
-	uri := "/v1/loadbalancer/instance_list"
-
-	req, err := l.client.NewRequest(ctx, http.MethodGet, uri, nil)
-	if err != nil {
-		return nil, err
-	}
-
-	q := req.URL.Query()
-	q.Add("SUBID", strconv.Itoa(ID))
-	req.URL.RawQuery = q.Encode()
-
-	var instances InstanceList
-
-	err = l.client.DoWithContext(ctx, req, &instances)
-	if err != nil {
-		return nil, err
-	}
-
-	return &instances, nil
+type lbRuleBase struct {
+	ForwardingRule *ForwardingRule `json:"forwarding_rule"`
 }
 
-// AttachInstance attaches a backend node to your load balancer subscription
-func (l *LoadBalancerHandler) AttachInstance(ctx context.Context, ID, backendNode int) error {
-	uri := "/v1/loadbalancer/instance_attach"
-
-	values := url.Values{
-		"SUBID":       {strconv.Itoa(ID)},
-		"backendNode": {strconv.Itoa(backendNode)},
-	}
-
-	req, err := l.client.NewRequest(ctx, http.MethodPost, uri, values)
-	if err != nil {
-		return err
-	}
-
-	err = l.client.DoWithContext(ctx, req, nil)
-	if err != nil {
-		return err
-	}
-
-	return nil
+type lbFWRulesBase struct {
+	FirewallRules []LBFirewallRule `json:"firewall_rules"`
+	Meta          *Meta            `json:"meta"`
 }
 
-// DetachInstance detaches a backend node to your load balancer subscription
-func (l *LoadBalancerHandler) DetachInstance(ctx context.Context, ID, backendNode int) error {
-	uri := "/v1/loadbalancer/instance_detach"
-
-	values := url.Values{
-		"SUBID":       {strconv.Itoa(ID)},
-		"backendNode": {strconv.Itoa(backendNode)},
-	}
+type lbFWRuleBase struct {
+	FirewallRule *LBFirewallRule `json:"firewall_rule"`
+}
 
-	req, err := l.client.NewRequest(ctx, http.MethodPost, uri, values)
+// Create a load balancer
+func (l *LoadBalancerHandler) Create(ctx context.Context, createReq *LoadBalancerReq) (*LoadBalancer, error) {
+	req, err := l.client.NewRequest(ctx, http.MethodPost, lbPath, createReq)
 	if err != nil {
-		return err
+		return nil, err
 	}
 
-	err = l.client.DoWithContext(ctx, req, nil)
-	if err != nil {
-		return err
+	var lb = new(lbBase)
+	if err = l.client.DoWithContext(ctx, req, &lb); err != nil {
+		return nil, err
 	}
 
-	return nil
+	return lb.LoadBalancer, nil
 }
 
-// GetHealthCheck retrieves the health check configuration for your load balancer subscription.
-func (l *LoadBalancerHandler) GetHealthCheck(ctx context.Context, ID int) (*HealthCheck, error) {
-	uri := "/v1/loadbalancer/health_check_info"
-
+// Get a load balancer
+func (l *LoadBalancerHandler) Get(ctx context.Context, ID string) (*LoadBalancer, error) {
+	uri := fmt.Sprintf("%s/%s", lbPath, ID)
 	req, err := l.client.NewRequest(ctx, http.MethodGet, uri, nil)
 	if err != nil {
 		return nil, err
 	}
 
-	q := req.URL.Query()
-	q.Add("SUBID", strconv.Itoa(ID))
-	req.URL.RawQuery = q.Encode()
-
-	var healthCheck HealthCheck
-	err = l.client.DoWithContext(ctx, req, &healthCheck)
-	if err != nil {
+	var lb = new(lbBase)
+	if err = l.client.DoWithContext(ctx, req, lb); err != nil {
 		return nil, err
 	}
 
-	return &healthCheck, nil
+	return lb.LoadBalancer, nil
 }
 
-// SetHealthCheck sets your health check configuration for your load balancer
-func (l *LoadBalancerHandler) SetHealthCheck(ctx context.Context, ID int, healthConfig *HealthCheck) error {
-	uri := "/v1/loadbalancer/health_check_update"
-
-	values := url.Values{
-		"SUBID": {strconv.Itoa(ID)},
-	}
-
-	if healthConfig != nil {
-		if healthConfig.Protocol != "" {
-			values.Add("protocol", healthConfig.Protocol)
-		}
-
-		if healthConfig.Port != 0 {
-			values.Add("port", strconv.Itoa(healthConfig.Port))
-		}
-
-		if healthConfig.CheckInterval != 0 {
-			values.Add("check_interval", strconv.Itoa(healthConfig.CheckInterval))
-		}
-
-		if healthConfig.ResponseTimeout != 0 {
-			values.Add("response_timeout", strconv.Itoa(healthConfig.ResponseTimeout))
-		}
-
-		if healthConfig.UnhealthyThreshold != 0 {
-			values.Add("unhealthy_threshold", strconv.Itoa(healthConfig.UnhealthyThreshold))
-		}
-
-		if healthConfig.HealthyThreshold != 0 {
-			values.Add("healthy_threshold", strconv.Itoa(healthConfig.HealthyThreshold))
-		}
-
-		if healthConfig.Path != "" {
-			values.Add("path", healthConfig.Path)
-		}
-	}
-
-	req, err := l.client.NewRequest(ctx, http.MethodPost, uri, values)
+// Update updates your your load balancer
+func (l *LoadBalancerHandler) Update(ctx context.Context, ID string, updateReq *LoadBalancerReq) error {
+	uri := fmt.Sprintf("%s/%s", lbPath, ID)
+	req, err := l.client.NewRequest(ctx, http.MethodPatch, uri, updateReq)
 	if err != nil {
 		return err
 	}
 
-	err = l.client.DoWithContext(ctx, req, nil)
-	if err != nil {
-		return err
-	}
-
-	return nil
+	return l.client.DoWithContext(ctx, req, nil)
 }
 
-// GetGenericInfo is the generic configuration of a load balancer subscription
-func (l *LoadBalancerHandler) GetGenericInfo(ctx context.Context, ID int) (*GenericInfo, error) {
-	uri := "/v1/loadbalancer/generic_info"
-
-	req, err := l.client.NewRequest(ctx, http.MethodGet, uri, nil)
-	if err != nil {
-		return nil, err
-	}
-
-	q := req.URL.Query()
-	q.Add("SUBID", strconv.Itoa(ID))
-	req.URL.RawQuery = q.Encode()
-
-	var info GenericInfo
-
-	err = l.client.DoWithContext(ctx, req, &info)
+// Delete a load balancer subscription.
+func (l *LoadBalancerHandler) Delete(ctx context.Context, ID string) error {
+	uri := fmt.Sprintf("%s/%s", lbPath, ID)
+	req, err := l.client.NewRequest(ctx, http.MethodDelete, uri, nil)
 	if err != nil {
-		return nil, err
+		return err
 	}
 
-	return &info, err
+	return l.client.DoWithContext(ctx, req, nil)
 }
 
-// ListForwardingRules lists all forwarding rules for a load balancer subscription
-func (l *LoadBalancerHandler) ListForwardingRules(ctx context.Context, ID int) (*ForwardingRules, error) {
-	uri := "v1/loadbalancer/forward_rule_list"
-
-	req, err := l.client.NewRequest(ctx, http.MethodGet, uri, nil)
+// List all load balancer subscriptions on the current account.
+func (l *LoadBalancerHandler) List(ctx context.Context, options *ListOptions) ([]LoadBalancer, *Meta, error) {
+	req, err := l.client.NewRequest(ctx, http.MethodGet, lbPath, nil)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	q := req.URL.Query()
-	q.Add("SUBID", strconv.Itoa(ID))
-	req.URL.RawQuery = q.Encode()
-
-	var frList ForwardingRules
-
-	err = l.client.DoWithContext(ctx, req, &frList)
+	newValues, err := query.Values(options)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	return &frList, nil
-}
-
-// DeleteForwardingRule removes a forwarding rule from a load balancer subscription
-func (l *LoadBalancerHandler) DeleteForwardingRule(ctx context.Context, ID int, RuleID string) error {
-	uri := "/v1/loadbalancer/forward_rule_delete"
-
-	values := url.Values{
-		"SUBID":  {strconv.Itoa(ID)},
-		"RULEID": {RuleID},
-	}
-
-	req, err := l.client.NewRequest(ctx, http.MethodPost, uri, values)
-	if err != nil {
-		return err
-	}
+	req.URL.RawQuery = newValues.Encode()
 
-	err = l.client.DoWithContext(ctx, req, nil)
-	if err != nil {
-		return err
+	lbs := new(lbsBase)
+	if err = l.client.DoWithContext(ctx, req, &lbs); err != nil {
+		return nil, nil, err
 	}
 
-	return nil
+	return lbs.LoadBalancers, lbs.Meta, nil
 }
 
 // CreateForwardingRule will create a new forwarding rule for your load balancer subscription.
 // Note the RuleID will be returned in the ForwardingRule struct
-func (l *LoadBalancerHandler) CreateForwardingRule(ctx context.Context, ID int, rule *ForwardingRule) (*ForwardingRule, error) {
-	uri := "/v1/loadbalancer/forward_rule_create"
-
-	values := url.Values{
-		"SUBID":             {strconv.Itoa(ID)},
-		"frontend_protocol": {rule.FrontendProtocol},
-		"backend_protocol":  {rule.BackendProtocol},
-		"frontend_port":     {strconv.Itoa(rule.FrontendPort)},
-		"backend_port":      {strconv.Itoa(rule.BackendPort)},
-	}
-
-	req, err := l.client.NewRequest(ctx, http.MethodPost, uri, values)
+func (l *LoadBalancerHandler) CreateForwardingRule(ctx context.Context, ID string, rule *ForwardingRule) (*ForwardingRule, error) {
+	uri := fmt.Sprintf("%s/%s/forwarding-rules", lbPath, ID)
+	req, err := l.client.NewRequest(ctx, http.MethodPost, uri, rule)
 	if err != nil {
 		return nil, err
 	}
 
-	var fr ForwardingRule
-	err = l.client.DoWithContext(ctx, req, &fr)
-	if err != nil {
+	fwRule := new(lbRuleBase)
+	if err = l.client.DoWithContext(ctx, req, fwRule); err != nil {
 		return nil, err
 	}
 
-	return &fr, nil
+	return fwRule.ForwardingRule, nil
 }
 
-// GetFullConfig retrieves the entire configuration of a load balancer subscription.
-func (l *LoadBalancerHandler) GetFullConfig(ctx context.Context, ID int) (*LBConfig, error) {
-	uri := "/v1/loadbalancer/conf_info"
-
+// GetForwardingRule will get a forwarding rule from your load balancer subscription.
+func (l *LoadBalancerHandler) GetForwardingRule(ctx context.Context, ID string, ruleID string) (*ForwardingRule, error) {
+	uri := fmt.Sprintf("%s/%s/forwarding-rules/%s", lbPath, ID, ruleID)
 	req, err := l.client.NewRequest(ctx, http.MethodGet, uri, nil)
 	if err != nil {
 		return nil, err
 	}
 
-	q := req.URL.Query()
-	q.Add("SUBID", strconv.Itoa(ID))
-	req.URL.RawQuery = q.Encode()
-
-	var lbConfig LBConfig
-	err = l.client.DoWithContext(ctx, req, &lbConfig)
-	if err != nil {
+	fwRule := new(lbRuleBase)
+	if err = l.client.DoWithContext(ctx, req, fwRule); err != nil {
 		return nil, err
 	}
 
-	return &lbConfig, nil
+	return fwRule.ForwardingRule, nil
 }
 
-// HasSSL retrieves whether or not your load balancer subscription has an SSL cert attached.
-func (l *LoadBalancerHandler) HasSSL(ctx context.Context, ID int) (*struct {
-	SSLInfo bool `json:"has_ssl"`
-}, error) {
-	uri := "/v1/loadbalancer/ssl_info"
-
+// ListForwardingRules lists all forwarding rules for a load balancer subscription
+func (l *LoadBalancerHandler) ListForwardingRules(ctx context.Context, ID string, options *ListOptions) ([]ForwardingRule, *Meta, error) {
+	uri := fmt.Sprintf("%s/%s/forwarding-rules", lbPath, ID)
 	req, err := l.client.NewRequest(ctx, http.MethodGet, uri, nil)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	q := req.URL.Query()
-	q.Add("SUBID", strconv.Itoa(ID))
-	req.URL.RawQuery = q.Encode()
-
-	ssl := &struct {
-		SSLInfo bool `json:"has_ssl"`
-	}{}
-	err = l.client.DoWithContext(ctx, req, ssl)
+	newValues, err := query.Values(options)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	return ssl, nil
-}
-
-// Create a load balancer
-func (l *LoadBalancerHandler) Create(ctx context.Context, region int, label string, genericInfo *GenericInfo, healthCheck *HealthCheck, rules []ForwardingRule, ssl *SSL, instances *InstanceList) (*LoadBalancers, error) {
-	uri := "/v1/loadbalancer/create"
+	req.URL.RawQuery = newValues.Encode()
 
-	values := url.Values{
-		"DCID": {strconv.Itoa(region)},
+	fwRules := new(lbRulesBase)
+	if err = l.client.DoWithContext(ctx, req, &fwRules); err != nil {
+		return nil, nil, err
 	}
 
-	if label != "" {
-		values.Add("label", label)
-	}
-
-	// Check generic info struct
-	if genericInfo != nil {
-		if genericInfo.SSLRedirect != nil {
-			if strconv.FormatBool(*genericInfo.SSLRedirect) == "true" {
-				values.Add("config_ssl_redirect", "true")
-			}
-		}
-
-		if genericInfo.BalancingAlgorithm != "" {
-			values.Add("balancing_algorithm", genericInfo.BalancingAlgorithm)
-		}
-
-		if genericInfo.StickySessions != nil {
-			if genericInfo.StickySessions.StickySessionsEnabled == "on" {
-				values.Add("sticky_sessions", genericInfo.StickySessions.StickySessionsEnabled)
-				values.Add("cookie_name", genericInfo.StickySessions.CookieName)
-			}
-		}
-
-		if genericInfo.ProxyProtocol != nil {
-			value := "off"
-			if strconv.FormatBool(*genericInfo.ProxyProtocol) == "true" {
-				value = "on"
-			}
-			values.Add("proxy_protocol", value)
-		}
-	}
-
-	if healthCheck != nil {
-		t, _ := json.Marshal(healthCheck)
-		values.Add("health_check", string(t))
-	}
-
-	if rules != nil {
-		t, e := json.Marshal(rules)
-		if e != nil {
-			panic(e)
-		}
-		values.Add("forwarding_rules", string(t))
-	}
-
-	if ssl != nil {
-		values.Add("ssl_private_key", ssl.PrivateKey)
-		values.Add("ssl_certificate", ssl.Certificate)
-
-		if ssl.Chain != "" {
-			values.Add("ssl_chain", ssl.Chain)
-		}
-	}
-
-	if instances != nil {
-		t, e := json.Marshal(instances.InstanceList)
-		if e != nil {
-			panic(e)
-		}
-		values.Add("attached_nodes", string(t))
-	}
-
-	req, err := l.client.NewRequest(ctx, http.MethodPost, uri, values)
-	if err != nil {
-		return nil, err
-	}
+	return fwRules.ForwardingRules, fwRules.Meta, nil
+}
 
-	var lb LoadBalancers
-	err = l.client.DoWithContext(ctx, req, &lb)
+// DeleteForwardingRule removes a forwarding rule from a load balancer subscription
+func (l *LoadBalancerHandler) DeleteForwardingRule(ctx context.Context, ID string, RuleID string) error {
+	uri := fmt.Sprintf("%s/%s/forwarding-rules/%s", lbPath, ID, RuleID)
+	req, err := l.client.NewRequest(ctx, http.MethodDelete, uri, nil)
 	if err != nil {
-		return nil, err
+		return err
 	}
 
-	return &lb, nil
+	return l.client.DoWithContext(ctx, req, nil)
 }
 
-// UpdateGenericInfo will update portions of your generic info section
-func (l *LoadBalancerHandler) UpdateGenericInfo(ctx context.Context, ID int, label string, genericInfo *GenericInfo) error {
-	uri := "/v1/loadbalancer/generic_update"
-
-	values := url.Values{
-		"SUBID": {strconv.Itoa(ID)},
-	}
-
-	if label != "" {
-		values.Add("label", label)
-	}
-
-	if genericInfo != nil {
-		if genericInfo.StickySessions != nil {
-			values.Add("sticky_sessions", genericInfo.StickySessions.StickySessionsEnabled)
-			values.Add("cookie_name", genericInfo.StickySessions.CookieName)
-		}
-
-		if genericInfo.SSLRedirect != nil {
-			values.Add("ssl_redirect", strconv.FormatBool(*genericInfo.SSLRedirect))
-		}
-
-		if genericInfo.BalancingAlgorithm != "" {
-			values.Add("balancing_algorithm", genericInfo.BalancingAlgorithm)
-		}
-
-		if genericInfo.ProxyProtocol != nil {
-			value := "off"
-			if strconv.FormatBool(*genericInfo.ProxyProtocol) == "true" {
-				value = "on"
-			}
-			values.Add("proxy_protocol", value)
-		}
-	}
-
-	req, err := l.client.NewRequest(ctx, http.MethodPost, uri, values)
+// GetFirewallRule will get a firewall rule from your load balancer subscription.
+func (l *LoadBalancerHandler) GetFirewallRule(ctx context.Context, ID string, ruleID string) (*LBFirewallRule, error) {
+	uri := fmt.Sprintf("%s/%s/firewall-rules/%s", lbPath, ID, ruleID)
+	req, err := l.client.NewRequest(ctx, http.MethodGet, uri, nil)
 	if err != nil {
-		return err
+		return nil, err
 	}
 
-	err = l.client.DoWithContext(ctx, req, nil)
-	if err != nil {
-		return err
+	fwRule := new(lbFWRuleBase)
+	if err = l.client.DoWithContext(ctx, req, fwRule); err != nil {
+		return nil, err
 	}
 
-	return nil
+	return fwRule.FirewallRule, nil
 }
 
-// AddSSL will attach an SSL certificate to a given load balancer
-func (l *LoadBalancerHandler) AddSSL(ctx context.Context, ID int, ssl *SSL) error {
-	uri := "/v1/loadbalancer/ssl_add"
-
-	values := url.Values{
-		"SUBID":           {strconv.Itoa(ID)},
-		"ssl_private_key": {ssl.PrivateKey},
-		"ssl_certificate": {ssl.Certificate},
-	}
-
-	if ssl.Chain != "" {
-		values.Add("ssl_chain", ssl.Chain)
-	}
-
-	req, err := l.client.NewRequest(ctx, http.MethodPost, uri, values)
+// ListFirewallRules lists all firewall rules for a load balancer subscription
+func (l *LoadBalancerHandler) ListFirewallRules(ctx context.Context, ID string, options *ListOptions) ([]LBFirewallRule, *Meta, error) {
+	uri := fmt.Sprintf("%s/%s/firewall-rules", lbPath, ID)
+	req, err := l.client.NewRequest(ctx, http.MethodGet, uri, nil)
 	if err != nil {
-		return err
+		return nil, nil, err
 	}
 
-	err = l.client.DoWithContext(ctx, req, nil)
+	newValues, err := query.Values(options)
 	if err != nil {
-		return err
+		return nil, nil, err
 	}
 
-	return nil
-}
-
-// RemoveSSL will remove an SSL certificate from a load balancer
-func (l *LoadBalancerHandler) RemoveSSL(ctx context.Context, ID int) error {
-	uri := "/v1/loadbalancer/ssl_remove"
+	req.URL.RawQuery = newValues.Encode()
 
-	values := url.Values{
-		"SUBID": {strconv.Itoa(ID)},
+	fwRules := new(lbFWRulesBase)
+	if err = l.client.DoWithContext(ctx, req, &fwRules); err != nil {
+		return nil, nil, err
 	}
 
-	req, err := l.client.NewRequest(ctx, http.MethodPost, uri, values)
-	if err != nil {
-		return err
-	}
-
-	err = l.client.DoWithContext(ctx, req, nil)
-	if err != nil {
-		return err
-	}
-	return nil
+	return fwRules.FirewallRules, fwRules.Meta, nil
 }
diff --git a/load_balancer_test.go b/load_balancer_test.go
index eba7e89..ad8bf3d 100644
--- a/load_balancer_test.go
+++ b/load_balancer_test.go
@@ -11,241 +11,341 @@ func TestLoadBalancerHandler_List(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/loadbalancer/list", func(writer http.ResponseWriter, request *http.Request) {
-		response := `[{"SUBID":1317575,"date_created":"2020-01-07 17:24:23","location":"New Jersey","label":"test","status":"active"}]`
+	mux.HandleFunc(lbPath, func(writer http.ResponseWriter, request *http.Request) {
+		response := `
+		{
+			"load_balancers" : [
+				{
+					"id": "1317575",
+					"date_created": "2020-01-07 17:24:23",
+					"region": "ewr",
+					"label": "my label",
+					"status": "active",
+					"ipv4": "123.123.123.123",
+					"ipv6": "2001:DB8:1000::100",
+					"generic_info": {
+						"balancing_algorithm": "roundrobin",
+						"ssl_redirect": false,
+						"proxy_protocol": false,
+						"private_network": "8d5bdbdb-3324-4d0c-b303-03e1315e1c02",
+						"sticky_sessions": {
+							"cookie_name": "my-cookie"
+						}
+					},
+					"health_check": {
+						"protocol": "http",
+						"port": 80,
+						"path": "/",
+						"check_interval": 15,
+						"response_timeout": 5,
+						"unhealthy_threshold": 5,
+						"healthy_threshold": 5
+					},
+					"has_ssl": false,
+					"forwarding_rules": [
+						{
+							"id": "abcd12345",
+							"frontend_protocol": "http",
+							"frontend_port": 80,
+							"backend_protocol": "http",
+							"backend_port": 80
+						}
+					],
+					"firewall_rules": [
+						{
+							"id": "abcd12345",
+							"port": 80,
+							"source": "0.0.0.0/0",
+							"ip_type": "v4"
+						}
+					],					
+					"instances": [
+						"12345"
+					]
+				}
+			],
+			"meta": {
+				"total":8,
+				"links": {
+					"next":"",
+					"prev":""
+				}
+			}
+		}
+		`
 		fmt.Fprintf(writer, response)
 	})
 
-	list, err := client.LoadBalancer.List(ctx)
+	list, meta, err := client.LoadBalancer.List(ctx, nil)
 
 	if err != nil {
 		t.Errorf("LoadBalancer.List returned %+v", err)
 	}
 
-	expected := []LoadBalancers{
+	expected := []LoadBalancer{
 		{
-			ID:          1317575,
+			ID:          "1317575",
 			DateCreated: "2020-01-07 17:24:23",
-			Location:    "New Jersey",
-			Label:       "test",
+			Label:       "my label",
 			Status:      "active",
-			RegionID:    0,
-			IPV6:        "",
-			IPV4:        "",
+			Region:      "ewr",
+			IPV6:        "2001:DB8:1000::100",
+			IPV4:        "123.123.123.123",
+			SSLInfo:     BoolToBoolPtr(false),
+			ForwardingRules: []ForwardingRule{
+				{
+					RuleID:           "abcd12345",
+					FrontendProtocol: "http",
+					FrontendPort:     80,
+					BackendProtocol:  "http",
+					BackendPort:      80,
+				},
+			},
+			GenericInfo: &GenericInfo{
+				BalancingAlgorithm: "roundrobin",
+				SSLRedirect:        BoolToBoolPtr(false),
+				ProxyProtocol:      BoolToBoolPtr(false),
+				PrivateNetwork:     "8d5bdbdb-3324-4d0c-b303-03e1315e1c02",
+				StickySessions: &StickySessions{
+					CookieName: "my-cookie",
+				},
+			},
+			HealthCheck: &HealthCheck{
+				Protocol:           "http",
+				Port:               80,
+				Path:               "/",
+				CheckInterval:      15,
+				ResponseTimeout:    5,
+				UnhealthyThreshold: 5,
+				HealthyThreshold:   5,
+			},
+			Instances: []string{"12345"},
+			FirewallRules: []LBFirewallRule{
+				{
+					RuleID: "abcd12345",
+					Port:   80,
+					Source: "0.0.0.0/0",
+					IPType: "v4",
+				},
+			},
 		},
 	}
 
-	if !reflect.DeepEqual(list, expected) {
-		t.Errorf("LoadBalancer.List returned %+v, expected %+v", list, expected)
-	}
-}
-
-func TestLoadBalancerHandler_Delete(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/loadbalancer/destroy", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.LoadBalancer.Delete(ctx, 12345)
-
-	if err != nil {
-		t.Errorf("LoadBalancer.Delete returned %+v", err)
-	}
-}
-
-func TestLoadBalancerHandler_SetLabel(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/loadbalancer/label_set", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.LoadBalancer.SetLabel(ctx, 12345, "label")
-
-	if err != nil {
-		t.Errorf("LoadBalancer.SetLabel returned %+v", err)
+	expectedMeta := &Meta{
+		Total: 8,
+		Links: &Links{},
 	}
-}
-
-func TestLoadBalancerHandler_AttachedInstances(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/loadbalancer/instance_list", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"instance_list": [1234, 2341]}`
-		fmt.Fprintf(writer, response)
-	})
-
-	instanceList, err := client.LoadBalancer.AttachedInstances(ctx, 12345)
-
-	if err != nil {
-		t.Errorf("LoadBalancer.AttachedInstances returned %+v ", err)
-	}
-
-	expected := &InstanceList{InstanceList: []int{1234, 2341}}
-
-	if !reflect.DeepEqual(instanceList, expected) {
-		t.Errorf("LoadBalancer.AttachedInstances returned %+v, expected %+v", instanceList, expected)
-	}
-}
-
-func TestLoadBalancerHandler_AttachInstance(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/loadbalancer/instance_attach", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.LoadBalancer.AttachInstance(ctx, 12345, 45678)
-
-	if err != nil {
-		t.Errorf("LoadBalancer.AttachInstance returned %+v", err)
-	}
-}
 
-func TestLoadBalancerHandler_DetachInstance(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/loadbalancer/instance_detach", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.LoadBalancer.DetachInstance(ctx, 12345, 45678)
-
-	if err != nil {
-		t.Errorf("LoadBalancer.DetachInstance returned %+v", err)
-	}
-}
-
-func TestLoadBalancerHandler_GetHealthCheck(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/loadbalancer/health_check_info", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{ "protocol": "http","port": 81,"path": "/test","check_interval": 10,"response_timeout": 45,"unhealthy_threshold": 1,"healthy_threshold": 2}`
-		fmt.Fprintf(writer, response)
-	})
-
-	health, err := client.LoadBalancer.GetHealthCheck(ctx, 12345)
-
-	if err != nil {
-		t.Errorf("LoadBalancer.GetHealthCheck returned %+v ", err)
+	if !reflect.DeepEqual(list, expected) {
+		t.Errorf("LoadBalancer.List returned %+v, expected %+v", list, expected)
 	}
 
-	expected := &HealthCheck{
-		Protocol:           "http",
-		Port:               81,
-		Path:               "/test",
-		CheckInterval:      10,
-		ResponseTimeout:    45,
-		UnhealthyThreshold: 1,
-		HealthyThreshold:   2,
+	if !reflect.DeepEqual(meta, expectedMeta) {
+		t.Errorf("LoadBalancer.List returned %+v, expected %+v", meta, expectedMeta)
 	}
 
-	if !reflect.DeepEqual(health, expected) {
-		t.Errorf("LoadBalancer.GetHealthCheck returned %+v, expected %+v", health, expected)
-	}
 }
 
-func TestLoadBalancerHandler_SetHealthCheck(t *testing.T) {
+func TestLoadBalancerHandler_Delete(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/loadbalancer/health_check_update", func(writer http.ResponseWriter, request *http.Request) {
+	uri := fmt.Sprintf("%s/%d", lbPath, 1317575)
+	mux.HandleFunc(uri, func(writer http.ResponseWriter, request *http.Request) {
 		fmt.Fprint(writer)
 	})
 
-	health := &HealthCheck{
-		Protocol:           "HTTPS",
-		Port:               8080,
-		Path:               "/health",
-		CheckInterval:      4,
-		ResponseTimeout:    5,
-		UnhealthyThreshold: 3,
-		HealthyThreshold:   4,
-	}
-	err := client.LoadBalancer.SetHealthCheck(ctx, 12345, health)
-
-	if err != nil {
-		t.Errorf("LoadBalancer.SetHealthCheck returned %+v", err)
+	if err := client.LoadBalancer.Delete(ctx, "1317575"); err != nil {
+		t.Errorf("LoadBalancer.Delete returned %+v", err)
 	}
 }
 
-func TestLoadBalancerHandler_GetGenericInfo(t *testing.T) {
+func TestLoadBalancerHandler_Get(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/loadbalancer/generic_info", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"balancing_algorithm":"roundrobin","ssl_redirect":false,"proxy_protocol": true,"sticky_sessions":{"cookie_name":"test"}}`
+	uri := fmt.Sprintf("%s/%d", lbPath, 1317575)
+	mux.HandleFunc(uri, func(writer http.ResponseWriter, request *http.Request) {
+		response := `
+		{
+			"load_balancer" : {
+				"id": "1317575",
+				"date_created": "2020-01-07 17:24:23",
+				"region": "ewr",
+				"label": "my label",
+				"status": "active",
+				"ipv4": "123.123.123.123",
+				"ipv6": "2001:DB8:1000::100",
+				"generic_info": {
+					"balancing_algorithm": "roundrobin",
+					"ssl_redirect": false,
+					"proxy_protocol": false,
+					"private_network": "8d5bdbdb-3324-4d0c-b303-03e1315e1c02",
+					"sticky_sessions": {
+						"cookie_name": "my-cookie"
+					}
+				},
+				"health_check": {
+					"protocol": "http",
+					"port": 80,
+					"path": "/",
+					"check_interval": 15,
+					"response_timeout": 5,
+					"unhealthy_threshold": 5,
+					"healthy_threshold": 5
+				},
+				"has_ssl": false,
+				"forwarding_rules": [
+					{
+						"id": "abcd12345",
+						"frontend_protocol": "http",
+						"frontend_port": 80,
+						"backend_protocol": "http",
+						"backend_port": 80
+					}
+				],
+				"firewall_rules": [
+					{
+						"id": "abcd12345",
+						"port": 80,
+						"source": "0.0.0.0/0",
+						"ip_type": "v4"
+					}
+				], 				
+				"instances": [
+					"12345"
+				]
+			}
+		}
+		`
 		fmt.Fprintf(writer, response)
 	})
 
-	info, err := client.LoadBalancer.GetGenericInfo(ctx, 12345)
+	info, err := client.LoadBalancer.Get(ctx, "1317575")
 
 	if err != nil {
-		t.Errorf("LoadBalancer.GetGenericInfo returned %+v", err)
-	}
-
-	redirect := false
-	proxy := true
-	expected := &GenericInfo{
-		BalancingAlgorithm: "roundrobin",
-		SSLRedirect:        &redirect,
-		ProxyProtocol:      &proxy,
-		StickySessions: &StickySessions{
-			CookieName: "test",
+		t.Errorf("LoadBalancer.Get returned %+v", err)
+	}
+
+	expected := &LoadBalancer{
+		ID:          "1317575",
+		DateCreated: "2020-01-07 17:24:23",
+		Label:       "my label",
+		Status:      "active",
+		Region:      "ewr",
+		IPV6:        "2001:DB8:1000::100",
+		IPV4:        "123.123.123.123",
+		SSLInfo:     BoolToBoolPtr(false),
+		ForwardingRules: []ForwardingRule{
+			{
+				RuleID:           "abcd12345",
+				FrontendProtocol: "http",
+				FrontendPort:     80,
+				BackendProtocol:  "http",
+				BackendPort:      80,
+			},
+		},
+		GenericInfo: &GenericInfo{
+			BalancingAlgorithm: "roundrobin",
+			SSLRedirect:        BoolToBoolPtr(false),
+			ProxyProtocol:      BoolToBoolPtr(false),
+			PrivateNetwork:     "8d5bdbdb-3324-4d0c-b303-03e1315e1c02",
+			StickySessions: &StickySessions{
+				CookieName: "my-cookie",
+			},
+		},
+		HealthCheck: &HealthCheck{
+			Protocol:           "http",
+			Port:               80,
+			Path:               "/",
+			CheckInterval:      15,
+			ResponseTimeout:    5,
+			UnhealthyThreshold: 5,
+			HealthyThreshold:   5,
+		},
+		Instances: []string{"12345"},
+		FirewallRules: []LBFirewallRule{
+			{
+				RuleID: "abcd12345",
+				Port:   80,
+				Source: "0.0.0.0/0",
+				IPType: "v4",
+			},
 		},
 	}
 
 	if !reflect.DeepEqual(info, expected) {
-		t.Errorf("LoadBalancer.GetGenericInfo returned %+v, expected %+v", info, expected)
+		t.Errorf("LoadBalancer.Get returned %+v, expected %+v", info, expected)
 	}
 }
 
 func TestLoadBalancerHandler_ListForwardingRules(t *testing.T) {
 	setup()
 	defer teardown()
-
-	mux.HandleFunc("/v1/loadbalancer/forward_rule_list", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"forward_rule_list":[{"RULEID":"0690a322c25890bc","frontend_protocol":"http","frontend_port":80,"backend_protocol":"http","backend_port":80}]}`
+	uri := fmt.Sprintf("%s/%d/forwarding-rules", lbPath, 12345)
+	mux.HandleFunc(uri, func(writer http.ResponseWriter, request *http.Request) {
+		response := `{
+			"forwarding_rules":[
+				{
+					"id":"0690a322c25890bc",
+					"frontend_protocol":"http",
+					"frontend_port":80,
+					"backend_protocol":"http",
+					"backend_port":80
+				}
+			],
+			"meta": {
+				"total":8,
+				"links": {
+					"next":"",
+					"prev":""
+				}
+			}
+		}
+		`
 		fmt.Fprintf(writer, response)
 	})
 
-	list, err := client.LoadBalancer.ListForwardingRules(ctx, 12345)
+	list, meta, err := client.LoadBalancer.ListForwardingRules(ctx, "12345", nil)
 
 	if err != nil {
 		t.Errorf("LoadBalancer.ListForwardingRules returned %+v", err)
 	}
 
-	expected := &ForwardingRules{ForwardRuleList: []ForwardingRule{{
-		RuleID:           "0690a322c25890bc",
-		FrontendProtocol: "http",
-		FrontendPort:     80,
-		BackendProtocol:  "http",
-		BackendPort:      80,
-	}}}
+	expected := []ForwardingRule{
+		{
+			RuleID:           "0690a322c25890bc",
+			FrontendProtocol: "http",
+			FrontendPort:     80,
+			BackendProtocol:  "http",
+			BackendPort:      80,
+		},
+	}
+
+	expectedMeta := &Meta{
+		Total: 8,
+		Links: &Links{},
+	}
 
 	if !reflect.DeepEqual(list, expected) {
 		t.Errorf("LoadBalancer.ListForwardingRules returned %+v, expected %+v", list, expected)
 	}
+
+	if !reflect.DeepEqual(meta, expectedMeta) {
+		t.Errorf("LoadBalancer.ListForwardingRules returned %+v, expected %+v", meta, expectedMeta)
+	}
 }
 
 func TestLoadBalancerHandler_DeleteForwardingRule(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/loadbalancer/forward_rule_delete", func(writer http.ResponseWriter, request *http.Request) {
+	uri := fmt.Sprintf("%s/%d/forwarding-rules/%s", lbPath, 12345, "abcde1234")
+	mux.HandleFunc(uri, func(writer http.ResponseWriter, request *http.Request) {
 		fmt.Fprint(writer)
 	})
 
-	err := client.LoadBalancer.DeleteForwardingRule(ctx, 12345, "abcde1234")
-
-	if err != nil {
+	if err := client.LoadBalancer.DeleteForwardingRule(ctx, "12345", "abcde1234"); err != nil {
 		t.Errorf("LoadBalancer.DeleteForwardingRule returned %+v", err)
 	}
 }
@@ -254,24 +354,41 @@ func TestLoadBalancerHandler_CreateForwardingRule(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/loadbalancer/forward_rule_create", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"RULEID": "abc123"}`
+	uri := fmt.Sprintf("%s/%d/forwarding-rules", lbPath, 1317575)
+	mux.HandleFunc(uri, func(writer http.ResponseWriter, request *http.Request) {
+		response := `
+		{
+			"forwarding_rule" : {
+				"id":"0690a322c25890bc",
+				"frontend_protocol":"http",
+				"frontend_port":80,
+				"backend_protocol":"http",
+				"backend_port":80
+			}
+		}
+		`
 		fmt.Fprintf(writer, response)
 	})
 
 	rule := &ForwardingRule{
+		RuleID:           "0690a322c25890bc",
 		FrontendProtocol: "http",
-		FrontendPort:     8080,
+		FrontendPort:     80,
 		BackendProtocol:  "http",
-		BackendPort:      8080,
+		BackendPort:      80,
 	}
-	ruleID, err := client.LoadBalancer.CreateForwardingRule(ctx, 123, rule)
+
+	ruleID, err := client.LoadBalancer.CreateForwardingRule(ctx, "1317575", rule)
 	if err != nil {
 		t.Errorf("LoadBalancer.CreateForwardingRule returned %+v", err)
 	}
 
 	expected := &ForwardingRule{
-		RuleID: "abc123",
+		RuleID:           "0690a322c25890bc",
+		FrontendProtocol: "http",
+		FrontendPort:     80,
+		BackendProtocol:  "http",
+		BackendPort:      80,
 	}
 
 	if !reflect.DeepEqual(ruleID, expected) {
@@ -279,30 +396,84 @@ func TestLoadBalancerHandler_CreateForwardingRule(t *testing.T) {
 	}
 }
 
-func TestLoadBalancerHandler_GetFullConfig(t *testing.T) {
+func TestLoadBalancerHandler_Create(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/loadbalancer/conf_info", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"generic_info":{"balancing_algorithm":"roundrobin","ssl_redirect":true,"proxy_protocol": true,"sticky_sessions":{"cookie_name":"cookiename"}},"health_checks_info":{"protocol":"http","port":80,"path":"\/","check_interval":15,"response_timeout":5,"unhealthy_threshold":5,"healthy_threshold":5},"has_ssl":true,"forward_rule_list":[{"RULEID":"b06ce4cd520eea15","frontend_protocol":"http","frontend_port":80,"backend_protocol":"http","backend_port":80}],"instance_list":[1317615]}`
+	mux.HandleFunc(lbPath, func(writer http.ResponseWriter, request *http.Request) {
+		response := `
+		{
+			"load_balancer" :
+				{
+					"id": "1317575",
+					"date_created": "2020-01-07 17:24:23",
+					"region": "ewr",
+					"label": "my label",
+					"status": "active",
+					"ipv4": "123.123.123.123",
+					"ipv6": "2001:DB8:1000::100",
+					"generic_info": {
+						"balancing_algorithm": "roundrobin",
+						"ssl_redirect": false,
+						"proxy_protocol": false,
+						"private_network": "8d5bdbdb-3324-4d0c-b303-03e1315e1c02",
+						"sticky_sessions": {
+							"cookie_name": "my-cookie"
+						}
+					},
+					"health_check": {
+						"protocol": "http",
+						"port": 80,
+						"path": "/",
+						"check_interval": 15,
+						"response_timeout": 5,
+						"unhealthy_threshold": 5,
+						"healthy_threshold": 5
+					},
+					"has_ssl": false,
+					"forwarding_rules": [
+						{
+							"id": "abcd12345",
+							"frontend_protocol": "http",
+							"frontend_port": 80,
+							"backend_protocol": "http",
+							"backend_port": 80
+						}
+					],
+					"firewall_rules": [
+						{
+							"id": "abcd12345",
+							"port": 80,
+							"source": "0.0.0.0/0",
+							"ip_type": "v4"
+						}
+					], 						
+					"instances": [
+						"1234"
+					]
+				}
+		}
+		`
 		fmt.Fprintf(writer, response)
 	})
 
-	config, err := client.LoadBalancer.GetFullConfig(ctx, 123)
-	if err != nil {
-		t.Errorf("LoadBalancer.GetFullConfig returned %+v", err)
-	}
-
-	redirect := true
-	proxy := true
-	expected := &LBConfig{
-		GenericInfo: GenericInfo{
-			BalancingAlgorithm: "roundrobin",
-			SSLRedirect:        &redirect,
-			ProxyProtocol:      &proxy,
-			StickySessions:     &StickySessions{CookieName: "cookiename"},
+	lbCreate := &LoadBalancerReq{
+		Label:  "my label",
+		Region: "ewr",
+		ForwardingRules: []ForwardingRule{
+			{
+				RuleID:           "abcd12345",
+				FrontendProtocol: "http",
+				FrontendPort:     80,
+				BackendProtocol:  "http",
+				BackendPort:      80,
+			},
 		},
-		HealthCheck: HealthCheck{
+		BalancingAlgorithm: "roundrobin",
+		SSLRedirect:        BoolToBoolPtr(false),
+		ProxyProtocol:      BoolToBoolPtr(false),
+		PrivateNetwork:     StringToStringPtr("8d5bdbdb-3324-4d0c-b303-03e1315e1c02"),
+		HealthCheck: &HealthCheck{
 			Protocol:           "http",
 			Port:               80,
 			Path:               "/",
@@ -311,164 +482,172 @@ func TestLoadBalancerHandler_GetFullConfig(t *testing.T) {
 			UnhealthyThreshold: 5,
 			HealthyThreshold:   5,
 		},
-		SSLInfo: true,
-		ForwardingRules: ForwardingRules{ForwardRuleList: []ForwardingRule{{
-			RuleID:           "b06ce4cd520eea15",
-			FrontendProtocol: "http",
-			FrontendPort:     80,
-			BackendProtocol:  "http",
-			BackendPort:      80,
-		}}},
-		InstanceList: InstanceList{InstanceList: []int{1317615}},
 	}
 
-	if !reflect.DeepEqual(config, expected) {
-		t.Errorf("LoadBalancer.GetFullConfigreturned %+v, expected %+v", config, expected)
-	}
-}
-
-func TestLoadBalancerHandler_HasSSL(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/loadbalancer/ssl_info", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"has_ssl":true}`
-		fmt.Fprintf(writer, response)
-	})
-
-	ssl, err := client.LoadBalancer.HasSSL(ctx, 123)
+	lb, err := client.LoadBalancer.Create(ctx, lbCreate)
 	if err != nil {
-		t.Errorf("LoadBalancer.HasSSL returned %+v", err)
+		t.Errorf("LoadBalancer.Create returned %+v", err)
 	}
 
-	expected := &struct {
-		SSLInfo bool `json:"has_ssl"`
-	}{SSLInfo: true}
-
-	if !reflect.DeepEqual(ssl, expected) {
-		t.Errorf("LoadBalancer.HasSSL returned %+v, expected %+v", ssl, expected)
-	}
-}
-
-func TestLoadBalancerHandler_Create(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/loadbalancer/create", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"SUBID": 1314840}`
-		fmt.Fprintf(writer, response)
-	})
-
-	redirect := true
-	proxy := true
-	info := GenericInfo{
-		BalancingAlgorithm: "roundrobin",
-		SSLRedirect:        &redirect,
-		ProxyProtocol:      &proxy,
-		StickySessions: &StickySessions{
-			StickySessionsEnabled: "on",
-			CookieName:            "cookie",
+	expected := &LoadBalancer{
+		ID:          "1317575",
+		DateCreated: "2020-01-07 17:24:23",
+		Label:       "my label",
+		Status:      "active",
+		Region:      "ewr",
+		IPV6:        "2001:DB8:1000::100",
+		IPV4:        "123.123.123.123",
+		SSLInfo:     BoolToBoolPtr(false),
+		ForwardingRules: []ForwardingRule{
+			{
+				RuleID:           "abcd12345",
+				FrontendProtocol: "http",
+				FrontendPort:     80,
+				BackendProtocol:  "http",
+				BackendPort:      80,
+			},
 		},
-	}
-
-	health := HealthCheck{
-		Protocol:           "http",
-		Port:               80,
-		Path:               "/",
-		CheckInterval:      5,
-		ResponseTimeout:    5,
-		UnhealthyThreshold: 5,
-		HealthyThreshold:   5,
-	}
-
-	rules := []ForwardingRule{
-		{
-			FrontendProtocol: "https",
-			FrontendPort:     80,
-			BackendProtocol:  "http",
-			BackendPort:      80,
+		GenericInfo: &GenericInfo{
+			BalancingAlgorithm: "roundrobin",
+			SSLRedirect:        BoolToBoolPtr(false),
+			ProxyProtocol:      BoolToBoolPtr(false),
+			PrivateNetwork:     "8d5bdbdb-3324-4d0c-b303-03e1315e1c02",
+			StickySessions: &StickySessions{
+				CookieName: "my-cookie",
+			},
+		},
+		HealthCheck: &HealthCheck{
+			Protocol:           "http",
+			Port:               80,
+			Path:               "/",
+			CheckInterval:      15,
+			ResponseTimeout:    5,
+			UnhealthyThreshold: 5,
+			HealthyThreshold:   5,
+		},
+		Instances: []string{"1234"},
+		FirewallRules: []LBFirewallRule{
+			{
+				RuleID: "abcd12345",
+				Port:   80,
+				Source: "0.0.0.0/0",
+				IPType: "v4",
+			},
 		},
 	}
 
-	ssl := SSL{
-		PrivateKey:  "key",
-		Certificate: "cert",
-		Chain:       "chain",
-	}
-
-	instances := InstanceList{[]int{1234}}
-
-	lb, err := client.LoadBalancer.Create(ctx, 1, "label", &info, &health, rules, &ssl, &instances)
-	if err != nil {
-		t.Errorf("LoadBalancer.Create returned %+v", err)
-	}
-
-	expected := LoadBalancers{
-		ID: 1314840,
-	}
-
-	if !reflect.DeepEqual(lb, &expected) {
+	if !reflect.DeepEqual(lb, expected) {
 		t.Errorf("LoadBalancer.Create returned %+v, expected %+v", lb, expected)
 	}
 }
 
-func TestLoadBalancerHandler_UpdateGenericInfo(t *testing.T) {
+func TestLoadBalancerHandler_Update(t *testing.T) {
 	setup()
 	defer teardown()
-
-	mux.HandleFunc("/v1/loadbalancer/generic_update", func(writer http.ResponseWriter, request *http.Request) {
+	uri := fmt.Sprintf("%s/%s", lbPath, "d9dbc01c-aaca-4d4b-8c4a-bbb24c946141")
+	mux.HandleFunc(uri, func(writer http.ResponseWriter, request *http.Request) {
 		fmt.Fprint(writer)
 	})
 
-	redirect := true
-	proxy := true
-	info := GenericInfo{
+	lbCreate := &LoadBalancerReq{
+		Label:  "my label",
+		Region: "ewr",
+		ForwardingRules: []ForwardingRule{
+			{
+				RuleID:           "abcd12345",
+				FrontendProtocol: "http",
+				FrontendPort:     80,
+				BackendProtocol:  "http",
+				BackendPort:      80,
+			},
+		},
 		BalancingAlgorithm: "roundrobin",
-		SSLRedirect:        &redirect,
-		ProxyProtocol:      &proxy,
-		StickySessions: &StickySessions{
-			StickySessionsEnabled: "on",
-			CookieName:            "cookie_name",
+		SSLRedirect:        BoolToBoolPtr(false),
+		ProxyProtocol:      BoolToBoolPtr(false),
+		PrivateNetwork:     StringToStringPtr("8d5bdbdb-3324-4d0c-b303-03e1315e1c02"),
+		HealthCheck: &HealthCheck{
+			Protocol:           "http",
+			Port:               80,
+			Path:               "/",
+			CheckInterval:      15,
+			ResponseTimeout:    5,
+			UnhealthyThreshold: 5,
+			HealthyThreshold:   5,
 		},
 	}
-	err := client.LoadBalancer.UpdateGenericInfo(ctx, 12345, "label", &info)
 
+	err := client.LoadBalancer.Update(ctx, "d9dbc01c-aaca-4d4b-8c4a-bbb24c946141", lbCreate)
 	if err != nil {
-		t.Errorf("LoadBalancer.UpdateGenericInfo returned %+v", err)
+		t.Errorf("LoadBalancer.Update returned %+v", err)
 	}
 }
 
-func TestLoadBalancerHandler_AddSSL(t *testing.T) {
+func TestLoadBalancerHandler_GetFowardingRule(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/loadbalancer/ssl_add", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
+	uri := fmt.Sprintf("%s/%s/forwarding-rules/%s", lbPath, "d9dbc01c-aaca-4d4b-8c4a-bbb24c946141", "d42585eb85b1f69d")
+	mux.HandleFunc(uri, func(writer http.ResponseWriter, request *http.Request) {
+		req := `{
+  "forwarding_rule": {
+    "id": "d42585eb85b1f69d",
+    "frontend_protocol": "http",
+    "frontend_port": 8080,
+    "backend_protocol": "http",
+    "backend_port": 80
+  }
+}`
+		fmt.Fprint(writer, req)
 	})
 
-	ssl := &SSL{
-		PrivateKey:  "key",
-		Certificate: "crt",
-		Chain:       "chain",
+	rule, err := client.LoadBalancer.GetForwardingRule(ctx, "d9dbc01c-aaca-4d4b-8c4a-bbb24c946141", "d42585eb85b1f69d")
+	if err != nil {
+		t.Errorf("LoadBalancer.GetForwardingRule returned %+v", err)
 	}
-	err := client.LoadBalancer.AddSSL(ctx, 12345, ssl)
 
-	if err != nil {
-		t.Errorf("LoadBalancer.AddSSL returned %+v", err)
+	expected := &ForwardingRule{
+		RuleID:           "d42585eb85b1f69d",
+		FrontendProtocol: "http",
+		FrontendPort:     8080,
+		BackendProtocol:  "http",
+		BackendPort:      80,
+	}
+
+	if !reflect.DeepEqual(rule, expected) {
+		t.Errorf("LoadBalancer.GetForwardingRule returned %+v, expected %+v", rule, expected)
 	}
 }
 
-func TestLoadBalancerHandler_RemoveSSL(t *testing.T) {
+func TestLoadBalancerHandler_GetFirewallRule(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/loadbalancer/ssl_remove", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
+	uri := fmt.Sprintf("%s/%s/firewall-rules/%s", lbPath, "d9dbc01c-aaca-4d4b-8c4a-bbb24c946141", "d42585eb85b1f69d")
+	mux.HandleFunc(uri, func(writer http.ResponseWriter, request *http.Request) {
+		req := `{
+  "firewall_rule": {
+    "id": "d42585eb85b1f69d",
+    "port": 80,
+    "source": "0.0.0.0/0",
+    "ip_type": "v4"
+  }
+}`
+		fmt.Fprint(writer, req)
 	})
 
-	err := client.LoadBalancer.RemoveSSL(ctx, 12345)
-
+	rule, err := client.LoadBalancer.GetFirewallRule(ctx, "d9dbc01c-aaca-4d4b-8c4a-bbb24c946141", "d42585eb85b1f69d")
 	if err != nil {
-		t.Errorf("LoadBalancer.RemoveSSL returned %+v", err)
+		t.Errorf("LoadBalancer.GetFirewallRule returned %+v", err)
+	}
+
+	expected := &LBFirewallRule{
+		RuleID: "d42585eb85b1f69d",
+		Port:   80,
+		Source: "0.0.0.0/0",
+		IPType: "v4",
+	}
+
+	if !reflect.DeepEqual(rule, expected) {
+		t.Errorf("LoadBalancer.GetFirewallRule returned %+v, expected %+v", rule, expected)
 	}
 }
diff --git a/meta.go b/meta.go
new file mode 100644
index 0000000..c361bf9
--- /dev/null
+++ b/meta.go
@@ -0,0 +1,13 @@
+package govultr
+
+// Meta represents the available pagination information
+type Meta struct {
+	Total int `json:"total"`
+	Links *Links
+}
+
+// Links represent the next/previous cursor in your pagination calls
+type Links struct {
+	Next string `json:"next"`
+	Prev string `json:"prev"`
+}
diff --git a/meta_test.go b/meta_test.go
new file mode 100644
index 0000000..49795e3
--- /dev/null
+++ b/meta_test.go
@@ -0,0 +1,36 @@
+package govultr
+
+import (
+	"encoding/json"
+	"testing"
+)
+
+var metaBytes = []byte(`
+	{
+        "total": 11,
+        "links": {
+            "next": "bmV4dF9fMTMxOTgxNQ==",
+            "prev": ""
+        }
+	}
+`)
+
+func TestMeta(t *testing.T) {
+	var meta *Meta
+
+	if err := json.Unmarshal(metaBytes, &meta); err != nil {
+		t.Fatal(err)
+	}
+
+	if meta.Total != 11 {
+		t.Fatal("Total did not equal 11")
+	}
+
+	if meta.Links.Next != "bmV4dF9fMTMxOTgxNQ==" {
+		t.Fatal("Next cursor did not equal bmV4dF9fMTMxOTgxNQ==")
+	}
+
+	if meta.Links.Prev != "" {
+		t.Fatal("Previous cursor was not empty")
+	}
+}
diff --git a/network.go b/network.go
index d6c32ea..652dab6 100644
--- a/network.go
+++ b/network.go
@@ -2,18 +2,22 @@ package govultr
 
 import (
 	"context"
-	"net"
+	"fmt"
 	"net/http"
-	"net/url"
-	"strconv"
+
+	"github.com/google/go-querystring/query"
 )
 
+const netPath = "/v2/private-networks"
+
 // NetworkService is the interface to interact with the network endpoints on the Vultr API
-// Link: https://www.vultr.com/api/#network
+// Link : https://www.vultr.com/api/#tag/private-Networks
 type NetworkService interface {
-	Create(ctx context.Context, regionID, description, cidrBlock string) (*Network, error)
+	Create(ctx context.Context, createReq *NetworkReq) (*Network, error)
+	Get(ctx context.Context, networkID string) (*Network, error)
+	Update(ctx context.Context, networkID string, description string) error
 	Delete(ctx context.Context, networkID string) error
-	List(ctx context.Context) ([]Network, error)
+	List(ctx context.Context, options *ListOptions) ([]Network, *Meta, error)
 }
 
 // NetworkServiceHandler handles interaction with the network methods for the Vultr API
@@ -23,98 +27,104 @@ type NetworkServiceHandler struct {
 
 // Network represents a Vultr private network
 type Network struct {
-	NetworkID    string `json:"NETWORKID"`
-	RegionID     string `json:"DCID"`
+	NetworkID    string `json:"id"`
+	Region       string `json:"region"`
 	Description  string `json:"description"`
 	V4Subnet     string `json:"v4_subnet"`
 	V4SubnetMask int    `json:"v4_subnet_mask"`
 	DateCreated  string `json:"date_created"`
 }
 
-// Create a new private network. A private network can only be used at the location for which it was created.
-func (n *NetworkServiceHandler) Create(ctx context.Context, regionID, description, cidrBlock string) (*Network, error) {
+// NetworkReq represents parameters to create or update Network resource
+type NetworkReq struct {
+	Region       string `json:"region"`
+	Description  string `json:"description"`
+	V4Subnet     string `json:"v4_subnet"`
+	V4SubnetMask int    `json:"v4_subnet_mask"`
+}
 
-	uri := "/v1/network/create"
+type networksBase struct {
+	Networks []Network `json:"networks"`
+	Meta     *Meta     `json:"meta"`
+}
 
-	values := url.Values{
-		"DCID": {regionID},
-	}
+type networkBase struct {
+	Network *Network `json:"network"`
+}
 
-	// Optional
-	if cidrBlock != "" {
-		_, ipNet, err := net.ParseCIDR(cidrBlock)
-		if err != nil {
-			return nil, err
-		}
-		if v4Subnet := ipNet.IP.To4(); v4Subnet != nil {
-			values.Add("v4_subnet", v4Subnet.String())
-		}
-		mask, _ := ipNet.Mask.Size()
-		values.Add("v4_subnet_mask", strconv.Itoa(mask))
+// Create a new private network. A private network can only be used at the location for which it was created.
+func (n *NetworkServiceHandler) Create(ctx context.Context, createReq *NetworkReq) (*Network, error) {
+	req, err := n.client.NewRequest(ctx, http.MethodPost, netPath, createReq)
+	if err != nil {
+		return nil, err
 	}
 
-	if description != "" {
-		values.Add("description", description)
+	network := new(networkBase)
+	if err = n.client.DoWithContext(ctx, req, network); err != nil {
+		return nil, err
 	}
 
-	req, err := n.client.NewRequest(ctx, http.MethodPost, uri, values)
+	return network.Network, nil
+}
 
+// Get gets the private networks of the requested ID
+func (n *NetworkServiceHandler) Get(ctx context.Context, networkID string) (*Network, error) {
+	uri := fmt.Sprintf("%s/%s", netPath, networkID)
+	req, err := n.client.NewRequest(ctx, http.MethodGet, uri, nil)
 	if err != nil {
 		return nil, err
 	}
 
-	network := new(Network)
-	err = n.client.DoWithContext(ctx, req, network)
-
-	if err != nil {
+	network := new(networkBase)
+	if err = n.client.DoWithContext(ctx, req, network); err != nil {
 		return nil, err
 	}
 
-	return network, nil
+	return network.Network, nil
 }
 
-// Delete a private network. Before deleting, a network must be disabled from all instances. See https://www.vultr.com/api/#server_private_network_disable
-func (n *NetworkServiceHandler) Delete(ctx context.Context, networkID string) error {
-	uri := "/v1/network/destroy"
-
-	values := url.Values{
-		"NETWORKID": {networkID},
-	}
-
-	req, err := n.client.NewRequest(ctx, http.MethodPost, uri, values)
+// Update updates a private network
+func (n *NetworkServiceHandler) Update(ctx context.Context, networkID string, description string) error {
+	uri := fmt.Sprintf("%s/%s", netPath, networkID)
 
+	netReq := RequestBody{"description": description}
+	req, err := n.client.NewRequest(ctx, http.MethodPut, uri, netReq)
 	if err != nil {
 		return err
 	}
 
-	err = n.client.DoWithContext(ctx, req, nil)
+	return n.client.DoWithContext(ctx, req, nil)
+}
 
+// Delete a private network. Before deleting, a network must be disabled from all instances
+func (n *NetworkServiceHandler) Delete(ctx context.Context, networkID string) error {
+	uri := fmt.Sprintf("%s/%s", netPath, networkID)
+	req, err := n.client.NewRequest(ctx, http.MethodDelete, uri, nil)
 	if err != nil {
 		return err
 	}
 
-	return nil
+	return n.client.DoWithContext(ctx, req, nil)
 }
 
 // List lists all private networks on the current account
-func (n *NetworkServiceHandler) List(ctx context.Context) ([]Network, error) {
-	uri := "/v1/network/list"
-
-	req, err := n.client.NewRequest(ctx, http.MethodGet, uri, nil)
+func (n *NetworkServiceHandler) List(ctx context.Context, options *ListOptions) ([]Network, *Meta, error) {
+	req, err := n.client.NewRequest(ctx, http.MethodGet, netPath, nil)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	var networkMap map[string]Network
-	err = n.client.DoWithContext(ctx, req, &networkMap)
+	newValues, err := query.Values(options)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	var networks []Network
-	for _, network := range networkMap {
-		networks = append(networks, network)
+	req.URL.RawQuery = newValues.Encode()
+
+	networks := new(networksBase)
+	if err = n.client.DoWithContext(ctx, req, networks); err != nil {
+		return nil, nil, err
 	}
 
-	return networks, nil
+	return networks.Networks, networks.Meta, nil
 }
diff --git a/network_test.go b/network_test.go
index 3fc8c13..2e2ab52 100644
--- a/network_test.go
+++ b/network_test.go
@@ -11,24 +11,41 @@ func TestNetworkServiceHandler_Create(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/network/create", func(writer http.ResponseWriter, request *http.Request) {
+	mux.HandleFunc("/v2/private-networks", func(writer http.ResponseWriter, request *http.Request) {
 		response := `
 		{
-			"NETWORKID": "net59a0526477dd3"
+			"network": {
+				"id": "net539626f0798d7",
+				"date_created": "2017-08-25 12:23:45",
+				"region": "ewr",
+				"description": "test1",
+				"v4_subnet": "10.99.0.0",
+				"v4_subnet_mask": 24
+			}
 		}
 		`
 
 		fmt.Fprint(writer, response)
 	})
 
-	net, err := client.Network.Create(ctx, "1", "go-test", "111.111.111.111/24")
+	options := &NetworkReq{
+		Region:      "ewr",
+		Description: "test1",
+	}
+
+	net, err := client.Network.Create(ctx, options)
 
 	if err != nil {
 		t.Errorf("Network.Create returned %+v, expected %+v", err, nil)
 	}
 
 	expected := &Network{
-		NetworkID: "net59a0526477dd3",
+		NetworkID:    "net539626f0798d7",
+		Region:       "ewr",
+		Description:  "test1",
+		V4Subnet:     "10.99.0.0",
+		V4SubnetMask: 24,
+		DateCreated:  "2017-08-25 12:23:45",
 	}
 
 	if !reflect.DeepEqual(net, expected) {
@@ -40,11 +57,11 @@ func TestNetworkServiceHandler_Delete(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/network/destroy", func(writer http.ResponseWriter, request *http.Request) {
+	mux.HandleFunc("/v2/private-networks/net539626f0798d7", func(writer http.ResponseWriter, request *http.Request) {
 		fmt.Fprint(writer)
 	})
 
-	err := client.Network.Delete(ctx, "foo")
+	err := client.Network.Delete(ctx, "net539626f0798d7")
 
 	if err != nil {
 		t.Errorf("Network.Delete returned %+v, expected %+v", err, nil)
@@ -55,23 +72,23 @@ func TestNetworkServiceHandler_List(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/network/list", func(writer http.ResponseWriter, request *http.Request) {
+	mux.HandleFunc("/v2/private-networks", func(writer http.ResponseWriter, request *http.Request) {
 		response := `
 		{
-			"net539626f0798d7": {
-				"DCID": "1",
-				"NETWORKID": "net539626f0798d7",
+			"networks": [{
+				"id": "net539626f0798d7",
 				"date_created": "2017-08-25 12:23:45",
+				"region": "ewr",
 				"description": "test1",
 				"v4_subnet": "10.99.0.0",
 				"v4_subnet_mask": 24
-			}
+			}]
 		}
 		`
 		fmt.Fprintf(writer, response)
 	})
 
-	networks, err := client.Network.List(ctx)
+	networks, _, err := client.Network.List(ctx, nil)
 
 	if err != nil {
 		t.Errorf("Network.List returned error: %v", err)
@@ -80,7 +97,7 @@ func TestNetworkServiceHandler_List(t *testing.T) {
 	expected := []Network{
 		{
 			NetworkID:    "net539626f0798d7",
-			RegionID:     "1",
+			Region:       "ewr",
 			Description:  "test1",
 			V4Subnet:     "10.99.0.0",
 			V4SubnetMask: 24,
@@ -92,3 +109,46 @@ func TestNetworkServiceHandler_List(t *testing.T) {
 		t.Errorf("Network.List returned %+v, expected %+v", networks, expected)
 	}
 }
+
+func TestNetworkServiceHandler_Update(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/private-networks/net539626f0798d7", func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
+	})
+
+	err := client.Network.Update(ctx, "net539626f0798d7", "update")
+
+	if err != nil {
+		t.Errorf("Network.Update returned %+v, expected %+v", err, nil)
+	}
+}
+
+func TestNetworkServiceHandler_Get(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/private-networks/net539626f0798d7", func(writer http.ResponseWriter, request *http.Request) {
+		req := `{"network": {"id": "cb676a46-66fd-4dfb-b839-443f2e6c0b60","date_created": "2020-10-10T01:56:20+00:00","region": "ewr","description": "sample desc","v4_subnet": "10.99.0.0","v4_subnet_mask": 24}}`
+		fmt.Fprint(writer, req)
+	})
+
+	network, err := client.Network.Get(ctx, "net539626f0798d7")
+	if err != nil {
+		t.Errorf("Network.Get returned %+v, expected %+v", err, nil)
+	}
+
+	expected := &Network{
+		NetworkID:    "cb676a46-66fd-4dfb-b839-443f2e6c0b60",
+		Region:       "ewr",
+		Description:  "sample desc",
+		V4Subnet:     "10.99.0.0",
+		V4SubnetMask: 24,
+		DateCreated:  "2020-10-10T01:56:20+00:00",
+	}
+
+	if !reflect.DeepEqual(network, expected) {
+		t.Errorf("Instance.Get returned %+v, expected %+v", network, expected)
+	}
+}
diff --git a/object_storage.go b/object_storage.go
index 1c10564..7fb722a 100644
--- a/object_storage.go
+++ b/object_storage.go
@@ -2,23 +2,23 @@ package govultr
 
 import (
 	"context"
+	"fmt"
 	"net/http"
-	"net/url"
-	"strconv"
+
+	"github.com/google/go-querystring/query"
 )
 
 // ObjectStorageService is the interface to interact with the object storage endpoints on the Vultr API.
-// Link: https://www.vultr.com/api/#objectstorage
+// Link : https://www.vultr.com/api/#tag/s3
 type ObjectStorageService interface {
-	Create(ctx context.Context, objectStoreClusterID int, Label string) (*struct {
-		ID int `json:"SUBID"`
-	}, error)
-	Delete(ctx context.Context, id int) error
-	SetLabel(ctx context.Context, id int, label string) error
-	List(ctx context.Context, options *ObjectListOptions) ([]ObjectStorage, error)
-	Get(ctx context.Context, id int) (*ObjectStorage, error)
-	ListCluster(ctx context.Context) ([]ObjectStorageCluster, error)
-	RegenerateKeys(ctx context.Context, id int, s3AccessKey string) (*S3Keys, error)
+	Create(ctx context.Context, clusterID int, label string) (*ObjectStorage, error)
+	Get(ctx context.Context, id string) (*ObjectStorage, error)
+	Update(ctx context.Context, id, label string) error
+	Delete(ctx context.Context, id string) error
+	List(ctx context.Context, options *ListOptions) ([]ObjectStorage, *Meta, error)
+
+	ListCluster(ctx context.Context, options *ListOptions) ([]ObjectStorageCluster, *Meta, error)
+	RegenerateKeys(ctx context.Context, id string) (*S3Keys, error)
 }
 
 // ObjectStorageServiceHandler handles interaction with the firewall rule methods for the Vultr API.
@@ -28,25 +28,16 @@ type ObjectStorageServiceHandler struct {
 
 // ObjectStorage represents a Vultr Object Storage subscription.
 type ObjectStorage struct {
-	ID                   int    `json:"SUBID"`
+	ID                   string `json:"id"`
 	DateCreated          string `json:"date_created"`
-	ObjectStoreClusterID int    `json:"OBJSTORECLUSTERID"`
-	RegionID             int    `json:"DCID"`
-	Location             string
-	Label                string
-	Status               string
+	ObjectStoreClusterID int    `json:"cluster_id"`
+	Region               string `json:"region"`
+	Location             string `json:"location"`
+	Label                string `json:"label"`
+	Status               string `json:"status"`
 	S3Keys
 }
 
-// ObjectStorageCluster represents a Vultr Object Storage cluster.
-type ObjectStorageCluster struct {
-	ObjectStoreClusterID int `json:"OBJSTORECLUSTERID"`
-	RegionID             int `json:"DCID"`
-	Location             string
-	Hostname             string
-	Deploy               string
-}
-
 // S3Keys define your api access to your cluster
 type S3Keys struct {
 	S3Hostname  string `json:"s3_hostname"`
@@ -54,204 +45,153 @@ type S3Keys struct {
 	S3SecretKey string `json:"s3_secret_key"`
 }
 
-// ObjectListOptions are your optional params you have available to list data.
-type ObjectListOptions struct {
-	IncludeS3 bool
-	Label     string
+// ObjectStorageCluster represents a Vultr Object Storage cluster.
+type ObjectStorageCluster struct {
+	ID       int    `json:"id"`
+	Region   string `json:"region"`
+	Hostname string `json:"hostname"`
+	Deploy   string `json:"deploy"`
 }
 
-// Create an object storage subscription
-func (o *ObjectStorageServiceHandler) Create(ctx context.Context, objectStoreClusterID int, Label string) (*struct {
-	ID int `json:"SUBID"`
-}, error) {
-	uri := "/v1/objectstorage/create"
-
-	values := url.Values{
-		"OBJSTORECLUSTERID": {strconv.Itoa(objectStoreClusterID)},
-		"label":             {Label},
-	}
-
-	req, err := o.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return nil, err
-	}
-
-	id := struct {
-		ID int `json:"SUBID"`
-	}{}
-
-	err = o.client.DoWithContext(ctx, req, &id)
-	if err != nil {
-		return nil, err
-	}
-
-	return &id, nil
+type objectStoragesBase struct {
+	ObjectStorages []ObjectStorage `json:"object_storages"`
+	Meta           *Meta           `json:"meta"`
 }
 
-// Delete an object storage subscription.
-func (o *ObjectStorageServiceHandler) Delete(ctx context.Context, id int) error {
-	uri := "/v1/objectstorage/destroy"
-
-	values := url.Values{
-		"SUBID": {strconv.Itoa(id)},
-	}
-
-	req, err := o.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = o.client.DoWithContext(ctx, req, nil)
+type objectStorageBase struct {
+	ObjectStorage *ObjectStorage `json:"object_storage"`
+}
 
-	if err != nil {
-		return err
-	}
+type objectStorageClustersBase struct {
+	Clusters []ObjectStorageCluster `json:"clusters"`
+	Meta     *Meta                  `json:"meta"`
+}
 
-	return nil
+type s3KeysBase struct {
+	S3Credentials *S3Keys `json:"s3_credentials"`
 }
 
-// SetLabel of an object storage subscription.
-func (o *ObjectStorageServiceHandler) SetLabel(ctx context.Context, id int, label string) error {
-	uri := "/v1/objectstorage/label_set"
+//// ObjectListOptions are your optional params you have available to list data.
+//type ObjectListOptions struct {
+//	IncludeS3 bool
+//	Label     string
+//}
 
-	values := url.Values{
-		"SUBID": {strconv.Itoa(id)},
-		"label": {label},
-	}
+// Create an object storage subscription
+func (o *ObjectStorageServiceHandler) Create(ctx context.Context, clusterID int, label string) (*ObjectStorage, error) {
+	uri := "/v2/object-storage"
 
+	values := RequestBody{"cluster_id": clusterID, "label": label}
 	req, err := o.client.NewRequest(ctx, http.MethodPost, uri, values)
-
 	if err != nil {
-		return err
+		return nil, err
 	}
 
-	err = o.client.DoWithContext(ctx, req, nil)
-
+	objectStorage := new(objectStorageBase)
+	err = o.client.DoWithContext(ctx, req, objectStorage)
 	if err != nil {
-		return err
+		return nil, err
 	}
 
-	return nil
+	return objectStorage.ObjectStorage, nil
 }
 
-// List returns all object storage subscriptions on the current account. This includes both pending and active subscriptions.
-func (o *ObjectStorageServiceHandler) List(ctx context.Context, options *ObjectListOptions) ([]ObjectStorage, error) {
-	uri := "/v1/objectstorage/list"
+// Get returns a specified object storage by the provided ID
+func (o *ObjectStorageServiceHandler) Get(ctx context.Context, id string) (*ObjectStorage, error) {
+	uri := fmt.Sprintf("/v2/object-storage/%s", id)
 
 	req, err := o.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
 	if err != nil {
 		return nil, err
 	}
 
-	if options != nil {
-		q := req.URL.Query()
-
-		// default behavior is true
-		if options.IncludeS3 == false {
-			q.Add("include_s3", "false")
-		}
-
-		if options.Label != "" {
-			q.Add("label", options.Label)
-		}
-
-		req.URL.RawQuery = q.Encode()
+	objectStorage := new(objectStorageBase)
+	if err = o.client.DoWithContext(ctx, req, objectStorage); err != nil {
+		return nil, err
 	}
 
-	var objectStorageMap map[string]ObjectStorage
+	return objectStorage.ObjectStorage, nil
+}
 
-	err = o.client.DoWithContext(ctx, req, &objectStorageMap)
+// Update a Object Storage Subscription.
+func (o *ObjectStorageServiceHandler) Update(ctx context.Context, id, label string) error {
+	uri := fmt.Sprintf("/v2/object-storage/%s", id)
 
+	value := RequestBody{"label": label}
+	req, err := o.client.NewRequest(ctx, http.MethodPut, uri, value)
 	if err != nil {
-		return nil, err
+		return err
 	}
 
-	var objectStorages []ObjectStorage
+	return o.client.DoWithContext(ctx, req, nil)
+}
+
+// Delete a object storage subscription.
+func (o *ObjectStorageServiceHandler) Delete(ctx context.Context, id string) error {
+	uri := fmt.Sprintf("/v2/object-storage/%s", id)
 
-	for _, o := range objectStorageMap {
-		objectStorages = append(objectStorages, o)
+	req, err := o.client.NewRequest(ctx, http.MethodDelete, uri, nil)
+	if err != nil {
+		return err
 	}
 
-	return objectStorages, nil
+	return o.client.DoWithContext(ctx, req, nil)
 }
 
-// Get returns a specified object storage by the provided ID
-func (o *ObjectStorageServiceHandler) Get(ctx context.Context, id int) (*ObjectStorage, error) {
-	uri := "/v1/objectstorage/list"
+// List all object storage subscriptions on the current account. This includes both pending and active subscriptions.
+func (o *ObjectStorageServiceHandler) List(ctx context.Context, options *ListOptions) ([]ObjectStorage, *Meta, error) {
+	uri := "/v2/object-storage"
 
 	req, err := o.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	if id != 0 {
-		q := req.URL.Query()
-		q.Add("SUBID", strconv.Itoa(id))
-		req.URL.RawQuery = q.Encode()
+	newValues, err := query.Values(options)
+	if err != nil {
+		return nil, nil, err
 	}
 
-	objStorage := make(map[string]ObjectStorage)
-	err = o.client.DoWithContext(ctx, req, &objStorage)
-	if err != nil {
-		return nil, err
+	req.URL.RawQuery = newValues.Encode()
+
+	objectStorage := new(objectStoragesBase)
+	if err = o.client.DoWithContext(ctx, req, objectStorage); err != nil {
+		return nil, nil, err
 	}
 
-	obj := objStorage[strconv.Itoa(id)]
-	return &obj, nil
+	return objectStorage.ObjectStorages, objectStorage.Meta, nil
 }
 
 // ListCluster returns back your object storage clusters.
 // Clusters may be removed over time. The "deploy" field can be used to determine whether or not new deployments are allowed in the cluster.
-func (o *ObjectStorageServiceHandler) ListCluster(ctx context.Context) ([]ObjectStorageCluster, error) {
-	uri := "/v1/objectstorage/list_cluster"
+func (o *ObjectStorageServiceHandler) ListCluster(ctx context.Context, options *ListOptions) ([]ObjectStorageCluster, *Meta, error) {
+	uri := "/v2/object-storage/clusters"
 	req, err := o.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	var objectClusterMap map[string]ObjectStorageCluster
-
-	err = o.client.DoWithContext(ctx, req, &objectClusterMap)
-
-	if err != nil {
-		return nil, err
+	clusters := new(objectStorageClustersBase)
+	if err = o.client.DoWithContext(ctx, req, clusters); err != nil {
+		return nil, nil, err
 	}
 
-	var objectStorageCluster []ObjectStorageCluster
-
-	for _, o := range objectClusterMap {
-		objectStorageCluster = append(objectStorageCluster, o)
-	}
-
-	return objectStorageCluster, nil
+	return clusters.Clusters, clusters.Meta, nil
 }
 
 // RegenerateKeys of the S3 API Keys for an object storage subscription
-func (o *ObjectStorageServiceHandler) RegenerateKeys(ctx context.Context, id int, s3AccessKey string) (*S3Keys, error) {
-	uri := "/v1/objectstorage/s3key_regenerate"
-
-	values := url.Values{
-		"SUBID":         {strconv.Itoa(id)},
-		"s3_access_key": {s3AccessKey},
-	}
-
-	req, err := o.client.NewRequest(ctx, http.MethodPost, uri, values)
+func (o *ObjectStorageServiceHandler) RegenerateKeys(ctx context.Context, id string) (*S3Keys, error) {
+	uri := fmt.Sprintf("/v2/object-storage/%s/regenerate-keys", id)
 
+	req, err := o.client.NewRequest(ctx, http.MethodPost, uri, nil)
 	if err != nil {
 		return nil, err
 	}
 
-	s3Keys := new(S3Keys)
-	err = o.client.DoWithContext(ctx, req, s3Keys)
-
-	if err != nil {
+	s3Keys := new(s3KeysBase)
+	if err = o.client.DoWithContext(ctx, req, s3Keys); err != nil {
 		return nil, err
 	}
 
-	return s3Keys, nil
+	return s3Keys.S3Credentials, nil
 }
diff --git a/object_storage_test.go b/object_storage_test.go
index 0620897..98402d6 100644
--- a/object_storage_test.go
+++ b/object_storage_test.go
@@ -11,65 +11,57 @@ func TestObjectStorageServiceHandler_Create(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/objectstorage/create", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"SUBID": 1234}`
+	mux.HandleFunc("/v2/object-storage", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"object_storage":{"id":"39239784","date_created":"2020-07-1414:07:28","cluster_id":2,"region":"ewr","location":"New Jersey","label":"api-obj-storage2","status":"pending","s3_hostname":"","s3_access_key":"","s3_secret_key":""}}`
 		fmt.Fprint(writer, response)
 	})
 
-	id, err := client.ObjectStorage.Create(ctx, 1, "s3 label")
+	objectStorage, err := client.ObjectStorage.Create(ctx, 2, "api-obj-storage2")
 	if err != nil {
 		t.Errorf("ObjectStorage.Create returned %+v", err)
 	}
 
-	expected := &struct {
-		ID int `json:"SUBID"`
-	}{ID: 1234}
-
-	if !reflect.DeepEqual(id, expected) {
-		t.Errorf("ObjectStorage.Create returned %+v, expected %+v", id, expected)
+	expected := &ObjectStorage{
+		ID:                   "39239784",
+		DateCreated:          "2020-07-1414:07:28",
+		ObjectStoreClusterID: 2,
+		Region:               "ewr",
+		Location:             "New Jersey",
+		Label:                "api-obj-storage2",
+		Status:               "pending",
+		S3Keys:               S3Keys{},
 	}
-}
-
-func TestObjectStorageServiceHandler_Delete(t *testing.T) {
-	setup()
-	defer teardown()
 
-	mux.HandleFunc("/v1/objectstorage/destroy", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.ObjectStorage.Delete(ctx, 1234)
-	if err != nil {
-		t.Errorf("ObjectStorage.Delete returned %+v", err)
+	if !reflect.DeepEqual(objectStorage, expected) {
+		t.Errorf("ObjectStorage.Create returned %+v, expected %+v", objectStorage, expected)
 	}
 }
 
 func TestObjectStorageServiceHandler_Get(t *testing.T) {
 	setup()
 	defer teardown()
-	mux.HandleFunc("/v1/objectstorage/list", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"1314217":{"SUBID": 1314217,"date_created": "2019-04-17 17:33:00","OBJSTORECLUSTERID": 1,"DCID": 1,"location": "New Jersey","label": "object1","status": "active","s3_hostname": "nj1.vultrobjects.com","s3_access_key": "abc1234","s3_secret_key": "def5678"}}`
+	mux.HandleFunc("/v2/object-storage/39239784", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"object_storage":{"id":"39239784","date_created":"2020-07-1414:07:28","cluster_id":2,"region":"ewr","label":"","status":"active","s3_hostname":"ewr1.vultrobjects.com","s3_access_key":"F123","s3_secret_key":"F1234"}}`
 		fmt.Fprint(writer, response)
 	})
 
-	s3, err := client.ObjectStorage.Get(ctx, 1314217)
+	s3, err := client.ObjectStorage.Get(ctx, "39239784")
 
 	if err != nil {
 		t.Errorf("ObjectStorage.Get returned %+v", err)
 	}
 
 	expected := &ObjectStorage{
-		ID:                   1314217,
-		DateCreated:          "2019-04-17 17:33:00",
-		ObjectStoreClusterID: 1,
-		RegionID:             1,
-		Location:             "New Jersey",
-		Label:                "object1",
+		ID:                   "39239784",
+		DateCreated:          "2020-07-1414:07:28",
+		ObjectStoreClusterID: 2,
+		Region:               "ewr",
+		Label:                "",
 		Status:               "active",
 		S3Keys: S3Keys{
-			S3Hostname:  "nj1.vultrobjects.com",
-			S3AccessKey: "abc1234",
-			S3SecretKey: "def5678",
+			S3Hostname:  "ewr1.vultrobjects.com",
+			S3AccessKey: "F123",
+			S3SecretKey: "F1234",
 		},
 	}
 	if !reflect.DeepEqual(s3, expected) {
@@ -77,53 +69,86 @@ func TestObjectStorageServiceHandler_Get(t *testing.T) {
 	}
 }
 
-func TestObjectStorageServiceHandler_List(t *testing.T) {
+func TestObjectStorageServiceHandler_Update(t *testing.T) {
 	setup()
 	defer teardown()
-	mux.HandleFunc("/v1/objectstorage/list", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"1314217": {"SUBID": 1314217,"date_created": "2019-04-17 17:33:00","OBJSTORECLUSTERID": 1,"DCID": 1,"location": "New Jersey","label": "object1","status": "active","s3_hostname": "nj1.vultrobjects.com","s3_access_key": "abc1234","s3_secret_key": "def5678"}}`
-		fmt.Fprint(writer, response)
+
+	mux.HandleFunc("/v2/object-storage/1234", func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
+	})
+
+	err := client.ObjectStorage.Update(ctx, "1234", "s3 label")
+	if err != nil {
+		t.Errorf("ObjectStorage.Create returned %+v", err)
+	}
+}
+
+func TestObjectStorageServiceHandler_Delete(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/object-storage/1234", func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
 	})
 
-	options := &ObjectListOptions{
-		IncludeS3: false,
-		Label:     "label",
+	err := client.ObjectStorage.Delete(ctx, "1234")
+	if err != nil {
+		t.Errorf("ObjectStorage.Delete returned %+v", err)
 	}
-	s3s, err := client.ObjectStorage.List(ctx, options)
+}
 
+func TestObjectStorageServiceHandler_List(t *testing.T) {
+	setup()
+	defer teardown()
+	mux.HandleFunc("/v2/object-storage", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"object_storages":[{"id":"39240368","date_created":"2020-07-1414:22:38","cluster_id":2,"region":"ewr","label":"govultr","status":"active","s3_hostname":"ewr1.vultrobjects.com","s3_access_key":"n1234","s3_secret_key":"b1234"}],"meta":{"total":1,"links":{"next":"","prev":""}}}`
+		fmt.Fprint(writer, response)
+	})
+
+	s3s, meta, err := client.ObjectStorage.List(ctx, nil)
 	if err != nil {
 		t.Errorf("ObjectStorage.List returned %+v", err)
 	}
-	expected := []ObjectStorage{
+
+	expectedObject := []ObjectStorage{
 		{
-			ID:                   1314217,
-			DateCreated:          "2019-04-17 17:33:00",
-			ObjectStoreClusterID: 1,
-			RegionID:             1,
-			Location:             "New Jersey",
-			Label:                "object1",
+			ID:                   "39240368",
+			DateCreated:          "2020-07-1414:22:38",
+			ObjectStoreClusterID: 2,
+			Region:               "ewr",
+			Label:                "govultr",
 			Status:               "active",
 			S3Keys: S3Keys{
-				S3Hostname:  "nj1.vultrobjects.com",
-				S3AccessKey: "abc1234",
-				S3SecretKey: "def5678",
+				S3Hostname:  "ewr1.vultrobjects.com",
+				S3AccessKey: "n1234",
+				S3SecretKey: "b1234",
 			},
 		},
 	}
-	if !reflect.DeepEqual(s3s, expected) {
-		t.Errorf("ObjectStorage.List returned %+v, expected %+v", s3s, expected)
+
+	if !reflect.DeepEqual(s3s, expectedObject) {
+		t.Errorf("ObjectStorage.List object returned %+v, expected %+v", s3s, expectedObject)
+	}
+
+	expectedmeta := &Meta{
+		Total: 1,
+		Links: &Links{},
+	}
+
+	if !reflect.DeepEqual(meta, expectedmeta) {
+		t.Errorf("ObjectStorage.List meta object returned %+v, expected %+v", meta, expectedmeta)
 	}
 }
 
 func TestObjectStorageServiceHandler_ListCluster(t *testing.T) {
 	setup()
 	defer teardown()
-	mux.HandleFunc("/v1/objectstorage/list_cluster", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"1": {"OBJSTORECLUSTERID": 1,"DCID": 1,"location": "New Jersey","hostname": "nj1.vultrobjects.com","deploy": "yes"}}`
+	mux.HandleFunc("/v2/object-storage/clusters", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"clusters":[{"id":2,"region":"ewr","hostname":"ewr1.vultrobjects.com","deploy":"yes"}],"meta":{"total":1,"links":{"next":"","prev":""}}}`
 		fmt.Fprint(writer, response)
 	})
 
-	clusterList, err := client.ObjectStorage.ListCluster(ctx)
+	clusters, meta, err := client.ObjectStorage.ListCluster(ctx, nil)
 
 	if err != nil {
 		t.Errorf("ObjectStorage.ListCluster returned %+v", err)
@@ -131,54 +156,48 @@ func TestObjectStorageServiceHandler_ListCluster(t *testing.T) {
 
 	expected := []ObjectStorageCluster{
 		{
-			ObjectStoreClusterID: 1,
-			RegionID:             1,
-			Location:             "New Jersey",
-			Hostname:             "nj1.vultrobjects.com",
-			Deploy:               "yes",
+			ID:       2,
+			Region:   "ewr",
+			Hostname: "ewr1.vultrobjects.com",
+			Deploy:   "yes",
 		},
 	}
 
-	if !reflect.DeepEqual(clusterList, expected) {
-		t.Errorf("ObjectStorage.ListCluster returned %+v, expected %+v", clusterList, expected)
+	if !reflect.DeepEqual(clusters, expected) {
+		t.Errorf("ObjectStorage.ListCluster clusters returned %+v, expected %+v", clusters, expected)
+	}
+
+	expectedMeta := &Meta{
+		Total: 1,
+		Links: &Links{},
+	}
+
+	if !reflect.DeepEqual(meta, expectedMeta) {
+		t.Errorf("ObjectStorage.List meta object returned %+v, expected %+v", meta, expectedMeta)
 	}
 }
 
 func TestObjectStorageServiceHandler_RegenerateKeys(t *testing.T) {
 	setup()
 	defer teardown()
-	mux.HandleFunc("/v1/objectstorage/s3key_regenerate", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"s3_hostname": "nj1.vultrobjects.com","s3_access_key": "abc1236","s3_secret_key": "def5679"}`
+	mux.HandleFunc("/v2/object-storage/1234/regenerate-keys", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"s3_credentials":{"s3_hostname":"ewr1.vultrobjects.com","s3_access_key":"f1234","s3_secret_key":"g1234"}}`
 		fmt.Fprint(writer, response)
 	})
 
-	s3Keys, err := client.ObjectStorage.RegenerateKeys(ctx, 1234, "acv123")
+	s3Keys, err := client.ObjectStorage.RegenerateKeys(ctx, "1234")
 
 	if err != nil {
 		t.Errorf("ObjectStorage.RegenerateKeys returned %+v", err)
 	}
 
 	expected := &S3Keys{
-		S3Hostname:  "nj1.vultrobjects.com",
-		S3AccessKey: "abc1236",
-		S3SecretKey: "def5679",
+		S3Hostname:  "ewr1.vultrobjects.com",
+		S3AccessKey: "f1234",
+		S3SecretKey: "g1234",
 	}
 
 	if !reflect.DeepEqual(s3Keys, expected) {
 		t.Errorf("ObjectStorage.RegenerateKeys returned %+v, expected %+v", s3Keys, expected)
 	}
 }
-
-func TestObjectStorageServiceHandler_SetLabel(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/objectstorage/label_set", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.ObjectStorage.SetLabel(ctx, 1, "s3 label")
-	if err != nil {
-		t.Errorf("ObjectStorage.Create returned %+v", err)
-	}
-}
diff --git a/os.go b/os.go
index 933ddaf..7c59609 100644
--- a/os.go
+++ b/os.go
@@ -2,16 +2,15 @@ package govultr
 
 import (
 	"context"
-	"encoding/json"
-	"fmt"
 	"net/http"
-	"strconv"
+
+	"github.com/google/go-querystring/query"
 )
 
 // OSService is the interface to interact with the operating system endpoint on the Vultr API
-// Link: https://www.vultr.com/api/#os
+// Link : https://www.vultr.com/api/#tag/os
 type OSService interface {
-	List(ctx context.Context) ([]OS, error)
+	List(ctx context.Context, options *ListOptions) ([]OS, *Meta, error)
 }
 
 // OSServiceHandler handles interaction with the operating system methods for the Vultr API
@@ -21,64 +20,37 @@ type OSServiceHandler struct {
 
 // OS represents a Vultr operating system
 type OS struct {
-	OsID    int    `json:"OSID"`
-	Name    string `json:"name"`
-	Arch    string `json:"arch"`
-	Family  string `json:"family"`
-	Windows bool   `json:"windows"`
+	ID     int    `json:"id"`
+	Name   string `json:"name"`
+	Arch   string `json:"arch"`
+	Family string `json:"family"`
 }
 
-// UnmarshalJSON implements json.Unmarshaller on OS to handle the inconsistent types returned from the Vultr API.
-func (o *OS) UnmarshalJSON(data []byte) (err error) {
-	if o == nil {
-		*o = OS{}
-	}
-
-	var v map[string]interface{}
-	if err := json.Unmarshal(data, &v); err != nil {
-		return err
-	}
-
-	i, err := strconv.Atoi(fmt.Sprintf("%v", v["OSID"]))
-	if err != nil {
-		return err
-	}
-	o.OsID = i
-
-	value := fmt.Sprintf("%v", v["windows"])
-	o.Windows = false
-	if value == "true" {
-		o.Windows = true
-	}
-
-	o.Name = fmt.Sprintf("%v", v["name"])
-	o.Arch = fmt.Sprintf("%v", v["arch"])
-	o.Family = fmt.Sprintf("%v", v["family"])
-
-	return nil
+type osBase struct {
+	OS   []OS  `json:"os"`
+	Meta *Meta `json:"meta"`
 }
 
+var _ OSService = &OSServiceHandler{}
+
 // List retrieves a list of available operating systems.
-// If the Windows flag is true, a Windows license will be included with the instance, which will increase the cost.
-func (o *OSServiceHandler) List(ctx context.Context) ([]OS, error) {
-	uri := "/v1/os/list"
+func (o *OSServiceHandler) List(ctx context.Context, options *ListOptions) ([]OS, *Meta, error) {
+	uri := "/v2/os"
 	req, err := o.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	osMap := make(map[string]OS)
-
-	err = o.client.DoWithContext(ctx, req, &osMap)
+	newValues, err := query.Values(options)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
+	req.URL.RawQuery = newValues.Encode()
 
-	var oses []OS
-	for _, os := range osMap {
-		oses = append(oses, os)
+	os := new(osBase)
+	if err = o.client.DoWithContext(ctx, req, os); err != nil {
+		return nil, nil, err
 	}
 
-	return oses, nil
+	return os.OS, os.Meta, nil
 }
diff --git a/os_test.go b/os_test.go
index e34564c..9a470ac 100644
--- a/os_test.go
+++ b/os_test.go
@@ -11,103 +11,34 @@ func TestOSServiceHandler_List(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/os/list", func(w http.ResponseWriter, r *http.Request) {
-
-		response := `
-		{
-			"127": {
-				"OSID": 127,
-				"name": "CentOS 6 x64",
-				"arch": "x64",
-				"family": "centos",
-				"windows": false
-			}
-		}
-		`
-
-		fmt.Fprint(w, response)
-	})
-
-	apps, err := client.OS.List(ctx)
-	if err != nil {
-		t.Errorf("OS.List returned error: %v", err)
-	}
-
-	expected := []OS{
-		{
-			OsID:    127,
-			Name:    "CentOS 6 x64",
-			Arch:    "x64",
-			Family:  "centos",
-			Windows: false,
-		},
-	}
-
-	if !reflect.DeepEqual(apps, expected) {
-		t.Errorf("OS.List returned %+v, expected %+v", apps, expected)
-	}
-}
-
-func TestOSServiceHandler_List_StringIDs(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/os/list", func(w http.ResponseWriter, r *http.Request) {
-
-		response := `
-		{
-			"127": {
-				"OSID": 127,
-				"name": "CentOS 6 x64",
-				"arch": "x64",
-				"family": "centos",
-				"windows": false
-			}
-		}
-		`
-
+	mux.HandleFunc("/v2/os", func(w http.ResponseWriter, r *http.Request) {
+		response := `{"os":[{"id":124,"name":"Windows 2012 R2 x64","arch":"x64","family":"windows"}],"meta":{"total":27,"links":{"next":"","prev":""}}}`
 		fmt.Fprint(w, response)
 	})
 
-	apps, err := client.OS.List(ctx)
+	os, meta, err := client.OS.List(ctx, nil)
 	if err != nil {
 		t.Errorf("OS.List returned error: %v", err)
 	}
 
-	expected := []OS{
+	expectedOS := []OS{
 		{
-			OsID:    127,
-			Name:    "CentOS 6 x64",
-			Arch:    "x64",
-			Family:  "centos",
-			Windows: false,
+			ID:     124,
+			Name:   "Windows 2012 R2 x64",
+			Arch:   "x64",
+			Family: "windows",
 		},
 	}
-
-	if !reflect.DeepEqual(apps, expected) {
-		t.Errorf("OS.List returned %+v, expected %+v", apps, expected)
+	expectedMeta := &Meta{
+		Total: 27,
+		Links: &Links{},
 	}
-}
-
-func TestOSServiceHandler_ListEmpty(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/os/list", func(w http.ResponseWriter, r *http.Request) {
-
-		response := `[]`
 
-		fmt.Fprint(w, response)
-	})
-
-	apps, err := client.OS.List(ctx)
-	if err != nil {
-		t.Errorf("OS.List returned error: %v", err)
+	if !reflect.DeepEqual(os, expectedOS) {
+		t.Errorf("OS.List os returned %+v, expected %+v", os, expectedOS)
 	}
 
-	var expected []OS
-
-	if !reflect.DeepEqual(apps, expected) {
-		t.Errorf("OS.List returned %+v, expected %+v", apps, expected)
+	if !reflect.DeepEqual(meta, expectedMeta) {
+		t.Errorf("OS.List meta returned %+v, expected %+v", meta, expectedMeta)
 	}
 }
diff --git a/plans.go b/plans.go
index 75287d5..66abfde 100644
--- a/plans.go
+++ b/plans.go
@@ -3,197 +3,109 @@ package govultr
 import (
 	"context"
 	"net/http"
+
+	"github.com/google/go-querystring/query"
 )
 
 // PlanService is the interface to interact with the Plans endpoints on the Vultr API
-// Link: https://www.vultr.com/api/#plans
+// Link : https://www.vultr.com/api/#tag/plans
 type PlanService interface {
-	List(ctx context.Context, planType string) ([]Plan, error)
-	GetBareMetalList(ctx context.Context) ([]BareMetalPlan, error)
-	GetVc2List(ctx context.Context) ([]VCPlan, error)
-	GetVdc2List(ctx context.Context) ([]VCPlan, error)
-	GetVc2zList(ctx context.Context) ([]VCPlan, error)
+	List(ctx context.Context, planType string, options *ListOptions) ([]Plan, *Meta, error)
+	ListBareMetal(ctx context.Context, options *ListOptions) ([]BareMetalPlan, *Meta, error)
 }
 
 // PlanServiceHandler handles interaction with the Plans methods for the Vultr API
 type PlanServiceHandler struct {
-	Client *Client
-}
-
-// Plan represents available Plans that Vultr offers
-type Plan struct {
-	PlanID      int    `json:"VPSPLANID,string"`
-	Name        string `json:"name"`
-	VCPUs       int    `json:"vcpu_count,string"`
-	RAM         string `json:"ram"`
-	Disk        string `json:"disk"`
-	Bandwidth   string `json:"bandwidth"`
-	BandwidthGB string `json:"bandwidth_gb"`
-	Price       string `json:"price_per_month"`
-	Windows     bool   `json:"windows"`
-	PlanType    string `json:"plan_type"`
-	Regions     []int  `json:"available_locations"`
-	Deprecated  bool   `json:"deprecated"`
+	client *Client
 }
 
 // BareMetalPlan represents bare metal plans
 type BareMetalPlan struct {
-	PlanID      string `json:"METALPLANID"`
-	Name        string `json:"name"`
-	CPUs        int    `json:"cpu_count"`
-	CPUModel    string `json:"cpu_model"`
-	RAM         int    `json:"ram"`
-	Disk        string `json:"disk"`
-	BandwidthTB int    `json:"bandwidth_tb"`
-	Price       int    `json:"price_per_month"`
-	PlanType    string `json:"plan_type"`
-	Deprecated  bool   `json:"deprecated"`
-	Regions     []int  `json:"available_locations"`
+	ID          string   `json:"id"`
+	CPUCount    int      `json:"cpu_count"`
+	CPUModel    string   `json:"cpu_model"`
+	CPUThreads  int      `json:"cpu_threads"`
+	RAM         int      `json:"ram"`
+	Disk        int      `json:"disk"`
+	DiskCount   int      `json:"disk_count"`
+	Bandwidth   int      `json:"bandwidth"`
+	MonthlyCost float32  `json:"monthly_cost"`
+	Type        string   `json:"type"`
+	Locations   []string `json:"locations"`
 }
 
-// VCPlan represents either a vdc2 or a vc2 plan
-type VCPlan struct {
-	PlanID      string `json:"VPSPLANID"`
-	Name        string `json:"name"`
-	VCPUs       string `json:"vcpu_count"`
-	RAM         string `json:"ram"`
-	Disk        string `json:"disk"`
-	Bandwidth   string `json:"bandwidth"`
-	BandwidthGB string `json:"bandwidth_gb"`
-	Price       string `json:"price_per_month"`
-	PlanType    string `json:"plan_type"`
+// Plan represents vc2, vdc, or vhf
+type Plan struct {
+	ID          string   `json:"id"`
+	VCPUCount   int      `json:"vcpu_count"`
+	RAM         int      `json:"ram"`
+	Disk        int      `json:"disk"`
+	DiskCount   int      `json:"disk_count"`
+	Bandwidth   int      `json:"bandwidth"`
+	MonthlyCost float32  `json:"monthly_cost"`
+	Type        string   `json:"type"`
+	Locations   []string `json:"locations"`
 }
 
-// List retrieves a list of all active plans.
-// planType is optional - pass an empty string to get all plans
-func (p *PlanServiceHandler) List(ctx context.Context, planType string) ([]Plan, error) {
-
-	uri := "/v1/plans/list"
-
-	req, err := p.Client.NewRequest(ctx, http.MethodGet, uri, nil)
-
-	if err != nil {
-		return nil, err
-	}
-
-	if planType != "" {
-		q := req.URL.Query()
-		q.Add("type", planType)
-		req.URL.RawQuery = q.Encode()
-	}
-
-	var planMap map[string]Plan
-	err = p.Client.DoWithContext(ctx, req, &planMap)
-
-	if err != nil {
-		return nil, err
-	}
-
-	var plans []Plan
-	for _, p := range planMap {
-		plans = append(plans, p)
-	}
-
-	return plans, nil
+type plansBase struct {
+	Plans []Plan `json:"plans"`
+	Meta  *Meta  `json:"meta"`
 }
 
-// GetBareMetalList retrieves a list of all active bare metal plans.
-func (p *PlanServiceHandler) GetBareMetalList(ctx context.Context) ([]BareMetalPlan, error) {
-
-	uri := "/v1/plans/list_baremetal"
-
-	req, err := p.Client.NewRequest(ctx, http.MethodGet, uri, nil)
-
-	if err != nil {
-		return nil, err
-	}
-
-	var bareMetalMap map[string]BareMetalPlan
-	err = p.Client.DoWithContext(ctx, req, &bareMetalMap)
-
-	if err != nil {
-		return nil, err
-	}
-
-	var bareMetalPlan []BareMetalPlan
-	for _, b := range bareMetalMap {
-		bareMetalPlan = append(bareMetalPlan, b)
-	}
-
-	return bareMetalPlan, nil
+type bareMetalPlansBase struct {
+	Plans []BareMetalPlan `json:"plans_metal"`
+	Meta  *Meta           `json:"meta"`
 }
 
-// GetVc2List retrieve a list of all active vc2 plans.
-func (p *PlanServiceHandler) GetVc2List(ctx context.Context) ([]VCPlan, error) {
-	uri := "/v1/plans/list_vc2"
-
-	req, err := p.Client.NewRequest(ctx, http.MethodGet, uri, nil)
+// List retrieves a list of all active plans.
+// planType is optional - pass an empty string to get all plans
+func (p *PlanServiceHandler) List(ctx context.Context, planType string, options *ListOptions) ([]Plan, *Meta, error) {
+	uri := "/v2/plans"
 
+	req, err := p.client.NewRequest(ctx, http.MethodGet, uri, nil)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	var vc2Plan map[string]VCPlan
-	err = p.Client.DoWithContext(ctx, req, &vc2Plan)
-
+	newValues, err := query.Values(options)
 	if err != nil {
-		return nil, err
-	}
-
-	var vc2 []VCPlan
-	for _, p := range vc2Plan {
-		vc2 = append(vc2, p)
+		return nil, nil, err
 	}
 
-	return vc2, nil
-}
-
-// GetVdc2List Retrieve a list of all active vdc2 plans
-func (p *PlanServiceHandler) GetVdc2List(ctx context.Context) ([]VCPlan, error) {
-	uri := "/v1/plans/list_vdc2"
-
-	req, err := p.Client.NewRequest(ctx, http.MethodGet, uri, nil)
-
-	if err != nil {
-		return nil, err
+	if planType != "" {
+		newValues.Add("type", planType)
 	}
 
-	var vdc2Map map[string]VCPlan
-	err = p.Client.DoWithContext(ctx, req, &vdc2Map)
+	req.URL.RawQuery = newValues.Encode()
 
-	if err != nil {
-		return nil, err
-	}
-
-	var vdc2 []VCPlan
-	for _, p := range vdc2Map {
-		vdc2 = append(vdc2, p)
+	plans := new(plansBase)
+	if err = p.client.DoWithContext(ctx, req, plans); err != nil {
+		return nil, nil, err
 	}
 
-	return vdc2, nil
+	return plans.Plans, plans.Meta, nil
 }
 
-// GetVc2zList Retrieve a list of all active vc2z plans (high frequency)
-func (p *PlanServiceHandler) GetVc2zList(ctx context.Context) ([]VCPlan, error) {
-	uri := "/v1/plans/list_vc2z"
-
-	req, err := p.Client.NewRequest(ctx, http.MethodGet, uri, nil)
+// ListBareMetal all active bare metal plans.
+func (p *PlanServiceHandler) ListBareMetal(ctx context.Context, options *ListOptions) ([]BareMetalPlan, *Meta, error) {
+	uri := "/v2/plans-metal"
 
+	req, err := p.client.NewRequest(ctx, http.MethodGet, uri, nil)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	var vc2zMap map[string]VCPlan
-	err = p.Client.DoWithContext(ctx, req, &vc2zMap)
-
+	newValues, err := query.Values(options)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	var vc2z []VCPlan
-	for _, p := range vc2zMap {
-		vc2z = append(vc2z, p)
+	req.URL.RawQuery = newValues.Encode()
+
+	bmPlans := new(bareMetalPlansBase)
+	if err = p.client.DoWithContext(ctx, req, bmPlans); err != nil {
+		return nil, nil, err
 	}
 
-	return vc2z, nil
+	return bmPlans.Plans, bmPlans.Meta, nil
 }
diff --git a/plans_test.go b/plans_test.go
index 6e06fe1..d78b614 100644
--- a/plans_test.go
+++ b/plans_test.go
@@ -11,168 +11,87 @@ func TestPlanServiceHandler_List(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/plans/list", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"201": {"VPSPLANID": "201","name": "1024 MB RAM,25 GB SSD,1.00 TB BW","vcpu_count": "1","ram": "1024","disk": "25","bandwidth": "1.00","bandwidth_gb": "1024","price_per_month": "5.00","plan_type": "SSD","windows": false,"available_locations": [1,2,3,4,5,6]}}`
+	mux.HandleFunc("/v2/plans", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{ "plans":[{ "id": "vc2-16c-64gb", "vcpu_count": 16, "ram": 65536, "disk": 1280, "disk_count": 1, "bandwidth": 10240, "monthly_cost": 320, "type": "vc2", "locations": [  "dfw"]}], "meta": { "total": 19, "links": { "next": "", "prev": "" } }}`
 		fmt.Fprint(writer, response)
 	})
 
-	plans, err := client.Plan.List(ctx, "vc2")
-
+	plans, meta, err := client.Plan.List(ctx, "vc2", nil)
 	if err != nil {
 		t.Errorf("Plan.List returned %+v", err)
 	}
 
-	expected := []Plan{{
-		PlanID:      201,
-		Name:        "1024 MB RAM,25 GB SSD,1.00 TB BW",
-		VCPUs:       1,
-		RAM:         "1024",
-		Disk:        "25",
-		Price:       "5.00",
-		Bandwidth:   "1.00",
-		BandwidthGB: "1024",
-		Windows:     false,
-		PlanType:    "SSD",
-		Regions:     []int{1, 2, 3, 4, 5, 6},
-	},
-	}
-
-	if !reflect.DeepEqual(plans, expected) {
-		t.Errorf("Plan.List  returned %+v, expected %+v", plans, expected)
-	}
-}
-
-func TestPlanServiceHandler_GetBareMetalList(t *testing.T) {
-	setup()
-	defer teardown()
-	mux.HandleFunc("/v1/plans/list_baremetal", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"99": {"METALPLANID": "99","name": "32768 MB RAM,4x 240 GB SSD,1.00 TB BW","cpu_count": 12,"cpu_model": "E-2186G","ram": 32768,"disk": "4x 240 GB SSD","bandwidth_tb": 1,"price_per_month": 600,"plan_type": "SSD","deprecated": false,"available_locations": [1]}}`
-		fmt.Fprint(writer, response)
-	})
-
-	bareMetalPlans, err := client.Plan.GetBareMetalList(ctx)
-
-	if err != nil {
-		t.Errorf("Plan.GetBareMetalList returned %+v", err)
-	}
-
-	expected := []BareMetalPlan{
+	expectedPlan := []Plan{
 		{
-			PlanID:      "99",
-			Name:        "32768 MB RAM,4x 240 GB SSD,1.00 TB BW",
-			CPUs:        12,
-			CPUModel:    "E-2186G",
-			RAM:         32768,
-			Disk:        "4x 240 GB SSD",
-			BandwidthTB: 1,
-			Price:       600,
-			PlanType:    "SSD",
-			Deprecated:  false,
-			Regions:     []int{1},
+			ID:          "vc2-16c-64gb",
+			VCPUCount:   16,
+			RAM:         65536,
+			Disk:        1280,
+			DiskCount:   1,
+			Bandwidth:   10240,
+			MonthlyCost: 320.00,
+			Type:        "vc2",
+			Locations: []string{
+				"dfw",
+			},
 		},
 	}
 
-	if !reflect.DeepEqual(bareMetalPlans, expected) {
-		t.Errorf("Plan.GetBareMetalList  returned %+v, expected %+v", bareMetalPlans, expected)
+	expectedMeta := &Meta{
+		Total: 19,
+		Links: &Links{},
 	}
-}
-
-func TestPlanServiceHandler_GetVc2List(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/plans/list_vc2", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"201": {"VPSPLANID": "201","name": "1024 MB RAM,25 GB SSD,1.00 TB BW","vcpu_count": "1","ram": "1024","disk": "25","bandwidth": "1.00","bandwidth_gb": "1024","price_per_month": "5.00","plan_type": "SSD"}}`
-		fmt.Fprint(writer, response)
-	})
-
-	vc2, err := client.Plan.GetVc2List(ctx)
 
-	if err != nil {
-		t.Errorf("Plan.GetVc2List returned %+v", err)
+	if !reflect.DeepEqual(plans, expectedPlan) {
+		t.Errorf("Plan.List  plans returned %+v, expected %+v", plans, expectedPlan)
 	}
 
-	expected := []VCPlan{
-		{
-			PlanID:      "201",
-			Name:        "1024 MB RAM,25 GB SSD,1.00 TB BW",
-			VCPUs:       "1",
-			RAM:         "1024",
-			Disk:        "25",
-			Bandwidth:   "1.00",
-			BandwidthGB: "1024",
-			Price:       "5.00",
-			PlanType:    "SSD",
-		},
-	}
-	if !reflect.DeepEqual(vc2, expected) {
-		t.Errorf("Plan.GetVc2List  returned %+v, expected %+v", vc2, expected)
+	if !reflect.DeepEqual(meta, expectedMeta) {
+		t.Errorf("Plan.List  meta returned %+v, expected %+v", meta, expectedMeta)
 	}
 }
 
-func TestPlanServiceHandler_GetVdc2List(t *testing.T) {
+func TestPlanServiceHandler_GetBareMetalList(t *testing.T) {
 	setup()
 	defer teardown()
-
-	mux.HandleFunc("/v1/plans/list_vdc2", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"115": {"VPSPLANID": "115","name": "8192 MB RAM,110 GB SSD,10.00 TB BW","vcpu_count": "2","ram": "8192","disk": "110","bandwidth": "10.00","bandwidth_gb": "10240","price_per_month": "60.00","plan_type": "DEDICATED"}}`
+	mux.HandleFunc("/v2/plans-metal", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{ "plans_metal":[{"id": "vbm-4c-32gb","cpu_count": 4,"cpu_threads": 8,"cpu_model": "E3-1270v6","ram": 32768,"disk": 240, "disk_count": 1, "bandwidth": 5120,"monthly_cost": 300,"type": "SSD", "locations": [ "dwf"]}], "meta": { "total": 19, "links": { "next": "", "prev": "" } }}`
 		fmt.Fprint(writer, response)
 	})
 
-	vdc2, err := client.Plan.GetVdc2List(ctx)
-
+	bareMetalPlans, meta, err := client.Plan.ListBareMetal(ctx, nil)
 	if err != nil {
-		t.Errorf("Plan.GetVdc2List returned %+v", err)
+		t.Errorf("Plan.GetBareMetalList returned %+v", err)
 	}
 
-	expected := []VCPlan{
+	expectedPlan := []BareMetalPlan{
 		{
-			PlanID:      "115",
-			Name:        "8192 MB RAM,110 GB SSD,10.00 TB BW",
-			VCPUs:       "2",
-			RAM:         "8192",
-			Disk:        "110",
-			Bandwidth:   "10.00",
-			BandwidthGB: "10240",
-			Price:       "60.00",
-			PlanType:    "DEDICATED",
+			ID:          "vbm-4c-32gb",
+			CPUCount:    4,
+			CPUModel:    "E3-1270v6",
+			CPUThreads:  8,
+			RAM:         32768,
+			Disk:        240,
+			DiskCount:   1,
+			Bandwidth:   5120,
+			MonthlyCost: 300,
+			Type:        "SSD",
+			Locations: []string{
+				"dwf",
+			},
 		},
 	}
 
-	if !reflect.DeepEqual(vdc2, expected) {
-		t.Errorf("Plan.GetVdc2List  returned %+v, expected %+v", vdc2, expected)
-	}
-}
-
-func TestPlanServiceHandler_GetVc2zList(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/plans/list_vc2z", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{ "401": {"VPSPLANID": "401","name": "2048 MB RAM,64 GB SSD,2.00 TB BW","vcpu_count": "1","ram": "2048","disk": "64","bandwidth": "2.00","price_per_month": "12.00","plan_type": "HIGHFREQUENCY"}}`
-		fmt.Fprint(writer, response)
-	})
-
-	vc2z, err := client.Plan.GetVc2zList(ctx)
-
-	if err != nil {
-		t.Errorf("Plan.GetVc2zList returned %+v", err)
+	expectedMeta := &Meta{
+		Total: 19,
+		Links: &Links{},
 	}
 
-	expected := []VCPlan{
-		{
-			PlanID:    "401",
-			Name:      "2048 MB RAM,64 GB SSD,2.00 TB BW",
-			VCPUs:     "1",
-			RAM:       "2048",
-			Disk:      "64",
-			Bandwidth: "2.00",
-			Price:     "12.00",
-			PlanType:  "HIGHFREQUENCY",
-		},
+	if !reflect.DeepEqual(bareMetalPlans, expectedPlan) {
+		t.Errorf("Plan.GetBareMetalList  returned %+v, expected %+v", bareMetalPlans, expectedPlan)
 	}
 
-	if !reflect.DeepEqual(vc2z, expected) {
-		t.Errorf("Plan.GetVc2zList  returned %+v, expected %+v", vc2z, expected)
+	if !reflect.DeepEqual(meta, expectedMeta) {
+		t.Errorf("Plan.List  meta returned %+v, expected %+v", meta, expectedMeta)
 	}
 }
diff --git a/regions.go b/regions.go
index cfdbbeb..bcc0cad 100644
--- a/regions.go
+++ b/regions.go
@@ -2,153 +2,90 @@ package govultr
 
 import (
 	"context"
+	"fmt"
 	"net/http"
-	"strconv"
+
+	"github.com/google/go-querystring/query"
 )
 
 // RegionService is the interface to interact with Region endpoints on the Vultr API
-// Link: https://www.vultr.com/api/#regions
+// Link : https://www.vultr.com/api/#tag/region
 type RegionService interface {
-	Availability(ctx context.Context, regionID int, planType string) ([]int, error)
-	BareMetalAvailability(ctx context.Context, regionID int) ([]int, error)
-	Vc2Availability(ctx context.Context, regionID int) ([]int, error)
-	Vdc2Availability(ctx context.Context, regionID int) ([]int, error)
-	List(ctx context.Context) ([]Region, error)
+	Availability(ctx context.Context, regionID string, planType string) (*PlanAvailability, error)
+	List(ctx context.Context, options *ListOptions) ([]Region, *Meta, error)
 }
 
+var _ RegionService = &RegionServiceHandler{}
+
 // RegionServiceHandler handles interaction with the region methods for the Vultr API
 type RegionServiceHandler struct {
-	Client *Client
+	client *Client
 }
 
 // Region represents a Vultr region
 type Region struct {
-	RegionID     string `json:"DCID"`
-	Name         string `json:"name"`
-	Country      string `json:"country"`
-	Continent    string `json:"continent"`
-	State        string `json:"state"`
-	Ddos         bool   `json:"ddos_protection"`
-	BlockStorage bool   `json:"block_storage"`
-	RegionCode   string `json:"regioncode"`
+	ID        string   `json:"id"`
+	City      string   `json:"city"`
+	Country   string   `json:"country"`
+	Continent string   `json:"continent,omitempty"`
+	Options   []string `json:"options"`
 }
 
-// Availability retrieves a list of the VPSPLANIDs currently available for a given location.
-func (r *RegionServiceHandler) Availability(ctx context.Context, regionID int, planType string) ([]int, error) {
-
-	uri := "/v1/regions/availability"
-
-	req, err := r.Client.NewRequest(ctx, http.MethodGet, uri, nil)
-
-	if err != nil {
-		return nil, err
-	}
-
-	q := req.URL.Query()
-	q.Add("DCID", strconv.Itoa(regionID))
-
-	// Optional planType filter
-	if planType != "" {
-		q.Add("type", planType)
-	}
-	req.URL.RawQuery = q.Encode()
-
-	var regions []int
-	err = r.Client.DoWithContext(ctx, req, &regions)
-
-	if err != nil {
-		return nil, err
-	}
-
-	return regions, nil
+type regionBase struct {
+	Regions []Region `json:"regions"`
+	Meta    *Meta
 }
 
-// BareMetalAvailability retrieve a list of the METALPLANIDs currently available for a given location.
-func (r *RegionServiceHandler) BareMetalAvailability(ctx context.Context, regionID int) ([]int, error) {
-
-	uri := "/v1/regions/availability_baremetal"
+// PlanAvailability contains all available plans.
+type PlanAvailability struct {
+	AvailablePlans []string `json:"available_plans"`
+}
 
-	regions, err := r.instanceAvailability(ctx, uri, regionID)
+// List returns all available regions
+func (r *RegionServiceHandler) List(ctx context.Context, options *ListOptions) ([]Region, *Meta, error) {
+	uri := "/v2/regions"
 
+	req, err := r.client.NewRequest(ctx, http.MethodGet, uri, nil)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	return regions, nil
-}
-
-// Vc2Availability retrieve a list of the vc2 VPSPLANIDs currently available for a given location.
-func (r *RegionServiceHandler) Vc2Availability(ctx context.Context, regionID int) ([]int, error) {
-
-	uri := "/v1/regions/availability_vc2"
-
-	regions, err := r.instanceAvailability(ctx, uri, regionID)
-
+	newValues, err := query.Values(options)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	return regions, nil
-}
-
-// Vdc2Availability retrieves a list of the vdc2 VPSPLANIDs currently available for a given location.
-func (r *RegionServiceHandler) Vdc2Availability(ctx context.Context, regionID int) ([]int, error) {
+	req.URL.RawQuery = newValues.Encode()
 
-	uri := "/v1/regions/availability_vdc2"
-
-	regions, err := r.instanceAvailability(ctx, uri, regionID)
-
-	if err != nil {
-		return nil, err
+	regions := new(regionBase)
+	if err = r.client.DoWithContext(ctx, req, &regions); err != nil {
+		return nil, nil, err
 	}
 
-	return regions, nil
+	return regions.Regions, regions.Meta, nil
 }
 
-// List retrieves a list of all active regions
-func (r *RegionServiceHandler) List(ctx context.Context) ([]Region, error) {
-
-	uri := "/v1/regions/list"
-
-	req, err := r.Client.NewRequest(ctx, http.MethodGet, uri, nil)
-
-	if err != nil {
-		return nil, err
-	}
+// Availability retrieves a list of the plan IDs currently available for a given location.
+func (r *RegionServiceHandler) Availability(ctx context.Context, regionID string, planType string) (*PlanAvailability, error) {
+	uri := fmt.Sprintf("/v2/regions/%s/availability", regionID)
 
-	var regionsMap map[string]Region
-	err = r.Client.DoWithContext(ctx, req, &regionsMap)
+	req, err := r.client.NewRequest(ctx, http.MethodGet, uri, nil)
 
 	if err != nil {
 		return nil, err
 	}
 
-	var region []Region
-	for _, r := range regionsMap {
-		region = append(region, r)
-	}
-
-	return region, nil
-}
-
-// instanceAvailability keeps the similar calls dry
-func (r *RegionServiceHandler) instanceAvailability(ctx context.Context, uri string, regionID int) ([]int, error) {
-	req, err := r.Client.NewRequest(ctx, http.MethodGet, uri, nil)
-
-	if err != nil {
-		return nil, err
+	// Optional planType filter
+	if planType != "" {
+		q := req.URL.Query()
+		q.Add("type", planType)
+		req.URL.RawQuery = q.Encode()
 	}
 
-	q := req.URL.Query()
-	q.Add("DCID", strconv.Itoa(regionID))
-	req.URL.RawQuery = q.Encode()
-
-	var regions []int
-	err = r.Client.DoWithContext(ctx, req, &regions)
-
-	if err != nil {
+	plans := new(PlanAvailability)
+	if err = r.client.DoWithContext(ctx, req, plans); err != nil {
 		return nil, err
 	}
 
-	return regions, nil
+	return plans, nil
 }
diff --git a/regions_test.go b/regions_test.go
index 62a896e..4688552 100644
--- a/regions_test.go
+++ b/regions_test.go
@@ -7,133 +7,62 @@ import (
 	"testing"
 )
 
-func TestRegionServiceHandler_Availability(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/regions/availability", func(writer http.ResponseWriter, request *http.Request) {
-		response := `[201,202,203,204,205,206,115,29,93,94,95,96,97,98,100]`
-		fmt.Fprint(writer, response)
-	})
-
-	region, err := client.Region.Availability(ctx, 1, "vc2")
-
-	if err != nil {
-		t.Errorf("Region.Availability returned error: %v", err)
-	}
-
-	expected := []int{201, 202, 203, 204, 205, 206, 115, 29, 93, 94, 95, 96, 97, 98, 100}
-
-	if !reflect.DeepEqual(region, expected) {
-		t.Errorf("Region.Availability returned %+v, expected %+v", region, expected)
-	}
-}
-
-func TestRegionServiceHandler_BareMetalAvailability(t *testing.T) {
+func TestRegionServiceHandler_List(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/regions/availability_baremetal", func(writer http.ResponseWriter, request *http.Request) {
-		response := `[1,2,3,4]`
+	mux.HandleFunc("/v2/regions", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"regions":[{"id":"ams","city": "test", "country":"NL","continent":"Europe","options":["ddos_protection"]}],"meta":{"total":1,"links":{"next":"","prev":""}}}`
 		fmt.Fprint(writer, response)
 	})
 
-	region, err := client.Region.BareMetalAvailability(ctx, 1)
+	region, meta, err := client.Region.List(ctx, nil)
 
 	if err != nil {
-		t.Errorf("Region.BareMetalAvailability returned error: %v", err)
-	}
-
-	expected := []int{1, 2, 3, 4}
-
-	if !reflect.DeepEqual(region, expected) {
-		t.Errorf("Region.BareMetalAvailability returned %+v, expected %+v", region, expected)
+		t.Errorf("Region.List returned error: %v", err)
 	}
-}
 
-func TestRegionServiceHandler_Vc2Availability(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/regions/availability_vc2", func(writer http.ResponseWriter, request *http.Request) {
-		response := `[115,29,93,94,95,96,97,98,100]`
-		fmt.Fprint(writer, response)
-	})
-
-	region, err := client.Region.Vc2Availability(ctx, 1)
-
-	if err != nil {
-		t.Errorf("Region.Vc2Availability returned error: %v", err)
+	expectedRegion := []Region{
+		{
+			ID:        "ams",
+			City:      "test",
+			Country:   "NL",
+			Continent: "Europe",
+			Options:   []string{"ddos_protection"},
+		},
 	}
 
-	expected := []int{115, 29, 93, 94, 95, 96, 97, 98, 100}
-
-	if !reflect.DeepEqual(region, expected) {
-		t.Errorf("Region.Vc2Availability returned %+v, expected %+v", region, expected)
+	expectedMeta := &Meta{
+		Total: 1,
+		Links: &Links{},
 	}
-}
-
-func TestRegionServiceHandler_Vdc2Availability(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/regions/availability_vdc2", func(writer http.ResponseWriter, request *http.Request) {
-		response := `[115,29,93,94]`
-		fmt.Fprint(writer, response)
-	})
-
-	region, err := client.Region.Vdc2Availability(ctx, 1)
 
-	if err != nil {
-		t.Errorf("Region.Vdc2Availability returned error: %v", err)
+	if !reflect.DeepEqual(region, expectedRegion) {
+		t.Errorf("Region.List region returned %+v, expected %+v", region, expectedRegion)
 	}
 
-	expected := []int{115, 29, 93, 94}
-
-	if !reflect.DeepEqual(region, expected) {
-		t.Errorf("Region.Vdc2Availability returned %+v, expected %+v", region, expected)
+	if !reflect.DeepEqual(meta, expectedMeta) {
+		t.Errorf("Region.List meta returned %+v, expected %+v", meta, expectedMeta)
 	}
 }
 
-func TestRegionServiceHandler_List(t *testing.T) {
+func TestRegionServiceHandler_Availability(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/regions/list", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"1": {"DCID": "1","name": "New Jersey","country": "US","continent": "North America","state": "NJ","ddos_protection": true,"block_storage": true,"regioncode": "EWR"},"2": {"DCID": "1","name": "New Jersey","country": "US","continent": "North America","state": "NJ","ddos_protection": true,"block_storage": true,"regioncode": "EWR"}}`
+	mux.HandleFunc("/v2/regions/ewr/availability", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"available_plans":["vc2-1c-1gb","vc2-1c-2gb","vc2-2c-4gb"]}`
 		fmt.Fprint(writer, response)
 	})
 
-	region, err := client.Region.List(ctx)
+	region, err := client.Region.Availability(ctx, "ewr", "")
 
 	if err != nil {
-		t.Errorf("Region.List returned error: %v", err)
-	}
-
-	expected := []Region{
-		{
-			RegionID:     "1",
-			Name:         "New Jersey",
-			Country:      "US",
-			Continent:    "North America",
-			State:        "NJ",
-			Ddos:         true,
-			BlockStorage: true,
-			RegionCode:   "EWR",
-		},
-		{
-			RegionID:     "1",
-			Name:         "New Jersey",
-			Country:      "US",
-			Continent:    "North America",
-			State:        "NJ",
-			Ddos:         true,
-			BlockStorage: true,
-			RegionCode:   "EWR",
-		},
+		t.Errorf("Region.Availability returned error: %v", err)
 	}
 
+	expected := &PlanAvailability{AvailablePlans: []string{"vc2-1c-1gb", "vc2-1c-2gb", "vc2-2c-4gb"}}
 	if !reflect.DeepEqual(region, expected) {
-		t.Errorf("Region.List returned %+v, expected %+v", region, expected)
+		t.Errorf("Region.Availability returned %+v, expected %+v", region, expected)
 	}
 }
diff --git a/reserved_ip.go b/reserved_ip.go
index ee9335c..18c43ba 100644
--- a/reserved_ip.go
+++ b/reserved_ip.go
@@ -2,22 +2,25 @@ package govultr
 
 import (
 	"context"
-	"encoding/json"
 	"fmt"
 	"net/http"
-	"net/url"
-	"strconv"
+
+	"github.com/google/go-querystring/query"
 )
 
+const ripPath = "/v2/reserved-ips"
+
 // ReservedIPService is the interface to interact with the reserved IP endpoints on the Vultr API
-// Link: https://www.vultr.com/api/#reservedip
+// Link : https://www.vultr.com/api/#tag/reserved-ip
 type ReservedIPService interface {
-	Attach(ctx context.Context, ip, InstanceID string) error
-	Convert(ctx context.Context, ip, InstanceID, label string) (*ReservedIP, error)
-	Create(ctx context.Context, regionID int, ipType, label string) (*ReservedIP, error)
-	Delete(ctx context.Context, ip string) error
-	Detach(ctx context.Context, ip, InstanceID string) error
-	List(ctx context.Context) ([]ReservedIP, error)
+	Create(ctx context.Context, ripCreate *ReservedIPReq) (*ReservedIP, error)
+	Get(ctx context.Context, id string) (*ReservedIP, error)
+	Delete(ctx context.Context, id string) error
+	List(ctx context.Context, options *ListOptions) ([]ReservedIP, *Meta, error)
+
+	Convert(ctx context.Context, ripConvert *ReservedIPConvertReq) (*ReservedIP, error)
+	Attach(ctx context.Context, id, instance string) error
+	Detach(ctx context.Context, id string) error
 }
 
 // ReservedIPServiceHandler handles interaction with the reserved IP methods for the Vultr API
@@ -27,247 +30,139 @@ type ReservedIPServiceHandler struct {
 
 // ReservedIP represents an reserved IP on Vultr
 type ReservedIP struct {
-	ReservedIPID string `json:"SUBID"`
-	RegionID     int    `json:"DCID"`
-	IPType       string `json:"ip_type"`
-	Subnet       string `json:"subnet"`
-	SubnetSize   int    `json:"subnet_size"`
-	Label        string `json:"label"`
-	AttachedID   string `json:"attached_SUBID"`
+	ID         string `json:"id"`
+	Region     string `json:"region"`
+	IPType     string `json:"ip_type"`
+	Subnet     string `json:"subnet"`
+	SubnetSize int    `json:"subnet_size"`
+	Label      string `json:"label"`
+	InstanceID string `json:"instance_id"`
 }
 
-// UnmarshalJSON implements json.Unmarshaller on ReservedIP to handle the inconsistent types returned from the Vultr API.
-func (r *ReservedIP) UnmarshalJSON(data []byte) (err error) {
-	if r == nil {
-		*r = ReservedIP{}
-	}
-
-	var v map[string]interface{}
-	if err := json.Unmarshal(data, &v); err != nil {
-		return err
-	}
+// ReservedIPReq represents the parameters for creating a new Reserved IP on Vultr
+type ReservedIPReq struct {
+	Region     string `json:"region,omitempty"`
+	IPType     string `json:"ip_type,omitempty"`
+	IPAddress  string `json:"ip_address,omitempty"`
+	Label      string `json:"label,omitempty"`
+	InstanceID string `json:"instance_id,omitempty"`
+}
 
-	r.ReservedIPID, err = r.unmarshalStr(fmt.Sprintf("%v", v["SUBID"]))
-	if err != nil {
-		return err
-	}
+type reservedIPsBase struct {
+	ReservedIPs []ReservedIP `json:"reserved_ips"`
+	Meta        *Meta        `json:"meta"`
+}
 
-	r.AttachedID, err = r.unmarshalStr(fmt.Sprintf("%v", v["attached_SUBID"]))
-	if err != nil {
-		return err
-	}
+type reservedIPBase struct {
+	ReservedIP *ReservedIP `json:"reserved_ip"`
+}
 
-	r.RegionID, err = r.unmarshalInt(fmt.Sprintf("%v", v["DCID"]))
-	if err != nil {
-		return err
-	}
+// ReservedIPConvertReq is the struct used for create and update calls.
+type ReservedIPConvertReq struct {
+	IPAddress string `json:"ip_address,omitempty"`
+	Label     string `json:"label,omitempty"`
+}
 
-	r.SubnetSize, err = r.unmarshalInt(fmt.Sprintf("%v", v["subnet_size"]))
+// Create adds the specified reserved IP to your Vultr account
+func (r *ReservedIPServiceHandler) Create(ctx context.Context, ripCreate *ReservedIPReq) (*ReservedIP, error) {
+	req, err := r.client.NewRequest(ctx, http.MethodPost, ripPath, ripCreate)
 	if err != nil {
-		return err
-	}
-
-	if r.Subnet = fmt.Sprintf("%v", v["subnet"]); r.Subnet == "<nil>" {
-		r.Subnet = ""
-	}
-
-	if r.IPType = fmt.Sprintf("%v", v["ip_type"]); r.IPType == "<nil>" {
-		r.IPType = ""
+		return nil, err
 	}
 
-	if r.Label = fmt.Sprintf("%v", v["label"]); r.Label == "<nil>" {
-		r.Label = ""
+	rip := new(reservedIPBase)
+	if err = r.client.DoWithContext(ctx, req, rip); err != nil {
+		return nil, err
 	}
 
-	return nil
+	return rip.ReservedIP, nil
 }
 
-func (r *ReservedIP) unmarshalInt(value string) (int, error) {
-	if len(value) == 0 || value == "<nil>" {
-		value = "0"
-	}
-
-	i, err := strconv.ParseInt(value, 10, 64)
+// Get gets the reserved IP associated with provided ID
+func (r *ReservedIPServiceHandler) Get(ctx context.Context, id string) (*ReservedIP, error) {
+	uri := fmt.Sprintf("%s/%s", ripPath, id)
+	req, err := r.client.NewRequest(ctx, http.MethodGet, uri, nil)
 	if err != nil {
-		return 0, err
-	}
-
-	return int(i), nil
-}
-
-func (r *ReservedIP) unmarshalStr(value string) (string, error) {
-	if len(value) == 0 || value == "<nil>" || value == "0" || value == "false" {
-		return "", nil
+		return nil, err
 	}
 
-	f, err := strconv.ParseFloat(value, 64)
-	if err != nil {
-		return "", err
+	rip := new(reservedIPBase)
+	if err = r.client.DoWithContext(ctx, req, rip); err != nil {
+		return nil, err
 	}
 
-	return strconv.FormatFloat(f, 'f', -1, 64), nil
+	return rip.ReservedIP, nil
 }
 
-// Attach a reserved IP to an existing subscription
-func (r *ReservedIPServiceHandler) Attach(ctx context.Context, ip, InstanceID string) error {
-	uri := "/v1/reservedip/attach"
-
-	values := url.Values{
-		"ip_address":   {ip},
-		"attach_SUBID": {InstanceID},
-	}
-
-	req, err := r.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = r.client.DoWithContext(ctx, req, nil)
-
+// Delete removes the specified reserved IP from your Vultr account
+func (r *ReservedIPServiceHandler) Delete(ctx context.Context, id string) error {
+	uri := fmt.Sprintf("%s/%s", ripPath, id)
+	req, err := r.client.NewRequest(ctx, http.MethodDelete, uri, nil)
 	if err != nil {
 		return err
 	}
 
-	return nil
+	return r.client.DoWithContext(ctx, req, nil)
 }
 
-// Convert an existing IP on a subscription to a reserved IP.
-func (r *ReservedIPServiceHandler) Convert(ctx context.Context, ip, InstanceID, label string) (*ReservedIP, error) {
-	uri := "/v1/reservedip/convert"
-
-	values := url.Values{
-		"SUBID":      {InstanceID},
-		"ip_address": {ip},
-	}
-
-	if label != "" {
-		values.Add("label", label)
-	}
-
-	req, err := r.client.NewRequest(ctx, http.MethodPost, uri, values)
-
+// List lists all the reserved IPs associated with your Vultr account
+func (r *ReservedIPServiceHandler) List(ctx context.Context, options *ListOptions) ([]ReservedIP, *Meta, error) {
+	req, err := r.client.NewRequest(ctx, http.MethodGet, ripPath, nil)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	rip := new(ReservedIP)
-
-	err = r.client.DoWithContext(ctx, req, rip)
-
+	newValues, err := query.Values(options)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	rip.Label = label
-
-	return rip, nil
-}
-
-// Create adds the specified reserved IP to your Vultr account
-func (r *ReservedIPServiceHandler) Create(ctx context.Context, regionID int, ipType, label string) (*ReservedIP, error) {
-
-	uri := "/v1/reservedip/create"
+	req.URL.RawQuery = newValues.Encode()
 
-	values := url.Values{
-		"DCID":    {strconv.Itoa(regionID)},
-		"ip_type": {ipType},
+	ips := new(reservedIPsBase)
+	if err = r.client.DoWithContext(ctx, req, ips); err != nil {
+		return nil, nil, err
 	}
 
-	if label != "" {
-		values.Add("label", label)
-	}
+	return ips.ReservedIPs, ips.Meta, nil
+}
 
-	req, err := r.client.NewRequest(ctx, http.MethodPost, uri, values)
+// Convert an existing IP on a subscription to a reserved IP.
+func (r *ReservedIPServiceHandler) Convert(ctx context.Context, ripConvert *ReservedIPConvertReq) (*ReservedIP, error) {
+	uri := fmt.Sprintf("%s/convert", ripPath)
+	req, err := r.client.NewRequest(ctx, http.MethodPost, uri, ripConvert)
 
 	if err != nil {
 		return nil, err
 	}
 
-	rip := new(ReservedIP)
-
-	err = r.client.DoWithContext(ctx, req, rip)
-
-	if err != nil {
+	rip := new(reservedIPBase)
+	if err = r.client.DoWithContext(ctx, req, rip); err != nil {
 		return nil, err
 	}
 
-	rip.RegionID = regionID
-	rip.IPType = ipType
-	rip.Label = label
-
-	return rip, nil
+	return rip.ReservedIP, nil
 }
 
-// Delete removes the specified reserved IP from your Vultr account
-func (r *ReservedIPServiceHandler) Delete(ctx context.Context, ip string) error {
-
-	uri := "/v1/reservedip/destroy"
-
-	values := url.Values{
-		"ip_address": {ip},
-	}
-
-	req, err := r.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = r.client.DoWithContext(ctx, req, nil)
-
+// Attach a reserved IP to an existing subscription
+func (r *ReservedIPServiceHandler) Attach(ctx context.Context, id, instance string) error {
+	uri := fmt.Sprintf("%s/%s/attach", ripPath, id)
+	reqBody := RequestBody{"instance_id": instance}
+	req, err := r.client.NewRequest(ctx, http.MethodPost, uri, reqBody)
 	if err != nil {
 		return err
 	}
 
-	return nil
+	return r.client.DoWithContext(ctx, req, nil)
 }
 
 // Detach a reserved IP from an existing subscription.
-func (r *ReservedIPServiceHandler) Detach(ctx context.Context, ip, InstanceID string) error {
-	uri := "/v1/reservedip/detach"
-
-	values := url.Values{
-		"ip_address":   {ip},
-		"detach_SUBID": {InstanceID},
-	}
-
-	req, err := r.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = r.client.DoWithContext(ctx, req, nil)
-
+func (r *ReservedIPServiceHandler) Detach(ctx context.Context, id string) error {
+	uri := fmt.Sprintf("%s/%s/detach", ripPath, id)
+	req, err := r.client.NewRequest(ctx, http.MethodPost, uri, nil)
 	if err != nil {
 		return err
 	}
 
-	return nil
-}
-
-// List lists all the reserved IPs associated with your Vultr account
-func (r *ReservedIPServiceHandler) List(ctx context.Context) ([]ReservedIP, error) {
-
-	uri := "/v1/reservedip/list"
-
-	req, err := r.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
-	if err != nil {
-		return nil, err
-	}
-
-	ipMap := make(map[string]ReservedIP)
-	err = r.client.DoWithContext(ctx, req, &ipMap)
-	if err != nil {
-		return nil, err
-	}
-
-	var ips []ReservedIP
-	for _, ip := range ipMap {
-		ips = append(ips, ip)
-	}
-
-	return ips, nil
+	return r.client.DoWithContext(ctx, req, nil)
 }
diff --git a/reserved_ip_test.go b/reserved_ip_test.go
index de4fa8f..0058553 100644
--- a/reserved_ip_test.go
+++ b/reserved_ip_test.go
@@ -7,17 +7,16 @@ import (
 	"testing"
 )
 
+// get test
 func TestReservedIPServiceHandler_Attach(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/reservedip/attach", func(writer http.ResponseWriter, request *http.Request) {
+	mux.HandleFunc("/v2/reserved-ips/12345/attach", func(writer http.ResponseWriter, request *http.Request) {
 		fmt.Fprint(writer)
 	})
 
-	err := client.ReservedIP.Attach(ctx, "111.111.111.111", "1")
-
-	if err != nil {
+	if err := client.ReservedIP.Attach(ctx, "12345", "1234"); err != nil {
 		t.Errorf("ReservedIP.Attach returned %+v, expected %+v", err, nil)
 	}
 }
@@ -26,30 +25,42 @@ func TestReservedIPServiceHandler_Convert(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/reservedip/convert", func(writer http.ResponseWriter, request *http.Request) {
+	mux.HandleFunc("/v2/reserved-ips/convert", func(writer http.ResponseWriter, request *http.Request) {
 		response := `
 		{
-			"SUBID": 1312965
+			"reserved_ip": {
+				"id": "1312965",
+				"region": "ewr",
+				"ip_type": "v4",
+				"subnet": "111.111.111.111",
+				"subnet_size": 32,
+				"label": "my first reserved ip",
+				"instance_id": "1234"
+			}
 		}
 		`
 
 		fmt.Fprint(writer, response)
 	})
 
-	ip, err := client.ReservedIP.Convert(ctx, "111.111.111.111", "1", "go-test")
+	options := &ReservedIPConvertReq{
+		IPAddress: "111.111.111.111",
+		Label:     "my first reserved ip",
+	}
+	ip, err := client.ReservedIP.Convert(ctx, options)
 
 	if err != nil {
 		t.Errorf("ReservedIP.Convert returned %+v, expected %+v", err, nil)
 	}
 
 	expected := &ReservedIP{
-		ReservedIPID: "1312965",
-		RegionID:     0,
-		IPType:       "",
-		Subnet:       "",
-		SubnetSize:   0,
-		Label:        "go-test",
-		AttachedID:   "",
+		ID:         "1312965",
+		Region:     "ewr",
+		IPType:     "v4",
+		Subnet:     "111.111.111.111",
+		SubnetSize: 32,
+		Label:      "my first reserved ip",
+		InstanceID: "1234",
 	}
 
 	if !reflect.DeepEqual(ip, expected) {
@@ -61,30 +72,42 @@ func TestReservedIPServiceHandler_Create(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/reservedip/create", func(writer http.ResponseWriter, request *http.Request) {
+	mux.HandleFunc("/v2/reserved-ips", func(writer http.ResponseWriter, request *http.Request) {
 		response := `
 		{
-			"SUBID": 1312965
+			"reserved_ip": {
+				"id": "1313044",
+				"region": "ewr",
+				"ip_type": "v4",
+				"subnet": "10.234.22.53",
+				"subnet_size": 32,
+				"label": "my first reserved ip",
+				"instance_id": ""
+			}
 		}
 		`
-
 		fmt.Fprint(writer, response)
 	})
 
-	ip, err := client.ReservedIP.Create(ctx, 1, "v4", "go-test")
+	options := &ReservedIPReq{
+		IPType: "v4",
+		Label:  "my first reserved ip",
+		Region: "ewr",
+	}
 
+	ip, err := client.ReservedIP.Create(ctx, options)
 	if err != nil {
 		t.Errorf("ReservedIP.Create returned %+v, expected %+v", err, nil)
 	}
 
 	expected := &ReservedIP{
-		ReservedIPID: "1312965",
-		RegionID:     1,
-		IPType:       "v4",
-		Subnet:       "",
-		SubnetSize:   0,
-		Label:        "go-test",
-		AttachedID:   "",
+		ID:         "1313044",
+		Region:     "ewr",
+		IPType:     "v4",
+		Subnet:     "10.234.22.53",
+		SubnetSize: 32,
+		Label:      "my first reserved ip",
+		InstanceID: "",
 	}
 
 	if !reflect.DeepEqual(ip, expected) {
@@ -96,11 +119,11 @@ func TestReservedIPServiceHandler_Delete(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/reservedip/destroy", func(writer http.ResponseWriter, request *http.Request) {
+	mux.HandleFunc("/v2/reserved-ips/12345", func(writer http.ResponseWriter, request *http.Request) {
 		fmt.Fprint(writer)
 	})
 
-	err := client.ReservedIP.Delete(ctx, "111.111.111.111")
+	err := client.ReservedIP.Delete(ctx, "12345")
 
 	if err != nil {
 		t.Errorf("ReservedIP.Delete returned %+v, expected %+v", err, nil)
@@ -111,39 +134,81 @@ func TestReservedIPServiceHandler_Detach(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/reservedip/detach", func(writer http.ResponseWriter, request *http.Request) {
+	mux.HandleFunc("/v2/reserved-ips/12345/detach", func(writer http.ResponseWriter, request *http.Request) {
 		fmt.Fprint(writer)
 	})
 
-	err := client.ReservedIP.Detach(ctx, "111.111.111.111", "1")
+	err := client.ReservedIP.Detach(ctx, "12345")
 
 	if err != nil {
 		t.Errorf("ReservedIP.Detach returned %+v, expected %+v", err, nil)
 	}
 }
 
-func TestReservedIPServiceHandler_List(t *testing.T) {
+func TestReservedIPServiceHandler_Get(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/reservedip/list", func(writer http.ResponseWriter, request *http.Request) {
+	mux.HandleFunc("/v2/reserved-ips/1313044", func(writer http.ResponseWriter, request *http.Request) {
 		response := `
 		{
-			"1313044": {
-				"SUBID": 1313044,
-				"DCID": 1,
+			"reserved_ip": {
+				"id": "1313044",
+				"region": "ewr",
 				"ip_type": "v4",
 				"subnet": "10.234.22.53",
 				"subnet_size": 32,
 				"label": "my first reserved ip",
-				"attached_SUBID": 123456
+				"instance_id": "123456"
 			}
 		}
 		`
 		fmt.Fprintf(writer, response)
 	})
 
-	ips, err := client.ReservedIP.List(ctx)
+	ip, err := client.ReservedIP.Get(ctx, "1313044")
+
+	if err != nil {
+		t.Errorf("ReservedIP.Get returned error: %v", err)
+	}
+
+	expected := &ReservedIP{
+		ID:         "1313044",
+		Region:     "ewr",
+		IPType:     "v4",
+		Subnet:     "10.234.22.53",
+		SubnetSize: 32,
+		Label:      "my first reserved ip",
+		InstanceID: "123456",
+	}
+
+	if !reflect.DeepEqual(ip, expected) {
+		t.Errorf("ReservedIP.Get returned %+v, expected %+v", ip, expected)
+	}
+}
+
+func TestReservedIPServiceHandler_List(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/reserved-ips", func(writer http.ResponseWriter, request *http.Request) {
+		response := `
+		{
+			"reserved_ips": [{
+				"id": "1313044",
+				"region": "ewr",
+				"ip_type": "v4",
+				"subnet": "10.234.22.53",
+				"subnet_size": 32,
+				"label": "my first reserved ip",
+				"instance_id": "123456"
+			}]
+		}
+		`
+		fmt.Fprintf(writer, response)
+	})
+
+	ips, _, err := client.ReservedIP.List(ctx, nil)
 
 	if err != nil {
 		t.Errorf("ReservedIP.List returned error: %v", err)
@@ -151,13 +216,13 @@ func TestReservedIPServiceHandler_List(t *testing.T) {
 
 	expected := []ReservedIP{
 		{
-			ReservedIPID: "1313044",
-			RegionID:     1,
-			IPType:       "v4",
-			Subnet:       "10.234.22.53",
-			SubnetSize:   32,
-			Label:        "my first reserved ip",
-			AttachedID:   "123456",
+			ID:         "1313044",
+			Region:     "ewr",
+			IPType:     "v4",
+			Subnet:     "10.234.22.53",
+			SubnetSize: 32,
+			Label:      "my first reserved ip",
+			InstanceID: "123456",
 		},
 	}
 
diff --git a/server.go b/server.go
deleted file mode 100644
index 7870466..0000000
--- a/server.go
+++ /dev/null
@@ -1,1469 +0,0 @@
-package govultr
-
-import (
-	"context"
-	"encoding/base64"
-	"net/http"
-	"net/url"
-	"strconv"
-	"strings"
-)
-
-// ServerService is the interface to interact with the server endpoints on the Vultr API
-// Link: https://www.vultr.com/api/#server
-type ServerService interface {
-	ChangeApp(ctx context.Context, instanceID, appID string) error
-	ListApps(ctx context.Context, instanceID string) ([]Application, error)
-	AppInfo(ctx context.Context, instanceID string) (*AppInfo, error)
-	EnableBackup(ctx context.Context, instanceID string) error
-	DisableBackup(ctx context.Context, instanceID string) error
-	GetBackupSchedule(ctx context.Context, instanceID string) (*BackupSchedule, error)
-	SetBackupSchedule(ctx context.Context, instanceID string, backup *BackupSchedule) error
-	RestoreBackup(ctx context.Context, instanceID, backupID string) error
-	RestoreSnapshot(ctx context.Context, instanceID, snapshotID string) error
-	SetLabel(ctx context.Context, instanceID, label string) error
-	SetTag(ctx context.Context, instanceID, tag string) error
-	Neighbors(ctx context.Context, instanceID string) ([]int, error)
-	EnablePrivateNetwork(ctx context.Context, instanceID, networkID string) error
-	DisablePrivateNetwork(ctx context.Context, instanceID, networkID string) error
-	ListPrivateNetworks(ctx context.Context, instanceID string) ([]PrivateNetwork, error)
-	ListUpgradePlan(ctx context.Context, instanceID string) ([]int, error)
-	UpgradePlan(ctx context.Context, instanceID, vpsPlanID string) error
-	ListOS(ctx context.Context, instanceID string) ([]OS, error)
-	ChangeOS(ctx context.Context, instanceID, osID string) error
-	IsoAttach(ctx context.Context, instanceID, isoID string) error
-	IsoDetach(ctx context.Context, instanceID string) error
-	IsoStatus(ctx context.Context, instanceID string) (*ServerIso, error)
-	SetFirewallGroup(ctx context.Context, instanceID, firewallGroupID string) error
-	GetUserData(ctx context.Context, instanceID string) (*UserData, error)
-	SetUserData(ctx context.Context, instanceID, userData string) error
-	IPV4Info(ctx context.Context, instanceID string, public bool) ([]IPV4, error)
-	IPV6Info(ctx context.Context, instanceID string) ([]IPV6, error)
-	AddIPV4(ctx context.Context, instanceID string) error
-	DestroyIPV4(ctx context.Context, instanceID, ip string) error
-	EnableIPV6(ctx context.Context, instanceID string) error
-	Bandwidth(ctx context.Context, instanceID string) ([]map[string]string, error)
-	ListReverseIPV6(ctx context.Context, instanceID string) ([]ReverseIPV6, error)
-	SetDefaultReverseIPV4(ctx context.Context, instanceID, ip string) error
-	DeleteReverseIPV6(ctx context.Context, instanceID, ip string) error
-	SetReverseIPV4(ctx context.Context, instanceID, ipv4, entry string) error
-	SetReverseIPV6(ctx context.Context, instanceID, ipv6, entry string) error
-	Start(ctx context.Context, instanceID string) error
-	Halt(ctx context.Context, instanceID string) error
-	Reboot(ctx context.Context, instanceID string) error
-	Reinstall(ctx context.Context, instanceID string) error
-	Delete(ctx context.Context, instanceID string) error
-	Create(ctx context.Context, regionID, vpsPlanID, osID int, options *ServerOptions) (*Server, error)
-	List(ctx context.Context) ([]Server, error)
-	ListByLabel(ctx context.Context, label string) ([]Server, error)
-	ListByMainIP(ctx context.Context, mainIP string) ([]Server, error)
-	ListByTag(ctx context.Context, tag string) ([]Server, error)
-	GetServer(ctx context.Context, instanceID string) (*Server, error)
-}
-
-// ServerServiceHandler handles interaction with the server methods for the Vultr API
-type ServerServiceHandler struct {
-	client *Client
-}
-
-// AppInfo represents information about the application on your VPS
-type AppInfo struct {
-	AppInfo string `json:"app_info"`
-}
-
-// BackupSchedule represents a schedule of a backup that runs on a VPS
-type BackupSchedule struct {
-	Enabled  bool   `json:"enabled"`
-	CronType string `json:"cron_type"`
-	NextRun  string `json:"next_scheduled_time_utc"`
-	Hour     int    `json:"hour"`
-	Dow      int    `json:"dow"`
-	Dom      int    `json:"dom"`
-}
-
-// PrivateNetwork represents a private network attached to a VPS
-type PrivateNetwork struct {
-	NetworkID  string `json:"NETWORKID"`
-	MacAddress string `json:"mac_address"`
-	IPAddress  string `json:"ip_address"`
-}
-
-// ServerIso represents a iso attached to a VPS
-type ServerIso struct {
-	State string `json:"state"`
-	IsoID string `json:"ISOID"`
-}
-
-// UserData represents the user data you can give a VPS
-type UserData struct {
-	UserData string `json:"userdata"`
-}
-
-// IPV4 represents IPV4 information for a VPS
-type IPV4 struct {
-	IP      string `json:"ip"`
-	Netmask string `json:"netmask"`
-	Gateway string `json:"gateway"`
-	Type    string `json:"type"`
-	Reverse string `json:"reverse"`
-}
-
-// IPV6 represents IPV6 information for a VPS
-type IPV6 struct {
-	IP          string `json:"ip"`
-	Network     string `json:"network"`
-	NetworkSize string `json:"network_size"`
-	Type        string `json:"type"`
-}
-
-// ReverseIPV6 represents IPV6 reverse DNS entries
-type ReverseIPV6 struct {
-	IP      string `json:"ip"`
-	Reverse string `json:"reverse"`
-}
-
-// Server represents a VPS
-type Server struct {
-	InstanceID       string      `json:"SUBID"`
-	Os               string      `json:"os"`
-	RAM              string      `json:"ram"`
-	Disk             string      `json:"disk"`
-	MainIP           string      `json:"main_ip"`
-	VPSCpus          string      `json:"vcpu_count"`
-	Location         string      `json:"location"`
-	RegionID         string      `json:"DCID"`
-	DefaultPassword  string      `json:"default_password"`
-	Created          string      `json:"date_created"`
-	PendingCharges   string      `json:"pending_charges"`
-	Status           string      `json:"status"`
-	Cost             string      `json:"cost_per_month"`
-	CurrentBandwidth float64     `json:"current_bandwidth_gb"`
-	AllowedBandwidth string      `json:"allowed_bandwidth_gb"`
-	NetmaskV4        string      `json:"netmask_v4"`
-	GatewayV4        string      `json:"gateway_v4"`
-	PowerStatus      string      `json:"power_status"`
-	ServerState      string      `json:"server_state"`
-	PlanID           string      `json:"VPSPLANID"`
-	V6Networks       []V6Network `json:"v6_networks"`
-	Label            string      `json:"label"`
-	InternalIP       string      `json:"internal_ip"`
-	KVMUrl           string      `json:"kvm_url"`
-	AutoBackups      string      `json:"auto_backups"`
-	Tag              string      `json:"tag"`
-	OsID             string      `json:"OSID"`
-	AppID            string      `json:"APPID"`
-	FirewallGroupID  string      `json:"FIREWALLGROUPID"`
-}
-
-// V6Network represents an IPV6 network on a VPS
-type V6Network struct {
-	Network     string `json:"v6_network"`
-	MainIP      string `json:"v6_main_ip"`
-	NetworkSize string `json:"v6_network_size"`
-}
-
-// ServerOptions are all optional fields that can be used during vps creation
-type ServerOptions struct {
-	IPXEChain            string
-	IsoID                int
-	SnapshotID           string
-	ScriptID             string
-	EnableIPV6           bool
-	EnablePrivateNetwork bool
-	NetworkID            []string
-	Label                string
-	SSHKeyIDs            []string
-	AutoBackups          bool
-	AppID                string
-	UserData             string
-	NotifyActivate       bool
-	DDOSProtection       bool
-	ReservedIPV4         string
-	Hostname             string
-	Tag                  string
-	FirewallGroupID      string
-}
-
-// ChangeApp changes the VPS to a different application.
-func (s *ServerServiceHandler) ChangeApp(ctx context.Context, instanceID, appID string) error {
-
-	uri := "/v1/server/app_change"
-
-	values := url.Values{
-		"SUBID": {instanceID},
-		"APPID": {appID},
-	}
-
-	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = s.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// ListApps retrieves a list of applications to which a virtual machine can be changed.
-func (s *ServerServiceHandler) ListApps(ctx context.Context, instanceID string) ([]Application, error) {
-
-	uri := "/v1/server/app_change_list"
-
-	req, err := s.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
-	if err != nil {
-		return nil, err
-	}
-
-	q := req.URL.Query()
-	q.Add("SUBID", instanceID)
-	req.URL.RawQuery = q.Encode()
-
-	var appMap map[string]Application
-	err = s.client.DoWithContext(ctx, req, &appMap)
-
-	if err != nil {
-		return nil, err
-	}
-
-	var appList []Application
-	for _, a := range appMap {
-		appList = append(appList, a)
-	}
-
-	return appList, nil
-}
-
-// AppInfo retrieves the application information for a given VPS ID
-func (s *ServerServiceHandler) AppInfo(ctx context.Context, instanceID string) (*AppInfo, error) {
-
-	uri := "/v1/server/get_app_info"
-
-	req, err := s.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
-	if err != nil {
-		return nil, err
-	}
-
-	q := req.URL.Query()
-	q.Add("SUBID", instanceID)
-	req.URL.RawQuery = q.Encode()
-
-	appInfo := new(AppInfo)
-
-	err = s.client.DoWithContext(ctx, req, appInfo)
-
-	if err != nil {
-		return nil, err
-	}
-
-	return appInfo, nil
-}
-
-// EnableBackup enables automatic backups on a given VPS
-func (s *ServerServiceHandler) EnableBackup(ctx context.Context, instanceID string) error {
-
-	uri := "/v1/server/backup_enable"
-
-	values := url.Values{
-		"SUBID": {instanceID},
-	}
-
-	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = s.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// DisableBackup disable automatic backups on a given VPS
-func (s *ServerServiceHandler) DisableBackup(ctx context.Context, instanceID string) error {
-
-	uri := "/v1/server/backup_disable"
-
-	values := url.Values{
-		"SUBID": {instanceID},
-	}
-
-	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = s.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// GetBackupSchedule retrieves the backup schedule for a given vps - all time values are in UTC
-func (s *ServerServiceHandler) GetBackupSchedule(ctx context.Context, instanceID string) (*BackupSchedule, error) {
-
-	uri := "/v1/server/backup_get_schedule"
-
-	values := url.Values{
-		"SUBID": {instanceID},
-	}
-
-	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return nil, err
-	}
-
-	backup := new(BackupSchedule)
-	err = s.client.DoWithContext(ctx, req, backup)
-
-	if err != nil {
-		return nil, err
-	}
-
-	return backup, nil
-}
-
-// SetBackupSchedule sets the backup schedule for a given vps - all time values are in UTC
-func (s *ServerServiceHandler) SetBackupSchedule(ctx context.Context, instanceID string, backup *BackupSchedule) error {
-
-	uri := "/v1/server/backup_set_schedule"
-
-	values := url.Values{
-		"SUBID":     {instanceID},
-		"cron_type": {backup.CronType},
-		"hour":      {strconv.Itoa(backup.Hour)},
-		"dow":       {strconv.Itoa(backup.Dow)},
-		"dom":       {strconv.Itoa(backup.Dom)},
-	}
-
-	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = s.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// RestoreBackup will restore the specified backup to the given VPS
-func (s *ServerServiceHandler) RestoreBackup(ctx context.Context, instanceID, backupID string) error {
-
-	uri := "/v1/server/restore_backup"
-
-	values := url.Values{
-		"SUBID":    {instanceID},
-		"BACKUPID": {backupID},
-	}
-
-	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = s.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// RestoreSnapshot will restore the specified snapshot to the given VPS
-func (s *ServerServiceHandler) RestoreSnapshot(ctx context.Context, instanceID, snapshotID string) error {
-
-	uri := "/v1/server/restore_snapshot"
-
-	values := url.Values{
-		"SUBID":      {instanceID},
-		"SNAPSHOTID": {snapshotID},
-	}
-
-	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = s.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// SetLabel will set a label for a given VPS
-func (s *ServerServiceHandler) SetLabel(ctx context.Context, instanceID, label string) error {
-
-	uri := "/v1/server/label_set"
-
-	values := url.Values{
-		"SUBID": {instanceID},
-		"label": {label},
-	}
-
-	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = s.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// SetTag will set a tag for a given VPS
-func (s *ServerServiceHandler) SetTag(ctx context.Context, instanceID, tag string) error {
-
-	uri := "/v1/server/tag_set"
-
-	values := url.Values{
-		"SUBID": {instanceID},
-		"tag":   {tag},
-	}
-
-	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = s.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// Neighbors will determine what other vps are hosted on the same physical host as a given vps.
-func (s *ServerServiceHandler) Neighbors(ctx context.Context, instanceID string) ([]int, error) {
-
-	uri := "/v1/server/neighbors"
-
-	req, err := s.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
-	if err != nil {
-		return nil, err
-	}
-
-	q := req.URL.Query()
-	q.Add("SUBID", instanceID)
-	req.URL.RawQuery = q.Encode()
-
-	var neighbors []int
-	err = s.client.DoWithContext(ctx, req, &neighbors)
-
-	if err != nil {
-		return nil, err
-	}
-
-	return neighbors, nil
-}
-
-// EnablePrivateNetwork enables private networking on a server.
-// The server will be automatically rebooted to complete the request.
-// No action occurs if private networking was already enabled
-func (s *ServerServiceHandler) EnablePrivateNetwork(ctx context.Context, instanceID, networkID string) error {
-
-	uri := "/v1/server/private_network_enable"
-
-	values := url.Values{
-		"SUBID":     {instanceID},
-		"NETWORKID": {networkID},
-	}
-
-	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = s.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// DisablePrivateNetwork removes a private network from a server.
-// The server will be automatically rebooted to complete the request.
-func (s *ServerServiceHandler) DisablePrivateNetwork(ctx context.Context, instanceID, networkID string) error {
-
-	uri := "/v1/server/private_network_disable"
-
-	values := url.Values{
-		"SUBID":     {instanceID},
-		"NETWORKID": {networkID},
-	}
-
-	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = s.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// ListPrivateNetworks will list private networks attached to a vps
-func (s *ServerServiceHandler) ListPrivateNetworks(ctx context.Context, instanceID string) ([]PrivateNetwork, error) {
-
-	uri := "/v1/server/private_networks"
-
-	req, err := s.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
-	if err != nil {
-		return nil, err
-	}
-
-	q := req.URL.Query()
-	q.Add("SUBID", instanceID)
-	req.URL.RawQuery = q.Encode()
-
-	var networkMap map[string]PrivateNetwork
-	err = s.client.DoWithContext(ctx, req, &networkMap)
-
-	if err != nil {
-		return nil, err
-	}
-
-	var privateNetworks []PrivateNetwork
-	for _, p := range networkMap {
-		privateNetworks = append(privateNetworks, p)
-	}
-
-	return privateNetworks, nil
-}
-
-// ListUpgradePlan Retrieve a list of the planIDs for which the vps can be upgraded.
-// An empty response array means that there are currently no upgrades available
-func (s *ServerServiceHandler) ListUpgradePlan(ctx context.Context, instanceID string) ([]int, error) {
-
-	uri := "/v1/server/upgrade_plan_list"
-
-	req, err := s.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
-	if err != nil {
-		return nil, err
-	}
-
-	q := req.URL.Query()
-	q.Add("SUBID", instanceID)
-	req.URL.RawQuery = q.Encode()
-
-	var plans []int
-	err = s.client.DoWithContext(ctx, req, &plans)
-
-	if err != nil {
-		return nil, err
-	}
-
-	return plans, nil
-}
-
-// UpgradePlan will upgrade the plan of a virtual machine.
-// The vps will be rebooted upon a successful upgrade.
-func (s *ServerServiceHandler) UpgradePlan(ctx context.Context, instanceID, vpsPlanID string) error {
-
-	uri := "/v1/server/upgrade_plan"
-
-	values := url.Values{
-		"SUBID":     {instanceID},
-		"VPSPLANID": {vpsPlanID},
-	}
-
-	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = s.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// ListOS retrieves a list of operating systems to which the VPS can be changed to.
-func (s *ServerServiceHandler) ListOS(ctx context.Context, instanceID string) ([]OS, error) {
-
-	uri := "/v1/server/os_change_list"
-
-	req, err := s.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
-	if err != nil {
-		return nil, err
-	}
-
-	q := req.URL.Query()
-	q.Add("SUBID", instanceID)
-	req.URL.RawQuery = q.Encode()
-
-	var osMap map[string]OS
-	err = s.client.DoWithContext(ctx, req, &osMap)
-
-	if err != nil {
-		return nil, err
-	}
-
-	var os []OS
-	for _, o := range osMap {
-		os = append(os, o)
-	}
-
-	return os, nil
-}
-
-// ChangeOS changes the VPS to a different operating system.
-// All data will be permanently lost.
-func (s *ServerServiceHandler) ChangeOS(ctx context.Context, instanceID, osID string) error {
-
-	uri := "/v1/server/os_change"
-
-	values := url.Values{
-		"SUBID": {instanceID},
-		"OSID":  {osID},
-	}
-
-	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = s.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// IsoAttach will attach an ISO to the given VPS and reboot it
-func (s *ServerServiceHandler) IsoAttach(ctx context.Context, instanceID, isoID string) error {
-
-	uri := "/v1/server/iso_attach"
-
-	values := url.Values{
-		"SUBID": {instanceID},
-		"ISOID": {isoID},
-	}
-
-	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = s.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// IsoDetach will detach the currently mounted ISO and reboot the server.
-func (s *ServerServiceHandler) IsoDetach(ctx context.Context, instanceID string) error {
-
-	uri := "/v1/server/iso_detach"
-
-	values := url.Values{
-		"SUBID": {instanceID},
-	}
-
-	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = s.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// IsoStatus retrieves the current ISO state for a given VPS.
-// The returned state may be one of: ready | isomounting | isomounted.
-func (s *ServerServiceHandler) IsoStatus(ctx context.Context, instanceID string) (*ServerIso, error) {
-
-	uri := "/v1/server/iso_status"
-
-	req, err := s.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
-	if err != nil {
-		return nil, err
-	}
-
-	q := req.URL.Query()
-	q.Add("SUBID", instanceID)
-	req.URL.RawQuery = q.Encode()
-
-	serverIso := new(ServerIso)
-	err = s.client.DoWithContext(ctx, req, serverIso)
-
-	if err != nil {
-		return nil, err
-	}
-
-	return serverIso, nil
-}
-
-// SetFirewallGroup will set, change, or remove the firewall group currently applied to a vps.
-//  A value of "0" means "no firewall group"
-func (s *ServerServiceHandler) SetFirewallGroup(ctx context.Context, instanceID, firewallGroupID string) error {
-
-	uri := "/v1/server/firewall_group_set"
-
-	values := url.Values{
-		"SUBID":           {instanceID},
-		"FIREWALLGROUPID": {firewallGroupID},
-	}
-
-	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = s.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// SetUserData sets the user-data for this subscription.
-// User-data is a generic data store, which some provisioning tools and cloud operating systems use as a configuration file.
-// It is generally consumed only once after an instance has been launched, but individual needs may vary.
-func (s *ServerServiceHandler) SetUserData(ctx context.Context, instanceID, userData string) error {
-
-	uri := "/v1/server/set_user_data"
-
-	encodedUserData := base64.StdEncoding.EncodeToString([]byte(userData))
-
-	values := url.Values{
-		"SUBID":    {instanceID},
-		"userdata": {encodedUserData},
-	}
-
-	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = s.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// GetUserData retrieves the (base64 encoded) user-data for this VPS
-func (s *ServerServiceHandler) GetUserData(ctx context.Context, instanceID string) (*UserData, error) {
-
-	uri := "/v1/server/get_user_data"
-
-	req, err := s.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
-	if err != nil {
-		return nil, err
-	}
-
-	q := req.URL.Query()
-	q.Add("SUBID", instanceID)
-	req.URL.RawQuery = q.Encode()
-
-	userData := new(UserData)
-	err = s.client.DoWithContext(ctx, req, userData)
-
-	if err != nil {
-		return nil, err
-	}
-
-	return userData, nil
-}
-
-// IPV4Info will list the IPv4 information of a virtual machine.
-// Public if set to 'true', includes information about the public network adapter (such as MAC address) with the "main_ip" entry.
-func (s *ServerServiceHandler) IPV4Info(ctx context.Context, instanceID string, public bool) ([]IPV4, error) {
-
-	uri := "/v1/server/list_ipv4"
-
-	req, err := s.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
-	if err != nil {
-		return nil, err
-	}
-
-	q := req.URL.Query()
-	q.Add("SUBID", instanceID)
-
-	if public == true {
-		q.Add("public_network", instanceID)
-	}
-
-	req.URL.RawQuery = q.Encode()
-
-	var ipMap map[string][]IPV4
-	err = s.client.DoWithContext(ctx, req, &ipMap)
-
-	if err != nil {
-		return nil, err
-	}
-
-	var ipv4 []IPV4
-	for _, i := range ipMap {
-		ipv4 = i
-	}
-
-	return ipv4, nil
-}
-
-// IPV6Info will list the IPv6 information of a virtual machine.
-// If the virtual machine does not have IPv6 enabled, then an empty array is returned.
-func (s *ServerServiceHandler) IPV6Info(ctx context.Context, instanceID string) ([]IPV6, error) {
-	uri := "/v1/server/list_ipv6"
-
-	req, err := s.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
-	if err != nil {
-		return nil, err
-	}
-
-	q := req.URL.Query()
-	q.Add("SUBID", instanceID)
-	req.URL.RawQuery = q.Encode()
-
-	var ipMap map[string][]IPV6
-	err = s.client.DoWithContext(ctx, req, &ipMap)
-
-	if err != nil {
-		return nil, err
-	}
-
-	var ipv6 []IPV6
-	for _, i := range ipMap {
-		ipv6 = i
-	}
-
-	return ipv6, nil
-}
-
-// AddIPV4 will add a new IPv4 address to a server.
-func (s *ServerServiceHandler) AddIPV4(ctx context.Context, instanceID string) error {
-
-	uri := "/v1/server/create_ipv4"
-
-	values := url.Values{
-		"SUBID": {instanceID},
-	}
-
-	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = s.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// DestroyIPV4 removes a secondary IPv4 address from a server.
-// Your server will be hard-restarted. We suggest halting the machine gracefully before removing IPs.
-func (s *ServerServiceHandler) DestroyIPV4(ctx context.Context, instanceID, ip string) error {
-
-	uri := "/v1/server/destroy_ipv4"
-
-	values := url.Values{
-		"SUBID": {instanceID},
-		"ip":    {ip},
-	}
-
-	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = s.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// EnableIPV6 enables IPv6 networking on a server by assigning an IPv6 subnet to it.
-func (s *ServerServiceHandler) EnableIPV6(ctx context.Context, instanceID string) error {
-
-	uri := "/v1/server/ipv6_enable"
-
-	values := url.Values{
-		"SUBID": {instanceID},
-	}
-
-	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = s.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// Bandwidth will get the bandwidth used by a VPS
-func (s *ServerServiceHandler) Bandwidth(ctx context.Context, instanceID string) ([]map[string]string, error) {
-
-	uri := "/v1/server/bandwidth"
-
-	req, err := s.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
-	if err != nil {
-		return nil, err
-	}
-
-	q := req.URL.Query()
-	q.Add("SUBID", instanceID)
-	req.URL.RawQuery = q.Encode()
-
-	var bandwidthMap map[string][][]string
-	err = s.client.DoWithContext(ctx, req, &bandwidthMap)
-
-	if err != nil {
-		return nil, err
-	}
-
-	var bandwidth []map[string]string
-
-	for _, b := range bandwidthMap["incoming_bytes"] {
-		inMap := make(map[string]string)
-		inMap["date"] = b[0]
-		inMap["incoming"] = b[1]
-		bandwidth = append(bandwidth, inMap)
-	}
-
-	for _, b := range bandwidthMap["outgoing_bytes"] {
-		for i := range bandwidth {
-			if bandwidth[i]["date"] == b[0] {
-				bandwidth[i]["outgoing"] = b[1]
-				break
-			}
-		}
-	}
-
-	return bandwidth, nil
-}
-
-// ListReverseIPV6 List the IPv6 reverse DNS entries of a virtual machine.
-// Reverse DNS entries are only available for virtual machines in the "active" state.
-// If the virtual machine does not have IPv6 enabled, then an empty array is returned.
-func (s *ServerServiceHandler) ListReverseIPV6(ctx context.Context, instanceID string) ([]ReverseIPV6, error) {
-
-	uri := "/v1/server/reverse_list_ipv6"
-
-	req, err := s.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
-	if err != nil {
-		return nil, err
-	}
-
-	q := req.URL.Query()
-	q.Add("SUBID", instanceID)
-	req.URL.RawQuery = q.Encode()
-
-	var reverseMap map[string][]ReverseIPV6
-	err = s.client.DoWithContext(ctx, req, &reverseMap)
-
-	if err != nil {
-		return nil, err
-	}
-
-	var reverseIPV6 []ReverseIPV6
-	for _, r := range reverseMap {
-
-		if len(r) == 0 {
-			break
-		}
-
-		for _, i := range r {
-			reverseIPV6 = append(reverseIPV6, i)
-		}
-	}
-
-	return reverseIPV6, nil
-}
-
-// SetDefaultReverseIPV4 will set a reverse DNS entry for an IPv4 address of a virtual machine to the original setting.
-// Upon success, DNS changes may take 6-12 hours to become active.
-func (s *ServerServiceHandler) SetDefaultReverseIPV4(ctx context.Context, instanceID, ip string) error {
-
-	uri := "/v1/server/reverse_default_ipv4"
-
-	values := url.Values{
-		"SUBID": {instanceID},
-		"ip":    {ip},
-	}
-
-	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = s.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// DeleteReverseIPV6 Remove a reverse DNS entry for an IPv6 address of a VPS.
-// Upon success, DNS changes may take 6-12 hours to become active.
-func (s *ServerServiceHandler) DeleteReverseIPV6(ctx context.Context, instanceID, ip string) error {
-
-	uri := "/v1/server/reverse_delete_ipv6"
-
-	values := url.Values{
-		"SUBID": {instanceID},
-		"ip":    {ip},
-	}
-
-	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = s.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// SetReverseIPV4 will set a reverse DNS entry for an IPv4 address of a virtual machine.
-// Upon success, DNS changes may take 6-12 hours to become active.
-func (s *ServerServiceHandler) SetReverseIPV4(ctx context.Context, instanceID, ipv4, entry string) error {
-
-	uri := "/v1/server/reverse_set_ipv4"
-
-	values := url.Values{
-		"SUBID": {instanceID},
-		"ip":    {ipv4},
-		"entry": {entry},
-	}
-
-	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = s.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// SetReverseIPV6 will set a reverse DNS entry for an IPv4 address of a virtual machine.
-// Upon success, DNS changes may take 6-12 hours to become active.
-func (s *ServerServiceHandler) SetReverseIPV6(ctx context.Context, instanceID, ipv6, entry string) error {
-	uri := "/v1/server/reverse_set_ipv6"
-
-	values := url.Values{
-		"SUBID": {instanceID},
-		"ip":    {ipv6},
-		"entry": {entry},
-	}
-
-	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = s.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// Start will start a vps. If the machine is already running, it will be restarted.
-func (s *ServerServiceHandler) Start(ctx context.Context, instanceID string) error {
-	uri := "/v1/server/start"
-
-	values := url.Values{
-		"SUBID": {instanceID},
-	}
-
-	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = s.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// Halt will halt a virtual machine. This is a hard power off
-func (s *ServerServiceHandler) Halt(ctx context.Context, instanceID string) error {
-
-	uri := "/v1/server/halt"
-
-	values := url.Values{
-		"SUBID": {instanceID},
-	}
-
-	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = s.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// Reboot will reboot a VPS. This is a hard reboot
-func (s *ServerServiceHandler) Reboot(ctx context.Context, instanceID string) error {
-
-	uri := "/v1/server/reboot"
-
-	values := url.Values{
-		"SUBID": {instanceID},
-	}
-
-	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = s.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// Reinstall will reinstall the operating system on a VPS.
-func (s *ServerServiceHandler) Reinstall(ctx context.Context, instanceID string) error {
-	uri := "/v1/server/reinstall"
-
-	values := url.Values{
-		"SUBID": {instanceID},
-	}
-
-	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = s.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// Delete a VPS. All data will be permanently lost, and the IP address will be released
-func (s *ServerServiceHandler) Delete(ctx context.Context, instanceID string) error {
-
-	uri := "/v1/server/destroy"
-
-	values := url.Values{
-		"SUBID": {instanceID},
-	}
-
-	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = s.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// Create will create a new VPS
-// In order to create a server using a snapshot, use OSID 164 and specify a SNAPSHOTID.
-// Similarly, to create a server using an ISO use OSID 159 and specify an ISOID.
-func (s *ServerServiceHandler) Create(ctx context.Context, regionID, vpsPlanID, osID int, options *ServerOptions) (*Server, error) {
-
-	uri := "/v1/server/create"
-
-	values := url.Values{
-		"DCID":      {strconv.Itoa(regionID)},
-		"VPSPLANID": {strconv.Itoa(vpsPlanID)},
-		"OSID":      {strconv.Itoa(osID)},
-	}
-
-	if options != nil {
-		if options.IPXEChain != "" {
-			values.Add("ipxe_chain_url", options.IPXEChain)
-		}
-
-		if options.IsoID != 0 {
-			values.Add("ISOID", strconv.Itoa(options.IsoID))
-		}
-
-		if options.SnapshotID != "" {
-			values.Add("SNAPSHOTID", options.SnapshotID)
-		}
-
-		if options.ScriptID != "" {
-			values.Add("SCRIPTID", options.ScriptID)
-		}
-
-		if options.EnableIPV6 == true {
-			values.Add("enable_ipv6", "yes")
-		}
-
-		// Use either EnabledPrivateNetwork or NetworkIDs, not both
-		if options.EnablePrivateNetwork == true {
-			values.Add("enable_private_network", "yes")
-		} else {
-			if options.NetworkID != nil && len(options.NetworkID) != 0 {
-				for _, n := range options.NetworkID {
-					values.Add("NETWORKID[]", n)
-				}
-			}
-		}
-
-		if options.Label != "" {
-			values.Add("label", options.Label)
-		}
-
-		if options.SSHKeyIDs != nil && len(options.SSHKeyIDs) != 0 {
-			values.Add("SSHKEYID", strings.Join(options.SSHKeyIDs, ","))
-		}
-
-		if options.AutoBackups == true {
-			values.Add("auto_backups", "yes")
-		}
-
-		if options.AppID != "" {
-			values.Add("APPID", options.AppID)
-		}
-
-		if options.UserData != "" {
-			values.Add("userdata", base64.StdEncoding.EncodeToString([]byte(options.UserData)))
-		}
-
-		if options.NotifyActivate == true {
-			values.Add("notify_activate", "yes")
-		} else if options.NotifyActivate == false {
-			values.Add("notify_activate", "no")
-		}
-
-		if options.DDOSProtection == true {
-			values.Add("ddos_protection", "yes")
-		}
-
-		if options.ReservedIPV4 != "" {
-			values.Add("reserved_ip_v4", options.ReservedIPV4)
-		}
-
-		if options.Hostname != "" {
-			values.Add("hostname", options.Hostname)
-		}
-
-		if options.Tag != "" {
-			values.Add("tag", options.Tag)
-		}
-
-		if options.FirewallGroupID != "" {
-			values.Add("FIREWALLGROUPID", options.FirewallGroupID)
-		}
-	}
-
-	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return nil, err
-	}
-
-	server := new(Server)
-	err = s.client.DoWithContext(ctx, req, server)
-
-	if err != nil {
-		return nil, err
-	}
-
-	return server, nil
-}
-
-// List lists all VPS on the current account. This includes both pending and active servers.
-func (s *ServerServiceHandler) List(ctx context.Context) ([]Server, error) {
-	return s.list(ctx, "", "")
-}
-
-// ListByLabel lists all VPS that match the given label on the current account. This includes both pending and active servers.
-func (s *ServerServiceHandler) ListByLabel(ctx context.Context, label string) ([]Server, error) {
-	return s.list(ctx, "label", label)
-}
-
-// ListByMainIP lists all VPS that match the given IP address on the current account. This includes both pending and active servers.
-func (s *ServerServiceHandler) ListByMainIP(ctx context.Context, mainIP string) ([]Server, error) {
-	return s.list(ctx, "main_ip", mainIP)
-}
-
-// ListByTag lists all VPS that match the given tag on the current account. This includes both pending and active servers.
-func (s *ServerServiceHandler) ListByTag(ctx context.Context, tag string) ([]Server, error) {
-	return s.list(ctx, "tag", tag)
-}
-
-// list is used to consolidate the optional params to get a VPS
-func (s *ServerServiceHandler) list(ctx context.Context, key, value string) ([]Server, error) {
-
-	uri := "/v1/server/list"
-
-	req, err := s.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
-	if err != nil {
-		return nil, err
-	}
-
-	if key != "" {
-		q := req.URL.Query()
-		q.Add(key, value)
-		req.URL.RawQuery = q.Encode()
-	}
-
-	var serverMap map[string]Server
-	err = s.client.DoWithContext(ctx, req, &serverMap)
-
-	if err != nil {
-		return nil, err
-	}
-
-	var servers []Server
-	for _, s := range serverMap {
-		servers = append(servers, s)
-	}
-
-	return servers, nil
-}
-
-// GetServer will get the server with the given instanceID
-func (s *ServerServiceHandler) GetServer(ctx context.Context, instanceID string) (*Server, error) {
-
-	uri := "/v1/server/list"
-
-	req, err := s.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
-	if err != nil {
-		return nil, err
-	}
-
-	q := req.URL.Query()
-	q.Add("SUBID", instanceID)
-	req.URL.RawQuery = q.Encode()
-
-	server := new(Server)
-	err = s.client.DoWithContext(ctx, req, server)
-
-	if err != nil {
-		return nil, err
-	}
-
-	return server, nil
-
-}
diff --git a/server_test.go b/server_test.go
deleted file mode 100644
index b333254..0000000
--- a/server_test.go
+++ /dev/null
@@ -1,1093 +0,0 @@
-package govultr
-
-import (
-	"fmt"
-	"net/http"
-	"reflect"
-	"testing"
-)
-
-func TestServerServiceHandler_ChangeApp(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/app_change", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.Server.ChangeApp(ctx, "1234", "24")
-
-	if err != nil {
-		t.Errorf("Server.ChangeApp returned %+v, ", err)
-	}
-}
-
-func TestServerServiceHandler_ListApps(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/app_change_list", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"1": {"APPID": "1","name": "LEMP","short_name": "lemp","deploy_name": "LEMP on CentOS 6 x64","surcharge": 0}}`
-		fmt.Fprint(writer, response)
-	})
-
-	application, err := client.Server.ListApps(ctx, "1234")
-
-	if err != nil {
-		t.Errorf("Server.ListApps returned %+v, ", err)
-	}
-
-	expected := []Application{
-		{
-			AppID:      "1",
-			Name:       "LEMP",
-			ShortName:  "lemp",
-			DeployName: "LEMP on CentOS 6 x64",
-			Surcharge:  0,
-		},
-	}
-
-	if !reflect.DeepEqual(application, expected) {
-		t.Errorf("Server.ListApps returned %+v, expected %+v", application, expected)
-	}
-}
-
-func TestServerServiceHandler_AppInfo(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/get_app_info", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"app_info": "test"}`
-		fmt.Fprint(writer, response)
-	})
-
-	appInfo, err := client.Server.AppInfo(ctx, "1234")
-
-	if err != nil {
-		t.Errorf("Server.AppInfo returned %+v, ", err)
-	}
-
-	expected := &AppInfo{AppInfo: "test"}
-
-	if !reflect.DeepEqual(appInfo, expected) {
-		t.Errorf("Server.AppInfo returned %+v, expected %+v", appInfo, expected)
-	}
-}
-
-func TestServerServiceHandler_EnableBackup(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/backup_enable", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.Server.EnableBackup(ctx, "1234")
-
-	if err != nil {
-		t.Errorf("Server.EnableBackup returned %+v, ", err)
-	}
-}
-
-func TestServerServiceHandler_DisableBackup(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/backup_disable", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.Server.DisableBackup(ctx, "1234")
-
-	if err != nil {
-		t.Errorf("Server.DisableBackup returned %+v, ", err)
-	}
-}
-
-func TestServerServiceHandler_GetBackupSchedule(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/backup_get_schedule", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{ "enabled": true,"cron_type": "weekly","next_scheduled_time_utc": "2016-05-07 08:00:00","hour": 8,"dow": 6,"dom": 0}`
-		fmt.Fprint(writer, response)
-	})
-
-	backup, err := client.Server.GetBackupSchedule(ctx, "1234")
-
-	if err != nil {
-		t.Errorf("Server.GetBackupSchedule returned %+v, ", err)
-	}
-
-	expected := &BackupSchedule{
-		Enabled:  true,
-		CronType: "weekly",
-		NextRun:  "2016-05-07 08:00:00",
-		Hour:     8,
-		Dow:      6,
-		Dom:      0,
-	}
-
-	if !reflect.DeepEqual(backup, expected) {
-		t.Errorf("Server.GetBackupSchedule returned %+v, expected %+v", backup, expected)
-	}
-}
-
-func TestServerServiceHandler_SetBackupSchedule(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/backup_set_schedule", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	bs := &BackupSchedule{
-		CronType: "",
-		Hour:     23,
-		Dow:      2,
-		Dom:      3,
-	}
-
-	err := client.Server.SetBackupSchedule(ctx, "1234", bs)
-
-	if err != nil {
-		t.Errorf("Server.SetBackupSchedule returned %+v, ", err)
-	}
-}
-
-func TestServerServiceHandler_RestoreBackup(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/restore_backup", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.Server.RestoreBackup(ctx, "1234", "45a31f4")
-
-	if err != nil {
-		t.Errorf("Server.RestoreBackup returned %+v, ", err)
-	}
-}
-
-func TestServerServiceHandler_RestoreSnapshot(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/restore_snapshot", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.Server.RestoreSnapshot(ctx, "1234", "45a31f4")
-
-	if err != nil {
-		t.Errorf("Server.RestoreSnapshot returned %+v, ", err)
-	}
-}
-
-func TestServerServiceHandler_SetLabel(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/label_set", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.Server.SetLabel(ctx, "1234", "new-label")
-
-	if err != nil {
-		t.Errorf("Server.SetLabel returned %+v, ", err)
-	}
-}
-
-func TestServerServiceHandler_SetTag(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/tag_set", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.Server.SetTag(ctx, "1234", "new-tag")
-
-	if err != nil {
-		t.Errorf("Server.SetTag returned %+v, ", err)
-	}
-}
-
-func TestServerServiceHandler_Neighbors(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/neighbors", func(writer http.ResponseWriter, request *http.Request) {
-		response := `[2345,1234]`
-		fmt.Fprint(writer, response)
-	})
-
-	neighbors, err := client.Server.Neighbors(ctx, "1234")
-
-	if err != nil {
-		t.Errorf("Server.Neighbors returned %+v, ", err)
-	}
-
-	expected := []int{2345, 1234}
-
-	if !reflect.DeepEqual(neighbors, expected) {
-		t.Errorf("Server.Neighbors returned %+v, expected %+v", neighbors, expected)
-	}
-}
-
-func TestServerServiceHandler_EnablePrivateNetwork(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/private_network_enable", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.Server.EnablePrivateNetwork(ctx, "1234", "45a31f4")
-
-	if err != nil {
-		t.Errorf("Server.EnablePrivateNetwork returned %+v, ", err)
-	}
-}
-
-func TestServerServiceHandler_DisablePrivateNetwork(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/private_network_disable", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.Server.DisablePrivateNetwork(ctx, "1234", "45a31f4")
-
-	if err != nil {
-		t.Errorf("Server.DisablePrivateNetwork returned %+v, ", err)
-	}
-}
-
-func TestServerServiceHandler_ListPrivateNetworks(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/private_networks", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"net539626f0798d7": {"NETWORKID": "net539626f0798d7","mac_address": "5a:02:00:00:24:e9","ip_address": "10.99.0.3"}}`
-		fmt.Fprint(writer, response)
-	})
-
-	privateNetwork, err := client.Server.ListPrivateNetworks(ctx, "12345")
-
-	if err != nil {
-		t.Errorf("Server.ListPrivateNetworks return %+v, ", err)
-	}
-
-	expected := []PrivateNetwork{
-		{
-			NetworkID:  "net539626f0798d7",
-			MacAddress: "5a:02:00:00:24:e9",
-			IPAddress:  "10.99.0.3",
-		},
-	}
-
-	if !reflect.DeepEqual(privateNetwork, expected) {
-		t.Errorf("Server.ListPrivateNetworks returned %+v, expected %+v", privateNetwork, expected)
-	}
-}
-
-func TestServerServiceHandler_ListUpgradePlan(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/upgrade_plan_list", func(writer http.ResponseWriter, request *http.Request) {
-		response := `[1, 2, 3, 4]`
-		fmt.Fprint(writer, response)
-	})
-
-	plans, err := client.Server.ListUpgradePlan(ctx, "123")
-
-	if err != nil {
-		t.Errorf("Server.ListUpgradePlan return %+v ", err)
-	}
-
-	expected := []int{1, 2, 3, 4}
-
-	if !reflect.DeepEqual(plans, expected) {
-		t.Errorf("Server.ListUpgradePlan returned %+v, expected %+v", plans, expected)
-	}
-}
-
-func TestServerServiceHandler_UpgradePlan(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/upgrade_plan", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.Server.UpgradePlan(ctx, "12351", "123")
-
-	if err != nil {
-		t.Errorf("Server.UpgradePlan return %+v ", err)
-	}
-}
-
-func TestServerServiceHandler_ListOS(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/os_change_list", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"127": {"OSID": 127,"name": "CentOS 6 x64","arch": "x64","family": "centos","windows": false,"surcharge": "0.00"}}`
-		fmt.Fprint(writer, response)
-	})
-
-	os, err := client.Server.ListOS(ctx, "1234")
-
-	if err != nil {
-		t.Errorf("Server.ListOS return %+v ", err)
-	}
-
-	expected := []OS{
-		{
-			OsID:    127,
-			Name:    "CentOS 6 x64",
-			Arch:    "x64",
-			Family:  "centos",
-			Windows: false,
-		},
-	}
-
-	if !reflect.DeepEqual(os, expected) {
-		t.Errorf("Server.ListOS returned %+v, expected %+v", os, expected)
-	}
-}
-
-func TestServerServiceHandler_ChangeOS(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/os_change", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.Server.ChangeOS(ctx, "1234", "1")
-
-	if err != nil {
-		t.Errorf("Server.ChangeOS return %+v ", err)
-	}
-}
-
-func TestServerServiceHandler_IsoAttach(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/iso_attach", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.Server.IsoAttach(ctx, "1234", "1")
-
-	if err != nil {
-		t.Errorf("Server.IsoAttach return %+v ", err)
-	}
-}
-
-func TestServerServiceHandler_IsoDetach(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/iso_detach", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.Server.IsoDetach(ctx, "1234")
-
-	if err != nil {
-		t.Errorf("Server.IsoDetach return %+v ", err)
-	}
-}
-
-func TestServerServiceHandler_IsoStatus(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/iso_status", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"state": "ready","ISOID": "12345"}`
-		fmt.Fprint(writer, response)
-	})
-
-	isoStatus, err := client.Server.IsoStatus(ctx, "1234")
-
-	if err != nil {
-		t.Errorf("Server.IsoStatus return %+v ", err)
-	}
-
-	expected := &ServerIso{State: "ready", IsoID: "12345"}
-
-	if !reflect.DeepEqual(isoStatus, expected) {
-		t.Errorf("Server.IsoStatus returned %+v, expected %+v", isoStatus, expected)
-	}
-}
-
-func TestServerServiceHandler_SetFirewallGroup(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/firewall_group_set", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.Server.SetFirewallGroup(ctx, "1234", "123")
-
-	if err != nil {
-		t.Errorf("Server.SetFirewallGroup return %+v ", err)
-	}
-}
-
-func TestServerServiceHandler_SetUserData(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/set_user_data", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.Server.SetUserData(ctx, "1234", "user-test-data")
-
-	if err != nil {
-		t.Errorf("Server.SetUserData return %+v ", err)
-	}
-}
-
-func TestServerServiceHandler_GetUserData(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/get_user_data", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"userdata": "ZWNobyBIZWxsbyBXb3JsZA=="}`
-		fmt.Fprint(writer, response)
-	})
-
-	userData, err := client.Server.GetUserData(ctx, "1234")
-
-	if err != nil {
-		t.Errorf("Server.GetUserData return %+v ", err)
-	}
-
-	expected := &UserData{UserData: "ZWNobyBIZWxsbyBXb3JsZA=="}
-
-	if !reflect.DeepEqual(userData, expected) {
-		t.Errorf("Server.GetUserData returned %+v, expected %+v", userData, expected)
-	}
-}
-
-func TestServerServiceHandler_IPV4Info(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/list_ipv4", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{ "576965": [{"ip": "123.123.123.123","netmask": "255.255.255.248","gateway": "123.123.123.1","type": "main_ip","reverse": "host1.example.com"}]}`
-		fmt.Fprint(writer, response)
-	})
-
-	ipv4, err := client.Server.IPV4Info(ctx, "1234", true)
-
-	if err != nil {
-		t.Errorf("Server.IPV4Info returned %+v", err)
-	}
-
-	expected := []IPV4{
-		{
-			IP:      "123.123.123.123",
-			Netmask: "255.255.255.248",
-			Gateway: "123.123.123.1",
-			Type:    "main_ip",
-			Reverse: "host1.example.com",
-		},
-	}
-
-	if !reflect.DeepEqual(ipv4, expected) {
-		t.Errorf("Server.IPV4Info returned %+v, expected %+v", ipv4, expected)
-	}
-}
-
-func TestServerServiceHandler_IPV6Info(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/list_ipv6", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"576965": [{"ip": "2001:DB8:1000::100","network": "2001:DB8:1000::","network_size": "64","type": "main_ip"}]}`
-		fmt.Fprint(writer, response)
-	})
-
-	ipv6, err := client.Server.IPV6Info(ctx, "1234")
-
-	if err != nil {
-		t.Errorf("Server.IPV6Info returned %+v", err)
-	}
-
-	expected := []IPV6{
-		{
-			IP:          "2001:DB8:1000::100",
-			Network:     "2001:DB8:1000::",
-			NetworkSize: "64",
-			Type:        "main_ip",
-		},
-	}
-
-	if !reflect.DeepEqual(ipv6, expected) {
-		t.Errorf("Server.IPV6Info returned %+v, expected %+v", ipv6, expected)
-	}
-}
-
-func TestServerServiceHandler_AddIPV4(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/create_ipv4", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.Server.AddIPV4(ctx, "1234")
-
-	if err != nil {
-		t.Errorf("Server.AddIPV4 returned %+v", err)
-	}
-}
-
-func TestServerServiceHandler_DestroyIPV4(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/destroy_ipv4", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.Server.DestroyIPV4(ctx, "1234", "192.168.0.1")
-
-	if err != nil {
-		t.Errorf("Server.DestroyIPV4 returned %+v", err)
-	}
-}
-
-func TestServerServiceHandler_EnableIPV6(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/ipv6_enable", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.Server.EnableIPV6(ctx, "1234")
-
-	if err != nil {
-		t.Errorf("Server.EnableIPV6 returned %+v", err)
-	}
-}
-
-func TestServerServiceHandler_Bandwidth(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/bandwidth", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"incoming_bytes": [["2014-06-10","81072581"]],"outgoing_bytes": [["2014-06-10","4059610"]]}`
-		fmt.Fprint(writer, response)
-	})
-
-	bandwidth, err := client.Server.Bandwidth(ctx, "123")
-
-	if err != nil {
-		t.Errorf("Server.Bandwidth returned %+v", err)
-	}
-
-	expected := []map[string]string{
-		{"date": "2014-06-10", "incoming": "81072581", "outgoing": "4059610"},
-	}
-
-	if !reflect.DeepEqual(bandwidth, expected) {
-		t.Errorf("Server.Bandwidth returned %+v, expected %+v", bandwidth, expected)
-	}
-}
-
-func TestServerServiceHandler_ListReverseIPV6(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/reverse_list_ipv6", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"576965": [{"ip": "2001:DB8:1000::101","reverse": "host1.example.com"}]}`
-		fmt.Fprint(writer, response)
-	})
-
-	reverseIPV6, err := client.Server.ListReverseIPV6(ctx, "123890")
-
-	if err != nil {
-		t.Errorf("Server.ListReverseIPV6 returned error: %v", err)
-	}
-
-	expected := []ReverseIPV6{
-		{IP: "2001:DB8:1000::101", Reverse: "host1.example.com"},
-	}
-
-	if !reflect.DeepEqual(reverseIPV6, expected) {
-		t.Errorf("Server.ListReverseIPV6 returned %+v, expected %+v", reverseIPV6, expected)
-	}
-}
-
-func TestServerServiceHandler_SetDefaultReverseIPV4(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/reverse_default_ipv4", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.Server.SetDefaultReverseIPV4(ctx, "1234", "129.123.123.1")
-
-	if err != nil {
-		t.Errorf("Server.SetDefaultReverseIPV4 returned %+v", err)
-	}
-}
-
-func TestServerServiceHandler_DeleteReverseIPV6(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/reverse_delete_ipv6", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.Server.DeleteReverseIPV6(ctx, "1234", "2001:19f0:8001:1480:5400:2ff:fe00:8228")
-
-	if err != nil {
-		t.Errorf("Server.DeleteReverseIPV6 returned %+v", err)
-	}
-}
-
-func TestServerServiceHandler_SetReverseIPV4(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/reverse_set_ipv4", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.Server.SetReverseIPV4(ctx, "1234", "192.168.0.1", "test.com")
-
-	if err != nil {
-		t.Errorf("Server.SetReverseIPV4 returned %+v", err)
-	}
-}
-
-func TestServerServiceHandler_SetReverseIPV6(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/reverse_set_ipv6", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.Server.SetReverseIPV6(ctx, "1234", "2001:19f0:8001:1480:5400:2ff:fe00:8228", "test.com")
-
-	if err != nil {
-		t.Errorf("Server.SetReverseIPV6 returned %+v", err)
-	}
-}
-
-func TestServerServiceHandler_Halt(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/halt", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.Server.Halt(ctx, "1234")
-
-	if err != nil {
-		t.Errorf("Server.Halt returned %+v", err)
-	}
-}
-
-func TestServerServiceHandler_Start(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/start", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.Server.Start(ctx, "1234")
-
-	if err != nil {
-		t.Errorf("Server.Start returned %+v", err)
-	}
-}
-
-func TestServerServiceHandler_Reboot(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/reboot", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.Server.Reboot(ctx, "1234")
-
-	if err != nil {
-		t.Errorf("Server.Reboot returned %+v", err)
-	}
-}
-
-func TestServerServiceHandler_Reinstall(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/reinstall", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.Server.Reinstall(ctx, "1234")
-
-	if err != nil {
-		t.Errorf("Server.Reinstall returned %+v", err)
-	}
-}
-
-func TestServerServiceHandler_Delete(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/destroy", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
-	})
-
-	err := client.Server.Delete(ctx, "1234")
-
-	if err != nil {
-		t.Errorf("Server.Delete returned %+v", err)
-	}
-}
-
-func TestServerServiceHandler_Create(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/create", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"SUBID": "1234151"}`
-		fmt.Fprint(writer, response)
-	})
-
-	optionsWithPrivateNetwork := &ServerOptions{
-		IPXEChain:            "test.org",
-		IsoID:                1,
-		ScriptID:             "213",
-		EnableIPV6:           true,
-		EnablePrivateNetwork: true,
-		AutoBackups:          true,
-		UserData:             "uno-dos-tres",
-		NotifyActivate:       true,
-		DDOSProtection:       true,
-		SnapshotID:           "12ab",
-		Hostname:             "hostname-3000",
-		Tag:                  "tagger",
-		Label:                "label-extreme",
-		SSHKeyIDs:            []string{"1234"},
-		ReservedIPV4:         "63.209.35.79",
-		FirewallGroupID:      "1234",
-		AppID:                "1234",
-	}
-
-	server, err := client.Server.Create(ctx, 1, 2, 3, optionsWithPrivateNetwork)
-
-	if err != nil {
-		t.Errorf("Server.Create returned %+v", err)
-	}
-
-	expected := &Server{InstanceID: "1234151"}
-
-	if !reflect.DeepEqual(server, expected) {
-		t.Errorf("Server.Create returned %+v, expected %+v", server, expected)
-	}
-
-	options := &ServerOptions{
-		NetworkID: []string{"1", "2", "3"},
-	}
-
-	serverWithNetwork, err := client.Server.Create(ctx, 1, 2, 3, options)
-
-	if err != nil {
-		t.Errorf("Server.Create returned %+v", err)
-	}
-
-	if !reflect.DeepEqual(serverWithNetwork, expected) {
-		t.Errorf("Server.Create returned %+v, expected %+v", serverWithNetwork, expected)
-	}
-}
-
-func TestServerServiceHandler_List(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/list", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"576965": {"SUBID": "576965","os": "CentOS 6 x64","ram": "4096 MB","disk": "Virtual 60 GB","main_ip": "123.123.123.123","vcpu_count": "2","location": "New Jersey","DCID": "1","default_password": "nreqnusibni","date_created": "2013-12-19 14:45:41","pending_charges": "46.67","status": "active","cost_per_month": "10.05","current_bandwidth_gb": 131.512,"allowed_bandwidth_gb": "1000","netmask_v4": "255.255.255.248","gateway_v4": "123.123.123.1","power_status": "running","server_state": "ok","VPSPLANID": "28","v6_main_ip": "2001:DB8:1000::100","v6_network_size": "64","v6_network": "2001:DB8:1000::","v6_networks": [{"v6_network": "2001:DB8:1000::","v6_main_ip": "2001:DB8:1000::100","v6_network_size": "64"}],"label": "my new server","internal_ip": "10.99.0.10","kvm_url": "https://my.vultr.com/subs/novnc/api.php?data=eawxFVZw2mXnhGUV","auto_backups": "yes","tag": "mytag","OSID": "127","APPID": "0","FIREWALLGROUPID": "0"}}`
-		fmt.Fprint(writer, response)
-	})
-
-	server, err := client.Server.List(ctx)
-
-	if err != nil {
-		t.Errorf("Server.List returned %+v", err)
-	}
-
-	expected := []Server{
-		{
-			InstanceID:       "576965",
-			Os:               "CentOS 6 x64",
-			RAM:              "4096 MB",
-			Disk:             "Virtual 60 GB",
-			MainIP:           "123.123.123.123",
-			VPSCpus:          "2",
-			Location:         "New Jersey",
-			RegionID:         "1",
-			DefaultPassword:  "nreqnusibni",
-			Created:          "2013-12-19 14:45:41",
-			PendingCharges:   "46.67",
-			Status:           "active",
-			Cost:             "10.05",
-			CurrentBandwidth: 131.512,
-			AllowedBandwidth: "1000",
-			NetmaskV4:        "255.255.255.248",
-			GatewayV4:        "123.123.123.1",
-			PowerStatus:      "running",
-			ServerState:      "ok",
-			PlanID:           "28",
-			V6Networks:       []V6Network{{Network: "2001:DB8:1000::", MainIP: "2001:DB8:1000::100", NetworkSize: "64"}},
-			Label:            "my new server",
-			InternalIP:       "10.99.0.10",
-			KVMUrl:           "https://my.vultr.com/subs/novnc/api.php?data=eawxFVZw2mXnhGUV",
-			AutoBackups:      "yes",
-			Tag:              "mytag",
-			OsID:             "127",
-			AppID:            "0",
-			FirewallGroupID:  "0",
-		},
-	}
-
-	if !reflect.DeepEqual(server, expected) {
-		t.Errorf("Server.List returned %+v, expected %+v", server, expected)
-	}
-}
-
-func TestServerServiceHandler_ListByLabel(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/list", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"576965": {"SUBID": "576965","os": "CentOS 6 x64","ram": "4096 MB","disk": "Virtual 60 GB","main_ip": "123.123.123.123","vcpu_count": "2","location": "New Jersey","DCID": "1","default_password": "nreqnusibni","date_created": "2013-12-19 14:45:41","pending_charges": "46.67","status": "active","cost_per_month": "10.05","current_bandwidth_gb": 131.512,"allowed_bandwidth_gb": "1000","netmask_v4": "255.255.255.248","gateway_v4": "123.123.123.1","power_status": "running","server_state": "ok","VPSPLANID": "28","v6_main_ip": "2001:DB8:1000::100","v6_network_size": "64","v6_network": "2001:DB8:1000::","v6_networks": [{"v6_network": "2001:DB8:1000::","v6_main_ip": "2001:DB8:1000::100","v6_network_size": "64"}],"label": "my new server","internal_ip": "10.99.0.10","kvm_url": "https://my.vultr.com/subs/novnc/api.php?data=eawxFVZw2mXnhGUV","auto_backups": "yes","tag": "mytag","OSID": "127","APPID": "0","FIREWALLGROUPID": "0"}}`
-		fmt.Fprint(writer, response)
-	})
-
-	server, err := client.Server.ListByLabel(ctx, "label")
-
-	if err != nil {
-		t.Errorf("Server.ListByLabel returned %+v", err)
-	}
-
-	expected := []Server{
-		{
-			InstanceID:       "576965",
-			Os:               "CentOS 6 x64",
-			RAM:              "4096 MB",
-			Disk:             "Virtual 60 GB",
-			MainIP:           "123.123.123.123",
-			VPSCpus:          "2",
-			Location:         "New Jersey",
-			RegionID:         "1",
-			DefaultPassword:  "nreqnusibni",
-			Created:          "2013-12-19 14:45:41",
-			PendingCharges:   "46.67",
-			Status:           "active",
-			Cost:             "10.05",
-			CurrentBandwidth: 131.512,
-			AllowedBandwidth: "1000",
-			NetmaskV4:        "255.255.255.248",
-			GatewayV4:        "123.123.123.1",
-			PowerStatus:      "running",
-			ServerState:      "ok",
-			PlanID:           "28",
-			V6Networks:       []V6Network{{Network: "2001:DB8:1000::", MainIP: "2001:DB8:1000::100", NetworkSize: "64"}},
-			Label:            "my new server",
-			InternalIP:       "10.99.0.10",
-			KVMUrl:           "https://my.vultr.com/subs/novnc/api.php?data=eawxFVZw2mXnhGUV",
-			AutoBackups:      "yes",
-			Tag:              "mytag",
-			OsID:             "127",
-			AppID:            "0",
-			FirewallGroupID:  "0",
-		},
-	}
-
-	if !reflect.DeepEqual(server, expected) {
-		t.Errorf("Server.ListByLabel returned %+v, expected %+v", server, expected)
-	}
-}
-
-func TestServerServiceHandler_ListByMainIP(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/list", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"576965": {"SUBID": "576965","os": "CentOS 6 x64","ram": "4096 MB","disk": "Virtual 60 GB","main_ip": "123.123.123.123","vcpu_count": "2","location": "New Jersey","DCID": "1","default_password": "nreqnusibni","date_created": "2013-12-19 14:45:41","pending_charges": "46.67","status": "active","cost_per_month": "10.05","current_bandwidth_gb": 131.512,"allowed_bandwidth_gb": "1000","netmask_v4": "255.255.255.248","gateway_v4": "123.123.123.1","power_status": "running","server_state": "ok","VPSPLANID": "28","v6_main_ip": "2001:DB8:1000::100","v6_network_size": "64","v6_network": "2001:DB8:1000::","v6_networks": [{"v6_network": "2001:DB8:1000::","v6_main_ip": "2001:DB8:1000::100","v6_network_size": "64"}],"label": "my new server","internal_ip": "10.99.0.10","kvm_url": "https://my.vultr.com/subs/novnc/api.php?data=eawxFVZw2mXnhGUV","auto_backups": "yes","tag": "mytag","OSID": "127","APPID": "0","FIREWALLGROUPID": "0"}}`
-		fmt.Fprint(writer, response)
-	})
-
-	server, err := client.Server.ListByMainIP(ctx, "label")
-
-	if err != nil {
-		t.Errorf("Server.ListByMainIP returned %+v", err)
-	}
-
-	expected := []Server{
-		{
-			InstanceID:       "576965",
-			Os:               "CentOS 6 x64",
-			RAM:              "4096 MB",
-			Disk:             "Virtual 60 GB",
-			MainIP:           "123.123.123.123",
-			VPSCpus:          "2",
-			Location:         "New Jersey",
-			RegionID:         "1",
-			DefaultPassword:  "nreqnusibni",
-			Created:          "2013-12-19 14:45:41",
-			PendingCharges:   "46.67",
-			Status:           "active",
-			Cost:             "10.05",
-			CurrentBandwidth: 131.512,
-			AllowedBandwidth: "1000",
-			NetmaskV4:        "255.255.255.248",
-			GatewayV4:        "123.123.123.1",
-			PowerStatus:      "running",
-			ServerState:      "ok",
-			PlanID:           "28",
-			V6Networks:       []V6Network{{Network: "2001:DB8:1000::", MainIP: "2001:DB8:1000::100", NetworkSize: "64"}},
-			Label:            "my new server",
-			InternalIP:       "10.99.0.10",
-			KVMUrl:           "https://my.vultr.com/subs/novnc/api.php?data=eawxFVZw2mXnhGUV",
-			AutoBackups:      "yes",
-			Tag:              "mytag",
-			OsID:             "127",
-			AppID:            "0",
-			FirewallGroupID:  "0",
-		},
-	}
-
-	if !reflect.DeepEqual(server, expected) {
-		t.Errorf("Server.ListByMainIP returned %+v, expected %+v", server, expected)
-	}
-}
-
-func TestServerServiceHandler_ListByTag(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/list", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"576965": {"SUBID": "576965","os": "CentOS 6 x64","ram": "4096 MB","disk": "Virtual 60 GB","main_ip": "123.123.123.123","vcpu_count": "2","location": "New Jersey","DCID": "1","default_password": "nreqnusibni","date_created": "2013-12-19 14:45:41","pending_charges": "46.67","status": "active","cost_per_month": "10.05","current_bandwidth_gb": 131.512,"allowed_bandwidth_gb": "1000","netmask_v4": "255.255.255.248","gateway_v4": "123.123.123.1","power_status": "running","server_state": "ok","VPSPLANID": "28","v6_main_ip": "2001:DB8:1000::100","v6_network_size": "64","v6_network": "2001:DB8:1000::","v6_networks": [{"v6_network": "2001:DB8:1000::","v6_main_ip": "2001:DB8:1000::100","v6_network_size": "64"}],"label": "my new server","internal_ip": "10.99.0.10","kvm_url": "https://my.vultr.com/subs/novnc/api.php?data=eawxFVZw2mXnhGUV","auto_backups": "yes","tag": "mytag","OSID": "127","APPID": "0","FIREWALLGROUPID": "0"}}`
-		fmt.Fprint(writer, response)
-	})
-
-	server, err := client.Server.ListByTag(ctx, "label")
-
-	if err != nil {
-		t.Errorf("Server.ListByTag returned %+v", err)
-	}
-
-	expected := []Server{
-		{
-			InstanceID:       "576965",
-			Os:               "CentOS 6 x64",
-			RAM:              "4096 MB",
-			Disk:             "Virtual 60 GB",
-			MainIP:           "123.123.123.123",
-			VPSCpus:          "2",
-			Location:         "New Jersey",
-			RegionID:         "1",
-			DefaultPassword:  "nreqnusibni",
-			Created:          "2013-12-19 14:45:41",
-			PendingCharges:   "46.67",
-			Status:           "active",
-			Cost:             "10.05",
-			CurrentBandwidth: 131.512,
-			AllowedBandwidth: "1000",
-			NetmaskV4:        "255.255.255.248",
-			GatewayV4:        "123.123.123.1",
-			PowerStatus:      "running",
-			ServerState:      "ok",
-			PlanID:           "28",
-			V6Networks:       []V6Network{{Network: "2001:DB8:1000::", MainIP: "2001:DB8:1000::100", NetworkSize: "64"}},
-			Label:            "my new server",
-			InternalIP:       "10.99.0.10",
-			KVMUrl:           "https://my.vultr.com/subs/novnc/api.php?data=eawxFVZw2mXnhGUV",
-			AutoBackups:      "yes",
-			Tag:              "mytag",
-			OsID:             "127",
-			AppID:            "0",
-			FirewallGroupID:  "0",
-		},
-	}
-
-	if !reflect.DeepEqual(server, expected) {
-		t.Errorf("Server.ListByTag returned %+v, expected %+v", server, expected)
-	}
-}
-
-func TestServerServiceHandler_GetServer(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/server/list", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"SUBID": "576965","os": "CentOS 6 x64","ram": "4096 MB","disk": "Virtual 60 GB","main_ip": "123.123.123.123","vcpu_count": "2","location": "New Jersey","DCID": "1","default_password": "nreqnusibni","date_created": "2013-12-19 14:45:41","pending_charges": "46.67","status": "active","cost_per_month": "10.05","current_bandwidth_gb": 131.512,"allowed_bandwidth_gb": "1000","netmask_v4": "255.255.255.248","gateway_v4": "123.123.123.1","power_status": "running","server_state": "ok","VPSPLANID": "28","v6_main_ip": "2001:DB8:1000::100","v6_network_size": "64","v6_network": "2001:DB8:1000::","v6_networks": [{"v6_network": "2001:DB8:1000::","v6_main_ip": "2001:DB8:1000::100","v6_network_size": "64"}],"label": "my new server","internal_ip": "10.99.0.10","kvm_url": "https://my.vultr.com/subs/novnc/api.php?data=eawxFVZw2mXnhGUV","auto_backups": "yes","tag": "mytag","OSID": "127","APPID": "0","FIREWALLGROUPID": "0"}`
-		fmt.Fprint(writer, response)
-	})
-
-	server, err := client.Server.GetServer(ctx, "1234")
-
-	if err != nil {
-		t.Errorf("Server.GetServer returned %+v", err)
-	}
-
-	expected := &Server{
-		InstanceID:       "576965",
-		Os:               "CentOS 6 x64",
-		RAM:              "4096 MB",
-		Disk:             "Virtual 60 GB",
-		MainIP:           "123.123.123.123",
-		VPSCpus:          "2",
-		Location:         "New Jersey",
-		RegionID:         "1",
-		DefaultPassword:  "nreqnusibni",
-		Created:          "2013-12-19 14:45:41",
-		PendingCharges:   "46.67",
-		Status:           "active",
-		Cost:             "10.05",
-		CurrentBandwidth: 131.512,
-		AllowedBandwidth: "1000",
-		NetmaskV4:        "255.255.255.248",
-		GatewayV4:        "123.123.123.1",
-		PowerStatus:      "running",
-		ServerState:      "ok",
-		PlanID:           "28",
-		V6Networks:       []V6Network{{Network: "2001:DB8:1000::", MainIP: "2001:DB8:1000::100", NetworkSize: "64"}},
-		Label:            "my new server",
-		InternalIP:       "10.99.0.10",
-		KVMUrl:           "https://my.vultr.com/subs/novnc/api.php?data=eawxFVZw2mXnhGUV",
-		AutoBackups:      "yes",
-		Tag:              "mytag",
-		OsID:             "127",
-		AppID:            "0",
-		FirewallGroupID:  "0",
-	}
-
-	if !reflect.DeepEqual(server, expected) {
-		t.Errorf("Server.GetServer returned %+v, expected %+v", server, expected)
-	}
-}
diff --git a/snapshot.go b/snapshot.go
index 92e53d0..5b6e837 100644
--- a/snapshot.go
+++ b/snapshot.go
@@ -2,167 +2,142 @@ package govultr
 
 import (
 	"context"
+	"fmt"
 	"net/http"
-	"net/url"
+
+	"github.com/google/go-querystring/query"
 )
 
 // SnapshotService is the interface to interact with Snapshot endpoints on the Vultr API
-// Link: https://www.vultr.com/api/#snapshot
+// Link : https://www.vultr.com/api/#tag/snapshot
 type SnapshotService interface {
-	Create(ctx context.Context, InstanceID, description string) (*Snapshot, error)
-	CreateFromURL(ctx context.Context, snapshotURL string) (*Snapshot, error)
-	Delete(ctx context.Context, snapshotID string) error
-	List(ctx context.Context) ([]Snapshot, error)
+	Create(ctx context.Context, snapshotReq *SnapshotReq) (*Snapshot, error)
+	CreateFromURL(ctx context.Context, snapshotURLReq *SnapshotURLReq) (*Snapshot, error)
 	Get(ctx context.Context, snapshotID string) (*Snapshot, error)
+	Delete(ctx context.Context, snapshotID string) error
+	List(ctx context.Context, options *ListOptions) ([]Snapshot, *Meta, error)
 }
 
 // SnapshotServiceHandler handles interaction with the snapshot methods for the Vultr API
 type SnapshotServiceHandler struct {
-	Client *Client
+	client *Client
 }
 
 // Snapshot represents a Vultr snapshot
 type Snapshot struct {
-	SnapshotID  string `json:"SNAPSHOTID"`
-	DateCreated string `json:"date_created"`
-	Description string `json:"description"`
-	Size        string `json:"size"`
-	Status      string `json:"status"`
-	OsID        string `json:"OSID"`
-	AppID       string `json:"APPID"`
+	ID             string `json:"id"`
+	DateCreated    string `json:"date_created"`
+	Description    string `json:"description"`
+	Size           int    `json:"size"`
+	CompressedSize int    `json:"compressed_size"`
+	Status         string `json:"status"`
+	OsID           int    `json:"os_id"`
+	AppID          int    `json:"app_id"`
 }
 
-// Snapshots represent a collection of snapshots
-type Snapshots []Snapshot
+// SnapshotReq struct is used to create snapshots.
+type SnapshotReq struct {
+	InstanceID  string `json:"instance_id,omitempty"`
+	Description string `json:"description,omitempty"`
+}
 
-// Create makes a snapshot of a provided server
-func (s *SnapshotServiceHandler) Create(ctx context.Context, InstanceID, description string) (*Snapshot, error) {
+// SnapshotURLReq struct is used to create snapshots from a URL.
+type SnapshotURLReq struct {
+	URL         string `json:"url"`
+	Description string `json:"description,omitempty"`
+}
 
-	uri := "/v1/snapshot/create"
+type snapshotsBase struct {
+	Snapshots []Snapshot `json:"snapshots"`
+	Meta      *Meta      `json:"meta"`
+}
 
-	values := url.Values{
-		"SUBID":       {InstanceID},
-		"description": {description},
-	}
+type snapshotBase struct {
+	Snapshot *Snapshot `json:"snapshot"`
+}
 
-	req, err := s.Client.NewRequest(ctx, http.MethodPost, uri, values)
+// Create makes a snapshot of a provided server
+func (s *SnapshotServiceHandler) Create(ctx context.Context, snapshotReq *SnapshotReq) (*Snapshot, error) {
+	uri := "/v2/snapshots"
 
+	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, snapshotReq)
 	if err != nil {
 		return nil, err
 	}
 
-	snapshot := new(Snapshot)
-	err = s.Client.DoWithContext(ctx, req, snapshot)
-
-	if err != nil {
+	snapshot := new(snapshotBase)
+	if err = s.client.DoWithContext(ctx, req, snapshot); err != nil {
 		return nil, err
 	}
 
-	snapshot.Description = description
-	return snapshot, nil
+	return snapshot.Snapshot, nil
 }
 
 // CreateFromURL will create a snapshot based on an image iso from a URL you provide
-func (s *SnapshotServiceHandler) CreateFromURL(ctx context.Context, snapshotURL string) (*Snapshot, error) {
-	uri := "/v1/snapshot/create_from_url"
-
-	values := url.Values{
-		"url": {snapshotURL},
-	}
-
-	req, err := s.Client.NewRequest(ctx, http.MethodPost, uri, values)
+func (s *SnapshotServiceHandler) CreateFromURL(ctx context.Context, snapshotURLReq *SnapshotURLReq) (*Snapshot, error) {
+	uri := "/v2/snapshots/create-from-url"
 
+	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, snapshotURLReq)
 	if err != nil {
 		return nil, err
 	}
 
-	snapshot := new(Snapshot)
-	err = s.Client.DoWithContext(ctx, req, snapshot)
-
-	if err != nil {
+	snapshot := new(snapshotBase)
+	if err = s.client.DoWithContext(ctx, req, snapshot); err != nil {
 		return nil, err
 	}
 
-	return snapshot, nil
+	return snapshot.Snapshot, nil
 }
 
-// Delete a snapshot based on snapshotID
-func (s *SnapshotServiceHandler) Delete(ctx context.Context, snapshotID string) error {
-	uri := "/v1/snapshot/destroy"
-
-	values := url.Values{
-		"SNAPSHOTID": {snapshotID},
-	}
-
-	req, err := s.Client.NewRequest(ctx, http.MethodPost, uri, values)
+// Get a specific snapshot
+func (s *SnapshotServiceHandler) Get(ctx context.Context, snapshotID string) (*Snapshot, error) {
+	uri := fmt.Sprintf("/v2/snapshots/%s", snapshotID)
 
+	req, err := s.client.NewRequest(ctx, http.MethodGet, uri, nil)
 	if err != nil {
-		return err
+		return nil, err
 	}
 
-	err = s.Client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
+	snapshot := new(snapshotBase)
+	if err = s.client.DoWithContext(ctx, req, snapshot); err != nil {
+		return nil, err
 	}
 
-	return nil
+	return snapshot.Snapshot, nil
 }
 
-// List of snapshots details
-func (s *SnapshotServiceHandler) List(ctx context.Context) ([]Snapshot, error) {
-	uri := "/v1/snapshot/list"
-
-	req, err := s.Client.NewRequest(ctx, http.MethodGet, uri, nil)
-
-	if err != nil {
-		return nil, err
-	}
-
-	snapshotMap := make(map[string]Snapshot)
-	err = s.Client.DoWithContext(ctx, req, &snapshotMap)
+// Delete a snapshot.
+func (s *SnapshotServiceHandler) Delete(ctx context.Context, snapshotID string) error {
+	uri := fmt.Sprintf("/v2/snapshots/%s", snapshotID)
 
+	req, err := s.client.NewRequest(ctx, http.MethodDelete, uri, nil)
 	if err != nil {
-		return nil, err
-	}
-
-	var snapshots []Snapshot
-
-	for _, s := range snapshotMap {
-		snapshots = append(snapshots, s)
+		return err
 	}
 
-	return snapshots, nil
+	return s.client.DoWithContext(ctx, req, nil)
 }
 
-// Get individual details of a snapshot based on snapshotID
-func (s *SnapshotServiceHandler) Get(ctx context.Context, snapshotID string) (*Snapshot, error) {
-	uri := "/v1/snapshot/list"
-
-	req, err := s.Client.NewRequest(ctx, http.MethodGet, uri, nil)
+// List all available snapshots.
+func (s *SnapshotServiceHandler) List(ctx context.Context, options *ListOptions) ([]Snapshot, *Meta, error) {
+	uri := "/v2/snapshots"
 
+	req, err := s.client.NewRequest(ctx, http.MethodGet, uri, nil)
 	if err != nil {
-		return nil, err
-	}
-
-	if snapshotID != "" {
-		q := req.URL.Query()
-		q.Add("SNAPSHOTID", snapshotID)
-		req.URL.RawQuery = q.Encode()
+		return nil, nil, err
 	}
-
-	snapshotMap := make(map[string]Snapshot)
-	err = s.Client.DoWithContext(ctx, req, &snapshotMap)
-
+	newValues, err := query.Values(options)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 
-	snapshot := new(Snapshot)
+	req.URL.RawQuery = newValues.Encode()
 
-	for _, s := range snapshotMap {
-		snapshot = &s
+	snapshots := new(snapshotsBase)
+	if err = s.client.DoWithContext(ctx, req, snapshots); err != nil {
+		return nil, nil, err
 	}
 
-	return snapshot, nil
+	return snapshots.Snapshots, snapshots.Meta, nil
 }
diff --git a/snapshot_test.go b/snapshot_test.go
index ba7cc06..fae22f4 100644
--- a/snapshot_test.go
+++ b/snapshot_test.go
@@ -11,19 +11,31 @@ func TestSnapshotServiceHandler_Create(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/snapshot/create", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"SNAPSHOTID": "1234567"}`
-
+	mux.HandleFunc("/v2/snapshots", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"snapshot":{"id": "5359435d28b9a","date_created": "2014-04-18 12:40:40","description": "Test snapshot","size": 42949672960,"compressed_size": 1078864689,"status": "complete","os_id": 127,"app_id": 0}}`
 		fmt.Fprint(writer, response)
 	})
 
-	snapshot, err := client.Snapshot.Create(ctx, "987654321", "unit-test-desc")
+	snap := &SnapshotReq{
+		InstanceID:  "12345",
+		Description: "Test snapshot",
+	}
 
+	snapshot, err := client.Snapshot.Create(ctx, snap)
 	if err != nil {
 		t.Errorf("Snapshot.Create returned error: %v", err)
 	}
 
-	expected := &Snapshot{SnapshotID: "1234567", Description: "unit-test-desc"}
+	expected := &Snapshot{
+		ID:             "5359435d28b9a",
+		DateCreated:    "2014-04-18 12:40:40",
+		Description:    "Test snapshot",
+		Size:           42949672960,
+		CompressedSize: 1078864689,
+		Status:         "complete",
+		OsID:           127,
+		AppID:          0,
+	}
 
 	if !reflect.DeepEqual(snapshot, expected) {
 		t.Errorf("Snapshot.Create returned %+v, expected %+v", snapshot, expected)
@@ -34,107 +46,114 @@ func TestSnapshotServiceHandler_CreateFromURL(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/snapshot/create_from_url", func(writer http.ResponseWriter, request *http.Request) {
-		response := `{"SNAPSHOTID": "544e52f31c706"}`
-
+	mux.HandleFunc("/v2/snapshots/create-from-url", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"snapshot":{"id": "5359435d28b9a","date_created": "2014-04-18 12:40:40","description": "Test snapshot","size": 42949672960,"compressed_size" : 1078864689,"status": "complete","os_id": 127,"app_id": 0}}`
 		fmt.Fprint(writer, response)
 	})
-
-	snapshot, err := client.Snapshot.CreateFromURL(ctx, "http://localhost/some.iso")
-
+	snap := SnapshotURLReq{URL: "http://vultr.com"}
+	snapshot, err := client.Snapshot.CreateFromURL(ctx, &snap)
 	if err != nil {
 		t.Errorf("Snapshot.CreateFromURL returned error: %v", err)
 	}
 
-	expected := &Snapshot{SnapshotID: "544e52f31c706"}
+	expected := &Snapshot{
+		ID:             "5359435d28b9a",
+		DateCreated:    "2014-04-18 12:40:40",
+		Description:    "Test snapshot",
+		Size:           42949672960,
+		CompressedSize: 1078864689,
+		Status:         "complete",
+		OsID:           127,
+		AppID:          0,
+	}
 
 	if !reflect.DeepEqual(snapshot, expected) {
 		t.Errorf("Snapshot.CreateFromURL returned %+v, expected %+v", snapshot, expected)
 	}
 }
 
-func TestSnapshotServiceHandler_Delete(t *testing.T) {
+func TestSnapshotServiceHandler_Get(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/snapshot/destroy", func(writer http.ResponseWriter, request *http.Request) {
-		fmt.Fprint(writer)
+	mux.HandleFunc("/v2/snapshots/5359435d28b9a", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"snapshot":{"id": "5359435d28b9a","date_created": "2014-04-18 12:40:40","description": "Test snapshot","size": 42949672960,"compressed_size": 1078864689,"status": "complete","os_id": 127,"app_id": 0}}`
+		fmt.Fprint(writer, response)
 	})
 
-	err := client.Snapshot.Delete(ctx, "7a05cbf361d98")
-
+	snapshot, err := client.Snapshot.Get(ctx, "5359435d28b9a")
 	if err != nil {
-		t.Errorf("Snapshot.Delete returned %+v, expected %+v", err, nil)
+		t.Errorf("Snapshot.Get returned error: %v", err)
 	}
 
+	expected := &Snapshot{
+		ID:             "5359435d28b9a",
+		DateCreated:    "2014-04-18 12:40:40",
+		Description:    "Test snapshot",
+		Size:           42949672960,
+		CompressedSize: 1078864689,
+		Status:         "complete",
+		OsID:           127,
+		AppID:          0,
+	}
+
+	if !reflect.DeepEqual(snapshot, expected) {
+		t.Errorf("Snapshot.Get returned %+v, expected %+v", snapshot, expected)
+	}
 }
 
-func TestSnapshotServiceHandler_List(t *testing.T) {
+func TestSnapshotServiceHandler_Delete(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/snapshot/list", func(writer http.ResponseWriter, request *http.Request) {
-		response := `
-			{
-		"5359435dc1df3": {
-		"SNAPSHOTID": "5359435dc1df3",
-		"date_created": "2014-04-22 16:11:46",
-		"description": "",
-		"size": "10000000",
-		"status": "complete",
-		"OSID": "127",
-		"APPID": "0"
-		}
-		}
-		`
-		fmt.Fprint(writer, response)
+	mux.HandleFunc("/v2/snapshots/7a05cbf361d98", func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
 	})
 
-	snapshots, err := client.Snapshot.List(ctx)
+	err := client.Snapshot.Delete(ctx, "7a05cbf361d98")
 
 	if err != nil {
-		t.Errorf("Snapshot.List returned error: %v", err)
-	}
-	expected := []Snapshot{
-		{SnapshotID: "5359435dc1df3", DateCreated: "2014-04-22 16:11:46", Description: "", Size: "10000000", Status: "complete", OsID: "127", AppID: "0"},
-	}
-
-	if !reflect.DeepEqual(snapshots, expected) {
-		t.Errorf("Snapshot.List returned %+v, expected %+v", snapshots, expected)
-
+		t.Errorf("Snapshot.Delete returned %+v, expected %+v", err, nil)
 	}
 }
 
-func TestSnapshotServiceHandler_Get(t *testing.T) {
+func TestSnapshotServiceHandler_List(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/snapshot/list", func(writer http.ResponseWriter, request *http.Request) {
-		response := `
-			{
-			"5359435dc1df3": {
-			"SNAPSHOTID": "5359435dc1df3",
-			"date_created": "2014-04-22 16:11:46",
-			"description": "",
-			"size": "10000000",
-			"status": "complete",
-			"OSID": "127",
-			"APPID": "0"
-			}
-			}
-			`
+	mux.HandleFunc("/v2/snapshots", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"snapshots": [{"id": "885ee0f4f263c","date_created": "2014-04-18 12:40:40","description": "Test snapshot","size": 42949672960,"compressed_size": 1078864689,"status": "complete","os_id": 127,"app_id": 0}],"meta": {"total": 4,"links": {"next": "","prev": ""}}}`
 		fmt.Fprint(writer, response)
 	})
 
-	snapshots, err := client.Snapshot.Get(ctx, "5359435dc1df3")
-
+	snapshots, meta, err := client.Snapshot.List(ctx, nil)
 	if err != nil {
-		t.Errorf("Snapshot.Get returned error: %v", err)
+		t.Errorf("Snapshot.List returned error: %v", err)
 	}
-	expected := &Snapshot{SnapshotID: "5359435dc1df3", DateCreated: "2014-04-22 16:11:46", Description: "", Size: "10000000", Status: "complete", OsID: "127", AppID: "0"}
 
-	if !reflect.DeepEqual(snapshots, expected) {
-		t.Errorf("Snapshot.Get returned %+v, expected %+v", snapshots, expected)
+	expectedSnap := []Snapshot{
+		{
+			ID:             "885ee0f4f263c",
+			DateCreated:    "2014-04-18 12:40:40",
+			Description:    "Test snapshot",
+			Size:           42949672960,
+			CompressedSize: 1078864689,
+			Status:         "complete",
+			OsID:           127,
+			AppID:          0,
+		},
+	}
+
+	expectedMeta := &Meta{
+		Total: 4,
+		Links: &Links{},
+	}
+
+	if !reflect.DeepEqual(snapshots, expectedSnap) {
+		t.Errorf("Snapshot.list snapshots returned %+v, expected %+v", snapshots, expectedSnap)
+	}
 
+	if !reflect.DeepEqual(meta, expectedMeta) {
+		t.Errorf("Snapshot.list meta returned %+v, expected %+v", meta, expectedMeta)
 	}
 }
diff --git a/ssh_key.go b/ssh_key.go
index 7f6b0a1..2b8605e 100644
--- a/ssh_key.go
+++ b/ssh_key.go
@@ -2,17 +2,20 @@ package govultr
 
 import (
 	"context"
+	"fmt"
 	"net/http"
-	"net/url"
+
+	"github.com/google/go-querystring/query"
 )
 
 // SSHKeyService is the interface to interact with the SSH Key endpoints on the Vultr API
-// Link: https://www.vultr.com/api/#sshkey
+// Link : https://www.vultr.com/api/#tag/ssh
 type SSHKeyService interface {
-	Create(ctx context.Context, name, sshKey string) (*SSHKey, error)
+	Create(ctx context.Context, sshKeyReq *SSHKeyReq) (*SSHKey, error)
+	Get(ctx context.Context, sshKeyID string) (*SSHKey, error)
+	Update(ctx context.Context, sshKeyID string, sshKeyReq *SSHKeyReq) error
 	Delete(ctx context.Context, sshKeyID string) error
-	List(ctx context.Context) ([]SSHKey, error)
-	Update(ctx context.Context, sshKey *SSHKey) error
+	List(ctx context.Context, options *ListOptions) ([]SSHKey, *Meta, error)
 }
 
 // SSHKeyServiceHandler handles interaction with the SSH Key methods for the Vultr API
@@ -22,119 +25,105 @@ type SSHKeyServiceHandler struct {
 
 // SSHKey represents an SSH Key on Vultr
 type SSHKey struct {
-	SSHKeyID    string `json:"SSHKEYID"`
+	ID          string `json:"id"`
 	Name        string `json:"name"`
-	Key         string `json:"ssh_key"`
+	SSHKey      string `json:"ssh_key"`
 	DateCreated string `json:"date_created"`
 }
 
-// Create will add the specified SSH Key to your Vultr account
-func (s *SSHKeyServiceHandler) Create(ctx context.Context, name, sshKey string) (*SSHKey, error) {
+// SSHKeyReq is the ssh key struct for create and update calls
+type SSHKeyReq struct {
+	Name   string `json:"name,omitempty"`
+	SSHKey string `json:"ssh_key,omitempty"`
+}
 
-	uri := "/v1/sshkey/create"
+type sshKeysBase struct {
+	SSHKeys []SSHKey `json:"ssh_keys"`
+	Meta    *Meta    `json:"meta"`
+}
 
-	values := url.Values{
-		"name":    {name},
-		"ssh_key": {sshKey},
-	}
+type sshKeyBase struct {
+	SSHKey *SSHKey `json:"ssh_key"`
+}
 
-	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
+// Create a ssh key
+func (s *SSHKeyServiceHandler) Create(ctx context.Context, sshKeyReq *SSHKeyReq) (*SSHKey, error) {
+	uri := "/v2/ssh-keys"
 
+	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, sshKeyReq)
 	if err != nil {
 		return nil, err
 	}
 
-	key := new(SSHKey)
-
-	err = s.client.DoWithContext(ctx, req, key)
-
-	if err != nil {
+	key := new(sshKeyBase)
+	if err = s.client.DoWithContext(ctx, req, key); err != nil {
 		return nil, err
 	}
 
-	key.Name = name
-	key.Key = sshKey
-
-	return key, nil
+	return key.SSHKey, nil
 }
 
-// Delete will delete the specified SHH Key from your Vultr account
-func (s *SSHKeyServiceHandler) Delete(ctx context.Context, sshKeyID string) error {
-
-	uri := "/v1/sshkey/destroy"
+// Get a specific ssh key.
+func (s *SSHKeyServiceHandler) Get(ctx context.Context, sshKeyID string) (*SSHKey, error) {
+	uri := fmt.Sprintf("/v2/ssh-keys/%s", sshKeyID)
 
-	values := url.Values{
-		"SSHKEYID": {sshKeyID},
+	req, err := s.client.NewRequest(ctx, http.MethodGet, uri, nil)
+	if err != nil {
+		return nil, err
 	}
 
-	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
+	sshKey := new(sshKeyBase)
+	if err = s.client.DoWithContext(ctx, req, sshKey); err != nil {
+		return nil, err
 	}
 
-	err = s.client.DoWithContext(ctx, req, nil)
+	return sshKey.SSHKey, nil
+}
 
+// Update will update the given SSH Key. Empty strings will be ignored.
+func (s *SSHKeyServiceHandler) Update(ctx context.Context, sshKeyID string, sshKeyReq *SSHKeyReq) error {
+	uri := fmt.Sprintf("/v2/ssh-keys/%s", sshKeyID)
+
+	req, err := s.client.NewRequest(ctx, http.MethodPatch, uri, sshKeyReq)
 	if err != nil {
 		return err
 	}
 
-	return nil
+	return s.client.DoWithContext(ctx, req, nil)
 }
 
-// List will list all the SSH Keys associated with your Vultr account
-func (s *SSHKeyServiceHandler) List(ctx context.Context) ([]SSHKey, error) {
-
-	uri := "/v1/sshkey/list"
-
-	req, err := s.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
-	if err != nil {
-		return nil, err
-	}
+// Delete a specific ssh-key.
+func (s *SSHKeyServiceHandler) Delete(ctx context.Context, sshKeyID string) error {
+	uri := fmt.Sprintf("/v2/ssh-keys/%s", sshKeyID)
 
-	sshKeysMap := make(map[string]SSHKey)
-	err = s.client.DoWithContext(ctx, req, &sshKeysMap)
+	req, err := s.client.NewRequest(ctx, http.MethodDelete, uri, nil)
 	if err != nil {
-		return nil, err
-	}
-
-	var sshKeys []SSHKey
-	for _, key := range sshKeysMap {
-		sshKeys = append(sshKeys, key)
+		return err
 	}
 
-	return sshKeys, nil
+	return s.client.DoWithContext(ctx, req, nil)
 }
 
-// Update will update the given SSH Key. Empty strings will be ignored.
-func (s *SSHKeyServiceHandler) Update(ctx context.Context, sshKey *SSHKey) error {
-
-	uri := "/v1/sshkey/update"
-
-	values := url.Values{
-		"SSHKEYID": {sshKey.SSHKeyID},
-	}
+// List all available SSH Keys.
+func (s *SSHKeyServiceHandler) List(ctx context.Context, options *ListOptions) ([]SSHKey, *Meta, error) {
+	uri := "/v2/ssh-keys"
 
-	// Optional
-	if sshKey.Name != "" {
-		values.Add("name", sshKey.Name)
-	}
-	if sshKey.Key != "" {
-		values.Add("ssh_key", sshKey.Key)
+	req, err := s.client.NewRequest(ctx, http.MethodGet, uri, nil)
+	if err != nil {
+		return nil, nil, err
 	}
 
-	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
-
+	newValues, err := query.Values(options)
 	if err != nil {
-		return err
+		return nil, nil, err
 	}
 
-	err = s.client.DoWithContext(ctx, req, nil)
+	req.URL.RawQuery = newValues.Encode()
 
-	if err != nil {
-		return err
+	sshKeys := new(sshKeysBase)
+	if err = s.client.DoWithContext(ctx, req, sshKeys); err != nil {
+		return nil, nil, err
 	}
 
-	return nil
+	return sshKeys.SSHKeys, sshKeys.Meta, nil
 }
diff --git a/ssh_key_test.go b/ssh_key_test.go
index 47c9a39..916d4ab 100644
--- a/ssh_key_test.go
+++ b/ssh_key_test.go
@@ -11,27 +11,26 @@ func TestSSHKeyServiceHandler_Create(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/sshkey/create", func(writer http.ResponseWriter, request *http.Request) {
-		response := `
-		{
-			"SSHKEYID": "541b4960f23bd"
-		}
-		`
-
+	mux.HandleFunc("/v2/ssh-keys", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"ssh_key": {"id": "5f05d5a71fe28","date_created": "2020-07-08 14:18:15","name": "api-test-ssh","ssh_key": "ssh-rsa AF+LbfYYw== test@admin.com"}}`
 		fmt.Fprint(writer, response)
 	})
 
-	key, err := client.SSHKey.Create(ctx, "foo", "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCyVGaw1PuEl98f4/7Kq3O9ZIvDw2OFOSXAFVqilSFNkHlefm1iMtPeqsIBp2t9cbGUf55xNDULz/bD/4BCV43yZ5lh0cUYuXALg9NI29ui7PEGReXjSpNwUD6ceN/78YOK41KAcecq+SS0bJ4b4amKZIJG3JWmDKljtv1dmSBCrTmEAQaOorxqGGBYmZS7NQumRe4lav5r6wOs8OACMANE1ejkeZsGFzJFNqvr5DuHdDL5FAudW23me3BDmrM9ifUzzjl1Jwku3bnRaCcjaxH8oTumt1a00mWci/1qUlaVFft085yvVq7KZbF2OPPbl+erDW91+EZ2FgEi+v1/CSJ5 your_username@hostname")
+	sshKey := &SSHKeyReq{
+		Name:   "api-test-ssh",
+		SSHKey: "ssh-rsa AF+LbfYYw== test@admin.com",
+	}
 
+	key, err := client.SSHKey.Create(ctx, sshKey)
 	if err != nil {
 		t.Errorf("SSHKey.Create returned %+v, expected %+v", err, nil)
 	}
 
 	expected := &SSHKey{
-		SSHKeyID:    "541b4960f23bd",
-		Name:        "foo",
-		Key:         "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCyVGaw1PuEl98f4/7Kq3O9ZIvDw2OFOSXAFVqilSFNkHlefm1iMtPeqsIBp2t9cbGUf55xNDULz/bD/4BCV43yZ5lh0cUYuXALg9NI29ui7PEGReXjSpNwUD6ceN/78YOK41KAcecq+SS0bJ4b4amKZIJG3JWmDKljtv1dmSBCrTmEAQaOorxqGGBYmZS7NQumRe4lav5r6wOs8OACMANE1ejkeZsGFzJFNqvr5DuHdDL5FAudW23me3BDmrM9ifUzzjl1Jwku3bnRaCcjaxH8oTumt1a00mWci/1qUlaVFft085yvVq7KZbF2OPPbl+erDW91+EZ2FgEi+v1/CSJ5 your_username@hostname",
-		DateCreated: "",
+		ID:          "5f05d5a71fe28",
+		Name:        "api-test-ssh",
+		SSHKey:      "ssh-rsa AF+LbfYYw== test@admin.com",
+		DateCreated: "2020-07-08 14:18:15",
 	}
 
 	if !reflect.DeepEqual(key, expected) {
@@ -39,15 +38,61 @@ func TestSSHKeyServiceHandler_Create(t *testing.T) {
 	}
 }
 
+func TestSSHKeyServiceHandler_Get(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/ssh-keys/abc123", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"ssh_key": {"id": "5f05d5a71fe28","date_created": "2020-07-08 14:18:15","name": "api-test-ssh","ssh_key": "ssh-rsa AF+LbfYYw== test@admin.com"}}`
+		fmt.Fprint(writer, response)
+	})
+
+	key, err := client.SSHKey.Get(ctx, "abc123")
+	if err != nil {
+		t.Errorf("SSHKey.Get returned %+v, expected %+v", err, nil)
+	}
+
+	expected := &SSHKey{
+		ID:          "5f05d5a71fe28",
+		Name:        "api-test-ssh",
+		SSHKey:      "ssh-rsa AF+LbfYYw== test@admin.com",
+		DateCreated: "2020-07-08 14:18:15",
+	}
+
+	if !reflect.DeepEqual(key, expected) {
+		t.Errorf("SSHKey.Create returned %+v, expected %+v", key, expected)
+	}
+}
+
+func TestSSHKeyServiceHandler_Update(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/ssh-keys/abc123", func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
+	})
+
+	sshKey := &SSHKeyReq{
+		Name:   "foo",
+		SSHKey: "ssh-rsa CCCCB3NzaC1yc your_username@hostname",
+	}
+
+	err := client.SSHKey.Update(ctx, "abc123", sshKey)
+
+	if err != nil {
+		t.Errorf("SSHKey.Update returned error: %+v", err)
+	}
+}
+
 func TestSSHKeyServiceHandler_Delete(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/sshkey/destroy", func(writer http.ResponseWriter, request *http.Request) {
+	mux.HandleFunc("/v2/ssh-keys/abc123", func(writer http.ResponseWriter, request *http.Request) {
 		fmt.Fprint(writer)
 	})
 
-	err := client.SSHKey.Delete(ctx, "foo")
+	err := client.SSHKey.Delete(ctx, "abc123")
 
 	if err != nil {
 		t.Errorf("SSHKey.Delete returned %+v, expected %+v", err, nil)
@@ -58,59 +103,35 @@ func TestSSHKeyServiceHandler_List(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/sshkey/list", func(writer http.ResponseWriter, request *http.Request) {
-		response := `
-		{
-			"541b4960f23bd": {
-				"SSHKEYID": "541b4960f23bd",
-				"date_created": null,
-				"name": "test",
-				"ssh_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCyVGaw1PuEl98f4/7Kq3O9ZIvDw2OFOSXAFVqilSFNkHlefm1iMtPeqsIBp2t9cbGUf55xNDULz/bD/4BCV43yZ5lh0cUYuXALg9NI29ui7PEGReXjSpNwUD6ceN/78YOK41KAcecq+SS0bJ4b4amKZIJG3JWmDKljtv1dmSBCrTmEAQaOorxqGGBYmZS7NQumRe4lav5r6wOs8OACMANE1ejkeZsGFzJFNqvr5DuHdDL5FAudW23me3BDmrM9ifUzzjl1Jwku3bnRaCcjaxH8oTumt1a00mWci/1qUlaVFft085yvVq7KZbF2OPPbl+erDW91+EZ2FgEi+v1/CSJ5 your_username@hostname"
-			}
-		}
-		`
+	mux.HandleFunc("/v2/ssh-keys", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"ssh_keys": [{"id": "5ed139d1890db","date_created": "2020-05-29 16:35:29","name": "api-test-ssh","ssh_key": "ssh-rsa AAAAB3NzaC1ycYYw== test@admin.com"}],"meta": {"total": 8,"links": {"next": "","prev": ""}}}`
 		fmt.Fprintf(writer, response)
 	})
 
-	sshKeys, err := client.SSHKey.List(ctx)
-
+	sshKeys, meta, err := client.SSHKey.List(ctx, nil)
 	if err != nil {
 		t.Errorf("SSHKey.List returned error: %v", err)
 	}
 
-	expected := []SSHKey{
+	expectedSSH := []SSHKey{
 		{
-			SSHKeyID:    "541b4960f23bd",
-			Name:        "test",
-			Key:         "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCyVGaw1PuEl98f4/7Kq3O9ZIvDw2OFOSXAFVqilSFNkHlefm1iMtPeqsIBp2t9cbGUf55xNDULz/bD/4BCV43yZ5lh0cUYuXALg9NI29ui7PEGReXjSpNwUD6ceN/78YOK41KAcecq+SS0bJ4b4amKZIJG3JWmDKljtv1dmSBCrTmEAQaOorxqGGBYmZS7NQumRe4lav5r6wOs8OACMANE1ejkeZsGFzJFNqvr5DuHdDL5FAudW23me3BDmrM9ifUzzjl1Jwku3bnRaCcjaxH8oTumt1a00mWci/1qUlaVFft085yvVq7KZbF2OPPbl+erDW91+EZ2FgEi+v1/CSJ5 your_username@hostname",
-			DateCreated: "",
+			ID:          "5ed139d1890db",
+			Name:        "api-test-ssh",
+			SSHKey:      "ssh-rsa AAAAB3NzaC1ycYYw== test@admin.com",
+			DateCreated: "2020-05-29 16:35:29",
 		},
 	}
 
-	if !reflect.DeepEqual(sshKeys, expected) {
-		t.Errorf("SSHKey.List returned %+v, expected %+v", sshKeys, expected)
+	expectedMeta := &Meta{
+		Total: 8,
+		Links: &Links{},
 	}
-}
-
-func TestSSHKeyServiceHandler_Update(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/sshkey/update", func(writer http.ResponseWriter, request *http.Request) {
 
-		fmt.Fprint(writer)
-	})
-
-	sshKey := &SSHKey{
-		SSHKeyID:    "561b4960f23cc",
-		Name:        "foo",
-		Key:         "ssh-rsa CCCCB3NzaC1yc2EAAAADAQABAAABAQCyVGaw1PuEl98f4/7Kq3O9ZIvDw2OFOSXAFVqilSFNkHlefm1iMtPeqsIBp2t9cbGUf55xNDULz/bD/4BCV43yZ5lh0cUYuXALg9NI29ui7PEGReXjSpNwUD6ceN/78YOK41KAcecq+SS0bJ4b4amKZIJG3JWmDKljtv1dmSBCrTmEAQaOorxqGGBYmZS7NQumRe4lav5r6wOs8OACMANE1ejkeZsGFzJFNqvr5DuHdDL5FAudW23me3BDmrM9ifUzzjl1Jwku3bnRaCcjaxH8oTumt1a00mWci/1qUlaVFft085yvVq7KZbF2OPPbl+erDW91+EZ2FgEi+v1/CSJ5 your_username@hostname",
-		DateCreated: "",
+	if !reflect.DeepEqual(sshKeys, expectedSSH) {
+		t.Errorf("SSHKey.List ssh-keys returned %+v, expected %+v", sshKeys, expectedSSH)
 	}
 
-	err := client.SSHKey.Update(ctx, sshKey)
-
-	if err != nil {
-		t.Errorf("SSHKey.Update returned error: %+v", err)
+	if !reflect.DeepEqual(meta, expectedMeta) {
+		t.Errorf("SSHKey.List meta returned %+v, expected %+v", meta, expectedMeta)
 	}
 }
diff --git a/startup_script.go b/startup_script.go
index cff9443..c225fc7 100644
--- a/startup_script.go
+++ b/startup_script.go
@@ -2,19 +2,22 @@ package govultr
 
 import (
 	"context"
-	"encoding/json"
 	"fmt"
 	"net/http"
-	"net/url"
+
+	"github.com/google/go-querystring/query"
 )
 
+const scriptPath = "/v2/startup-scripts"
+
 // StartupScriptService is the interface to interact with the startup script endpoints on the Vultr API
-// Link: https://www.vultr.com/api/#startupscript
+// Link : https://www.vultr.com/api/#tag/startup
 type StartupScriptService interface {
-	Create(ctx context.Context, name, script, scriptType string) (*StartupScript, error)
+	Create(ctx context.Context, req *StartupScriptReq) (*StartupScript, error)
+	Get(ctx context.Context, scriptID string) (*StartupScript, error)
+	Update(ctx context.Context, scriptID string, scriptReq *StartupScriptReq) error
 	Delete(ctx context.Context, scriptID string) error
-	List(ctx context.Context) ([]StartupScript, error)
-	Update(ctx context.Context, script *StartupScript) error
+	List(ctx context.Context, options *ListOptions) ([]StartupScript, *Meta, error)
 }
 
 // StartupScriptServiceHandler handles interaction with the startup script methods for the Vultr API
@@ -24,7 +27,7 @@ type StartupScriptServiceHandler struct {
 
 // StartupScript represents an startup script on Vultr
 type StartupScript struct {
-	ScriptID     string `json:"SCRIPTID"`
+	ID           string `json:"id"`
 	DateCreated  string `json:"date_created"`
 	DateModified string `json:"date_modified"`
 	Name         string `json:"name"`
@@ -32,141 +35,97 @@ type StartupScript struct {
 	Script       string `json:"script"`
 }
 
-// UnmarshalJSON implements json.Unmarshaller on StartupScript to handle the inconsistent types returned from the Vultr API.
-func (s *StartupScript) UnmarshalJSON(data []byte) (err error) {
-	if s == nil {
-		*s = StartupScript{}
-	}
-
-	var v map[string]interface{}
-	if err := json.Unmarshal(data, &v); err != nil {
-		return err
-	}
-
-	s.ScriptID = fmt.Sprintf("%v", v["SCRIPTID"])
-	s.DateCreated = fmt.Sprintf("%v", v["date_created"])
-	s.DateModified = fmt.Sprintf("%v", v["date_modified"])
-	s.Name = fmt.Sprintf("%v", v["name"])
-	s.Type = fmt.Sprintf("%v", v["type"])
-	s.Script = fmt.Sprintf("%v", v["script"])
-
-	return nil
+// StartupScriptReq is the user struct for create and update calls
+type StartupScriptReq struct {
+	Name   string `json:"name"`
+	Type   string `json:"type"`
+	Script string `json:"script"`
 }
 
-// Create will add the specified startup script to your Vultr account
-func (s *StartupScriptServiceHandler) Create(ctx context.Context, name, script, scriptType string) (*StartupScript, error) {
-
-	uri := "/v1/startupscript/create"
-
-	values := url.Values{
-		"name":   {name},
-		"script": {script},
-	}
+type startupScriptsBase struct {
+	StartupScripts []StartupScript `json:"startup_scripts"`
+	Meta           *Meta           `json:"meta"`
+}
 
-	if scriptType != "" {
-		values.Add("type", scriptType)
-	}
+type startupScriptBase struct {
+	StartupScript *StartupScript `json:"startup_script"`
+}
 
-	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
+var _ StartupScriptService = &StartupScriptServiceHandler{}
 
+// Create a startup script
+func (s *StartupScriptServiceHandler) Create(ctx context.Context, scriptReq *StartupScriptReq) (*StartupScript, error) {
+	req, err := s.client.NewRequest(ctx, http.MethodPost, scriptPath, scriptReq)
 	if err != nil {
 		return nil, err
 	}
 
-	ss := new(StartupScript)
-
-	err = s.client.DoWithContext(ctx, req, ss)
-
-	if err != nil {
+	script := new(startupScriptBase)
+	if err = s.client.DoWithContext(ctx, req, script); err != nil {
 		return nil, err
 	}
 
-	ss.DateCreated = ""
-	ss.DateModified = ""
-	ss.Name = name
-	ss.Type = scriptType
-	ss.Script = script
-
-	return ss, nil
-}
-
-// Delete will delete the specified startup script from your Vultr account
-func (s *StartupScriptServiceHandler) Delete(ctx context.Context, scriptID string) error {
-
-	uri := "/v1/startupscript/destroy"
-
-	values := url.Values{
-		"SCRIPTID": {scriptID},
-	}
-
-	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
-	}
-
-	err = s.client.DoWithContext(ctx, req, nil)
-
-	if err != nil {
-		return err
-	}
-
-	return nil
+	return script.StartupScript, nil
 }
 
-// List will list all the startup scripts associated with your Vultr account
-func (s *StartupScriptServiceHandler) List(ctx context.Context) ([]StartupScript, error) {
-
-	uri := "/v1/startupscript/list"
+// Get a single startup script
+func (s *StartupScriptServiceHandler) Get(ctx context.Context, scriptID string) (*StartupScript, error) {
+	uri := fmt.Sprintf("%s/%s", scriptPath, scriptID)
 
 	req, err := s.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
 	if err != nil {
 		return nil, err
 	}
 
-	scriptsMap := make(map[string]StartupScript)
-	err = s.client.DoWithContext(ctx, req, &scriptsMap)
-	if err != nil {
+	script := new(startupScriptBase)
+	if err = s.client.DoWithContext(ctx, req, script); err != nil {
 		return nil, err
 	}
 
-	var scripts []StartupScript
-	for _, key := range scriptsMap {
-		scripts = append(scripts, key)
-	}
-
-	return scripts, nil
+	return script.StartupScript, nil
 }
 
 // Update will update the given startup script. Empty strings will be ignored.
-func (s *StartupScriptServiceHandler) Update(ctx context.Context, script *StartupScript) error {
-
-	uri := "/v1/startupscript/update"
+func (s *StartupScriptServiceHandler) Update(ctx context.Context, scriptID string, scriptReq *StartupScriptReq) error {
+	uri := fmt.Sprintf("%s/%s", scriptPath, scriptID)
 
-	values := url.Values{
-		"SCRIPTID": {script.ScriptID},
+	req, err := s.client.NewRequest(ctx, http.MethodPatch, uri, scriptReq)
+	if err != nil {
+		return err
 	}
 
-	// Optional
-	if script.Name != "" {
-		values.Add("name", script.Name)
-	}
-	if script.Script != "" {
-		values.Add("script", script.Script)
-	}
+	return s.client.DoWithContext(ctx, req, nil)
+}
 
-	req, err := s.client.NewRequest(ctx, http.MethodPost, uri, values)
+// Delete the specified startup script from your account.
+func (s *StartupScriptServiceHandler) Delete(ctx context.Context, scriptID string) error {
+	uri := fmt.Sprintf("%s/%s", scriptPath, scriptID)
 
+	req, err := s.client.NewRequest(ctx, http.MethodDelete, uri, nil)
 	if err != nil {
 		return err
 	}
 
-	err = s.client.DoWithContext(ctx, req, nil)
+	return s.client.DoWithContext(ctx, req, nil)
+}
 
+// List all the startup scripts associated with your Vultr account
+func (s *StartupScriptServiceHandler) List(ctx context.Context, options *ListOptions) ([]StartupScript, *Meta, error) {
+	req, err := s.client.NewRequest(ctx, http.MethodGet, scriptPath, nil)
 	if err != nil {
-		return err
+		return nil, nil, err
+	}
+
+	newValues, err := query.Values(options)
+	if err != nil {
+		return nil, nil, err
+	}
+	req.URL.RawQuery = newValues.Encode()
+
+	scripts := new(startupScriptsBase)
+	if err = s.client.DoWithContext(ctx, req, scripts); err != nil {
+		return nil, nil, err
 	}
 
-	return nil
+	return scripts.StartupScripts, scripts.Meta, nil
 }
diff --git a/startup_script_test.go b/startup_script_test.go
index 8bd8ac4..c9b3bbb 100644
--- a/startup_script_test.go
+++ b/startup_script_test.go
@@ -12,29 +12,29 @@ func TestStartupScriptServiceHandler_Create(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/startupscript/create", func(writer http.ResponseWriter, request *http.Request) {
-		response := `
-		{
-			"SCRIPTID": 5
-		}
-		`
-
+	mux.HandleFunc("/v2/startup-scripts", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"startup_script": {"id": "14356","date_created": "2020-07-07 18:52:56","date_modified": "2020-07-07 18:59:54","name": "govultr","type": "boot","script": "dGVzdGFwaXVwZGF0ZQ=="}}`
 		fmt.Fprint(writer, response)
 	})
 
-	s, err := client.StartupScript.Create(context.Background(), "foo", "#!/bin/bash\necho hello world > /root/hello", "pxe")
+	script := &StartupScriptReq{
+		Name:   "govultr",
+		Type:   "boot",
+		Script: "dGVzdGFwaXVwZGF0ZQ==",
+	}
+	s, err := client.StartupScript.Create(context.Background(), script)
 
 	if err != nil {
 		t.Errorf("StartupScript.Create returned %+v, expected %+v", err, nil)
 	}
 
 	expected := &StartupScript{
-		ScriptID:     "5",
-		DateCreated:  "",
-		DateModified: "",
-		Name:         "foo",
-		Type:         "pxe",
-		Script:       "#!/bin/bash\necho hello world > /root/hello",
+		ID:           "14356",
+		DateCreated:  "2020-07-07 18:52:56",
+		DateModified: "2020-07-07 18:59:54",
+		Name:         "govultr",
+		Type:         "boot",
+		Script:       "dGVzdGFwaXVwZGF0ZQ==",
 	}
 
 	if !reflect.DeepEqual(s, expected) {
@@ -42,15 +42,65 @@ func TestStartupScriptServiceHandler_Create(t *testing.T) {
 	}
 }
 
+func TestStartupScriptServiceHandler_GET(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/startup-scripts/14350", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"startup_script": {"id": "14350","date_created": "2020-06-08 17:58:10","date_modified": "2020-06-08 17:59:54","name": "govultr","type": "pxe","script": "dGVzdA=="}}`
+		fmt.Fprintf(writer, response)
+	})
+
+	scripts, err := client.StartupScript.Get(ctx, "14350")
+
+	if err != nil {
+		t.Errorf("StartupScript.Get returned error: %v", err)
+	}
+
+	expectedScript := &StartupScript{
+		ID:           "14350",
+		DateCreated:  "2020-06-08 17:58:10",
+		DateModified: "2020-06-08 17:59:54",
+		Name:         "govultr",
+		Type:         "pxe",
+		Script:       "dGVzdA==",
+	}
+
+	if !reflect.DeepEqual(scripts, expectedScript) {
+		t.Errorf("StartupScript.Get scripts returned %+v, expected %+v", scripts, expectedScript)
+	}
+}
+
+func TestStartupScriptServiceHandler_Update(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/startup-scripts/1234", func(writer http.ResponseWriter, request *http.Request) {
+		fmt.Fprint(writer)
+	})
+
+	script := &StartupScriptReq{
+		Name:   "foo",
+		Type:   "boot",
+		Script: "dGVzdA==",
+	}
+
+	err := client.StartupScript.Update(ctx, "1234", script)
+
+	if err != nil {
+		t.Errorf("StartupScript.Update returned error: %+v", err)
+	}
+}
+
 func TestStartupScriptServiceHandler_Delete(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/startupscript/destroy", func(writer http.ResponseWriter, request *http.Request) {
+	mux.HandleFunc("/v2/startup-scripts/1234", func(writer http.ResponseWriter, request *http.Request) {
 		fmt.Fprint(writer)
 	})
 
-	err := client.StartupScript.Delete(ctx, "foo")
+	err := client.StartupScript.Delete(ctx, "1234")
 
 	if err != nil {
 		t.Errorf("StartupScript.Delete returned %+v, expected %+v", err, nil)
@@ -61,63 +111,38 @@ func TestStartupScriptServiceHandler_List(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/startupscript/list", func(writer http.ResponseWriter, request *http.Request) {
-		response := `
-		{
-			"3": {
-				"SCRIPTID": "3",
-				"date_created": "2014-05-21 15:27:18",
-				"date_modified": "2014-05-21 15:27:18",
-				"name": "foo",
-				"type": "boot",
-				"script": "#!/bin/bash echo Hello World > /root/hello"
-			}
-		}
-		`
+	mux.HandleFunc("/v2/startup-scripts", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"startup_scripts": [{"id": "14350","date_created": "2020-06-08 17:58:10","date_modified": "2020-06-08 17:59:54","name": "govultr","type": "pxe","script": "dGVzdA=="}],"meta": {"total": 1,"links": {"next": "","prev": ""}}}`
 		fmt.Fprintf(writer, response)
 	})
 
-	scripts, err := client.StartupScript.List(ctx)
+	scripts, meta, err := client.StartupScript.List(ctx, nil)
 
 	if err != nil {
 		t.Errorf("StartupScript.List returned error: %v", err)
 	}
 
-	expected := []StartupScript{
+	expectedScript := []StartupScript{
 		{
-			ScriptID:     "3",
-			Name:         "foo",
-			Type:         "boot",
-			Script:       "#!/bin/bash echo Hello World > /root/hello",
-			DateCreated:  "2014-05-21 15:27:18",
-			DateModified: "2014-05-21 15:27:18",
+			ID:           "14350",
+			DateCreated:  "2020-06-08 17:58:10",
+			DateModified: "2020-06-08 17:59:54",
+			Name:         "govultr",
+			Type:         "pxe",
+			Script:       "dGVzdA==",
 		},
 	}
 
-	if !reflect.DeepEqual(scripts, expected) {
-		t.Errorf("StartupScript.List returned %+v, expected %+v", scripts, expected)
+	expectedMeta := &Meta{
+		Total: 1,
+		Links: &Links{},
 	}
-}
-
-func TestStartupScriptServiceHandler_Update(t *testing.T) {
-	setup()
-	defer teardown()
-
-	mux.HandleFunc("/v1/startupscript/update", func(writer http.ResponseWriter, request *http.Request) {
 
-		fmt.Fprint(writer)
-	})
-
-	script := &StartupScript{
-		ScriptID: "1",
-		Name:     "foo",
-		Type:     "boot",
-		Script:   "#!/bin/bash echo Hello World > /root/hello",
+	if !reflect.DeepEqual(scripts, expectedScript) {
+		t.Errorf("StartupScript.List scripts returned %+v, expected %+v", scripts, expectedScript)
 	}
 
-	err := client.StartupScript.Update(ctx, script)
-
-	if err != nil {
-		t.Errorf("StartupScript.Update returned error: %+v", err)
+	if !reflect.DeepEqual(meta, expectedMeta) {
+		t.Errorf("StartupScript.List meta returned %+v, expected %+v", meta, expectedMeta)
 	}
 }
diff --git a/user.go b/user.go
index 40e4040..01540ff 100644
--- a/user.go
+++ b/user.go
@@ -2,19 +2,26 @@ package govultr
 
 import (
 	"context"
+	"fmt"
 	"net/http"
-	"net/url"
+
+	"github.com/google/go-querystring/query"
 )
 
+const path = "/v2/users"
+
 // UserService is the interface to interact with the user management endpoints on the Vultr API
-// Link: https://www.vultr.com/api/#user
+// Link : https://www.vultr.com/api/#tag/users
 type UserService interface {
-	Create(ctx context.Context, email, name, password, apiEnabled string, acls []string) (*User, error)
+	Create(ctx context.Context, userCreate *UserReq) (*User, error)
+	Get(ctx context.Context, userID string) (*User, error)
+	Update(ctx context.Context, userID string, userReq *UserReq) error
 	Delete(ctx context.Context, userID string) error
-	List(ctx context.Context) ([]User, error)
-	Update(ctx context.Context, user *User) error
+	List(ctx context.Context, options *ListOptions) ([]User, *Meta, error)
 }
 
+var _ UserService = &UserServiceHandler{}
+
 // UserServiceHandler handles interaction with the user methods for the Vultr API
 type UserServiceHandler struct {
 	client *Client
@@ -22,136 +29,105 @@ type UserServiceHandler struct {
 
 // User represents an user on Vultr
 type User struct {
-	UserID     string   `json:"USERID"`
+	ID         string   `json:"id"`
 	Name       string   `json:"name"`
 	Email      string   `json:"email"`
-	Password   string   `json:"password"`
-	APIEnabled string   `json:"api_enabled"`
-	ACL        []string `json:"acls"`
-	APIKey     string   `json:"api_key"`
+	APIEnabled *bool    `json:"api_enabled"`
+	APIKey     string   `json:"api_key,omitempty"`
+	ACL        []string `json:"acls,omitempty"`
 }
 
-// Create will add the specified user to your Vultr account
-func (u *UserServiceHandler) Create(ctx context.Context, email, name, password, apiEnabled string, acls []string) (*User, error) {
-
-	uri := "/v1/user/create"
-
-	values := url.Values{
-		"email":    {email},
-		"name":     {name},
-		"password": {password},
-		"acls[]":   acls,
-	}
+// UserReq is the user struct for create and update calls
+type UserReq struct {
+	Email      string   `json:"email,omitempty"`
+	Name       string   `json:"name,omitempty"`
+	APIEnabled *bool    `json:"api_enabled,omitempty"`
+	ACL        []string `json:"acls,omitempty"`
+	Password   string   `json:"password,omitempty"`
+}
 
-	if apiEnabled != "" {
-		values.Add("api_enabled", apiEnabled)
-	}
+type usersBase struct {
+	Users []User `json:"users"`
+	Meta  *Meta  `json:"meta"`
+}
 
-	req, err := u.client.NewRequest(ctx, http.MethodPost, uri, values)
+type userBase struct {
+	User *User `json:"user"`
+}
 
+// Create will add the specified user to your Vultr account
+func (u *UserServiceHandler) Create(ctx context.Context, userCreate *UserReq) (*User, error) {
+	req, err := u.client.NewRequest(ctx, http.MethodPost, path, userCreate)
 	if err != nil {
 		return nil, err
 	}
 
-	user := new(User)
-
-	err = u.client.DoWithContext(ctx, req, user)
-
-	if err != nil {
+	user := new(userBase)
+	if err = u.client.DoWithContext(ctx, req, user); err != nil {
 		return nil, err
 	}
 
-	user.Name = name
-	user.Email = email
-	user.APIEnabled = apiEnabled
-	user.ACL = acls
-
-	return user, nil
+	return user.User, nil
 }
 
-// Delete will remove the specified user from your Vultr account
-func (u *UserServiceHandler) Delete(ctx context.Context, userID string) error {
+// Get will retrieve a specific user account
+func (u *UserServiceHandler) Get(ctx context.Context, userID string) (*User, error) {
+	uri := fmt.Sprintf("%s/%s", path, userID)
 
-	uri := "/v1/user/delete"
-
-	values := url.Values{
-		"USERID": {userID},
+	req, err := u.client.NewRequest(ctx, http.MethodGet, uri, nil)
+	if err != nil {
+		return nil, err
 	}
 
-	req, err := u.client.NewRequest(ctx, http.MethodPost, uri, values)
-
-	if err != nil {
-		return err
+	user := new(userBase)
+	if err = u.client.DoWithContext(ctx, req, user); err != nil {
+		return nil, err
 	}
 
-	err = u.client.DoWithContext(ctx, req, nil)
+	return user.User, nil
+}
 
+// Update will update the given user. Empty strings will be ignored.
+func (u *UserServiceHandler) Update(ctx context.Context, userID string, userReq *UserReq) error {
+	uri := fmt.Sprintf("%s/%s", path, userID)
+	req, err := u.client.NewRequest(ctx, http.MethodPatch, uri, userReq)
 	if err != nil {
 		return err
 	}
 
-	return nil
+	return u.client.DoWithContext(ctx, req, nil)
 }
 
-// List will list all the users associated with your Vultr account
-func (u *UserServiceHandler) List(ctx context.Context) ([]User, error) {
-
-	uri := "/v1/user/list"
-
-	req, err := u.client.NewRequest(ctx, http.MethodGet, uri, nil)
-
-	if err != nil {
-		return nil, err
-	}
+// Delete will remove the specified user from your Vultr account
+func (u *UserServiceHandler) Delete(ctx context.Context, userID string) error {
+	uri := fmt.Sprintf("%s/%s", path, userID)
 
-	var users []User
-	err = u.client.DoWithContext(ctx, req, &users)
+	req, err := u.client.NewRequest(ctx, http.MethodDelete, uri, nil)
 	if err != nil {
-		return nil, err
+		return err
 	}
 
-	return users, nil
+	return u.client.DoWithContext(ctx, req, nil)
 }
 
-// Update will update the given user. Empty strings will be ignored.
-func (u *UserServiceHandler) Update(ctx context.Context, user *User) error {
-
-	uri := "/v1/user/update"
-
-	values := url.Values{
-		"USERID": {user.UserID},
-	}
-
-	// Optional
-	if user.Email != "" {
-		values.Add("email", user.Email)
-	}
-	if user.Name != "" {
-		values.Add("name", user.Name)
-	}
-	if user.Password != "" {
-		values.Add("password", user.Password)
-	}
-	if user.APIEnabled != "" {
-		values.Add("api_enabled", user.APIEnabled)
-	}
-	if len(user.ACL) > 0 {
-		for _, acl := range user.ACL {
-			values.Add("acls[]", acl)
-		}
+// List will list all the users associated with your Vultr account
+func (u *UserServiceHandler) List(ctx context.Context, options *ListOptions) ([]User, *Meta, error) {
+	req, err := u.client.NewRequest(ctx, http.MethodGet, path, nil)
+	if err != nil {
+		return nil, nil, err
 	}
 
-	req, err := u.client.NewRequest(ctx, http.MethodPost, uri, values)
-
+	newValues, err := query.Values(options)
 	if err != nil {
-		return err
+		return nil, nil, err
 	}
 
-	err = u.client.DoWithContext(ctx, req, nil)
+	req.URL.RawQuery = newValues.Encode()
 
-	if err != nil {
-		return err
+	users := new(usersBase)
+	if err = u.client.DoWithContext(ctx, req, &users); err != nil {
+		return nil, nil, err
 	}
 
-	return nil
+	return users.Users, users.Meta, nil
 }
diff --git a/user_test.go b/user_test.go
index 9cd74c6..7dda3dd 100644
--- a/user_test.go
+++ b/user_test.go
@@ -11,30 +11,32 @@ func TestUserServiceHandler_Create(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/user/create", func(writer http.ResponseWriter, request *http.Request) {
-		response := `
-		{
-			"USERID": "564a1a88947b4",
-			"api_key": "AAAAAAAA"
-		}
-		`
+	mux.HandleFunc("/v2/users", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"user": {"id": "564a1a88947b4","name": "Example User","email": "example@vultr.com","api_key": "aaavvvvvvbbbbbb","api_enabled": true,"acls": []}}`
 
 		fmt.Fprint(writer, response)
 	})
+	api := true
+	userReq := &UserReq{
+		Email:      "example@vultr.com",
+		Name:       "Example User",
+		APIEnabled: &api,
+		Password:   "password",
+	}
 
-	user, err := client.User.Create(ctx, "example@vultr.com", "Example User", "t0rbj0rn!", "no", []string{"support", "abuse", "alerts"})
+	user, err := client.User.Create(ctx, userReq)
 
 	if err != nil {
 		t.Errorf("User.Create returned %+v, expected %+v", err, nil)
 	}
 
 	expected := &User{
-		UserID:     "564a1a88947b4",
+		ID:         "564a1a88947b4",
 		Name:       "Example User",
 		Email:      "example@vultr.com",
-		APIEnabled: "no",
-		ACL:        []string{"support", "abuse", "alerts"},
-		APIKey:     "AAAAAAAA",
+		APIEnabled: BoolToBoolPtr(true),
+		APIKey:     "aaavvvvvvbbbbbb",
+		ACL:        []string{},
 	}
 
 	if !reflect.DeepEqual(user, expected) {
@@ -46,11 +48,11 @@ func TestUserServiceHandler_Delete(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/user/delete", func(writer http.ResponseWriter, request *http.Request) {
+	mux.HandleFunc("/v2/users/123abc", func(writer http.ResponseWriter, request *http.Request) {
 		fmt.Fprint(writer)
 	})
 
-	err := client.User.Delete(ctx, "foo")
+	err := client.User.Delete(ctx, "123abc")
 
 	if err != nil {
 		t.Errorf("User.Delete returned %+v, expected %+v", err, nil)
@@ -61,37 +63,34 @@ func TestUserServiceHandler_List(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/user/list", func(writer http.ResponseWriter, request *http.Request) {
+	mux.HandleFunc("/v2/users", func(writer http.ResponseWriter, request *http.Request) {
 		response := `
-		[
-			{
-				"USERID": "564a1a7794d83",
-				"name": "example user 1",
-				"email": "example@vultr.com",
-				"api_enabled": "yes",
-				"acls": [
-					"manage_users",
-					"subscriptions",
-					"billing",
-					"provisioning"
-				]
-			},
-			{
-				"USERID": "564a1a88947b4",
-				"name": "example user 2",
-				"email": "example@vultr.com",
-				"api_enabled": "no",
-				"acls": [
-					"support",
-					"dns"
-				]
-			}
-		]
+	{
+    "users": [
+        {
+            "id": "f255efc9700d9",
+            "name": "test api",
+            "email": "newmanapi@vultr.com",
+            "api_enabled": true,
+            "acls": []
+        }
+    ],
+    "meta": {
+        "total": 1,
+        "links": {
+            "next": "thisismycusror",
+            "prev": ""
+        }
+    }
+}
 		`
 		fmt.Fprintf(writer, response)
 	})
 
-	Users, err := client.User.List(ctx)
+	options := &ListOptions{
+		PerPage: 1,
+	}
+	users, meta, err := client.User.List(ctx, options)
 
 	if err != nil {
 		t.Errorf("User.List returned error: %v", err)
@@ -99,23 +98,28 @@ func TestUserServiceHandler_List(t *testing.T) {
 
 	expected := []User{
 		{
-			UserID:     "564a1a7794d83",
-			Name:       "example user 1",
-			Email:      "example@vultr.com",
-			APIEnabled: "yes",
-			ACL:        []string{"manage_users", "subscriptions", "billing", "provisioning"},
+			ID:         "f255efc9700d9",
+			Name:       "test api",
+			Email:      "newmanapi@vultr.com",
+			APIEnabled: BoolToBoolPtr(true),
+			ACL:        []string{},
 		},
-		{
-			UserID:     "564a1a88947b4",
-			Name:       "example user 2",
-			Email:      "example@vultr.com",
-			APIEnabled: "no",
-			ACL:        []string{"support", "dns"},
+	}
+
+	if !reflect.DeepEqual(users, expected) {
+		t.Errorf("User.List users returned %+v, expected %+v", users, expected)
+	}
+
+	expectedMeta := &Meta{
+		Total: 1,
+		Links: &Links{
+			Next: "thisismycusror",
+			Prev: "",
 		},
 	}
 
-	if !reflect.DeepEqual(Users, expected) {
-		t.Errorf("User.List returned %+v, expected %+v", Users, expected)
+	if !reflect.DeepEqual(meta, expectedMeta) {
+		t.Errorf("User.List meta returned %+v, expected %+v", meta, expectedMeta)
 	}
 }
 
@@ -123,23 +127,48 @@ func TestUserServiceHandler_Update(t *testing.T) {
 	setup()
 	defer teardown()
 
-	mux.HandleFunc("/v1/user/update", func(writer http.ResponseWriter, request *http.Request) {
-
+	mux.HandleFunc("/v2/users/abc123", func(writer http.ResponseWriter, request *http.Request) {
 		fmt.Fprint(writer)
 	})
 
-	user := &User{
-		UserID:     "2e35cc32f9923",
+	api := true
+	user := &UserReq{
 		Name:       "Example User",
 		Password:   "w1a4dcnst0n!",
 		Email:      "example@vultr.com",
-		APIEnabled: "yes",
+		APIEnabled: &api,
 		ACL:        []string{"support"},
 	}
 
-	err := client.User.Update(ctx, user)
+	err := client.User.Update(ctx, "abc123", user)
 
 	if err != nil {
 		t.Errorf("User.Update returned error: %+v", err)
 	}
 }
+
+func TestUserServiceHandler_Get(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/v2/users/abc123", func(writer http.ResponseWriter, request *http.Request) {
+		response := `{"user": {"id": "f255efc9c69ac","name": "Unit Test","email": "test@vultr.com","api_enabled": true,"acls": []}}`
+		fmt.Fprint(writer, response)
+	})
+
+	user, err := client.User.Get(ctx, "abc123")
+	if err != nil {
+		t.Errorf("User.Get returned error: %v", err)
+	}
+	expected := &User{
+		ID:         "f255efc9c69ac",
+		Name:       "Unit Test",
+		Email:      "test@vultr.com",
+		APIEnabled: BoolToBoolPtr(true),
+		ACL:        []string{},
+	}
+
+	if !reflect.DeepEqual(user, expected) {
+		t.Errorf("User.List users returned %+v, expected %+v", user, expected)
+	}
+}