diff --git a/.gitignore b/.gitignore
index 8c09811d196e402bd273d828868eacd5ae8e855d..ccce815bf6e02ba5ab615afdcdee9c2fa44b42e5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
 .env
-backoffice.db
\ No newline at end of file
+backoffice.db
+meili_data/
\ No newline at end of file
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 8add34982dc6870e6fe686dd0f8de91bb29a3468..da3a8c41db6a7509af70ad003d3b52eefbaa7f25 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -25,11 +25,14 @@
         "TOKEN_URL": "http://localhost:8090/token",
         "USERINFO_URL": "http://localhost:8090/admininfo",
         
-        "DATABASE_USER": "",
+        "DATABASE_USER": "root",
         "DATABASE_PASSWORD": "password",
         "DATABASE_NAME": "backoffice",
         "DATABASE_HOST": "127.0.0.1",
         "LOGOUT_URL": "/",
+        "SGE_API_TOKEN": "sgeapitoken",
+        "MEILI_HOST": "http://localhost:7700",
+        "MEILI_MASTER_KEY": "masterkey"
       },
       "showLog": true
     },
@@ -55,4 +58,4 @@
       "showLog": true
     }
   ]
-}
+}
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
index 8aa22632efe030ac4a7aec18404210a10b1c2b38..87bf2455f69ae98ac71702ff7ca3d35a0b2a70ca 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -4,13 +4,16 @@
 # STEP 1 build executable binary #
 ##################################
 
-FROM golang:alpine as builder
+FROM golang as builder
 
 # Install git + SSL ca certificates.
 # Git is required for fetching the dependencies.
 # Ca-certificates is required to call HTTPS endpoints.
-RUN apk update && apk add --no-cache git ca-certificates tzdata libcap mailcap && update-ca-certificates
-RUN apk add build-base
+RUN apt-get update && apt-get install -y git ca-certificates tzdata libcap2-bin mailcap curl && update-ca-certificates
+
+# Get meilisearch binary
+RUN curl -L https://install.meilisearch.com | sh
+RUN mv ./meilisearch /usr/bin/
 
 # Create appuser
 ENV USER=appuser
@@ -29,17 +32,9 @@ WORKDIR /app
 
 ADD . .
 
-RUN chown -Rf "${UID}" ./*
-
-# Get dependencies and run tests
-RUN go version
-RUN go get -d -v
-RUN CGO_ENABLED=1 go test ./...
+RUN ./start-meilisearch-test-and-build.sh
 
-# Build the binary
-RUN CGO_ENABLED=1 go build \
-    -ldflags='-w -s -extldflags "-static"' -a \
-    -o /app/backoffice-server .
+RUN chown -Rf "${UID}" ./*
 
 # Allow running on ports < 1000
 RUN setcap cap_net_bind_service=+ep /app/backoffice-server
@@ -47,7 +42,7 @@ RUN setcap cap_net_bind_service=+ep /app/backoffice-server
 ##############################
 # STEP 2 build a small image #
 ##############################
-FROM alpine:3.14.0
+FROM scratch
 
 WORKDIR /app
 
diff --git a/docker-compose.yml b/docker-compose.yml
index ca2476473ed949939736274e10c63ae3f1224c1b..1f0cb5cf3e993c793c6711ed58d6b86e784bcd7a 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -3,23 +3,44 @@ version: '3.1'
 services: 
     database:
         image: mysql:5
+        healthcheck:
+            test: mysqladmin ping -h 127.0.0.1 -u root --password=$$MYSQL_ROOT_PASSWORD
+            interval: 5s
+            timeout: 10s
+            retries: 60
+        volumes:
+            - ./dbinit:/dbinit
+        networks:
+            - ecolyo-agent-network
         ports:
             - 3306:3306
         environment:
             MYSQL_ROOT_PASSWORD: ${DATABASE_PASSWORD}
             MYSQL_DATABASE: ${DATABASE_NAME}
+
+    meilisearch:
+        image: getmeili/meilisearch:v0.27.2
         healthcheck:
-            test: mysqladmin ping -h 127.0.0.1 -u root --password=$$MYSQL_ROOT_PASSWORD
-            interval: 5s
+            test: ["CMD", "curl", "-f", "http://0.0.0.0:7700"]
+            interval: 10s
             timeout: 10s
-            retries: 60
+            retries: 3
         volumes:
-            - ./dbinit:/dbinit
+            - ./meili_data:/meili_data
+        networks:
+            - ecolyo-agent-network
+        ports:
+            - 7700:7700
+        environment:
+            - MEILI_MASTER_KEY=${MEILI_MASTER_KEY}
+
 
     phpmyadmin:
         image: phpmyadmin/phpmyadmin:latest
         depends_on:
             - database
+        networks:
+            - ecolyo-agent-network
         ports:
             - 8008:80
         environment:
@@ -30,6 +51,8 @@ services:
         depends_on:
             database:
                 condition: service_healthy
+            meilisearch:
+                condition: service_healthy
         build: .
         restart: unless-stopped
         volumes:
@@ -38,6 +61,8 @@ services:
             - ./letsencrypt_cache:/app/letsencrypt_cache
             - ./data:/app/data
             - ./../${IMAGE_FOLDER}:/app/${IMAGE_FOLDER}
+        networks:
+            - ecolyo-agent-network
         ports:
             - ${HTTPS_PORT}:${HTTPS_PORT}
             - 8090:8090
@@ -60,4 +85,7 @@ services:
             - DATABASE_HOST=database
 
 volumes:
-    db_data:
\ No newline at end of file
+    db_data:
+
+networks:
+    ecolyo-agent-network:
\ No newline at end of file
diff --git a/go.mod b/go.mod
index 6f731e4c0e51da8154808194ce57f0bc3ed82b47..0f8ad00874dc5106a17c233084d163e67fe537e7 100644
--- a/go.mod
+++ b/go.mod
@@ -4,6 +4,7 @@ go 1.15
 
 require (
 	github.com/gorilla/mux v1.8.0
+	github.com/meilisearch/meilisearch-go v0.20.1
 	github.com/swaggo/http-swagger v1.3.0
 	github.com/swaggo/swag v1.8.3
 	golang.org/x/oauth2 v0.0.0-20220630143837-2104d58473e0
diff --git a/go.sum b/go.sum
index 97b6e2d25eda8a8ca66e0b56364c078f59857f9f..22f6658a70d06f336ff686829051601b8ee3f005 100644
--- a/go.sum
+++ b/go.sum
@@ -61,8 +61,9 @@ github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6Xge
 github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
 github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
 github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
-github.com/agiledragon/gomonkey/v2 v2.3.1 h1:k+UnUY0EMNYUFUAQVETGY9uUTxjMdnUkP0ARyJS1zzs=
 github.com/agiledragon/gomonkey/v2 v2.3.1/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY=
+github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
+github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
 github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
@@ -113,6 +114,8 @@ github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyr
 github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
 github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
 github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
+github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
 github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -138,7 +141,6 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU
 github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
 github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
 github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
-github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
 github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
 github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
 github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
@@ -154,7 +156,6 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
 github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k=
 github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
@@ -212,6 +213,9 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
+github.com/klauspost/compress v1.15.6 h1:6D9PcO8QWu0JyaQ2zUMmu16T1T+zjjEpP91guRsvDfY=
+github.com/klauspost/compress v1.15.6/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
@@ -219,20 +223,22 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
 github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
 github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
-github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
 github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
+github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
+github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
 github.com/mattn/go-sqlite3 v1.14.12 h1:TJ1bhYJPV44phC+IMu1u2K/i5RriLTPe+yc68XDJ1Z0=
 github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
+github.com/meilisearch/meilisearch-go v0.20.1 h1:Lddkf3C/f/Uv0+eD2f9qtpykmK5E7IZStJpIV0UVxu4=
+github.com/meilisearch/meilisearch-go v0.20.1/go.mod h1:jUGQlQNFYcni/mSG/d71utwqPuKG0bRT+63Xenw2B+0=
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
-github.com/otiai10/copy v1.7.0 h1:hVoPiN+t+7d2nzzwMiDHPSOogsWAStewq3TwU05+clE=
 github.com/otiai10/copy v1.7.0/go.mod h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U=
 github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
-github.com/otiai10/curr v1.0.0 h1:TJIWdbX0B+kpNagQrjgq8bCMrbhiuX73M2XwgtDMoOI=
 github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
 github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
-github.com/otiai10/mint v1.3.3 h1:7JgpsBaN0uMkyju4tbYHu0mnM55hNKVYLsXmwr15NQI=
 github.com/otiai10/mint v1.3.3/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
@@ -244,25 +250,28 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1
 github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
 github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
 github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/swaggo/files v0.0.0-20210815190702-a29dd2bc99b2 h1:+iNTcqQJy0OZ5jk6a5NLib47eqXK8uYcPX+O4+cBpEM=
-github.com/swaggo/files v0.0.0-20210815190702-a29dd2bc99b2/go.mod h1:lKJPbtWzJ9JhsTN1k1gZgleJWY/cqq0psdoMmaThG3w=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
 github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe h1:K8pHPVoTgxFJt1lXuIzzOX7zZhZFldJQK/CgKx9BFIc=
 github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe/go.mod h1:lKJPbtWzJ9JhsTN1k1gZgleJWY/cqq0psdoMmaThG3w=
-github.com/swaggo/http-swagger v1.2.7 h1:q0jLKqJRtmQzwmI2eHX8V6Hgr0TGg3IqBMDN78G6eQI=
-github.com/swaggo/http-swagger v1.2.7/go.mod h1:FrQwV7rx+A5t11PIX8d+tFJa2GKx11RdAXQptllPQHg=
 github.com/swaggo/http-swagger v1.3.0 h1:1+6M4qRorIbdyTWTsGrwnb0r9jGK5dcWN82O6oY/yHQ=
 github.com/swaggo/http-swagger v1.3.0/go.mod h1:9glekdg40lwclrrKNRGgj/IMDxpNPZ3kzab4oPcF8EM=
-github.com/swaggo/swag v1.8.1 h1:JuARzFX1Z1njbCGz+ZytBR15TFJwF2Q7fu8puJHhQYI=
 github.com/swaggo/swag v1.8.1/go.mod h1:ugemnJsPZm/kRwFUnzBlbHRd0JY9zE1M4F+uy2pAaPQ=
 github.com/swaggo/swag v1.8.3 h1:3pZSSCQ//gAH88lfmxM3Cd1+JCsxV8Md6f36b9hrZ5s=
 github.com/swaggo/swag v1.8.3/go.mod h1:jMLeXOOmYyjk8PvHTsXBdrubsNd9gUJTTCzL5iBnseg=
 github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
+github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
+github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
+github.com/valyala/fasthttp v1.37.1-0.20220607072126-8a320890c08d h1:xS9QTPgKl9ewGsAOPc+xW7DeStJDqYPfisDmeSCcbco=
+github.com/valyala/fasthttp v1.37.1-0.20220607072126-8a320890c08d/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I=
+github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
 github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -284,6 +293,7 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -359,11 +369,11 @@ golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1
 golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
-golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 h1:HVyaeDAYux4pnY+D/SiwmLOR36ewZ4iGQIIrtnuCjFA=
 golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
 golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e h1:TsQ7F31D3bUCLeqPT0u+yjp1guoArKaNKmCr22PYgTQ=
@@ -386,7 +396,6 @@ golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ
 golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
 golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
 golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
-golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 h1:OSnWWcOd/CtWQC2cYSBgbTSJv3ciqd8r54ySIW2y3RE=
 golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
 golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
 golang.org/x/oauth2 v0.0.0-20220630143837-2104d58473e0 h1:VnGaRqoLmqZH/3TMLJwYCEWkR4j1nuIU1U9TvbqsDUw=
@@ -454,7 +463,6 @@ golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
 golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -538,7 +546,6 @@ golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
@@ -588,7 +595,6 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
 google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
 google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
-google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc=
 google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
 google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
 google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
@@ -711,7 +717,6 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
 google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
-google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
 google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
@@ -728,20 +733,14 @@ gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
 gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
 gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gorm.io/driver/mysql v1.3.3 h1:jXG9ANrwBc4+bMvBcSl8zCfPBaVoPyBEBshA8dA93X8=
-gorm.io/driver/mysql v1.3.3/go.mod h1:ChK6AHbHgDCFZyJp0F+BmVGb06PSIoh9uVYKAlRbb2U=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gorm.io/driver/mysql v1.3.4 h1:/KoBMgsUHC3bExsekDcmNYaBnfH2WNeFuXqqrqMc98Q=
 gorm.io/driver/mysql v1.3.4/go.mod h1:s4Tq0KmD0yhPGHbZEwg1VPlH0vT/GBHJZorPzhcxBUE=
-gorm.io/driver/sqlite v1.3.2 h1:nWTy4cE52K6nnMhv23wLmur9Y3qWbZvOBz+V4PrGAxg=
-gorm.io/driver/sqlite v1.3.2/go.mod h1:B+8GyC9K7VgzJAcrcXMRPdnMcck+8FgJynEehEPM16U=
 gorm.io/driver/sqlite v1.3.6 h1:Fi8xNYCUplOqWiPa3/GuCeowRNBRGTf62DEmhMDHeQQ=
 gorm.io/driver/sqlite v1.3.6/go.mod h1:Sg1/pvnKtbQ7jLXxfZa+jSHvoX8hoZA8cn4xllOMTgE=
-gorm.io/gorm v1.23.1/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
 gorm.io/gorm v1.23.4/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
-gorm.io/gorm v1.23.5 h1:TnlF26wScKSvknUC/Rn8t0NLLM22fypYBlvj1+aH6dM=
-gorm.io/gorm v1.23.5/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
 gorm.io/gorm v1.23.8 h1:h8sGJ+biDgBA1AD1Ha9gFCx7h8npU7AsLdlkX0n2TpE=
 gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
diff --git a/internal/auth/auth.go b/internal/auth/auth.go
index fd469bd976ef40a065a9513654c1fe904fecbf08..23cfb6862d6c976a30c30aa1ffcad1718190a9ef 100644
--- a/internal/auth/auth.go
+++ b/internal/auth/auth.go
@@ -25,8 +25,9 @@ const (
 
 var (
 	// AdminRole represents the role reserved for admins
-	AdminRole = common.StringValueFromEnv("ADMIN_ROLE", "ADMINS")
-	hostname  = common.StringValueFromEnv("HOSTNAME", "ecolyobackoffice.127.0.0.1.nip.io")
+	AdminRole   = common.StringValueFromEnv("ADMIN_ROLE", "ADMINS")
+	hostname    = common.StringValueFromEnv("HOSTNAME", "ecolyobackoffice.127.0.0.1.nip.io")
+	SGEApiToken = common.StringValueFromEnv("SGE_API_TOKEN", "sgetoken")
 )
 
 // User represents a logged in user
@@ -116,6 +117,18 @@ func ValidateAuthMiddleware(next http.Handler, allowedRoles []string, checkXSRF
 	return http.HandlerFunc(roleChecker)
 }
 
+func SGEAuthMiddleware(next http.Handler) http.Handler {
+	tokenChecker := func(w http.ResponseWriter, r *http.Request) {
+		// Check API Token
+		if r.Header.Get("Authorization") != "Bearer "+SGEApiToken {
+			http.Error(w, "invalid token", http.StatusUnauthorized)
+			return
+		}
+		next.ServeHTTP(w, r)
+	}
+	return http.HandlerFunc(tokenChecker)
+}
+
 // HandleLogout remove the user from the cookie store
 func (m Manager) HandleLogout(w http.ResponseWriter, r *http.Request) {
 	// Delete the auth cookie
diff --git a/internal/common/common.go b/internal/common/common.go
index 3ee2d9635c1200ec11750e2fcbc8a2820c83e302..9497fe81a905602d405657dff4701c224dc4dad1 100644
--- a/internal/common/common.go
+++ b/internal/common/common.go
@@ -172,6 +172,51 @@ func YearMonthFromRequest(r *http.Request) (year int, month int, err error) {
 	return year, month, nil
 }
 
+func IdFromRequest(r *http.Request) (id int, err error) {
+	vars := mux.Vars(r)
+	idStr := vars["id"]
+
+	if idStr == "" {
+		return 0, errors.New("missing id")
+	}
+
+	id, err = strconv.Atoi(idStr)
+	if err != nil {
+		return 0, errors.New("id is not an integer")
+	}
+
+	return id, nil
+}
+
+func PageLimitFromRequest(r *http.Request) (page int, limit int, err error) {
+	pageStr := r.URL.Query().Get("page")
+	limitStr := r.URL.Query().Get("limit")
+
+	if pageStr == "" || limitStr == "" {
+		return 0, 0, errors.New("missing query element")
+	}
+
+	page, err = strconv.Atoi(pageStr)
+	if err != nil {
+		return 0, 0, errors.New("page is not an integer")
+	}
+	limit, err = strconv.Atoi(limitStr)
+	if err != nil {
+		return 0, 0, errors.New("limite is not an integer")
+	}
+
+	if page < 0 {
+		page = 0
+	}
+	switch {
+	case limit > 100:
+		limit = 100
+	case limit < 10:
+		limit = 10
+	}
+	return page, limit, nil
+}
+
 //Get fluidType from Request
 func FluidTypeFromRequest(r *http.Request) (fluidtype int, err error) {
 	vars := mux.Vars(r)
@@ -188,6 +233,3 @@ func FluidTypeFromRequest(r *http.Request) (fluidtype int, err error) {
 
 	return fluidtype, nil
 }
-
-
-
diff --git a/internal/models/consent.go b/internal/models/consent.go
new file mode 100644
index 0000000000000000000000000000000000000000..e7ed2da030cfc55a18b42d4851d6019759c2ac21
--- /dev/null
+++ b/internal/models/consent.go
@@ -0,0 +1,212 @@
+package models
+
+import (
+	"encoding/json"
+	"fmt"
+	"log"
+	"net/http"
+	"time"
+
+	"forge.grandlyon.com/web-et-numerique/llle_project/backoffice-server/internal/common"
+	"github.com/meilisearch/meilisearch-go"
+	"gorm.io/gorm"
+)
+
+type Consent struct {
+	gorm.Model
+	Firstname  string    `json:"firstname"`
+	Lastname   string    `json:"lastname"`
+	Address    string    `json:"address"`
+	PointID    int       `json:"pointID"`
+	PostalCode string    `json:"postalCode"`
+	InseeCode  string    `json:"inseeCode"`
+	EndDate    time.Time `json:"endDate"`
+	ServiceID  int       `json:"serviceID,omitempty"`
+}
+
+func (dh *DataHandler) GetConsentById(w http.ResponseWriter, r *http.Request) {
+	id, err := common.IdFromRequest(r)
+	if err != nil {
+		http.Error(w, err.Error(), http.StatusBadRequest)
+		return
+	}
+
+	var consent Consent
+	err = dh.sqlClient.First(&consent, id).Error
+	if err != nil {
+		http.Error(w, "couldn't find consent", http.StatusInternalServerError)
+		return
+	}
+
+	w.Header().Set("Content-Type", "application/json")
+	json.NewEncoder(w).Encode(consent)
+
+	log.Printf("| get consent | name : %v | %v", consent.Lastname, r.RemoteAddr)
+}
+
+func (dh *DataHandler) PostConsent(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 consent Consent
+	err := decoder.Decode(&consent)
+	if err != nil {
+		http.Error(w, "couldn't parse body", http.StatusInternalServerError)
+		log.Println(err.Error())
+		return
+	}
+	consent.EndDate = time.Now().AddDate(1, 0, 0)
+
+	// Create a consent in SQL
+	err = dh.sqlClient.Create(&consent).Error
+	if err != nil {
+		http.Error(w, "couldn't create consent", http.StatusInternalServerError)
+		log.Println(err.Error())
+		return
+	}
+	// Adding consent in Meilisearch
+	_, err = dh.meiliClient.Index("consents").AddDocuments(consent)
+	if err != nil {
+		log.Println(err)
+		http.Error(w, "error when saving new consent", http.StatusInternalServerError)
+		return
+	}
+
+	w.Header().Set("Content-Type", "application/json")
+	w.WriteHeader(http.StatusCreated)
+	json.NewEncoder(w).Encode(consent)
+
+	log.Printf("| new consent | name : %v | %v", consent.Lastname, r.RemoteAddr)
+}
+
+func (dh *DataHandler) UpdateConsent(w http.ResponseWriter, r *http.Request) {
+	if r.Body == http.NoBody {
+		http.Error(w, "request body is empty", http.StatusBadRequest)
+		return
+	}
+	id, err := common.IdFromRequest(r)
+	if err != nil {
+		http.Error(w, err.Error(), http.StatusBadRequest)
+		return
+	}
+
+	// Find consent
+	var consent Consent
+	err = dh.sqlClient.First(&consent, id).Error
+	if err != nil {
+		http.Error(w, "couldn't find consent", http.StatusInternalServerError)
+		log.Println(err.Error())
+		return
+	}
+	// Get service ID
+	decoder := json.NewDecoder(r.Body)
+	var body struct {
+		ServiceID int `json:"serviceID"`
+	}
+	err = decoder.Decode(&body)
+	if err != nil {
+		http.Error(w, "couldn't parse body", http.StatusInternalServerError)
+		return
+	}
+	if body.ServiceID <= 0 {
+		http.Error(w, "invalid service id", http.StatusBadRequest)
+		return
+	}
+
+	// Update and save consent
+	consent.ServiceID = body.ServiceID
+	err = dh.sqlClient.Save(&consent).Error
+	if err != nil {
+		w.WriteHeader(http.StatusInternalServerError)
+		log.Println(err.Error())
+		return
+	}
+
+	w.Header().Set("Content-Type", "application/json")
+	json.NewEncoder(w).Encode(consent)
+
+	log.Printf("| updated consent | name : %v | serviceID : %v | %v", consent.Lastname, consent.ServiceID, r.RemoteAddr)
+}
+
+func (dh *DataHandler) DeleteConsentById(w http.ResponseWriter, r *http.Request) {
+	id, err := common.IdFromRequest(r)
+	if err != nil {
+		http.Error(w, err.Error(), http.StatusBadRequest)
+		return
+	}
+
+	var consent = Consent{}
+	err = dh.sqlClient.First(&consent, id).Error
+	if err != nil {
+		http.Error(w, "couldn't find consent", http.StatusInternalServerError)
+		log.Println(err.Error())
+		return
+	}
+
+	// Update and save consent
+	consent.EndDate = time.Now()
+	err = dh.sqlClient.Save(&consent).Error
+	if err != nil {
+		w.WriteHeader(http.StatusInternalServerError)
+		log.Println(err.Error())
+		return
+	}
+
+	dh.sqlClient.Delete(&consent)
+
+	log.Printf("| deleted consent | id : %d | %v", id, r.RemoteAddr)
+}
+
+func (dh *DataHandler) SearchConsent(w http.ResponseWriter, r *http.Request) {
+	search := r.URL.Query().Get("search")
+	if search != "" {
+		resp, err := dh.meiliClient.Index("consents").Search(search, &meilisearch.SearchRequest{
+			Limit: 50,
+		})
+		if err != nil {
+			http.Error(w, "error when searching consents", http.StatusInternalServerError)
+			log.Println(err.Error())
+			return
+		}
+
+		hits, err := json.Marshal(resp.Hits)
+		if err != nil {
+			fmt.Println("error:", err)
+		}
+		var consents []Consent
+		err = json.Unmarshal(hits, &consents)
+
+		w.Header().Set("Content-Type", "application/json")
+		json.NewEncoder(w).Encode(consents)
+
+		log.Printf("| searched consents | search : %v | %v", search, r.RemoteAddr)
+	} else {
+		page, limit, err := common.PageLimitFromRequest(r)
+		if err != nil {
+			http.Error(w, err.Error(), http.StatusBadRequest)
+			return
+		}
+
+		var totalRows int64
+		dh.sqlClient.Model(Consent{}).Count(&totalRows)
+		offset := page * limit
+
+		var consents []Consent
+		dh.sqlClient.Offset(offset).Limit(limit).Find(&consents)
+
+		var pagination struct {
+			TotalRows int64     `json:"totalRows"`
+			Rows      []Consent `json:"rows"`
+		}
+		pagination.TotalRows = totalRows
+		pagination.Rows = consents
+
+		w.Header().Set("Content-Type", "application/json")
+		json.NewEncoder(w).Encode(pagination)
+
+		log.Printf("| get all consents | limit : %d | page : %d | %v", limit, page, r.RemoteAddr)
+	}
+}
diff --git a/internal/models/mailSubject.go b/internal/models/mailSubject.go
index ba37ac11aff523e7c33368f71795eaa0d34670a7..556568b12ed959d4ad18a6faec7cbe21f40bb3de 100644
--- a/internal/models/mailSubject.go
+++ b/internal/models/mailSubject.go
@@ -34,7 +34,7 @@ func (dh *DataHandler) GetSingleMailSubject(w http.ResponseWriter, r *http.Reque
 	w.Header().Set("Content-Type", "application/json")
 
 	var mailSubject MailSubject
-	err = dh.db.Where("year = ? AND month = ?", year, month).First(&mailSubject).Error
+	err = dh.sqlClient.Where("year = ? AND month = ?", year, month).First(&mailSubject).Error
 	if err != nil {
 		// If not found, answer "not found"
 		w.WriteHeader(http.StatusNotFound)
@@ -70,11 +70,11 @@ func (dh *DataHandler) SaveMailSubject(w http.ResponseWriter, r *http.Request) {
 	}
 
 	// Check if this mailSubject exists
-	err = dh.db.Where("year = ? AND month = ?", mailSubject.Year, mailSubject.Month).First(&MailSubject{}).Error
+	err = dh.sqlClient.Where("year = ? AND month = ?", mailSubject.Year, mailSubject.Month).First(&MailSubject{}).Error
 
 	if err != nil {
 		// Create a mailSubject
-		err = dh.db.Create(&MailSubject{
+		err = dh.sqlClient.Create(&MailSubject{
 			Year:    mailSubject.Year,
 			Month:   mailSubject.Month,
 			Subject: mailSubject.Subject,
@@ -91,7 +91,7 @@ func (dh *DataHandler) SaveMailSubject(w http.ResponseWriter, r *http.Request) {
 
 	} else {
 		// Update object
-		err = dh.db.Model(&MailSubject{}).Where("year = ? AND month = ?", mailSubject.Year, mailSubject.Month).Update("subject", mailSubject.Subject).Error
+		err = dh.sqlClient.Model(&MailSubject{}).Where("year = ? AND month = ?", mailSubject.Year, mailSubject.Month).Update("subject", mailSubject.Subject).Error
 		if err != nil {
 			w.WriteHeader(http.StatusInternalServerError)
 			return
@@ -119,7 +119,7 @@ func (dh *DataHandler) DeleteMailSubject(w http.ResponseWriter, r *http.Request)
 		return
 	}
 
-	err = dh.db.Where("year = ? AND month = ?", year, month).Delete(&MailSubject{}).Error
+	err = dh.sqlClient.Where("year = ? AND month = ?", year, month).Delete(&MailSubject{}).Error
 	if err != nil {
 		http.Error(w, err.Error(), http.StatusNotFound)
 		return
diff --git a/internal/models/models.go b/internal/models/models.go
index 50f40e5dab13dae7dca6c52d5a256aeee8203259..607f8f8ed828a2124876716dc17645f771a86292 100644
--- a/internal/models/models.go
+++ b/internal/models/models.go
@@ -4,13 +4,15 @@ import (
 	"fmt"
 
 	"forge.grandlyon.com/web-et-numerique/llle_project/backoffice-server/internal/common"
+	"github.com/meilisearch/meilisearch-go"
 	"gorm.io/driver/mysql"
 	"gorm.io/driver/sqlite"
 	"gorm.io/gorm"
 )
 
 type DataHandler struct {
-	db *gorm.DB
+	sqlClient   *gorm.DB
+	meiliClient *meilisearch.Client
 }
 
 var (
@@ -22,35 +24,75 @@ var (
 
 // NewDataHandler init a DataHandler and returns a pointer to it
 func NewDataHandler() *DataHandler {
-	var db *gorm.DB
+	// SQL setup
+	var sqlClient *gorm.DB
 	var err error
 	if dbUser == "" || dbPassword == "" || dbName == "" {
-		db, err = gorm.Open(sqlite.Open("backoffice.db"), &gorm.Config{})
+		sqlClient, err = gorm.Open(sqlite.Open("backoffice.db"), &gorm.Config{})
 		if err != nil {
 			panic("failed to connect database")
 		}
 	} else {
 		dsn := fmt.Sprintf("%v:%v@tcp(%v:3306)/%v?charset=utf8mb4&parseTime=True&loc=Local", dbUser, dbPassword, dbHost, dbName)
-		db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
+		sqlClient, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
 		if err != nil {
 			panic("failed to connect database")
 		}
 	}
 
 	// Migrate the schema
-	db.AutoMigrate(&MailSubject{})
-	db.AutoMigrate(&MonthlyInfo{})
-	db.AutoMigrate(&MonthlyNews{})
-	db.AutoMigrate(&Poll{})
-	db.AutoMigrate(&PartnersInfo{})
-	db.AutoMigrate(&Price{})
+	sqlClient.AutoMigrate(&MailSubject{})
+	sqlClient.AutoMigrate(&MonthlyInfo{})
+	sqlClient.AutoMigrate(&MonthlyNews{})
+	sqlClient.AutoMigrate(&Poll{})
+	sqlClient.AutoMigrate(&PartnersInfo{})
+	sqlClient.AutoMigrate(&Price{})
+	sqlClient.AutoMigrate(&Consent{})
 
 	// Create default partner status
-	db.Create(&PartnersInfo{
+	sqlClient.Create(&PartnersInfo{
 		GRDFFailure:           false,
 		EnedisFailure:         false,
 		EGLFailure:            false,
 		NotificationActivated: false,
 	})
-	return &DataHandler{db: db}
+
+	// Meilisearch setup
+	meiliClient := meilisearch.NewClient(meilisearch.ClientConfig{
+		Host:   common.StringValueFromEnv("MEILI_HOST", ""),
+		APIKey: common.StringValueFromEnv("MEILI_MASTER_KEY", ""),
+	})
+
+	settings := meilisearch.Settings{
+		DisplayedAttributes: []string{
+			"ID",
+			"CreatedAt",
+			"firstname",
+			"lastname",
+			"pointID",
+		},
+		SearchableAttributes: []string{
+			"pointID",
+			"lastname",
+			"firstname",
+		},
+		RankingRules: []string{
+			"words",
+			"typo",
+			"proximity",
+			"attribute",
+			"sort",
+			"exactness",
+		},
+		TypoTolerance: &meilisearch.TypoTolerance{
+			MinWordSizeForTypos: meilisearch.MinWordSizeForTypos{
+				OneTypo:  4,
+				TwoTypos: 8,
+			},
+		},
+	}
+
+	meiliClient.Index("consents").UpdateSettings(&settings)
+
+	return &DataHandler{sqlClient: sqlClient, meiliClient: meiliClient}
 }
diff --git a/internal/models/monthlyInfo.go b/internal/models/monthlyInfo.go
index 5425f8b5e41b57a6c004aa76205d116f0fefa532..2f6b1da76838f5f2d3407fd5a54f3fe7379e857d 100644
--- a/internal/models/monthlyInfo.go
+++ b/internal/models/monthlyInfo.go
@@ -24,7 +24,7 @@ type MonthlyInfo struct {
 // @Router /api/admin/monthlyInfo [get]
 func (dh *DataHandler) GetAllMonthlyInfo(w http.ResponseWriter, r *http.Request) {
 	var monthlyInfo []MonthlyInfo
-	dh.db.Find(&monthlyInfo)
+	dh.sqlClient.Find(&monthlyInfo)
 
 	w.Header().Set("Content-Type", "application/json")
 	json.NewEncoder(w).Encode(monthlyInfo)
@@ -51,7 +51,7 @@ func (dh *DataHandler) GetSingleMonthlyInfo(w http.ResponseWriter, r *http.Reque
 	w.Header().Set("Content-Type", "application/json")
 
 	var monthlyInfo MonthlyInfo
-	err = dh.db.Where("year = ? AND month = ?", year, month).First(&monthlyInfo).Error
+	err = dh.sqlClient.Where("year = ? AND month = ?", year, month).First(&monthlyInfo).Error
 	if err != nil {
 		// If not found, answer "not found"
 		w.WriteHeader(http.StatusNotFound)
@@ -87,11 +87,11 @@ func (dh *DataHandler) SaveMonthlyInfo(w http.ResponseWriter, r *http.Request) {
 	}
 
 	// Check if this monthlyInfo exists
-	err = dh.db.Where("year = ? AND month = ?", monthlyInfo.Year, monthlyInfo.Month).First(&MonthlyInfo{}).Error
+	err = dh.sqlClient.Where("year = ? AND month = ?", monthlyInfo.Year, monthlyInfo.Month).First(&MonthlyInfo{}).Error
 
 	if err != nil {
 		// Create a monthlyInfo
-		err = dh.db.Create(&MonthlyInfo{
+		err = dh.sqlClient.Create(&MonthlyInfo{
 			Year:  monthlyInfo.Year,
 			Month: monthlyInfo.Month,
 			Info:  monthlyInfo.Info,
@@ -109,14 +109,14 @@ func (dh *DataHandler) SaveMonthlyInfo(w http.ResponseWriter, r *http.Request) {
 
 	} else {
 		// Update info
-		err = dh.db.Model(&MonthlyInfo{}).Where("year = ? AND month = ?", monthlyInfo.Year, monthlyInfo.Month).Update("info", monthlyInfo.Info).Error
+		err = dh.sqlClient.Model(&MonthlyInfo{}).Where("year = ? AND month = ?", monthlyInfo.Year, monthlyInfo.Month).Update("info", monthlyInfo.Info).Error
 		if err != nil {
 			w.WriteHeader(http.StatusInternalServerError)
 			return
 		}
 
 		// Update info
-		err = dh.db.Model(&MonthlyInfo{}).Where("year = ? AND month = ?", monthlyInfo.Year, monthlyInfo.Month).Update("image", monthlyInfo.Image).Error
+		err = dh.sqlClient.Model(&MonthlyInfo{}).Where("year = ? AND month = ?", monthlyInfo.Year, monthlyInfo.Month).Update("image", monthlyInfo.Image).Error
 		if err != nil {
 			w.WriteHeader(http.StatusInternalServerError)
 			return
@@ -144,7 +144,7 @@ func (dh *DataHandler) DeleteMonthlyInfo(w http.ResponseWriter, r *http.Request)
 		return
 	}
 
-	err = dh.db.Where("year = ? AND month = ?", year, month).Delete(&MonthlyInfo{}).Error
+	err = dh.sqlClient.Where("year = ? AND month = ?", year, month).Delete(&MonthlyInfo{}).Error
 	if err != nil {
 		http.Error(w, err.Error(), http.StatusNotFound)
 		return
diff --git a/internal/models/monthlyNews.go b/internal/models/monthlyNews.go
index 638df1c08975cb7cd271339776c1ba0365b9f2d2..eab06f0f1f029342267c49feff5fe88fae6a6e66 100644
--- a/internal/models/monthlyNews.go
+++ b/internal/models/monthlyNews.go
@@ -24,7 +24,7 @@ type MonthlyNews struct {
 // @Router /api/admin/monthlyNews [get]
 func (dh *DataHandler) GetAllMonthlyNews(w http.ResponseWriter, r *http.Request) {
 	var monthlyNews []MonthlyNews
-	dh.db.Find(&monthlyNews)
+	dh.sqlClient.Find(&monthlyNews)
 
 	w.Header().Set("Content-Type", "application/json")
 	json.NewEncoder(w).Encode(monthlyNews)
@@ -51,7 +51,7 @@ func (dh *DataHandler) GetSingleMonthlyNews(w http.ResponseWriter, r *http.Reque
 	w.Header().Set("Content-Type", "application/json")
 
 	var monthlyNews MonthlyNews
-	err = dh.db.Where("year = ? AND month = ?", year, month).First(&monthlyNews).Error
+	err = dh.sqlClient.Where("year = ? AND month = ?", year, month).First(&monthlyNews).Error
 	if err != nil {
 		// If not found, answer "not found"
 		w.WriteHeader(http.StatusNotFound)
@@ -87,7 +87,7 @@ func (dh *DataHandler) SaveMonthlyNews(w http.ResponseWriter, r *http.Request) {
 	}
 
 	// Check if this monthlyNews exists
-	err = dh.db.Where("year = ? AND month = ?", monthlyNews.Year, monthlyNews.Month).First(&MonthlyNews{}).Error
+	err = dh.sqlClient.Where("year = ? AND month = ?", monthlyNews.Year, monthlyNews.Month).First(&MonthlyNews{}).Error
 
 	// Default title
 	if monthlyNews.Title == "" && monthlyNews.Content != "" {
@@ -97,7 +97,7 @@ func (dh *DataHandler) SaveMonthlyNews(w http.ResponseWriter, r *http.Request) {
 	if err != nil {
 
 		// Create a monthlyNews
-		err = dh.db.Create(&MonthlyNews{Year: monthlyNews.Year, Month: monthlyNews.Month, Title: monthlyNews.Title, Content: monthlyNews.Content}).Error
+		err = dh.sqlClient.Create(&MonthlyNews{Year: monthlyNews.Year, Month: monthlyNews.Month, Title: monthlyNews.Title, Content: monthlyNews.Content}).Error
 		if err != nil {
 			w.WriteHeader(http.StatusInternalServerError)
 			return
@@ -110,13 +110,13 @@ func (dh *DataHandler) SaveMonthlyNews(w http.ResponseWriter, r *http.Request) {
 
 	} else {
 		// Update title
-		err = dh.db.Model(&MonthlyNews{}).Where("year = ? AND month = ?", monthlyNews.Year, monthlyNews.Month).Update("title", monthlyNews.Title).Error
+		err = dh.sqlClient.Model(&MonthlyNews{}).Where("year = ? AND month = ?", monthlyNews.Year, monthlyNews.Month).Update("title", monthlyNews.Title).Error
 		if err != nil {
 			w.WriteHeader(http.StatusInternalServerError)
 			return
 		}
 		// Update content
-		err = dh.db.Model(&MonthlyNews{}).Where("year = ? AND month = ?", monthlyNews.Year, monthlyNews.Month).Update("content", monthlyNews.Content).Error
+		err = dh.sqlClient.Model(&MonthlyNews{}).Where("year = ? AND month = ?", monthlyNews.Year, monthlyNews.Month).Update("content", monthlyNews.Content).Error
 		if err != nil {
 			w.WriteHeader(http.StatusInternalServerError)
 			return
@@ -144,7 +144,7 @@ func (dh *DataHandler) DeleteMonthlyNews(w http.ResponseWriter, r *http.Request)
 		return
 	}
 
-	err = dh.db.Where("year = ? AND month = ?", year, month).Delete(&MonthlyNews{}).Error
+	err = dh.sqlClient.Where("year = ? AND month = ?", year, month).Delete(&MonthlyNews{}).Error
 	if err != nil {
 		http.Error(w, err.Error(), http.StatusNotFound)
 		return
diff --git a/internal/models/monthlyReport.go b/internal/models/monthlyReport.go
index a11c50f747ce908952e29b1374749b5b95af17bb..7ba6549e6555223363fdb6bab576e6187235b10e 100644
--- a/internal/models/monthlyReport.go
+++ b/internal/models/monthlyReport.go
@@ -81,20 +81,20 @@ func (dh *DataHandler) GetCurrentMonthlyReport(w http.ResponseWriter, r *http.Re
 
 func (dh *DataHandler) getMonthlyReport(year int, month int) (monthlyReport MonthlyReport, err error) {
 	var monthlyInfo MonthlyInfo
-	dh.db.Where("year = ? AND month = ?", year, month).First(&monthlyInfo)
+	dh.sqlClient.Where("year = ? AND month = ?", year, month).First(&monthlyInfo)
 
 	var mailSubject MailSubject
-	err = dh.db.Where("year = ? AND month = ?", year, month).First(&mailSubject).Error
+	err = dh.sqlClient.Where("year = ? AND month = ?", year, month).First(&mailSubject).Error
 	if err != nil {
 		// Build default object
 		mailSubject.Subject = fmt.Sprintf("[Ecolyo] Votre bilan %s %v", getMonthNameWithPrep(month-1), year)
 	}
 
 	var monthlyNews MonthlyNews
-	dh.db.Where("year = ? AND month = ?", year, month).First(&monthlyNews)
+	dh.sqlClient.Where("year = ? AND month = ?", year, month).First(&monthlyNews)
 
 	var poll Poll
-	dh.db.Where("year = ? AND month = ?", year, month).First(&poll)
+	dh.sqlClient.Where("year = ? AND month = ?", year, month).First(&poll)
 
 	monthlyReport = MonthlyReport{
 		Year:        year,
diff --git a/internal/models/partnersInfo.go b/internal/models/partnersInfo.go
index 35652e7cdf9ed941b72140b7f383a82b4598608a..c21596a839935683c952c24c07dec5ca5f22c102 100644
--- a/internal/models/partnersInfo.go
+++ b/internal/models/partnersInfo.go
@@ -10,11 +10,11 @@ import (
 )
 
 type PartnersInfo struct {
-	ID                    uint   `gorm:"<-:create"`
-	GRDFFailure           bool   `json:"grdf_failure"`
-	EnedisFailure         bool   `json:"enedis_failure"`
-	EGLFailure            bool   `json:"egl_failure"`
-	NotificationActivated bool   `json:"notification_activated"`
+	ID                    uint `gorm:"<-:create"`
+	GRDFFailure           bool `json:"grdf_failure"`
+	EnedisFailure         bool `json:"enedis_failure"`
+	EGLFailure            bool `json:"egl_failure"`
+	NotificationActivated bool `json:"notification_activated"`
 }
 
 // GetPartnersInfo godoc
@@ -27,7 +27,7 @@ type PartnersInfo struct {
 // @Router /api/common/partnersInfo [get]
 func (dh *DataHandler) GetPartnersInfo(w http.ResponseWriter, r *http.Request) {
 	var partnersInfo PartnersInfo
-	err := dh.db.First(&partnersInfo).Error
+	err := dh.sqlClient.First(&partnersInfo).Error
 
 	if errors.Is(err, gorm.ErrRecordNotFound) {
 		http.Error(w, "partners status not found", http.StatusNotFound)
@@ -66,7 +66,7 @@ func (dh *DataHandler) SavePartnersInfo(w http.ResponseWriter, r *http.Request)
 
 	var updatedPartnersInfo PartnersInfo
 
-	err = dh.db.First(&updatedPartnersInfo).Error
+	err = dh.sqlClient.First(&updatedPartnersInfo).Error
 	if err != nil {
 		w.WriteHeader(http.StatusInternalServerError)
 		return
@@ -77,7 +77,7 @@ func (dh *DataHandler) SavePartnersInfo(w http.ResponseWriter, r *http.Request)
 	updatedPartnersInfo.EGLFailure = partnersInfo.EGLFailure
 	updatedPartnersInfo.NotificationActivated = partnersInfo.NotificationActivated
 
-	dh.db.Save(&updatedPartnersInfo)
+	dh.sqlClient.Save(&updatedPartnersInfo)
 
 	w.Header().Set("Content-Type", "application/json")
 	json.NewEncoder(w).Encode(partnersInfo)
diff --git a/internal/models/poll.go b/internal/models/poll.go
index 76acbc8dac5585019cc47f8c6f28945fcb5a235e..02bb2abb4df55c844efa6d6f53f6533896eb1d55 100644
--- a/internal/models/poll.go
+++ b/internal/models/poll.go
@@ -24,7 +24,7 @@ type Poll struct {
 // @Router /api/admin/poll [get]
 func (dh *DataHandler) GetAllPolls(w http.ResponseWriter, r *http.Request) {
 	var polls []Poll
-	err := dh.db.Find(&polls).Error
+	err := dh.sqlClient.Find(&polls).Error
 	if err != nil {
 		w.WriteHeader(http.StatusInternalServerError)
 		return
@@ -55,7 +55,7 @@ func (dh *DataHandler) GetSinglePoll(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 
 	var poll Poll
-	err = dh.db.Where("year = ? AND month = ?", year, month).First(&poll).Error
+	err = dh.sqlClient.Where("year = ? AND month = ?", year, month).First(&poll).Error
 	if err != nil {
 		// If not found, answer "not found"
 		w.WriteHeader(http.StatusNotFound)
@@ -91,11 +91,11 @@ func (dh *DataHandler) SavePoll(w http.ResponseWriter, r *http.Request) {
 	}
 
 	// Check if this poll exists
-	err = dh.db.Where("year = ? AND month = ?", poll.Year, poll.Month).First(&Poll{}).Error
+	err = dh.sqlClient.Where("year = ? AND month = ?", poll.Year, poll.Month).First(&Poll{}).Error
 
 	if err != nil {
 		// Create a poll
-		err = dh.db.Create(&Poll{Year: poll.Year, Month: poll.Month, Question: poll.Question, Link: poll.Link}).Error
+		err = dh.sqlClient.Create(&Poll{Year: poll.Year, Month: poll.Month, Question: poll.Question, Link: poll.Link}).Error
 		if err != nil {
 			w.WriteHeader(http.StatusInternalServerError)
 			return
@@ -107,13 +107,13 @@ func (dh *DataHandler) SavePoll(w http.ResponseWriter, r *http.Request) {
 
 	} else {
 		// Update question
-		err = dh.db.Model(&Poll{}).Where("year = ? AND month = ?", poll.Year, poll.Month).Update("question", poll.Question).Error
+		err = dh.sqlClient.Model(&Poll{}).Where("year = ? AND month = ?", poll.Year, poll.Month).Update("question", poll.Question).Error
 		if err != nil {
 			w.WriteHeader(http.StatusInternalServerError)
 			return
 		}
 		// Update link
-		err = dh.db.Model(&Poll{}).Where("year = ? AND month = ?", poll.Year, poll.Month).Update("link", poll.Link).Error
+		err = dh.sqlClient.Model(&Poll{}).Where("year = ? AND month = ?", poll.Year, poll.Month).Update("link", poll.Link).Error
 		if err != nil {
 			w.WriteHeader(http.StatusInternalServerError)
 			return
@@ -141,7 +141,7 @@ func (dh *DataHandler) DeletePoll(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	err = dh.db.Where("year = ? AND month = ?", year, month).Delete(&Poll{}).Error
+	err = dh.sqlClient.Where("year = ? AND month = ?", year, month).Delete(&Poll{}).Error
 	if err != nil {
 		http.Error(w, err.Error(), http.StatusNotFound)
 		return
diff --git a/internal/models/price.go b/internal/models/price.go
index 013c5d5b41f85cabe738c95949c9425ad05a2a94..b5130d93a9f02ea2fbb416d1edbfa27287ca354a 100644
--- a/internal/models/price.go
+++ b/internal/models/price.go
@@ -11,10 +11,10 @@ import (
 )
 
 type Price struct {
-	FluidType 	int 	`json:"fluidType"`
-	Price 		float32 `json:"price"`
-	StartDate 	string 	`json:"startDate"`
-	EndDate 	string 	`json:"endDate"`
+	FluidType int     `json:"fluidType"`
+	Price     float32 `json:"price"`
+	StartDate string  `json:"startDate"`
+	EndDate   string  `json:"endDate"`
 	gorm.Model
 }
 
@@ -28,7 +28,7 @@ type Price struct {
 // @Router /api/common/prices [get]
 func (dh *DataHandler) GetAllPrices(w http.ResponseWriter, r *http.Request) {
 	var prices []Price
-	dh.db.Find(&prices)
+	dh.sqlClient.Find(&prices)
 
 	w.Header().Set("Content-Type", "application/json")
 	json.NewEncoder(w).Encode(prices)
@@ -52,17 +52,16 @@ func (dh *DataHandler) GetPricesByFluid(w http.ResponseWriter, r *http.Request)
 	}
 	var price []Price
 	w.Header().Set("Content-Type", "application/json")
-	err = dh.db.Where("fluid_type = ? ", fluidtype).Order("start_date desc").Find(&price).Error
+	err = dh.sqlClient.Where("fluid_type = ? ", fluidtype).Order("start_date desc").Find(&price).Error
 
 	if err != nil {
 		http.Error(w, err.Error(), http.StatusBadRequest)
 		return
 	}
 	json.NewEncoder(w).Encode(price)
-	log.Printf("| Get prices by fluid : %v | %v",fluidtype,  r.RemoteAddr)
+	log.Printf("| Get prices by fluid : %v | %v", fluidtype, r.RemoteAddr)
 }
 
-
 // SavePrice godoc
 // @Summary Add a new price entry
 // @Description Add a new price entry
@@ -90,13 +89,13 @@ func (dh *DataHandler) SavePrice(w http.ResponseWriter, r *http.Request) {
 	}
 
 	// Check if this price exists
-	err = dh.db.Where("fluid_type = ? AND start_date = ?", price.FluidType, price.StartDate).First(&Price{}).Error
+	err = dh.sqlClient.Where("fluid_type = ? AND start_date = ?", price.FluidType, price.StartDate).First(&Price{}).Error
 
 	if err != nil {
 		println("Price does not exist in database")
 		//Gets the last price for this fluid
 		var lastPrice Price
-		err = dh.db.Where("fluid_type = ?", price.FluidType).Order("start_date desc").Limit(1).Find(&lastPrice).Error
+		err = dh.sqlClient.Where("fluid_type = ?", price.FluidType).Order("start_date desc").Limit(1).Find(&lastPrice).Error
 		if err != nil {
 			println("Failed to get last price for this fluid")
 			w.WriteHeader(http.StatusInternalServerError)
@@ -107,15 +106,15 @@ func (dh *DataHandler) SavePrice(w http.ResponseWriter, r *http.Request) {
 		updatedEndDate := t.Add(-1 * time.Minute).Format(time.RFC3339)
 		lastPrice.EndDate = updatedEndDate
 
-		dh.db.Save(&lastPrice)
+		dh.sqlClient.Save(&lastPrice)
 		log.Printf("updated last price")
-		
+
 		// Create a new price
-		err = dh.db.Create(&Price{
-			FluidType:  price.FluidType,
-			Price: price.Price,
-			StartDate:  price.StartDate,
-			EndDate: "",
+		err = dh.sqlClient.Create(&Price{
+			FluidType: price.FluidType,
+			Price:     price.Price,
+			StartDate: price.StartDate,
+			EndDate:   "",
 		}).Error
 		if err != nil {
 			println("Failed to create price")
@@ -132,7 +131,7 @@ func (dh *DataHandler) SavePrice(w http.ResponseWriter, r *http.Request) {
 		priceToUpdate := price
 		isEditable := false
 		// If price is not included in the last 3 editable prices, throw error
-		err = dh.db.Where("fluid_type = ? ", price.FluidType).Order("start_date desc").Limit(3).Find(&editablePrices).Error
+		err = dh.sqlClient.Where("fluid_type = ? ", price.FluidType).Order("start_date desc").Limit(3).Find(&editablePrices).Error
 		if err != nil {
 			w.WriteHeader(http.StatusInternalServerError)
 			return
@@ -143,14 +142,14 @@ func (dh *DataHandler) SavePrice(w http.ResponseWriter, r *http.Request) {
 				isEditable = true
 			}
 		}
-		
+
 		if isEditable == false {
 			w.WriteHeader(http.StatusForbidden)
 			log.Printf("Unallowed to edit price because is not included in the the last 3 editable prices")
 			return
 		}
 		// Update existing price
-		err = dh.db.Model(&Price{}).Where("start_date = ? AND fluid_type = ?", priceToUpdate.StartDate, priceToUpdate.FluidType).Update("price", priceToUpdate.Price).Error
+		err = dh.sqlClient.Model(&Price{}).Where("start_date = ? AND fluid_type = ?", priceToUpdate.StartDate, priceToUpdate.FluidType).Update("price", priceToUpdate.Price).Error
 		if err != nil {
 			w.WriteHeader(http.StatusInternalServerError)
 			return
@@ -161,4 +160,3 @@ func (dh *DataHandler) SavePrice(w http.ResponseWriter, r *http.Request) {
 		log.Printf("| Updated price | fluidType : %d price : %v | startDate : %v | %v", priceToUpdate.FluidType, priceToUpdate.Price, priceToUpdate.StartDate, r.RemoteAddr)
 	}
 }
-
diff --git a/internal/rootmux/rootmux.go b/internal/rootmux/rootmux.go
index 8dcc835e4bb0ec67f51b4c604d2a641979e7c182..a3d236f786a52a1fc53aa85907a6c89f3cd20239 100644
--- a/internal/rootmux/rootmux.go
+++ b/internal/rootmux/rootmux.go
@@ -74,6 +74,15 @@ func CreateRootMux() RootMux {
 
 	apiAdmin.HandleFunc("/prices", dh.SavePrice).Methods(http.MethodPut)
 
+	apiAdmin.HandleFunc("/consent", dh.SearchConsent).Methods(http.MethodGet)
+
+	apiSGE := r.PathPrefix("/api/sge").Subrouter()
+	apiSGE.Use(auth.SGEAuthMiddleware)
+	apiSGE.HandleFunc("/consent", dh.PostConsent).Methods(http.MethodPost)
+	apiSGE.HandleFunc("/consent/{id}", dh.GetConsentById).Methods(http.MethodGet)
+	apiSGE.HandleFunc("/consent/{id}", dh.UpdateConsent).Methods(http.MethodPut)
+	apiSGE.HandleFunc("/consent/{id}", dh.DeleteConsentById).Methods(http.MethodDelete)
+
 	// Swagger
 	r.PathPrefix("/swagger").Handler(httpSwagger.WrapHandler)
 
diff --git a/internal/rootmux/rootmux_test.go b/internal/rootmux/rootmux_test.go
index 63ba50e8a032eb54758efca018aa5edc71a0a51c..d6ee76e3c989b05859f3af0af360527cdacbbc1f 100644
--- a/internal/rootmux/rootmux_test.go
+++ b/internal/rootmux/rootmux_test.go
@@ -8,6 +8,7 @@ import (
 	"net/url"
 	"os"
 	"testing"
+	"time"
 
 	"forge.grandlyon.com/web-et-numerique/llle_project/backoffice-server/internal/auth"
 	"forge.grandlyon.com/web-et-numerique/llle_project/backoffice-server/internal/mocks"
@@ -28,6 +29,8 @@ var (
 	newPollStr      string
 	partnersInfo    = models.PartnersInfo{ID: 1, GRDFFailure: false, EnedisFailure: false, EGLFailure: true, NotificationActivated: true}
 	partnersInfoStr string
+	consent         = models.Consent{Firstname: "Foo", Lastname: "Bar", PointID: 123456}
+	consentStr      string
 	noH             map[string]string
 )
 
@@ -45,6 +48,9 @@ func TestMain(m *testing.M) {
 	os.Setenv("TOKEN_URL", oAuth2Server.URL+"/token")
 	os.Setenv("USERINFO_URL", oAuth2Server.URL+"/userinfo")
 	os.Setenv("LOGOUT_URL", oAuth2Server.URL+"/logout")
+	os.Setenv("MEILI_MASTER_KEY", "masterkey")
+	os.Setenv("MEILI_HOST", "http://localhost:7700")
+	os.Setenv("SGE_API_TOKEN", "sgeApiToken")
 
 	// Setup the token manager to use debug mode
 	os.Setenv("DEBUG_MODE", "true")
@@ -61,6 +67,8 @@ func TestMain(m *testing.M) {
 	partnersInfoStr = string(partnersInfoBytes)
 	newPollBytes, _ := json.Marshal(newPoll)
 	newPollStr = string(newPollBytes)
+	consentBytes, _ := json.Marshal(consent)
+	consentStr = string(consentBytes)
 
 	code := m.Run()
 	// Remove the database
@@ -75,10 +83,11 @@ func TestAll(t *testing.T) {
 	oauth2Tests(t)
 	os.Setenv("AUTH_URL", oAuth2Server.URL+"/auth") // Set the server to access the correct OAuth2Endpoint
 	unloggedTests(t)
-
 	os.Setenv("USERINFO_URL", oAuth2Server.URL+"/admininfo")
 	adminTests(t)
 
+	// SGE API tests
+	sgeTests(t)
 }
 
 /**
@@ -212,6 +221,48 @@ func adminTests(t *testing.T) {
 	do("GET", "/api/admin/monthlyNews", noH, "", http.StatusUnauthorized, "error extracting token")
 	// Try to get a poll again (must fail)
 	do("GET", "/api/admin/poll", noH, "", http.StatusUnauthorized, "error extracting token")
+
+}
+
+func sgeTests(t *testing.T) {
+	// Create the tester
+	ts, do, _ := createTester(t)
+	defer ts.Close() // Close the tester
+	// Try to create a consent  (must fail)
+	do("POST", "/api/sge/consent", noH, consentStr, http.StatusUnauthorized, "invalid token")
+	// Try to get a consent  (must fail)
+	do("GET", "/api/sge/consent/1", noH, "", http.StatusUnauthorized, "invalid token")
+	// Try to update a consent  (must fail)
+	do("PUT", "/api/sge/consent/1", noH, "", http.StatusUnauthorized, "invalid token")
+	// Try to delete a consent  (must fail)
+	do("DELETE", "/api/sge/consent/1", noH, "", http.StatusUnauthorized, "invalid token")
+
+	// Create correct authorization header
+	sgeApiHeader := map[string]string{"Authorization": "Bearer " + auth.SGEApiToken}
+	// Try to create a consent  (must pass)
+	do("POST", "/api/sge/consent", sgeApiHeader, consentStr, http.StatusCreated, `{"ID":1`)
+	// Wait for new documents to be indexed
+	time.Sleep(1 * time.Second)
+	// Try to update a consent  (must pass)
+	do("PUT", "/api/sge/consent/1", sgeApiHeader, `{"serviceId":123456}`, http.StatusOK, `{"ID":1`)
+	// Try to get a consent  (must pass)
+	do("GET", "/api/sge/consent/1", sgeApiHeader, `{"serviceId":123456}`, http.StatusOK, `{"ID":1`)
+
+	// Try to login (must pass)
+	do("GET", "/OAuth2Login", noH, "", http.StatusOK, "")
+
+	response := do("GET", "/api/common/WhoAmI", noH, "", http.StatusOK, "")
+	token := auth.TokenData{}
+	json.Unmarshal([]byte(response), &token)
+	xsrfHeader := map[string]string{"XSRF-TOKEN": token.XSRFToken}
+
+	// Try to get first 50 consents  (must pass)
+	do("GET", "/api/admin/consent?limit=50&page=0", xsrfHeader, "", http.StatusOK, `{"totalRows":1,"rows":[{"ID":1`)
+	// Try to search for a consent  (must pass)
+	do("GET", "/api/admin/consent?search=123456", xsrfHeader, "", http.StatusOK, `[{"ID":1`)
+	// Try to delete a consent  (must pass)
+	do("DELETE", "/api/sge/consent/1", sgeApiHeader, "", http.StatusOK, "")
+
 }
 
 func createTester(t *testing.T) (*httptest.Server, tester.DoFn, tester.DoFn) {
diff --git a/start-meilisearch-test-and-build.sh b/start-meilisearch-test-and-build.sh
new file mode 100755
index 0000000000000000000000000000000000000000..cfe1951e27df78052bb1554c28cf097c123085a8
--- /dev/null
+++ b/start-meilisearch-test-and-build.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+set -e
+
+# Start the process
+meilisearch &
+
+# Get dependencies and run tests
+go version
+go get -d -v
+CGO_ENABLED=1 go test ./...
+
+# Build the binary
+CGO_ENABLED=0 go build \
+    -ldflags='-w -s -extldflags "-static"' -a \
+    -o /app/backoffice-server .