diff --git a/internal/models/models.go b/internal/models/models.go
index 2788b429c8d1be7fd07cb7ec603bc6cb53b86fc0..6f0f1150a0d93cf1099c13f2ee0725e5ee893885 100644
--- a/internal/models/models.go
+++ b/internal/models/models.go
@@ -87,13 +87,13 @@ type Desk struct {
 
 // Party represent a political party or tendance
 type Party struct {
-	ID            uint       `gorm:"primary_key"`
-	CreatedAt     time.Time  `json:"-"`
-	UpdatedAt     time.Time  `json:"-"`
-	DeletedAt     *time.Time `json:"-"`
-	Name          string
-	Color         string
-	CandidateList []CandidateList
+	ID             uint       `gorm:"primary_key"`
+	CreatedAt      time.Time  `json:"-"`
+	UpdatedAt      time.Time  `json:"-"`
+	DeletedAt      *time.Time `json:"-"`
+	Name           string
+	Color          string
+	CandidateLists []CandidateList
 }
 
 // Capturer is a user who can capture the results on the desks he is affected
@@ -234,6 +234,8 @@ func (d *DataHandler) ProcessAPI(w http.ResponseWriter, r *http.Request) {
 		d.handleDeskRound(w, r)
 	case "CapturerDeskRound":
 		d.handleCapturerDeskRound(w, r)
+	case "Party":
+		d.handleParty(w, r)
 	}
 
 }
diff --git a/internal/models/party.go b/internal/models/party.go
new file mode 100644
index 0000000000000000000000000000000000000000..9036b57797c69eb6b68963c41105d26af9cad665
--- /dev/null
+++ b/internal/models/party.go
@@ -0,0 +1,115 @@
+package models
+
+import (
+	"encoding/json"
+	"net/http"
+	"strconv"
+	"strings"
+
+	"forge.grandlyon.com/apoyen/elections/internal/auth"
+)
+
+func (d *DataHandler) handleParty(w http.ResponseWriter, r *http.Request) {
+	id, _ := strconv.Atoi(strings.TrimPrefix(r.URL.Path, "/api/Party/"))
+	switch method := r.Method; method {
+	case "GET":
+		switch auth.GetLoggedUserTechnical(w, r).Role {
+		case "ADMIN", "CAPTURER", "VISUALIZER":
+			d.getParty(w, r, id)
+		default:
+			http.Error(w, ErrorRoleOfLoggedUser, http.StatusInternalServerError)
+		}
+	case "POST":
+		switch auth.GetLoggedUserTechnical(w, r).Role {
+		case "ADMIN":
+			d.postParty(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.putParty(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.deleteParty(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) getParty(w http.ResponseWriter, r *http.Request, id int) {
+	if id != 0 {
+		var o Party
+		if err := d.db.Preload("CandidateLists").First(&o, id).Error; err != nil {
+			http.Error(w, ErrorIDIsMissing, http.StatusNotFound)
+			return
+		}
+		json.NewEncoder(w).Encode(o)
+	} else {
+		var o []Party
+		d.db.Preload("CandidateLists").Find(&o)
+		json.NewEncoder(w).Encode(o)
+	}
+}
+
+func (d *DataHandler) postParty(w http.ResponseWriter, r *http.Request) {
+	var o Party
+	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)
+	json.NewEncoder(w).Encode(o)
+
+}
+
+func (d *DataHandler) putParty(w http.ResponseWriter, r *http.Request, id int) {
+	var o Party
+	if err := d.db.Preload("CandidateLists").First(&o, id).Error; err != nil {
+		http.Error(w, ErrorIDIsMissing, http.StatusNotFound)
+		return
+	}
+	var party Party
+	err := json.NewDecoder(r.Body).Decode(&party)
+	if err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+	o.Name = party.Name
+	o.Color = party.Color
+	d.db.Save(&o)
+	json.NewEncoder(w).Encode(o)
+
+}
+
+func (d *DataHandler) deleteParty(w http.ResponseWriter, r *http.Request, id int) {
+	if id != 0 {
+		var o Party
+		if err := d.db.Preload("CandidateLists").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/rootmux/admin_test.go b/internal/rootmux/admin_test.go
index 64b1c739a43020dc9d79e2eec04265c46ab9da91..68e96e5abc3fedb8fc397153beebe1bbfd3194d8 100644
--- a/internal/rootmux/admin_test.go
+++ b/internal/rootmux/admin_test.go
@@ -92,9 +92,19 @@ func AdminTests(t *testing.T) {
 		// Remove DeskRound to capturer
 		do("DELETE", "/api/CapturerDeskRound/1", xsrfHeader, `{"CapturerID":1,"DeskRoundID":1}`, 200, ``)
 
-		// Update a DeskRound should be done after desk completion by capturing votes
-		// do("PUT", "/api/DeskRound/1", xsrfHeader, `{"ID":1,"Validated":true}`, 200, `{"ID":1,"RoundID":1,"DeskID":1,"Capturers":[],"Completed":false,"DateCompletion":"0001-01-01T00:00:00Z","Validated":true,"Votes":[]}`)
+		// Create a Party
+		do("POST", "/api/Party", xsrfHeader, `{"Name":"MyGreatParty","Color":"#FFFFFF"}`, 200, `{"ID":1,"Name":"MyGreatParty","Color":"#FFFFFF","CandidateLists":null}`)
+		// Get a Party
+		do("GET", "/api/Party/1", xsrfHeader, ``, 200, `{"ID":1,"Name":"MyGreatParty","Color":"#FFFFFF","CandidateLists":[]}`)
+		// Get Parties
+		do("GET", "/api/Party/", xsrfHeader, ``, 200, `[{"ID":1,"Name":"MyGreatParty","Color":"#FFFFFF","CandidateLists":[]}]`)
+		// Update a Party
+		do("PUT", "/api/Party/1", xsrfHeader, `{"ID":1,"Name":"MyBigParty","Color":"#000000"}`, 200, `{"ID":1,"Name":"MyBigParty","Color":"#000000","CandidateLists":[]}`)
 
+		// TODO Update a DeskRound to Validated=true can only be done when votes are captured
+
+		// Delete a Party
+		do("DELETE", "/api/Party/1", xsrfHeader, ``, 200, ``)
 		// Delete a Round
 		do("DELETE", "/api/Round/1", xsrfHeader, ``, 200, ``)
 		// Delete a desk
diff --git a/internal/rootmux/capturer_test.go b/internal/rootmux/capturer_test.go
index 2de600a1517f14a07cb3a7cf8bc6a07ae7fe1a89..11b4a515dad570b1389bee26ece16723890da354 100644
--- a/internal/rootmux/capturer_test.go
+++ b/internal/rootmux/capturer_test.go
@@ -91,14 +91,27 @@ func CapturerTests(t *testing.T) {
 		do("DELETE", "/api/Round/1", xsrfHeader, ``, 405, `You're not authorize to execute this method on this ressource.`)
 
 		// Create a DeskRound should fail with 400
-		do("POST", "/api/DeskRound", xsrfHeader, `{"Test":1,"Date":"2020-06-28","Round":1}`, 400, `method not allowed`)
+		do("POST", "/api/DeskRound", xsrfHeader, `{"ID":1,"RoundID":1,"DeskID":1,"Validated":false}`, 400, `method not allowed`)
 		// Get a DeskRound
 		do("GET", "/api/DeskRound/1", xsrfHeader, ``, 200, `{"ID":1,"RoundID":1,"DeskID":1,"Capturers":[],"Completed":false,"DateCompletion":"0001-01-01T00:00:00Z","Validated":false,"Votes":[]}`)
 		// Get DeskRounds
 		do("GET", "/api/DeskRound/", xsrfHeader, ``, 200, `[{"ID":1,"RoundID":1,"DeskID":1,"Capturers":[],"Completed":false,"DateCompletion":"0001-01-01T00:00:00Z","Validated":false,"Votes":[]}]`)
+		// Update a desk should fail with 405
+		do("PUT", "/api/DeskRound/1", xsrfHeader, `{"ID":1,"RoundID":1,"DeskID":1,"Validated":false}`, 405, `You're not authorize to execute this method on this ressource.`)
 		// Delete a DeskRound should fail with 400
 		do("DELETE", "/api/DeskRound/1", xsrfHeader, ``, 400, `method not allowed`)
 
+		// Create a Party should fail with 405
+		do("POST", "/api/Party", xsrfHeader, `{"Name":"MyGreatParty","Color":"#FFFFFF"}`, 405, `You're not authorize to execute this method on this ressource.`)
+		// Get a party
+		do("GET", "/api/Party/1", xsrfHeader, "", 200, `{"ID":1,"Name":"MyGreatParty","Color":"#FFFFFF","CandidateLists":[]}`)
+		// Get all the parties
+		do("GET", "/api/Party/", xsrfHeader, "", 200, `[{"ID":1,"Name":"MyGreatParty","Color":"#FFFFFF","CandidateLists":[]}]`)
+		// Update a party should fail with 405
+		do("PUT", "/api/Party/1", xsrfHeader, `{"ID":1,"Name":"MyBigParty","Color":"#000000"}`, 405, `You're not authorize to execute this method on this ressource.`)
+		// Delete a party should fail with 405
+		do("DELETE", "/api/Party/1", xsrfHeader, ``, 405, `You're not authorize to execute this method on this ressource.`)
+
 		// Add deskround to capturer should fail with 405
 		do("POST", "/api/CapturerDeskRound", xsrfHeader, `{"CapturerID":1,"DeskRoundID":1}`, 405, `You're not authorize to execute this method on this ressource.`)
 		// Remove DeskRound to capturer
diff --git a/internal/rootmux/rootmux_test.go b/internal/rootmux/rootmux_test.go
index c8dfb25d5fde42419d09056d66d9c4af2e8561f7..11becea427954e407b88a8685ce2243cb37dcdb3 100644
--- a/internal/rootmux/rootmux_test.go
+++ b/internal/rootmux/rootmux_test.go
@@ -101,6 +101,8 @@ func appTests(t *testing.T) {
 		// Verify that a DeskRound can't be validated witout being completed
 		do("PUT", "/api/DeskRound/1", xsrfHeader, `{"ID":1,"Validated":true}`, 500, `Le bureau doit être complété avant de le valider`)
 
+		// TODO After capturing all votes for a DeskRound, it should be mark as completed
+
 		// Verify that on Desk deletion deskRounds are deleted
 		do("GET", "/api/Desk/1", xsrfHeader, ``, 200, `{"ID":1,"SectionID":1,"Name":"Desk 1","WitnessDesk":true,"Subscribed":9587,"DeskRounds":[{"ID":1,"RoundID":1,"DeskID":1,"Capturers":null,"Completed":false,"DateCompletion":"0001-01-01T00:00:00Z","Validated":false,"Votes":null}]}`)
 		do("DELETE", "/api/Desk/1", xsrfHeader, ``, 200, ``)
@@ -216,6 +218,7 @@ func resetDataWithData(t *testing.T) {
 		do("POST", "/api/Section", xsrfHeader, `{"AreaID":1,"Name":"Section 1","MapID":"1"}`, 200, `{"ID":1,"AreaID":1,"Name":"Section 1","MapID":"1","Desks":null}`)
 		do("POST", "/api/Desk", xsrfHeader, `{"SectionID":1,"Name":"Desk 1","WitnessDesk":true,"Subscribed":9587}`, 200, `{"ID":1,"SectionID":1,"Name":"Desk 1","WitnessDesk":true,"Subscribed":9587,"DeskRounds":null}`)
 		do("POST", "/api/Round", xsrfHeader, `{"ElectionID":1,"Date":"2020-06-28","Round":1}`, 200, `{"ID":1,"ElectionID":1,"Parameter":{"ID":0,"CountBlankAndNull":false,"ShowOnlyCompleted":false,"ShowMap":false},"Date":"2020-06-28","Round":1,"DeskRounds":null,"CandidateLists":null}`)
+		do("POST", "/api/Party", xsrfHeader, `{"Name":"MyGreatParty","Color":"#FFFFFF"}`, 200, `{"ID":1,"Name":"MyGreatParty","Color":"#FFFFFF","CandidateLists":null}`)
 	}
 	do("POST", "/Login", noH, `{"login": "admin","password": "password"}`, 200, "")
 	init()
diff --git a/internal/rootmux/visualizer_test.go b/internal/rootmux/visualizer_test.go
index a36147f1b636ada67e491bb5610c11945e4cb6c0..e798698f5a2fa8a15fea7737dc7dc7a61f7597c3 100644
--- a/internal/rootmux/visualizer_test.go
+++ b/internal/rootmux/visualizer_test.go
@@ -78,14 +78,27 @@ func VisualizerTests(t *testing.T) {
 		do("DELETE", "/api/Round/1", xsrfHeader, ``, 405, `You're not authorize to execute this method on this ressource.`)
 
 		// Create a DeskRound should fail with 400
-		do("POST", "/api/DeskRound", xsrfHeader, `{"Test":1,"Date":"2020-06-28","Round":1}`, 400, `method not allowed`)
+		do("POST", "/api/DeskRound", xsrfHeader, `{"ID":1,"RoundID":1,"DeskID":1,"Validated":false}`, 400, `method not allowed`)
 		// Get a DeskRound
 		do("GET", "/api/DeskRound/1", xsrfHeader, ``, 200, `{"ID":1,"RoundID":1,"DeskID":1,"Capturers":[],"Completed":false,"DateCompletion":"0001-01-01T00:00:00Z","Validated":false,"Votes":[]}`)
 		// Get DeskRounds
 		do("GET", "/api/DeskRound/", xsrfHeader, ``, 200, `[{"ID":1,"RoundID":1,"DeskID":1,"Capturers":[],"Completed":false,"DateCompletion":"0001-01-01T00:00:00Z","Validated":false,"Votes":[]}]`)
+		// Update a desk should fail with 405
+		do("PUT", "/api/DeskRound/1", xsrfHeader, `{"ID":1,"RoundID":1,"DeskID":1,"Validated":false}`, 405, `You're not authorize to execute this method on this ressource.`)
 		// Delete a DeskRound should fail with 400
 		do("DELETE", "/api/DeskRound/1", xsrfHeader, ``, 400, `method not allowed`)
 
+		// Create a Party should fail with 405
+		do("POST", "/api/Party", xsrfHeader, `{"Name":"MyGreatParty","Color":"#FFFFFF"}`, 405, `You're not authorize to execute this method on this ressource.`)
+		// Get a party
+		do("GET", "/api/Party/1", xsrfHeader, "", 200, `{"ID":1,"Name":"MyGreatParty","Color":"#FFFFFF","CandidateLists":[]}`)
+		// Get all the parties
+		do("GET", "/api/Party/", xsrfHeader, "", 200, `[{"ID":1,"Name":"MyGreatParty","Color":"#FFFFFF","CandidateLists":[]}]`)
+		// Update a party should fail with 405
+		do("PUT", "/api/Party/1", xsrfHeader, `{"ID":1,"Name":"MyBigParty","Color":"#000000"}`, 405, `You're not authorize to execute this method on this ressource.`)
+		// Delete a party should fail with 405
+		do("DELETE", "/api/Party/1", xsrfHeader, ``, 405, `You're not authorize to execute this method on this ressource.`)
+
 		// Add deskround to capturer should fail with 405
 		do("POST", "/api/CapturerDeskRound", xsrfHeader, `{"CapturerID":1,"DeskRoundID":1}`, 405, `You're not authorize to execute this method on this ressource.`)
 		// Remove DeskRound to capturer