diff --git a/.env.template b/.env.template
new file mode 100644
index 0000000000000000000000000000000000000000..3857e7545eb6bda96276d5f9560866b4f8eb8343
--- /dev/null
+++ b/.env.template
@@ -0,0 +1,24 @@
+# Common settings
+HOSTNAME=localhost
+ADMIN_ROLE
+DEBUG_MODE
+MOCK_OAUTH2
+HTTPS_PORT
+IMAGE_FOLDER
+
+# Needed to user OAuth2 authentication :
+REDIRECT_URL
+CLIENT_ID
+CLIENT_SECRET
+AUTH_URL
+TOKEN_URL
+USERINFO_URL
+
+# Access to the database
+DATABASE_USER
+DATABASE_PASSWORD
+DATABASE_NAME
+
+SGE_API_TOKEN
+MEILI_MASTER_KEY
+MEILI_HOST
\ No newline at end of file
diff --git a/.vscode/launch.json b/.vscode/launch.json
index da3a8c41db6a7509af70ad003d3b52eefbaa7f25..785de51e7d28b3291e390b6a6b5bff5a867d362c 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -12,19 +12,19 @@
       "program": "${workspaceFolder}/main.go",
       "env": {
         "HOSTNAME": "localhost",
-        "ADMIN_ROLE" : "ADMINS",
+        "ADMIN_ROLE": "ADMINS",
         "DEBUG_MODE": "true",
         "MOCK_OAUTH2": "true",
         "HTTPS_PORT": "1443",
         "IMAGE_FOLDER": "image-lib",
 
-        "REDIRECT_URL": "http://localhost:1443/OAuth2Callback",
+        "REDIRECT_URL": "https://localhost:1443/OAuth2Callback",
         "CLIENT_ID": "foo",
         "CLIENT_SECRET": "bar",
         "AUTH_URL": "http://localhost:8090/auth",
         "TOKEN_URL": "http://localhost:8090/token",
         "USERINFO_URL": "http://localhost:8090/admininfo",
-        
+
         "DATABASE_USER": "root",
         "DATABASE_PASSWORD": "password",
         "DATABASE_NAME": "backoffice",
@@ -58,4 +58,4 @@
       "showLog": true
     }
   ]
-}
\ No newline at end of file
+}
diff --git a/README.md b/README.md
index 7b6ca2b6f5008bc280d79e5e4ad42cd0f428ac3f..e530d50ca65412d6dfa7d5fe9f15a9cd29c01841 100644
--- a/README.md
+++ b/README.md
@@ -14,13 +14,13 @@ This repository contains the backend part of this backoffice.
 
 # How to setup :
 
-This backend should be deployed with the frontend from [this repo](https://forge.grandlyon.com/web-et-numerique/llle_project/backoffice-client) 
+This backend should be deployed with the frontend from [this repo](https://forge.grandlyon.com/web-et-numerique/llle_project/backoffice-client)
 
 However this backend can be run in standalone :
 
 - Clone the repository
 
-- Set a .env file at the root and add all variables declared in the [template.env](https://forge.grandlyon.com/web-et-numerique/llle_project/backoffice-server/-/blob/dev/template.env) file
+- Set a .env file at the root and add all variables declared in the [template.env](https://forge.grandlyon.com/web-et-numerique/llle_project/backoffice-server/-/blob/dev/.env.template)
 
 - (**Optionnal**) you can create new certificates by running `cd dev_certificates && ./generate-certificates.sh`
 
@@ -30,7 +30,8 @@ Once deployed, you can access to a Swagger documentation of the API on https://$
 
 ## Launch locally
 
-To launch it locally : 
+To launch it locally :
+
 - Run `docker-compose up -d`
 
 In local you can access phpmyadmin interface to manage the database : http://localhost:8008
@@ -39,11 +40,16 @@ In local you can access phpmyadmin interface to manage the database : http://loc
 
 To launch the backend for development goal:
 
-- edit *main.go* file, uncomment the last line "log.Fatal(http.ListenAndServe(":"+strconv.Itoa(httpsPort), rootMux.Router))" and comment the line above "log.Fatal(http.ListenAndServeTLS(":"+strconv.Itoa(httpsPort), "./dev_certificates/localhost.crt", "./dev_certificates/localhost.key", rootMux.Router))"
+- edit _main.go_ file, uncomment the last line "log.Fatal(http.ListenAndServe(":"+strconv.Itoa(httpsPort), rootMux.Router))" and comment the line above "log.Fatal(http.ListenAndServeTLS(":"+strconv.Itoa(httpsPort), "./dev_certificates/localhost.crt", "./dev_certificates/localhost.key", rootMux.Router))"
 - This way you disable https so make sure your requests goes on http adresses
-- in *vscode/launch.json* set  "REDIRECT_URL" to "http://localhost:1443/OAuth2Callback",
+- in _vscode/launch.json_ set "REDIRECT_URL" to "http://localhost:1443/OAuth2Callback",
 - also comment the port and host values
 - if you comment the DATABASE_USER line, it will launches with a sqlite database instead of mysql
 - launch the app by pressing F5 on vscode, you will see the logs on the debug console.
 - this way you won't have the login every time you relaunch the backend for development
 
+## Build image for local
+
+```
+docker build . -t backoffice-server
+```
diff --git a/docker-compose.yml b/docker-compose.yml
index 1f0cb5cf3e993c793c6711ed58d6b86e784bcd7a..3242f2542137d5c242928b68174cbc9b4fbd2589 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -47,7 +47,7 @@ services:
             PMA_HOST: database
 
     backoffice-container:
-        image: backoffice        
+        image: backoffice
         depends_on:
             database:
                 condition: service_healthy
diff --git a/internal/models/customPopup.go b/internal/models/customPopup.go
new file mode 100644
index 0000000000000000000000000000000000000000..db4aa73c1d4e17a13fbc906664e4f639152f1b27
--- /dev/null
+++ b/internal/models/customPopup.go
@@ -0,0 +1,83 @@
+package models
+
+import (
+	"encoding/json"
+	"errors"
+	"log"
+	"net/http"
+
+	"gorm.io/gorm"
+)
+
+type CustomPopup struct {
+	ID           uint   `gorm:"<-:create"`
+	PopupEnabled bool   `json:"popupEnabled"`
+	Title        string `json:"title"`
+	Description  string `json:"description"`
+}
+
+// GetCustomPopup godoc
+// @Summary Give status of custom popup
+// @Description Give status of custom poup
+// @Tags customPopup
+// @Produce  json
+// @Success 200 {object} CustomPopup
+// @Failure 404 {string} string "Not found"
+// @Router /api/common/customPopup [get]
+func (dh *DataHandler) GetCustomPopup(w http.ResponseWriter, r *http.Request) {
+	var popupInfo CustomPopup
+	err := dh.sqlClient.First(&popupInfo).Error
+
+	if errors.Is(err, gorm.ErrRecordNotFound) {
+		http.Error(w, "custom popup status not found", http.StatusNotFound)
+		return
+	}
+
+	w.Header().Set("Content-Type", "application/json")
+	json.NewEncoder(w).Encode(popupInfo)
+	log.Printf("| get customPopup | %v", r.RemoteAddr)
+}
+
+// SaveCustomPopup godoc
+// @Summary Update custom popup content
+// @Description Update custom popup content
+// @Tags customPopup
+// @Accept json
+// @Produce json
+// @Success 200 {object} CustomPopup "Updated successfully"
+// @Failure 400 {string} string "Bad Request"
+// @Failure 500 {string} string "Internal server error"
+// @Param customPopup body CustomPopup true "CustomPopup to create/update with new content"
+// @Router /api/admin/customPopup [put]
+func (dh *DataHandler) SaveCustomPopup(w http.ResponseWriter, r *http.Request) {
+	if r.Body == http.NoBody {
+		http.Error(w, "request body is empty", http.StatusBadRequest)
+		return
+	}
+
+	decoder := json.NewDecoder(r.Body)
+	var customPopup CustomPopup
+	err := decoder.Decode(&customPopup)
+	if err != nil {
+		w.WriteHeader(http.StatusInternalServerError)
+		return
+	}
+
+	var updatedCustomPopup CustomPopup
+
+	err = dh.sqlClient.First(&updatedCustomPopup).Error
+	if err != nil {
+		w.WriteHeader(http.StatusInternalServerError)
+		return
+	}
+
+	updatedCustomPopup.PopupEnabled = customPopup.PopupEnabled
+	updatedCustomPopup.Title = customPopup.Title
+	updatedCustomPopup.Description = customPopup.Description
+
+	dh.sqlClient.Save(&updatedCustomPopup)
+
+	w.Header().Set("Content-Type", "application/json")
+	json.NewEncoder(w).Encode(customPopup)
+	log.Printf("| updated customPopup | %v", r.RemoteAddr)
+}
diff --git a/internal/models/models.go b/internal/models/models.go
index 607f8f8ed828a2124876716dc17645f771a86292..35d828b99568bb548f257abd1078e814b3ad2101 100644
--- a/internal/models/models.go
+++ b/internal/models/models.go
@@ -46,9 +46,11 @@ func NewDataHandler() *DataHandler {
 	sqlClient.AutoMigrate(&MonthlyNews{})
 	sqlClient.AutoMigrate(&Poll{})
 	sqlClient.AutoMigrate(&PartnersInfo{})
+	sqlClient.AutoMigrate(&CustomPopup{})
 	sqlClient.AutoMigrate(&Price{})
 	sqlClient.AutoMigrate(&Consent{})
 
+	//TODO fix recreate on server init
 	// Create default partner status
 	sqlClient.Create(&PartnersInfo{
 		GRDFFailure:           false,
@@ -57,6 +59,13 @@ func NewDataHandler() *DataHandler {
 		NotificationActivated: false,
 	})
 
+	// Create default custom popup
+	sqlClient.Create(&CustomPopup{
+		PopupEnabled: false,
+		Title:        "",
+		Description:  "",
+	})
+
 	// Meilisearch setup
 	meiliClient := meilisearch.NewClient(meilisearch.ClientConfig{
 		Host:   common.StringValueFromEnv("MEILI_HOST", ""),
diff --git a/internal/rootmux/rootmux.go b/internal/rootmux/rootmux.go
index a3d236f786a52a1fc53aa85907a6c89f3cd20239..a7907c07027cdef927f0cddcc722de7d185136ea 100644
--- a/internal/rootmux/rootmux.go
+++ b/internal/rootmux/rootmux.go
@@ -43,6 +43,7 @@ func CreateRootMux() RootMux {
 	r.HandleFunc("/api/common/monthlyReport", dh.GetMonthlyReport).Methods(http.MethodGet)
 	r.HandleFunc("/api/common/monthlyReport/{year}/{month}", dh.GetMonthlyReport).Methods(http.MethodGet)
 	r.HandleFunc("/api/common/partnersInfo", dh.GetPartnersInfo).Methods(http.MethodGet)
+	r.HandleFunc("/api/common/customPopup", dh.GetCustomPopup).Methods(http.MethodGet)
 	r.HandleFunc("/api/common/prices", dh.GetAllPrices).Methods(http.MethodGet)
 	r.HandleFunc("/api/common/prices/{fluidtype}", dh.GetPricesByFluid).Methods(http.MethodGet)
 
@@ -69,6 +70,7 @@ func CreateRootMux() RootMux {
 	apiAdmin.HandleFunc("/poll/{year}/{month}", dh.DeletePoll).Methods(http.MethodDelete)
 
 	apiAdmin.HandleFunc("/partnersInfo", dh.SavePartnersInfo).Methods(http.MethodPut)
+	apiAdmin.HandleFunc("/customPopup", dh.SaveCustomPopup).Methods(http.MethodPut)
 
 	apiAdmin.HandleFunc("/imageNames", file.GetEcogestureImages).Methods(http.MethodGet)
 
diff --git a/internal/rootmux/rootmux_test.go b/internal/rootmux/rootmux_test.go
index f22c2cf9f939a77ecfd06ebeacec24d5a26262fb..a215fc17f898c5046f06781bebb70afbae108852 100644
--- a/internal/rootmux/rootmux_test.go
+++ b/internal/rootmux/rootmux_test.go
@@ -29,6 +29,8 @@ var (
 	newPollStr      string
 	partnersInfo    = models.PartnersInfo{ID: 1, GRDFFailure: false, EnedisFailure: false, EGLFailure: true, NotificationActivated: true}
 	partnersInfoStr string
+	customPopupInfo = models.CustomPopup{ID: 1, PopupEnabled: false, Title: "Alerte personnalisée", Description: "Ecolyo 4ever"}
+	customPopupStr  string
 	consent         = models.Consent{Firstname: "Foo", Lastname: "Bar", PointID: 123456}
 	consentStr      string
 	noH             map[string]string
@@ -65,6 +67,8 @@ func TestMain(m *testing.M) {
 	monthlyInfoStr = string(monthlyInfoBytes)
 	partnersInfoBytes, _ := json.Marshal(partnersInfo)
 	partnersInfoStr = string(partnersInfoBytes)
+	customPopupBytes, _ := json.Marshal(customPopupInfo)
+	customPopupStr = string(customPopupBytes)
 	newPollBytes, _ := json.Marshal(newPoll)
 	newPollStr = string(newPollBytes)
 	consentBytes, _ := json.Marshal(consent)
@@ -90,9 +94,11 @@ func TestAll(t *testing.T) {
 	sgeTests(t)
 }
 
-/**
+/*
+*
 SECURITY TESTS (this tests are to check that the security protections works)
-**/
+*
+*/
 func oauth2Tests(t *testing.T) {
 	// Create the tester
 	ts, do, _ := createTester(t)
@@ -101,9 +107,11 @@ func oauth2Tests(t *testing.T) {
 	do("GET", "/OAuth2Login", noH, "", http.StatusInternalServerError, "invalid oauth state")
 }
 
-/**
+/*
+*
 UNLOGGED USER TESTS (this tests are to check that the security protections works)
-**/
+*
+*/
 func unloggedTests(t *testing.T) {
 	// Create the tester
 	ts, do, _ := createTester(t)
@@ -119,9 +127,11 @@ func unloggedTests(t *testing.T) {
 	do("GET", "/api/common/partnersInfo", noH, "", http.StatusOK, `{"ID":1,"grdf_failure":false,"enedis_failure":false,"egl_failure":false,"notification_activated":false}`)
 }
 
-/**
+/*
+*
 ADMIN TESTS (this tests are to check that an administrator can edit a newsletter's content)
-**/
+*
+*/
 func adminTests(t *testing.T) {
 	// Create the tester
 	ts, do, _ := createTester(t)
@@ -179,13 +189,13 @@ func adminTests(t *testing.T) {
 
 		// Try to update the partnersInfo (must pass)
 		do("PUT", "/api/admin/partnersInfo", xsrfHeader, partnersInfoStr, http.StatusOK, partnersInfoStr)
-		// Try to get the monthlyInfo created (must pass)
+		// Try to get the partnersInfo created (must pass)
 		do("GET", "/api/common/partnersInfo", xsrfHeader, "", http.StatusOK, partnersInfoStr)
 
-		// Try to update the partnersInfo (must pass)
-		do("PUT", "/api/admin/partnersInfo", xsrfHeader, partnersInfoStr, http.StatusOK, partnersInfoStr)
-		// Try to get the monthlyInfo created (must pass)
-		do("GET", "/api/common/partnersInfo", xsrfHeader, "", http.StatusOK, partnersInfoStr)
+		// Try to update the customPopup (must pass)
+		do("PUT", "/api/admin/customPopup", xsrfHeader, customPopupStr, http.StatusOK, customPopupStr)
+		// Try to get the partnersInfo created (must pass)
+		do("GET", "/api/common/customPopup", xsrfHeader, "", http.StatusOK, customPopupStr)
 
 		// Try to delete the monthlyNews created (must pass)
 		do("DELETE", "/api/admin/monthlyNews/2021/1", xsrfHeader, "", http.StatusOK, "successful delete")
diff --git a/template.env b/template.env
deleted file mode 100644
index 46c59570a6efe18afdc9997e871923124479cfe0..0000000000000000000000000000000000000000
--- a/template.env
+++ /dev/null
@@ -1,20 +0,0 @@
-# Common settings
-HOSTNAME=
-ADMIN_ROLE=
-DEBUG_MODE=
-MOCK_OAUTH2=
-HTTPS_PORT=
-IMAGE_FOLDER=
-
-# Needed to user OAuth2 authentication :
-REDIRECT_URL=
-CLIENT_ID=
-CLIENT_SECRET=
-AUTH_URL=
-TOKEN_URL=
-USERINFO_URL=
-
-# Access to the database
-DATABASE_USER=
-DATABASE_PASSWORD=
-DATABASE_NAME=
\ No newline at end of file