diff --git a/AUTHORS b/AUTHORS
index 9032852adf576561c151b375ca69de745c712559..30dd8446ea96de4099e613e62712f6e854ca6fa8 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -10,3 +10,4 @@ Matt Layher	<mlayher@digitalocean.com>
 Contributors
 ------------
 Allan Liu <aliu@digitalocean.com>
+Dave Cameron <dcameron@digitalocean.com>
diff --git a/netbox/client.go b/netbox/client.go
index 194079a2cbebf2eac8414ee5895dcac28b69d4be..f1274d0d540298fa51da335645297d5089a548b2 100644
--- a/netbox/client.go
+++ b/netbox/client.go
@@ -69,7 +69,7 @@ func NewClient(addr string, client *http.Client) (*Client, error) {
 		client: client,
 	}
 
-	c.DCIM = &DCIMService{c: c}
+	c.DCIM = NewDCIMService(c)
 	c.IPAM = &IPAMService{c: c}
 	c.Tenancy = NewTenancyService(c)
 
diff --git a/netbox/dcim.go b/netbox/dcim.go
index a7f4dffd91eef822c77d72c6a028753fd08aec37..0f955bd01e51c7197122fadd79123d353df3ecf6 100644
--- a/netbox/dcim.go
+++ b/netbox/dcim.go
@@ -16,7 +16,18 @@ package netbox
 
 // A DCIMService is used in a Client to access NetBox's DCIM API methods.
 type DCIMService struct {
-	c *Client
+	c              *Client
+	InventoryItems *InventoryItemsService
+}
+
+// NewDCIMService returns a DCIMService initialized with all sub-services.
+func NewDCIMService(client *Client) *DCIMService {
+	return &DCIMService{
+		c: client,
+		InventoryItems: &InventoryItemsService{
+			c: client,
+		},
+	}
 }
 
 // SimpleIdentifier represents a simple object that consists of only an ID,
diff --git a/netbox/dcim_inventory-items.go b/netbox/dcim_inventory-items.go
new file mode 100644
index 0000000000000000000000000000000000000000..73a9ff4eaa92be178e1f01d4275ca27c61dd264e
--- /dev/null
+++ b/netbox/dcim_inventory-items.go
@@ -0,0 +1,118 @@
+// Copyright 2017 The go-netbox Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Code generated by generate_functions.go. DO NOT EDIT.
+
+package netbox
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/http"
+)
+
+// InventoryItemsService is used in a Client to access NetBox's dcim/inventory-items API methods.
+type InventoryItemsService struct {
+	c *Client
+}
+
+// Get retrieves an InventoryItem object from NetBox by its ID.
+func (s *InventoryItemsService) Get(id int) (*InventoryItem, error) {
+	req, err := s.c.NewRequest(
+		http.MethodGet,
+		fmt.Sprintf("api/dcim/inventory-items/%d/", id),
+		nil,
+	)
+	if err != nil {
+		return nil, err
+	}
+
+	t := new(InventoryItem)
+	err = s.c.Do(req, t)
+	if err != nil {
+		return nil, err
+	}
+	return t, nil
+}
+
+// List returns a Page associated with an NetBox API Endpoint.
+func (s *InventoryItemsService) List(options *ListInventoryItemOptions) *Page {
+	return NewPage(s.c, "api/dcim/inventory-items/", options)
+}
+
+// Extract retrives a list of InventoryItem objects from page.
+func (s *InventoryItemsService) Extract(page *Page) ([]*InventoryItem, error) {
+	if err := page.Err(); err != nil {
+		return nil, err
+	}
+
+	var groups []*InventoryItem
+	if err := json.Unmarshal(page.data.Results, &groups); err != nil {
+		return nil, err
+	}
+	return groups, nil
+}
+
+// Create creates a new InventoryItem object in NetBox and returns the ID of the new object.
+func (s *InventoryItemsService) Create(data *InventoryItem) (int, error) {
+	req, err := s.c.NewJSONRequest(http.MethodPost, "api/dcim/inventory-items/", nil, data)
+	if err != nil {
+		return 0, err
+	}
+
+	g := new(writableInventoryItem)
+	err = s.c.Do(req, g)
+	if err != nil {
+		return 0, err
+	}
+	return g.ID, nil
+}
+
+// Update changes an existing InventoryItem object in NetBox, and returns the ID of the new object.
+func (s *InventoryItemsService) Update(data *InventoryItem) (int, error) {
+	req, err := s.c.NewJSONRequest(
+		http.MethodPatch,
+		fmt.Sprintf("api/dcim/inventory-items/%d/", data.ID),
+		nil,
+		data,
+	)
+	if err != nil {
+		return 0, err
+	}
+
+	// g is just used to verify correct api result.
+	// data is not changed, because the g is not the full representation that one would
+	// get with Get. But if the response was unmarshaled into writableInventoryItem correctly,
+	// everything went fine, and we do not need to update data.
+	g := new(writableInventoryItem)
+	err = s.c.Do(req, g)
+	if err != nil {
+		return 0, err
+	}
+	return g.ID, nil
+}
+
+// Delete deletes an existing InventoryItem object from NetBox.
+func (s *InventoryItemsService) Delete(data *InventoryItem) error {
+	req, err := s.c.NewRequest(
+		http.MethodDelete,
+		fmt.Sprintf("api/dcim/inventory-items/%d/", data.ID),
+		nil,
+	)
+	if err != nil {
+		return err
+	}
+
+	return s.c.Do(req, nil)
+}
diff --git a/netbox/dcim_inventory-items_basic_test.go b/netbox/dcim_inventory-items_basic_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..fbf62e8f9a7c3e5924fb019d56b0eabf57181022
--- /dev/null
+++ b/netbox/dcim_inventory-items_basic_test.go
@@ -0,0 +1,299 @@
+// Copyright 2017 The go-netbox Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Code generated by generate_basic_tests.go. DO NOT EDIT.
+
+package netbox
+
+import (
+	"encoding/json"
+	"errors"
+	"fmt"
+	"net/http"
+	"reflect"
+	"testing"
+)
+
+// Using this to override MarshalJSON
+// In all cases when posting data to netbox-API, the InventoryItem.MarshalJSON is what you want,
+// but not here as a return in testHandler
+type serverDataInventoryItem InventoryItem
+
+func convertToServerDataInventoryItem(data []*InventoryItem) []*serverDataInventoryItem {
+	dataWant := make([]*serverDataInventoryItem, len(data))
+	for i := range data {
+		tmp := serverDataInventoryItem(*data[i])
+		dataWant[i] = &tmp
+	}
+	return dataWant
+}
+
+func TestBasicInventoryItemGet(t *testing.T) {
+	var tests = []struct {
+		desc string
+		want *InventoryItem
+	}{
+		{
+			desc: "Simple InventoryItem",
+			want: testInventoryItem(1),
+		},
+	}
+
+	for i, tt := range tests {
+		t.Run(fmt.Sprintf("[%d] %s", i, tt.desc), func(t *testing.T) {
+			serverData := serverDataInventoryItem(*tt.want)
+
+			c, done := testClient(t, testHandler(t, http.MethodGet, "/api/dcim/inventory-items/1/", &serverData))
+			defer done()
+
+			res, err := c.DCIM.InventoryItems.Get(1)
+			if err != nil {
+				t.Fatalf("unexpected error from Client.DCIM.InventoryItems.Get: %v", err)
+			}
+
+			if want, got := tt.want, res; !reflect.DeepEqual(want, got) {
+				t.Fatalf("unexpected InventoryItem:\n- want: %v\n-  got: %v", want, got)
+			}
+		})
+	}
+}
+
+func TestBasicInventoryItemGet404(t *testing.T) {
+	c, done := testClient(t, testStatusHandler(t, http.MethodGet, "/api/dcim/inventory-items/1/", &struct {
+		Detail string `json:"detail"`
+	}{
+		Detail: "Not found.",
+	},
+		http.StatusNotFound))
+	defer done()
+
+	res, err := c.DCIM.InventoryItems.Get(1)
+	errstr := "404 - Not found."
+	if want, got := errors.New(errstr), err; !reflect.DeepEqual(want, got) {
+		t.Fatalf("unexpected error from Client.DCIM.InventoryItems.Get:\n- want: %v\n-  got: %v", want, got)
+	}
+
+	if res != nil {
+		t.Fatalf("unexpected result:\n- want: %v\n-  got: %v", nil, res)
+	}
+}
+
+func TestBasicListExtractInventoryItem(t *testing.T) {
+	want := []*InventoryItem{
+		testInventoryItem(1),
+		testInventoryItem(2),
+	}
+	serverWant := convertToServerDataInventoryItem(want)
+	serverData, _ := json.Marshal(serverWant)
+	c, done := testClient(t, testHandler(t, http.MethodGet, "/api/dcim/inventory-items/", &pageData{
+		Count:       2,
+		NextURL:     "",
+		PreviousURL: "",
+		Results:     serverData,
+	}))
+	defer done()
+
+	page := c.DCIM.InventoryItems.List(nil)
+
+	if page == nil {
+		t.Fatalf("unexpexted result from c.DCIM.InventoryItems.List.")
+	}
+
+	got := []*InventoryItem{}
+	counter := 0
+	for page.Next() {
+		var err error
+		got, err = c.DCIM.InventoryItems.Extract(page)
+		if err != nil {
+			t.Fatalf("unexpected error from c.DCIM.InventoryItems.Extract: %v", err)
+		}
+		counter = counter + 1
+		if counter > 2 { // Safe guard
+			break
+		}
+	}
+	if counter != 1 {
+		t.Fatalf("unexpected page count:\n- want: 1\n-  got: %d", counter)
+	}
+
+	if !reflect.DeepEqual(want, got) {
+		t.Fatalf("unexpected result:\n- want: %v\n-  got: %v", want, got)
+	}
+
+	if page.Err() != nil {
+		t.Fatalf("unexpected error from page:\n- want: %v\n-  got: %v", want, got)
+	}
+}
+
+func TestBasicCreateInventoryItem(t *testing.T) {
+	var tests = []struct {
+		desc       string
+		data       *InventoryItem
+		want       int
+		serverData interface{}
+		status     int
+		errstr     string
+	}{
+		{
+			desc:       "Create with ID 0",
+			data:       testInventoryItemCreate(1),
+			want:       1,
+			status:     0,
+			errstr:     "",
+			serverData: testInventoryItem(1),
+		},
+		{
+			desc:   "Create duplicate",
+			data:   testInventoryItemCreate(1),
+			want:   0,
+			status: http.StatusBadRequest,
+			errstr: "400 - {\"name\":[\"InventoryItemsService with this name already exists.\"]}\n",
+			serverData: &struct {
+				Name []string `json:"name"`
+			}{
+				Name: []string{"InventoryItemsService with this name already exists."},
+			},
+		},
+	}
+
+	for i, tt := range tests {
+		t.Run(fmt.Sprintf("[%d] %s", i, tt.desc), func(t *testing.T) {
+			c, done := testClient(t, testStatusHandler(t, http.MethodPost, "/api/dcim/inventory-items/", tt.serverData, tt.status))
+			defer done()
+
+			var terr error
+			if tt.errstr != "" {
+				terr = errors.New(tt.errstr) // Using errstr and initialize real err here, to satisfy golint
+			}
+
+			res, err := c.DCIM.InventoryItems.Create(tt.data)
+			if want, got := terr, err; !reflect.DeepEqual(want, got) {
+				t.Fatalf("unexpected error:\n- want: %v\n-  got: %v", want, got)
+			}
+			if want, got := tt.want, res; !reflect.DeepEqual(want, got) {
+				t.Fatalf("unexpected InventoryItem:\n- want: %v\n-  got: %v", want, got)
+			}
+		})
+	}
+}
+
+func TestBasicUpdateInventoryItem(t *testing.T) {
+	var tests = []struct {
+		desc       string
+		data       *InventoryItem
+		want       int
+		serverData interface{}
+		status     int
+		errstr     string
+	}{
+		{
+			desc:       "Update with ID 1",
+			data:       testInventoryItem(1),
+			want:       1,
+			serverData: testInventoryItem(1),
+			status:     0,
+			errstr:     "",
+		},
+		{
+			desc: "Update not found",
+			data: testInventoryItem(1),
+			want: 0,
+			serverData: &struct {
+				Detail string
+			}{
+				Detail: "Not found.",
+			},
+			status: http.StatusNotFound,
+			errstr: "404 - Not found.",
+		},
+		{
+			desc: "Update to duplicate",
+			data: testInventoryItem(1),
+			want: 0,
+			serverData: &struct {
+				Name []string `json:"name"`
+			}{
+				Name: []string{"InventoryItemsService with this name already exists."},
+			},
+			status: http.StatusBadRequest,
+			errstr: "400 - {\"name\":[\"InventoryItemsService with this name already exists.\"]}\n",
+		},
+	}
+
+	for i, tt := range tests {
+		t.Run(fmt.Sprintf("[%d] %s", i, tt.desc), func(t *testing.T) {
+			c, done := testClient(t, testStatusHandler(t, http.MethodPatch, "/api/dcim/inventory-items/1/", tt.serverData, tt.status))
+			defer done()
+
+			var terr error
+			if tt.errstr != "" {
+				terr = errors.New(tt.errstr) // Using errstr and initialize real err here, to satisfy golint
+			}
+
+			res, err := c.DCIM.InventoryItems.Update(tt.data)
+			if want, got := terr, err; !reflect.DeepEqual(want, got) {
+				t.Fatalf("unexpected error:\n- want: %v\n-  got: %v", want, got)
+			}
+			if want, got := tt.want, res; !reflect.DeepEqual(want, got) {
+				t.Fatalf("unexpected InventoryItem:\n- want: %v\n-  got: %v", want, got)
+			}
+		})
+	}
+}
+
+func TestBasicDeleteInventoryItem(t *testing.T) {
+	var tests = []struct {
+		desc       string
+		data       *InventoryItem
+		serverData interface{}
+		status     int
+		errstr     string
+	}{
+		{
+			desc:       "Delete ID 1",
+			data:       testInventoryItem(1),
+			serverData: testInventoryItem(1),
+			status:     0,
+			errstr:     "",
+		},
+		{
+			desc: "Delete not Found",
+			data: testInventoryItem(1),
+			serverData: &struct {
+				Detail string `json:"detail"`
+			}{
+				Detail: "Not found.",
+			},
+			status: http.StatusNotFound,
+			errstr: "404 - Not found.",
+		},
+	}
+
+	for i, tt := range tests {
+		t.Run(fmt.Sprintf("[%d] %s", i, tt.desc), func(t *testing.T) {
+			c, done := testClient(t, testStatusHandler(t, http.MethodDelete, "/api/dcim/inventory-items/1/", tt.serverData, tt.status))
+			defer done()
+
+			var terr error
+			if tt.errstr != "" {
+				terr = errors.New(tt.errstr) // Using errstr and initialize real err here, to satisfy golint
+			}
+
+			err := c.DCIM.InventoryItems.Delete(tt.data)
+			if want, got := terr, err; !reflect.DeepEqual(want, got) {
+				t.Fatalf("unexpected error:\n- want: %v\n-  got: %v", want, got)
+			}
+		})
+	}
+}
diff --git a/netbox/dcim_inventory-items_test.go b/netbox/dcim_inventory-items_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..527a6d9b33c26760b098cc9cec191b3598d7c122
--- /dev/null
+++ b/netbox/dcim_inventory-items_test.go
@@ -0,0 +1,294 @@
+// Copyright 2017 The go-netbox Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package netbox
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"net/url"
+	"reflect"
+	"testing"
+)
+
+func TestInventoryItemGet(t *testing.T) {
+	var tests = []struct {
+		desc             string
+		want             *InventoryItem
+		wantManufacturer *NestedManufacturer
+	}{
+		{
+			desc: "InventoryItem without Manufacturer",
+			want: testInventoryItem(1),
+		},
+		{
+			desc: "InventoryItem with Manufacturer",
+			want: testInventoryItemWithManufacturer(1),
+		},
+	}
+
+	for idx, ii := range tests {
+		t.Run(fmt.Sprintf("[%d] %s", idx, ii.desc), func(t *testing.T) {
+			serverData := serverDataInventoryItem(*ii.want)
+
+			c, done := testClient(t, testHandler(t, http.MethodGet, "/api/dcim/inventory-items/1/", &serverData))
+			defer done()
+
+			res, err := c.DCIM.InventoryItems.Get(1)
+			if err != nil {
+				t.Fatalf("unexpected error from c.DCIM.InventoryItems.Get: %v", err)
+			}
+
+			if want, got := ii.want, res; !reflect.DeepEqual(want, got) {
+				t.Fatalf("unexpected InventoryItem\n- want: %v\n- got: %v", want, got)
+			}
+		})
+	}
+}
+
+func TestInventoryItemUnmarshalJSON(t *testing.T) {
+	parentID := 4
+	var tests = []struct {
+		desc string
+		data []byte
+		want *InventoryItem
+	}{
+		{
+			desc: "Minimal inventory item",
+			data: []byte(`{ "id": 4, "device": { "id": 1, "url": "http://localhost:8000/api/dcim/devices/1/", "name": "Test Device 1", "display_name": "Test Device 1"}, "parent": null, "name": "device name", "manufacturer": null }`),
+			want: &InventoryItem{
+				ID: 4,
+				Device: NestedDevice{
+					ID:          1,
+					URL:         "http://localhost:8000/api/dcim/devices/1/",
+					Name:        "Test Device 1",
+					DisplayName: "Test Device 1",
+				},
+				Name:         "device name",
+				Parent:       nil,
+				Manufacturer: nil,
+			},
+		},
+		{
+			desc: "Maximal inventory item",
+			data: []byte(`{ "id": 2, "device": { "id": 1, "url": "http://localhost:8000/api/dcim/devices/1/", "name": "Test Device 1", "display_name": "Test Device 1" }, "parent": 4, "name": "the device name", "manufacturer": { "id": 10, "url": "http://localhost:8000/api/dcim/manufacturers/10/", "name": "manufacturer name", "slug": "mfg-name" }, "part_id": "the part ID", "serial": "the serial", "discovered": true }`),
+			want: &InventoryItem{
+				ID: 2,
+				Device: NestedDevice{
+					ID:          1,
+					URL:         "http://localhost:8000/api/dcim/devices/1/",
+					Name:        "Test Device 1",
+					DisplayName: "Test Device 1",
+				},
+				Parent: &parentID,
+				Name:   "the device name",
+				Manufacturer: &NestedManufacturer{
+					ID:   10,
+					URL:  "http://localhost:8000/api/dcim/manufacturers/10/",
+					Name: "manufacturer name",
+					Slug: "mfg-name",
+				},
+				PartID:     "the part ID",
+				Serial:     "the serial",
+				Discovered: true,
+			},
+		},
+	}
+
+	for idx, ii := range tests {
+		t.Run(fmt.Sprintf("[%d] %s", idx, ii.desc), func(t *testing.T) {
+			result := new(InventoryItem)
+			err := json.Unmarshal(ii.data, result)
+			if err != nil {
+				t.Fatalf("unexpected error from InventoryItem.UnmarshalJSON: %v", err)
+			}
+
+			if want, got := ii.want, result; !reflect.DeepEqual(want, got) {
+				t.Fatalf("unexpected InventoryItem:\n- want: %v\n-  got: %v", want, got)
+			}
+		})
+	}
+}
+
+func TestInventoryItemMarshalJSON(t *testing.T) {
+	var tests = []struct {
+		desc string
+		data *InventoryItem
+		want []byte
+	}{
+		{
+			desc: "Inventory item without manufacturer",
+			data: testInventoryItem(1),
+			want: []byte(`{"id":1,"device":10001,"name":"Inventory Item 1","part_id":"Part ID 1","serial":"Serial 1","discovered":true}`),
+		},
+		{
+			desc: "Inventory item with manufacturer",
+			data: testInventoryItemWithManufacturer(2),
+			want: []byte(`{"device":10002,"name":"Inventory Item 2","manufacturer":20002,"part_id":"Part ID 2","serial":"Serial 2","discovered":true}`),
+		},
+	}
+
+	for idx, ii := range tests {
+		t.Run(fmt.Sprintf("[%d] %s", idx, ii.desc), func(t *testing.T) {
+			result, err := json.Marshal(ii.data)
+			if err != nil {
+				t.Fatalf("unexpected error from writableInventoryItem.MarshalJSON: %v", err)
+			}
+
+			if want, got := ii.want, result; bytes.Compare(want, got) != 0 {
+				t.Fatalf("unexpected JSON:\n- want: %v\n-  got: %v", string(want), string(got))
+			}
+		})
+	}
+}
+
+func TestWritableInventoryItemUnmarshalJSON(t *testing.T) {
+	parentID := 4
+	manufacturerID := 6
+	var tests = []struct {
+		desc string
+		data []byte
+		want *writableInventoryItem
+	}{
+		{
+			desc: "Minimal inventory item",
+			data: []byte(`{ "device": 1, "parent": null, "name": "device name" }`),
+			want: &writableInventoryItem{Device: 1, Name: "device name"},
+		},
+		{
+			desc: "Maximal inventory item",
+			data: []byte(`{ "id": 2, "device": 3, "parent": 4, "name": "the device name", "manufacturer": 6, "part_id": "the part ID", "serial": "the serial", "discovered": true }`),
+			want: &writableInventoryItem{
+				ID:           2,
+				Device:       3,
+				Parent:       &parentID,
+				Name:         "the device name",
+				Manufacturer: &manufacturerID,
+				PartID:       "the part ID",
+				Serial:       "the serial",
+				Discovered:   true,
+			},
+		},
+	}
+
+	for idx, ii := range tests {
+		t.Run(fmt.Sprintf("[%d] %s", idx, ii.desc), func(t *testing.T) {
+			result := new(writableInventoryItem)
+			err := json.Unmarshal(ii.data, result)
+			if err != nil {
+				t.Fatalf("unexpected error from writableInventoryItem.UnmarshalJSON: %v", err)
+			}
+
+			if want, got := ii.want, result; !reflect.DeepEqual(want, got) {
+				t.Fatalf("unexpected writableInventoryItem:\n- want: %v\n-  got: %v", want, got)
+			}
+		})
+	}
+}
+
+func TestListInventoryItemOptions(t *testing.T) {
+	var tests = []struct {
+		desc string
+		o    *ListInventoryItemOptions
+		v    url.Values
+	}{
+		{
+			desc: "empty options",
+		},
+		{
+			desc: "full options",
+			o: &ListInventoryItemOptions{
+				Name:     "Hello",
+				DeviceID: 1,
+				Device:   "node_name_1",
+			},
+			v: url.Values{
+				"name":      []string{"Hello"},
+				"device_id": []string{"1"},
+			},
+		},
+		{
+			desc: "device name",
+			o: &ListInventoryItemOptions{
+				Name:   "Hello",
+				Device: "node_name_1",
+			},
+			v: url.Values{
+				"name":   []string{"Hello"},
+				"device": []string{"node_name_1"},
+			},
+		},
+	}
+
+	for i, tt := range tests {
+		t.Run(fmt.Sprintf("[%d] %s", i, tt.desc), func(t *testing.T) {
+			v, err := tt.o.Values()
+			if err != nil {
+				t.Fatalf("unexpected Values error: %v", err)
+			}
+
+			if want, got := tt.v, v; !reflect.DeepEqual(want, got) {
+				t.Fatalf("unexpected url.Values map:\n- want: %v\n-  got: %v", want, got)
+			}
+		})
+	}
+}
+
+func testInventoryItem(id int) *InventoryItem {
+	return testInventoryItemHelper(id, false, nil)
+}
+
+func testInventoryItemCreate(id int) *InventoryItem {
+	return testInventoryItemHelper(id, true, nil)
+}
+
+func testInventoryItemWithManufacturer(id int) *InventoryItem {
+	return testInventoryItemHelper(id, true, testNestedManufacturer(id+20000))
+}
+
+func testNestedManufacturer(id int) *NestedManufacturer {
+	return &NestedManufacturer{
+		ID:   id,
+		URL:  fmt.Sprintf("http://localhost:8000/api/dcim/manufacturers/%d/", id),
+		Name: fmt.Sprintf("Test nested manufacturer %d", id),
+		Slug: fmt.Sprintf("test-nested-manufacturer-%d", id),
+	}
+}
+
+func testInventoryItemHelper(id int, create bool, manufacturer *NestedManufacturer) *InventoryItem {
+	deviceID := id + 10000
+	device := NestedDevice{
+		ID:          deviceID,
+		URL:         fmt.Sprintf("http://example.host/api/dcim/devices/%d/", deviceID),
+		Name:        fmt.Sprintf("Device %d", deviceID),
+		DisplayName: fmt.Sprintf("Display Device %d", deviceID),
+	}
+
+	itemID := id
+	if create {
+		itemID = 0
+	}
+	return &InventoryItem{
+		ID:           itemID,
+		Device:       device,
+		Parent:       nil,
+		Name:         fmt.Sprintf("Inventory Item %d", id),
+		Manufacturer: manufacturer,
+		PartID:       fmt.Sprintf("Part ID %d", id),
+		Serial:       fmt.Sprintf("Serial %d", id),
+		Discovered:   true,
+	}
+}
diff --git a/netbox/dcim_inventory-items_types.go b/netbox/dcim_inventory-items_types.go
new file mode 100644
index 0000000000000000000000000000000000000000..0df73921ed687dc53355c8b531ea57fc371efbcf
--- /dev/null
+++ b/netbox/dcim_inventory-items_types.go
@@ -0,0 +1,123 @@
+// Copyright 2017 The go-netbox Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package netbox
+
+import (
+	"encoding/json"
+	"net/url"
+	"strconv"
+)
+
+// A NestedManufacturer corresponds to the Netbox API's
+// nested serializer, when a manufacturer appears as a
+// parent of another object.
+//
+// https://netbox.readthedocs.io/en/stable/api/overview/#serialization
+type NestedManufacturer struct {
+	ID   int    `json:"id"`
+	URL  string `json:"url"`
+	Name string `json:"name"`
+	Slug string `json:"slug"`
+}
+
+// A NestedDevice corresponds to the Netbox API's
+// nested serializer, when a device appears as a
+// parent of another object.
+type NestedDevice struct {
+	ID          int    `json:"id"`
+	URL         string `json:"url"`
+	Name        string `json:"name"`
+	DisplayName string `json:"display_name"`
+}
+
+// An InventoryItem corresponds to the Netbox API's
+// base serializer for Inventory Items.
+type InventoryItem struct {
+	ID           int                 `json:"id,omitempty"`
+	Device       NestedDevice        `json:"device"`
+	Parent       *int                `json:"parent,omitempty"`
+	Name         string              `json:"name"`
+	Manufacturer *NestedManufacturer `json:"manufacturer,omitempty"`
+	PartID       string              `json:"part_id,omitempty"`
+	Serial       string              `json:"serial,omitempty"`
+	Discovered   bool                `json:"discovered,omitempty"`
+}
+
+// A writableInventoryItem corresponds to the Netbox API's
+// writable serializer for an InventoryItem. It is used transparently
+// when IventoryItems are serialized in to JSON.
+type writableInventoryItem struct {
+	ID           int    `json:"id,omitempty"`
+	Device       int    `json:"device"`
+	Parent       *int   `json:"parent,omitempty"`
+	Name         string `json:"name"`
+	Manufacturer *int   `json:"manufacturer,omitempty"`
+	PartID       string `json:"part_id,omitempty"`
+	Serial       string `json:"serial,omitempty"`
+	Discovered   bool   `json:"discovered,omitempty"`
+}
+
+// MarshalJSON marshals an InventoryItem into JSON bytes,
+// and is used by the standard json package.
+func (i *InventoryItem) MarshalJSON() ([]byte, error) {
+	var manufacturerID *int
+	if i.Manufacturer != nil {
+		manufacturerID = &i.Manufacturer.ID
+	}
+	return json.Marshal(writableInventoryItem{
+		ID:           i.ID,
+		Device:       i.Device.ID,
+		Parent:       i.Parent,
+		Name:         i.Name,
+		Manufacturer: manufacturerID,
+		PartID:       i.PartID,
+		Serial:       i.Serial,
+		Discovered:   i.Discovered,
+	})
+}
+
+// ListInventoryItemOptions is used as an argument for Client.DCIM.InventoryItems.List.
+// Integer fields with an *ID suffix are preferred over their string
+// counterparts, and if both are set, only the *ID field will be used.
+type ListInventoryItemOptions struct {
+	Name     string
+	DeviceID int
+	Device   string
+}
+
+// Values generates a url.Values map from the data in ListTenantOptions.
+func (o *ListInventoryItemOptions) Values() (url.Values, error) {
+	if o == nil {
+		return nil, nil
+	}
+
+	v := url.Values{}
+
+	if o.Name != "" {
+		v.Set("name", o.Name)
+	}
+
+	switch {
+	case o.DeviceID != 0:
+		v.Set("device_id", strconv.Itoa(o.DeviceID))
+	case o.Device != "":
+		v.Set("device", o.Device)
+	}
+
+	return v, nil
+}
+
+//go:generate go run generate_functions.go -type-name InventoryItem -update-type-name writableInventoryItem -service-name InventoryItemsService -endpoint dcim -service inventory-items
+//go:generate go run generate_basic_tests.go -type-name InventoryItem -service-name InventoryItemsService -endpoint dcim -service inventory-items -client-endpoint DCIM -client-service InventoryItems
diff --git a/netbox/tenancy.go b/netbox/tenancy.go
index b44124f2a8a1211831becba9475d548d1cb2e81f..fb5b3e9b2bd136ae9c404febb76b250b92c2b31d 100644
--- a/netbox/tenancy.go
+++ b/netbox/tenancy.go
@@ -14,7 +14,7 @@
 
 package netbox
 
-// A TenancyService is udes in a Client to access NetBox's Tenancy API methods.
+// A TenancyService is used in a Client to access NetBox's Tenancy API methods.
 type TenancyService struct {
 	c            *Client
 	TenantGroups *TenantGroupsService
diff --git a/netbox/tenancy_tenant-groups_basic_test.go b/netbox/tenancy_tenant-groups_basic_test.go
index 2e3322e38d8a969f7887bec47ef8ac5ee61ed8c7..3af212483acf34c801bfa17aff6021ec785c876d 100644
--- a/netbox/tenancy_tenant-groups_basic_test.go
+++ b/netbox/tenancy_tenant-groups_basic_test.go
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// Code generated by generate_functions.go. DO NOT EDIT.
+// Code generated by generate_basic_tests.go. DO NOT EDIT.
 
 package netbox
 
diff --git a/netbox/tenancy_tenants_basic_test.go b/netbox/tenancy_tenants_basic_test.go
index e26756f54541e2f987bbaf66b60977033db5b968..6e87fd6616b1cfd3178c916486c972903d747f1a 100644
--- a/netbox/tenancy_tenants_basic_test.go
+++ b/netbox/tenancy_tenants_basic_test.go
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// Code generated by generate_functions.go. DO NOT EDIT.
+// Code generated by generate_basic_tests.go. DO NOT EDIT.
 
 package netbox
 
diff --git a/netbox/tenancy_tenants_test.go b/netbox/tenancy_tenants_test.go
index b46f9ead3bf34212a9b2ea5b7c1e0471825a3cde..5e74b31be18ff87340e977f7a0efa8c0eea4210b 100644
--- a/netbox/tenancy_tenants_test.go
+++ b/netbox/tenancy_tenants_test.go
@@ -26,19 +26,16 @@ import (
 
 func TestTenantGet(t *testing.T) {
 	var tests = []struct {
-		desc      string
-		want      *Tenant
-		wantGroup *TenantGroup
+		desc string
+		want *Tenant
 	}{
 		{
-			desc:      "Without TenantGroup",
-			want:      testTenantWithGroup(1, nil),
-			wantGroup: nil,
+			desc: "Without TenantGroup",
+			want: testTenantWithGroup(1, nil),
 		},
 		{
-			desc:      "With TenantGroup",
-			want:      testTenantWithGroup(1, testTenantGroup(1)),
-			wantGroup: testTenantGroup(1),
+			desc: "With TenantGroup",
+			want: testTenantWithGroup(1, testTenantGroup(1)),
 		},
 	}
 
@@ -57,9 +54,6 @@ func TestTenantGet(t *testing.T) {
 			if want, got := tt.want, res; !reflect.DeepEqual(want, got) {
 				t.Fatalf("unexpected Tenant:\n- want: %v\n-  got: %v", want, got)
 			}
-			if want, got := tt.wantGroup, res.Group; !reflect.DeepEqual(want, got) {
-				t.Fatalf("unexpected TenantGroup:\n- want: %v\n-  got: %v", want, got)
-			}
 		})
 	}
 }
diff --git a/netbox/tenancy_tenants_types.go b/netbox/tenancy_tenants_types.go
index ea64d3de37e63a22a20e0a8c569eb76452e09eec..75fbfd02684368b4d1c92420026ea8e4cc0b2375 100644
--- a/netbox/tenancy_tenants_types.go
+++ b/netbox/tenancy_tenants_types.go
@@ -57,7 +57,7 @@ func (t *Tenant) MarshalJSON() ([]byte, error) {
 	})
 }
 
-// ListTenantOptions is used as an argument for Client.Tenancy.Tenant.List.
+// ListTenantOptions is used as an argument for Client.Tenancy.Tenants.List.
 // Integer fields with an *ID suffix are preferred over their string
 // counterparts, and if both are set, only the *ID field will be used.
 type ListTenantOptions struct {