diff --git a/app/api/network.py b/app/api/network.py
index b48e05dba65f551130d85510ec4d7a73c2e2e1ef..0a0b7bf43bc36e2b595e095141686c99ffdc39c1 100644
--- a/app/api/network.py
+++ b/app/api/network.py
@@ -65,6 +65,21 @@ def create_interface():
     return create_generic_model(models.Interface, mandatory_fields=('network', 'ip', 'name'))
 
 
+@bp.route('/hosts')
+@jwt_required
+def get_hosts():
+    return get_generic_model(models.Host,
+                             order_by=models.Host.name)
+
+
+@bp.route('/hosts', methods=['POST'])
+@jwt_required
+@jwt_groups_accepted('admin', 'create')
+def create_host():
+    """Create a new host"""
+    return create_generic_model(models.Host, mandatory_fields=('name',))
+
+
 @bp.route('/macs')
 @jwt_required
 def get_macs():
diff --git a/tests/functional/test_api.py b/tests/functional/test_api.py
index 8ef3c98541179ef0859d986602a3627d393722e3..708fc7bacb896f9d1cb50492e4540a710e029f8f 100644
--- a/tests/functional/test_api.py
+++ b/tests/functional/test_api.py
@@ -25,12 +25,13 @@ ENDPOINT_MODEL = {
     'inventory/items': models.Item,
     'network/networks': models.Network,
     'network/interfaces': models.Interface,
+    'network/hosts': models.Host,
     'network/macs': models.Mac,
 }
 GENERIC_GET_ENDPOINTS = [key for key in ENDPOINT_MODEL.keys()
-                         if key not in ('inventory/items', 'network/macs', 'network/networks', 'network/interfaces')]
+                         if key.startswith('inventory') and key != 'inventory/items']
 GENERIC_CREATE_ENDPOINTS = [key for key in ENDPOINT_MODEL.keys()
-                            if key not in ('inventory/items', 'inventory/actions', 'network/macs', 'network/networks', 'network/interfaces')]
+                            if key.startswith('inventory') and key not in ('inventory/items', 'inventory/actions')]
 CREATE_AUTH_ENDPOINTS = [key for key in ENDPOINT_MODEL.keys() if key != 'inventory/actions']
 
 
@@ -695,3 +696,41 @@ def test_create_mac_invalid_address(address, client, user_token):
     data = {'address': address}
     response = post(client, f'{API_URL}/network/macs', data=data, token=user_token)
     check_response_message(response, f"'{address}' does not appear to be a MAC address", 422)
+
+
+def test_get_hosts(client, host_factory, readonly_token):
+    # Create some hosts
+    host1 = host_factory()
+    host2 = host_factory()
+    response = get(client, f'{API_URL}/network/hosts', token=readonly_token)
+    assert response.status_code == 200
+    assert len(response.json) == 2
+    check_input_is_subset_of_response(response, (host1.to_dict(), host2.to_dict()))
+
+
+def test_create_host(client, item_factory, user_token):
+    item = item_factory()
+    # check that name is mandatory
+    response = post(client, f'{API_URL}/network/hosts', data={}, token=user_token)
+    check_response_message(response, "Missing mandatory field 'name'", 422)
+
+    data = {'name': 'my-hostname'}
+    response = post(client, f'{API_URL}/network/hosts', data=data, token=user_token)
+    assert response.status_code == 201
+    assert {'id', 'name', 'type', 'description',
+            'item', 'interfaces', 'created_at',
+            'updated_at', 'user'} == set(response.json.keys())
+    assert response.json['name'] == data['name']
+
+    # Check that name shall be unique
+    response = post(client, f'{API_URL}/network/hosts', data=data, token=user_token)
+    check_response_message(response, '(psycopg2.IntegrityError) duplicate key value violates unique constraint', 422)
+
+    # Check that we can pass an item_id
+    data2 = {'name': 'another-hostname',
+             'item_id': item.id}
+    response = post(client, f'{API_URL}/network/hosts', data=data2, token=user_token)
+    assert response.status_code == 201
+
+    # check that all items were created
+    assert models.Host.query.count() == 2