diff --git a/internal/models/area.go b/internal/models/area.go
new file mode 100644
index 0000000000000000000000000000000000000000..978d84699d61306c6ca5a63cc1a351ad0a76ced4
--- /dev/null
+++ b/internal/models/area.go
@@ -0,0 +1,123 @@
+package models
+
+import (
+	"encoding/json"
+	"net/http"
+	"strconv"
+	"strings"
+
+	"forge.grandlyon.com/apoyen/elections/internal/auth"
+)
+
+func (d *DataHandler) HandleArea(w http.ResponseWriter, r *http.Request) {
+	id, _ := strconv.Atoi(strings.TrimPrefix(r.URL.Path, "/api/Area/"))
+	switch method := r.Method; method {
+	case "GET":
+		switch auth.GetLoggedUserTechnical(w, r).Role {
+		case "ADMIN":
+			d.getAreaAdmin(w, r, id)
+		case "CAPTURER", "VISUALIZER":
+			http.Error(w, ErrorNotAuthorizeMethodOnRessource, http.StatusMethodNotAllowed)
+		default:
+			http.Error(w, ErrorRoleOfLoggedUser, http.StatusInternalServerError)
+		}
+	case "POST":
+		switch auth.GetLoggedUserTechnical(w, r).Role {
+		case "ADMIN":
+			d.postAreaAdmin(w, r)
+		case "CAPTURER", "VISUALIZER":
+			http.Error(w, ErrorNotAuthorizeMethodOnRessource, http.StatusMethodNotAllowed)
+		default:
+			http.Error(w, ErrorRoleOfLoggedUser, http.StatusInternalServerError)
+		}
+
+	case "PUT":
+		switch auth.GetLoggedUserTechnical(w, r).Role {
+		case "ADMIN":
+			d.putAreaAdmin(w, r, id)
+		case "CAPTURER", "VISUALIZER":
+			http.Error(w, ErrorNotAuthorizeMethodOnRessource, http.StatusMethodNotAllowed)
+		default:
+			http.Error(w, ErrorRoleOfLoggedUser, http.StatusInternalServerError)
+		}
+	case "DELETE":
+		switch auth.GetLoggedUserTechnical(w, r).Role {
+		case "ADMIN":
+			d.deleteAreaAdmin(w, r, id)
+		case "CAPTURER", "VISUALIZER":
+			http.Error(w, ErrorNotAuthorizeMethodOnRessource, http.StatusMethodNotAllowed)
+		default:
+			http.Error(w, ErrorRoleOfLoggedUser, http.StatusInternalServerError)
+		}
+	default:
+		http.Error(w, "method not allowed", 400)
+	}
+}
+
+func (d *DataHandler) getAreaAdmin(w http.ResponseWriter, r *http.Request, id int) {
+	if id != 0 {
+		var o Area
+		if err := d.db.Preload("Sections").First(&o, id).Error; err != nil {
+			http.Error(w, ErrorIDIsMissing, http.StatusNotFound)
+			return
+		}
+		json.NewEncoder(w).Encode(o)
+	} else {
+		var o []Area
+		d.db.Preload("Sections").Find(&o)
+		json.NewEncoder(w).Encode(o)
+	}
+}
+
+func (d *DataHandler) postAreaAdmin(w http.ResponseWriter, r *http.Request) {
+	var o Area
+	err := json.NewDecoder(r.Body).Decode(&o)
+	if err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+	// Check that ElectionID exist
+	var election Election
+	if err := d.db.First(&election, o.ElectionID).Error; err != nil {
+		http.Error(w, ErrorParentNotFound, http.StatusInternalServerError)
+		return
+	}
+
+	d.db.Create(&o)
+	d.db.Last(&o)
+	json.NewEncoder(w).Encode(o)
+
+}
+
+func (d *DataHandler) putAreaAdmin(w http.ResponseWriter, r *http.Request, id int) {
+	var o Area
+	if err := d.db.Preload("Sections").First(&o, id).Error; err != nil {
+		http.Error(w, ErrorIDIsMissing, http.StatusNotFound)
+		return
+	}
+	var area Area
+	err := json.NewDecoder(r.Body).Decode(&area)
+	if err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+	o.Name = area.Name
+	o.SeatNumber = area.SeatNumber
+	o.MapID = area.MapID
+	d.db.Save(&o)
+	json.NewEncoder(w).Encode(o)
+
+}
+
+func (d *DataHandler) deleteAreaAdmin(w http.ResponseWriter, r *http.Request, id int) {
+	if id != 0 {
+		var o Area
+		if err := d.db.First(&o, id).Error; err != nil {
+			http.Error(w, ErrorIDIsMissing, http.StatusNotFound)
+			return
+		}
+		d.db.Delete(&o)
+	} else {
+		http.Error(w, ErrorIDIsMissing, http.StatusNotFound)
+	}
+}
diff --git a/internal/models/capturer.go b/internal/models/capturer.go
index f048bcbbfafbe3b5c661608a50f5944d1eb20651..f16f3273e091a08ba052d33cd12b5f2930928f5c 100644
--- a/internal/models/capturer.go
+++ b/internal/models/capturer.go
@@ -100,6 +100,7 @@ func (d *DataHandler) postCapturerAdmin(w http.ResponseWriter, r *http.Request)
 	err := json.NewDecoder(r.Body).Decode(&o)
 	if err != nil {
 		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
 	}
 	var capturer Capturer
 	if err := d.db.Where("user_id = ?", o.UserID).First(&capturer).Error; err == nil {
@@ -122,6 +123,7 @@ func (d *DataHandler) putCapturerAdmin(w http.ResponseWriter, r *http.Request, i
 	err := json.NewDecoder(r.Body).Decode(&capturer)
 	if err != nil {
 		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
 	}
 	o.Name = capturer.Name
 	d.db.Save(&o)
diff --git a/internal/models/election.go b/internal/models/election.go
index 00f4a11fb71c2ac865ef03e2c7b0d9f5d1f5a561..f415e973dc920b0afa085193203ab9bafd81e236 100644
--- a/internal/models/election.go
+++ b/internal/models/election.go
@@ -74,6 +74,7 @@ func (d *DataHandler) postElectionAdmin(w http.ResponseWriter, r *http.Request)
 	err := json.NewDecoder(r.Body).Decode(&o)
 	if err != nil {
 		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
 	}
 	d.db.Create(&o)
 	d.db.Last(&o)
@@ -91,6 +92,7 @@ func (d *DataHandler) putElectionAdmin(w http.ResponseWriter, r *http.Request, i
 	err := json.NewDecoder(r.Body).Decode(&election)
 	if err != nil {
 		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
 	}
 	o.Name = election.Name
 	o.BallotType = election.BallotType
diff --git a/internal/models/models.go b/internal/models/models.go
index e2371675fbda232ee29b0e8fb5bb806ae5cf32c5..675c97beb9dede6a5a95ad16527e2365e1c1647a 100644
--- a/internal/models/models.go
+++ b/internal/models/models.go
@@ -32,6 +32,9 @@ const ErrorRoleOfLoggedUser = "Could not get role of logged user"
 // ErrorNotAuthorizeMethodOnRessource = "You're not authorize to execute this method on this ressource." with 405 http.StatusMethodNotAllowed
 const ErrorNotAuthorizeMethodOnRessource = "You're not authorize to execute this method on this ressource."
 
+// ErrorParentNotFound = "Could not get the parent associated to the object" with 500 http.StatusInternalServerError
+const ErrorParentNotFound = "Could not get the parent associated to the object"
+
 // Election
 type Election struct {
 	ID         uint       `gorm:"primary_key"`
@@ -218,6 +221,8 @@ func (d *DataHandler) ProcessAPI(w http.ResponseWriter, r *http.Request) {
 		d.HandleCapturer(w, r)
 	case "Election":
 		d.HandleElection(w, r)
+	case "Area":
+		d.HandleArea(w, r)
 	}
 
 }
diff --git a/internal/rootmux/admin_test.go b/internal/rootmux/admin_test.go
index 12082873dc589318264268f02a9f0f99c677ea51..3ab03776c06c42858055bbacc22025c266366c24 100644
--- a/internal/rootmux/admin_test.go
+++ b/internal/rootmux/admin_test.go
@@ -34,14 +34,26 @@ func AdminTests(t *testing.T) {
 		do("DELETE", "/api/Capturer/3", xsrfHeader, ``, 200, ``)
 
 		// Create an Election
-		do("POST", "/api/Election", xsrfHeader, `{"Name":"Grand Lyon 2020", "BallotType":"metropolitan-direct"}`, 200, `{"ID":1,"Name":"Grand Lyon 2020","BallotType":"metropolitan-direct","Areas":null,"Rounds":null}`)
+		do("POST", "/api/Election", xsrfHeader, `{"Name":"Grand Lyon 2020","BallotType":"metropolitan-direct"}`, 200, `{"ID":1,"Name":"Grand Lyon 2020","BallotType":"metropolitan-direct","Areas":null,"Rounds":null}`)
 		// Get the election
 		do("GET", "/api/Election/1", xsrfHeader, ``, 200, `{"ID":1,"Name":"Grand Lyon 2020","BallotType":"metropolitan-direct","Areas":[],"Rounds":null}`)
 		// Get all the elections
 		do("GET", "/api/Election/", xsrfHeader, ``, 200, `[{"ID":1,"Name":"Grand Lyon 2020","BallotType":"metropolitan-direct","Areas":[],"Rounds":null}]`)
-		// Update a election
+		// Update an election
 		do("PUT", "/api/Election/1", xsrfHeader, `{"ID":1,"Name":"Grand-Lyon 2020", "BallotType":"metropolitan-direct"}`, 200, `{"ID":1,"Name":"Grand-Lyon 2020","BallotType":"metropolitan-direct","Areas":[],"Rounds":null}`)
-		// Delete a election
+
+		// Create an Area
+		do("POST", "/api/Area", xsrfHeader, `{"ElectionID":1,"Name":"Area 1","SeatNumber":9,"MapID":"1"}`, 200, `{"ID":1,"ElectionID":1,"Name":"Area 1","SeatNumber":9,"MapID":"1","Sections":null}`)
+		// Get the election
+		do("GET", "/api/Area/1", xsrfHeader, ``, 200, `{"ID":1,"ElectionID":1,"Name":"Area 1","SeatNumber":9,"MapID":"1","Sections":[]}`)
+		// Get all the areas
+		do("GET", "/api/Area/", xsrfHeader, ``, 200, `[{"ID":1,"ElectionID":1,"Name":"Area 1","SeatNumber":9,"MapID":"1","Sections":[]}]`)
+		// Update an area
+		do("PUT", "/api/Area/1", xsrfHeader, `{"ID":1,"ElectionID":1,"Name":"Area 1","SeatNumber":7,"MapID":"1"}`, 200, `{"ID":1,"ElectionID":1,"Name":"Area 1","SeatNumber":7,"MapID":"1","Sections":[]}`)
+
+		// Delete an area
+		do("DELETE", "/api/Areas/1", xsrfHeader, ``, 200, ``)
+		// Delete an election
 		do("DELETE", "/api/Election/1", xsrfHeader, ``, 200, ``)
 
 	}
diff --git a/internal/rootmux/capturer_test.go b/internal/rootmux/capturer_test.go
index 0f91790f0e855c02a7d11aee17d07689b522d5a3..89367267590245bb6395178838a2401143950c5b 100644
--- a/internal/rootmux/capturer_test.go
+++ b/internal/rootmux/capturer_test.go
@@ -46,6 +46,17 @@ func CapturerTests(t *testing.T) {
 		// Delete an election should fail with 405
 		do("DELETE", "/api/Election/1", xsrfHeader, ``, 405, `You're not authorize to execute this method on this ressource.`)
 
+		// Create an area should fail with 405
+		do("POST", "/api/Area", xsrfHeader, `{"ElectionID":1,"Name":"Area 1","SeatNumber":9,"MapID":"1"}`, 405, `You're not authorize to execute this method on this ressource.`)
+		// Get an area should fail with 405
+		do("GET", "/api/Area/1", xsrfHeader, "", 405, `You're not authorize to execute this method on this ressource.`)
+		// Get all the areas should fail with 405
+		do("GET", "/api/Area/", xsrfHeader, "", 405, `You're not authorize to execute this method on this ressource.`)
+		// Update an area should fail with 405
+		do("PUT", "/api/Area/1", xsrfHeader, `{"ID":1,"ElectionID":1,"Name":"Area 1","SeatNumber":9,"MapID":"1"}`, 405, `You're not authorize to execute this method on this ressource.`)
+		// Delete an area should fail with 405
+		do("DELETE", "/api/Area/1", xsrfHeader, ``, 405, `You're not authorize to execute this method on this ressource.`)
+
 	}
 	// Do a in memory login with an known admin
 	do("POST", "/Login", noH, `{"login": "capturer","password": "password"}`, 200, "")
diff --git a/internal/rootmux/visualizer_test.go b/internal/rootmux/visualizer_test.go
index 08841a72b871f99fad2187b6d258d57978c54b0a..31b5a05ece3d45812b482be5735402a33776e85a 100644
--- a/internal/rootmux/visualizer_test.go
+++ b/internal/rootmux/visualizer_test.go
@@ -44,6 +44,16 @@ func VisualizerTests(t *testing.T) {
 		// Delete an election should fail with 405
 		do("DELETE", "/api/Election/1", xsrfHeader, ``, 405, `You're not authorize to execute this method on this ressource.`)
 
+		// Create an area should fail with 405
+		do("POST", "/api/Area", xsrfHeader, `{"ElectionID":1,"Name":"Area 1","SeatNumber":9,"MapID":"1"}`, 405, `You're not authorize to execute this method on this ressource.`)
+		// Get an area should fail with 405
+		do("GET", "/api/Area/1", xsrfHeader, "", 405, `You're not authorize to execute this method on this ressource.`)
+		// Get all the areas should fail with 405
+		do("GET", "/api/Area/", xsrfHeader, "", 405, `You're not authorize to execute this method on this ressource.`)
+		// Update an area should fail with 405
+		do("PUT", "/api/Area/1", xsrfHeader, `{"ID":1,"ElectionID":1,"Name":"Area 1","SeatNumber":9,"MapID":"1"}`, 405, `You're not authorize to execute this method on this ressource.`)
+		// Delete an area should fail with 405
+		do("DELETE", "/api/Area/1", xsrfHeader, ``, 405, `You're not authorize to execute this method on this ressource.`)
 	}
 	// Do a in memory login with an known admin
 	do("POST", "/Login", noH, `{"login": "visualizer","password": "password"}`, 200, "")