diff --git a/docs/docs.go b/docs/docs.go
index 9e72b0b029a24d96014014b30d84b4ff9b06e6ad..49b75f3556829fa1845dddc0737e82c9ab85bc01 100644
--- a/docs/docs.go
+++ b/docs/docs.go
@@ -1523,10 +1523,7 @@ const docTemplate = `{
                                     "type": "object",
                                     "properties": {
                                         "data": {
-                                            "type": "array",
-                                            "items": {
-                                                "$ref": "#/definitions/material.Material"
-                                            }
+                                            "$ref": "#/definitions/material.Material"
                                         }
                                     }
                                 }
@@ -1738,6 +1735,119 @@ const docTemplate = `{
                 }
             }
         },
+        "/quiz/{id}/solution": {
+            "get": {
+                "description": "Take a quiz",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "quiz"
+                ],
+                "summary": "Get Quiz Solution",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Authenticate User (any role)",
+                        "name": "Authorization",
+                        "in": "header",
+                        "required": true
+                    },
+                    {
+                        "type": "string",
+                        "format": "uuid",
+                        "description": "Quiz id",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/web.BaseResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/quiz.QuizDetail"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/quiz/{id}/take": {
+            "post": {
+                "description": "Finish quiz session and get the score",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "quiz"
+                ],
+                "summary": "Finish Quiz",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Authenticate User (any role)",
+                        "name": "Authorization",
+                        "in": "header",
+                        "required": true
+                    },
+                    {
+                        "description": "Quiz Finish payload",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/quiz.FinishQuizPayload"
+                        }
+                    },
+                    {
+                        "type": "string",
+                        "format": "uuid",
+                        "description": "Quiz id",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/web.BaseResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/quiz.QuizDetail"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
         "/reset/confirm": {
             "put": {
                 "description": "Do confirmation to reset password",
@@ -2249,6 +2359,37 @@ const docTemplate = `{
                 }
             }
         },
+        "quiz.AnswerOption": {
+            "type": "object",
+            "properties": {
+                "answer": {
+                    "type": "string"
+                },
+                "id": {
+                    "type": "string"
+                },
+                "is_solution": {
+                    "type": "boolean"
+                },
+                "media_id": {
+                    "type": "array",
+                    "items": {
+                        "type": "string"
+                    }
+                }
+            }
+        },
+        "quiz.FinishQuizPayload": {
+            "type": "object",
+            "properties": {
+                "data": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/quiz.Response"
+                    }
+                }
+            }
+        },
         "quiz.Quiz": {
             "type": "object",
             "properties": {
@@ -2261,8 +2402,88 @@ const docTemplate = `{
                 "id": {
                     "type": "string"
                 },
+                "nama": {
+                    "type": "string"
+                }
+            }
+        },
+        "quiz.QuizDetail": {
+            "type": "object",
+            "properties": {
+                "course_id": {
+                    "type": "string"
+                },
+                "description": {
+                    "type": "string"
+                },
+                "help": {
+                    "type": "string"
+                },
+                "id": {
+                    "type": "string"
+                },
+                "media": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/quiz.QuizMedia"
+                    }
+                },
                 "name": {
                     "type": "string"
+                },
+                "problems": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/quiz.QuizProblem"
+                    }
+                }
+            }
+        },
+        "quiz.QuizMedia": {
+            "type": "object",
+            "properties": {
+                "id": {
+                    "type": "string"
+                },
+                "type": {
+                    "type": "string"
+                },
+                "url": {
+                    "type": "string"
+                }
+            }
+        },
+        "quiz.QuizProblem": {
+            "type": "object",
+            "properties": {
+                "answers": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/quiz.AnswerOption"
+                    }
+                },
+                "id": {
+                    "type": "string"
+                },
+                "media_id": {
+                    "type": "array",
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "question": {
+                    "type": "string"
+                }
+            }
+        },
+        "quiz.Response": {
+            "type": "object",
+            "properties": {
+                "answer_id": {
+                    "type": "string"
+                },
+                "problem_id": {
+                    "type": "string"
                 }
             }
         },
diff --git a/docs/swagger.json b/docs/swagger.json
index 07c6617ab34c4011a16323b020510a7289432e12..883d3d799d994fab91eb3dbf9e1aee4d8483c36f 100644
--- a/docs/swagger.json
+++ b/docs/swagger.json
@@ -1515,10 +1515,7 @@
                                     "type": "object",
                                     "properties": {
                                         "data": {
-                                            "type": "array",
-                                            "items": {
-                                                "$ref": "#/definitions/material.Material"
-                                            }
+                                            "$ref": "#/definitions/material.Material"
                                         }
                                     }
                                 }
@@ -1730,6 +1727,119 @@
                 }
             }
         },
+        "/quiz/{id}/solution": {
+            "get": {
+                "description": "Take a quiz",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "quiz"
+                ],
+                "summary": "Get Quiz Solution",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Authenticate User (any role)",
+                        "name": "Authorization",
+                        "in": "header",
+                        "required": true
+                    },
+                    {
+                        "type": "string",
+                        "format": "uuid",
+                        "description": "Quiz id",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/web.BaseResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/quiz.QuizDetail"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
+        "/quiz/{id}/take": {
+            "post": {
+                "description": "Finish quiz session and get the score",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "quiz"
+                ],
+                "summary": "Finish Quiz",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "Authenticate User (any role)",
+                        "name": "Authorization",
+                        "in": "header",
+                        "required": true
+                    },
+                    {
+                        "description": "Quiz Finish payload",
+                        "name": "data",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/quiz.FinishQuizPayload"
+                        }
+                    },
+                    {
+                        "type": "string",
+                        "format": "uuid",
+                        "description": "Quiz id",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "allOf": [
+                                {
+                                    "$ref": "#/definitions/web.BaseResponse"
+                                },
+                                {
+                                    "type": "object",
+                                    "properties": {
+                                        "data": {
+                                            "$ref": "#/definitions/quiz.QuizDetail"
+                                        }
+                                    }
+                                }
+                            ]
+                        }
+                    }
+                }
+            }
+        },
         "/reset/confirm": {
             "put": {
                 "description": "Do confirmation to reset password",
@@ -2241,6 +2351,37 @@
                 }
             }
         },
+        "quiz.AnswerOption": {
+            "type": "object",
+            "properties": {
+                "answer": {
+                    "type": "string"
+                },
+                "id": {
+                    "type": "string"
+                },
+                "is_solution": {
+                    "type": "boolean"
+                },
+                "media_id": {
+                    "type": "array",
+                    "items": {
+                        "type": "string"
+                    }
+                }
+            }
+        },
+        "quiz.FinishQuizPayload": {
+            "type": "object",
+            "properties": {
+                "data": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/quiz.Response"
+                    }
+                }
+            }
+        },
         "quiz.Quiz": {
             "type": "object",
             "properties": {
@@ -2253,8 +2394,88 @@
                 "id": {
                     "type": "string"
                 },
+                "nama": {
+                    "type": "string"
+                }
+            }
+        },
+        "quiz.QuizDetail": {
+            "type": "object",
+            "properties": {
+                "course_id": {
+                    "type": "string"
+                },
+                "description": {
+                    "type": "string"
+                },
+                "help": {
+                    "type": "string"
+                },
+                "id": {
+                    "type": "string"
+                },
+                "media": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/quiz.QuizMedia"
+                    }
+                },
                 "name": {
                     "type": "string"
+                },
+                "problems": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/quiz.QuizProblem"
+                    }
+                }
+            }
+        },
+        "quiz.QuizMedia": {
+            "type": "object",
+            "properties": {
+                "id": {
+                    "type": "string"
+                },
+                "type": {
+                    "type": "string"
+                },
+                "url": {
+                    "type": "string"
+                }
+            }
+        },
+        "quiz.QuizProblem": {
+            "type": "object",
+            "properties": {
+                "answers": {
+                    "type": "array",
+                    "items": {
+                        "$ref": "#/definitions/quiz.AnswerOption"
+                    }
+                },
+                "id": {
+                    "type": "string"
+                },
+                "media_id": {
+                    "type": "array",
+                    "items": {
+                        "type": "string"
+                    }
+                },
+                "question": {
+                    "type": "string"
+                }
+            }
+        },
+        "quiz.Response": {
+            "type": "object",
+            "properties": {
+                "answer_id": {
+                    "type": "string"
+                },
+                "problem_id": {
+                    "type": "string"
                 }
             }
         },
diff --git a/docs/swagger.yaml b/docs/swagger.yaml
index ee7cc0f2bd3089513cd4d4688a70efda551cca03..58ea9348fb473426c5890cff161bd98360f62bf0 100644
--- a/docs/swagger.yaml
+++ b/docs/swagger.yaml
@@ -298,6 +298,26 @@ definitions:
       upload_link:
         type: string
     type: object
+  quiz.AnswerOption:
+    properties:
+      answer:
+        type: string
+      id:
+        type: string
+      is_solution:
+        type: boolean
+      media_id:
+        items:
+          type: string
+        type: array
+    type: object
+  quiz.FinishQuizPayload:
+    properties:
+      data:
+        items:
+          $ref: '#/definitions/quiz.Response'
+        type: array
+    type: object
   quiz.Quiz:
     properties:
       course_id:
@@ -306,8 +326,60 @@ definitions:
         type: string
       id:
         type: string
+      nama:
+        type: string
+    type: object
+  quiz.QuizDetail:
+    properties:
+      course_id:
+        type: string
+      description:
+        type: string
+      help:
+        type: string
+      id:
+        type: string
+      media:
+        items:
+          $ref: '#/definitions/quiz.QuizMedia'
+        type: array
       name:
         type: string
+      problems:
+        items:
+          $ref: '#/definitions/quiz.QuizProblem'
+        type: array
+    type: object
+  quiz.QuizMedia:
+    properties:
+      id:
+        type: string
+      type:
+        type: string
+      url:
+        type: string
+    type: object
+  quiz.QuizProblem:
+    properties:
+      answers:
+        items:
+          $ref: '#/definitions/quiz.AnswerOption'
+        type: array
+      id:
+        type: string
+      media_id:
+        items:
+          type: string
+        type: array
+      question:
+        type: string
+    type: object
+  quiz.Response:
+    properties:
+      answer_id:
+        type: string
+      problem_id:
+        type: string
     type: object
   refresh.RefreshResponsePayload:
     description: Refresh endpoint response when process success
@@ -1393,9 +1465,7 @@ paths:
             - $ref: '#/definitions/web.BaseResponse'
             - properties:
                 data:
-                  items:
-                    $ref: '#/definitions/material.Material'
-                  type: array
+                  $ref: '#/definitions/material.Material'
               type: object
       summary: Get material detail
       tags:
@@ -1505,6 +1575,76 @@ paths:
       summary: Get Quiz Detail
       tags:
       - quiz
+  /quiz/{id}/solution:
+    get:
+      consumes:
+      - application/json
+      description: Take a quiz
+      parameters:
+      - description: Authenticate User (any role)
+        in: header
+        name: Authorization
+        required: true
+        type: string
+      - description: Quiz id
+        format: uuid
+        in: path
+        name: id
+        required: true
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/web.BaseResponse'
+            - properties:
+                data:
+                  $ref: '#/definitions/quiz.QuizDetail'
+              type: object
+      summary: Get Quiz Solution
+      tags:
+      - quiz
+  /quiz/{id}/take:
+    post:
+      consumes:
+      - application/json
+      description: Finish quiz session and get the score
+      parameters:
+      - description: Authenticate User (any role)
+        in: header
+        name: Authorization
+        required: true
+        type: string
+      - description: Quiz Finish payload
+        in: body
+        name: data
+        required: true
+        schema:
+          $ref: '#/definitions/quiz.FinishQuizPayload'
+      - description: Quiz id
+        format: uuid
+        in: path
+        name: id
+        required: true
+        type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            allOf:
+            - $ref: '#/definitions/web.BaseResponse'
+            - properties:
+                data:
+                  $ref: '#/definitions/quiz.QuizDetail'
+              type: object
+      summary: Finish Quiz
+      tags:
+      - quiz
   /reset/confirm:
     put:
       description: Do confirmation to reset password
diff --git a/handler/quiz/take.go b/handler/quiz/take.go
new file mode 100644
index 0000000000000000000000000000000000000000..530f4f77823001b1a5027b76d610b8c9ccafcaad
--- /dev/null
+++ b/handler/quiz/take.go
@@ -0,0 +1,219 @@
+package quiz
+
+import (
+	"net/http"
+
+	"github.com/go-chi/chi/v5"
+	"github.com/go-playground/validator/v10"
+	"github.com/google/uuid"
+	"gitlab.informatika.org/ocw/ocw-backend/middleware/guard"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web"
+	authToken "gitlab.informatika.org/ocw/ocw-backend/model/web/auth/token"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web/quiz"
+)
+
+// Index godoc
+//
+//	@Tags					quiz
+//	@Summary			Take Quiz
+//	@Description	Take a quiz
+//	@Produce			json
+//	@Accept				json
+//	@Param				Authorization	header		string							true "Authenticate User (any role)"
+//	@Param				id path string true "Quiz id" Format(uuid)
+//	@Success			200	{object}	web.BaseResponse{data=quiz.QuizDetail}
+//	@Router				/quiz/{id}/take [post]
+func (m QuizHandlerImpl) TakeQuiz(w http.ResponseWriter, r *http.Request) {
+	rawQuizId := chi.URLParam(r, "id")
+
+	if rawQuizId == "" {
+		payload := m.WrapperUtil.ErrorResponseWrap("quiz id is required", nil)
+		m.HttpUtil.WriteJson(w, http.StatusUnsupportedMediaType, payload)
+		return
+	}
+
+	quizId, err := uuid.Parse(rawQuizId)
+
+	if err != nil {
+		payload := m.WrapperUtil.ErrorResponseWrap("quiz id is not valid", nil)
+		m.HttpUtil.WriteJson(w, http.StatusUnsupportedMediaType, payload)
+		return
+	}
+
+	user, ok := r.Context().Value(guard.UserContext).(authToken.UserClaim)
+
+	if !ok {
+		m.Logger.Error("Context is not found")
+		payload := m.WrapperUtil.ErrorResponseWrap("internal server error", nil)
+		m.HttpUtil.WriteJson(w, http.StatusInternalServerError, payload)
+		return
+	}
+
+	detail, err := m.DoTakeQuiz(r.Context(), quizId, user.Email)
+
+	if err != nil {
+		respErr, ok := err.(web.ResponseError)
+		if ok {
+			payload := m.WrapperUtil.ErrorResponseWrap(respErr.Error(), respErr)
+			m.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+		} else {
+			payload := m.WrapperUtil.ErrorResponseWrap("internal server error", nil)
+			m.HttpUtil.WriteJson(w, http.StatusInternalServerError, payload)
+		}
+		return
+	}
+
+	responsePayload := m.WrapperUtil.SuccessResponseWrap(detail)
+	m.HttpUtil.WriteSuccessJson(w, responsePayload)
+}
+
+// Index godoc
+//
+//	@Tags					quiz
+//	@Summary			Get Quiz Solution
+//	@Description	Take a quiz
+//	@Produce			json
+//	@Accept				json
+//	@Param				Authorization	header		string							true "Authenticate User (any role)"
+//	@Param				id path string true "Quiz id" Format(uuid)
+//	@Success			200	{object}	web.BaseResponse{data=quiz.QuizDetail}
+//	@Router				/quiz/{id}/solution [get]
+func (m QuizHandlerImpl) GetQuizSolution(w http.ResponseWriter, r *http.Request) {
+	rawQuizId := chi.URLParam(r, "id")
+
+	if rawQuizId == "" {
+		payload := m.WrapperUtil.ErrorResponseWrap("quiz id is required", nil)
+		m.HttpUtil.WriteJson(w, http.StatusUnsupportedMediaType, payload)
+		return
+	}
+
+	quizId, err := uuid.Parse(rawQuizId)
+
+	if err != nil {
+		payload := m.WrapperUtil.ErrorResponseWrap("quiz id is not valid", nil)
+		m.HttpUtil.WriteJson(w, http.StatusUnsupportedMediaType, payload)
+		return
+	}
+
+	user, ok := r.Context().Value(guard.UserContext).(authToken.UserClaim)
+
+	if !ok {
+		m.Logger.Error("Context is not found")
+		payload := m.WrapperUtil.ErrorResponseWrap("internal server error", nil)
+		m.HttpUtil.WriteJson(w, http.StatusInternalServerError, payload)
+		return
+	}
+
+	detail, err := m.GetSolutionQuiz(r.Context(), quizId, user.Email)
+
+	if err != nil {
+		respErr, ok := err.(web.ResponseError)
+		if ok {
+			if respErr.Code == "ERR_NOT_ALLOWED" {
+				payload := m.WrapperUtil.ErrorResponseWrap(respErr.Error(), respErr)
+				m.HttpUtil.WriteJson(w, http.StatusForbidden, payload)
+			} else {
+				payload := m.WrapperUtil.ErrorResponseWrap(respErr.Error(), respErr)
+				m.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+			}
+		} else {
+			payload := m.WrapperUtil.ErrorResponseWrap("internal server error", nil)
+			m.HttpUtil.WriteJson(w, http.StatusInternalServerError, payload)
+		}
+		return
+	}
+
+	responsePayload := m.WrapperUtil.SuccessResponseWrap(detail)
+	m.HttpUtil.WriteSuccessJson(w, responsePayload)
+}
+
+// Index godoc
+//
+//	@Tags					quiz
+//	@Summary			Finish Quiz
+//	@Description	Finish quiz session and get the score
+//	@Produce			json
+//	@Accept				json
+//	@Param				Authorization	header		string										true "Authenticate User (any role)"
+//	@Param			  data	body		quiz.FinishQuizPayload							true	"Quiz Finish payload"
+//	@Param				id path string true "Quiz id" Format(uuid)
+//	@Success			200	{object}	web.BaseResponse{data=quiz.QuizDetail}
+//	@Router				/quiz/{id}/take [post]
+func (m QuizHandlerImpl) FinishQuiz(w http.ResponseWriter, r *http.Request) {
+	payload := quiz.FinishQuizPayload{}
+
+	/* Get user */
+	user, ok := r.Context().Value(guard.UserContext).(authToken.UserClaim)
+
+	if !ok {
+		m.Logger.Error("Context is not found")
+		payload := m.WrapperUtil.ErrorResponseWrap("internal server error", nil)
+		m.HttpUtil.WriteJson(w, http.StatusInternalServerError, payload)
+		return
+	}
+	/* Get user */
+
+	/* Validate input */
+	validate := validator.New()
+
+	if r.Header.Get("Content-Type") != "application/json" {
+		payload := m.WrapperUtil.ErrorResponseWrap("this service only receive json input", nil)
+		m.HttpUtil.WriteJson(w, http.StatusUnsupportedMediaType, payload)
+		return
+	}
+
+	if err := m.HttpUtil.ParseJson(r, &payload); err != nil {
+		payload := m.WrapperUtil.ErrorResponseWrap("invalid json input", err.Error())
+		m.HttpUtil.WriteJson(w, http.StatusUnprocessableEntity, payload)
+		return
+	}
+
+	if err := validate.Struct(payload); err != nil {
+		if _, ok := err.(*validator.InvalidValidationError); ok {
+			payload := m.WrapperUtil.ErrorResponseWrap(err.Error(), nil)
+			m.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+			return
+		}
+
+		errPayload := web.NewResponseErrorFromValidator(err.(validator.ValidationErrors))
+		payload := m.WrapperUtil.ErrorResponseWrap(errPayload.Error(), errPayload)
+		m.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+		return
+	}
+	/* End of validate */
+
+	/* Get quiz id */
+	rawQuizId := chi.URLParam(r, "id")
+
+	if rawQuizId == "" {
+		payload := m.WrapperUtil.ErrorResponseWrap("quiz id is required", nil)
+		m.HttpUtil.WriteJson(w, http.StatusUnsupportedMediaType, payload)
+		return
+	}
+
+	quizId, err := uuid.Parse(rawQuizId)
+
+	if err != nil {
+		payload := m.WrapperUtil.ErrorResponseWrap("quiz id is not valid", nil)
+		m.HttpUtil.WriteJson(w, http.StatusUnsupportedMediaType, payload)
+		return
+	}
+	/* end of get quiz id */
+
+	res, err := m.DoFinishQuiz(r.Context(), quizId, user.Email, payload.Data)
+
+	if err != nil {
+		respErr, ok := err.(web.ResponseError)
+		if ok {
+			payload := m.WrapperUtil.ErrorResponseWrap(respErr.Error(), respErr)
+			m.HttpUtil.WriteJson(w, http.StatusBadRequest, payload)
+		} else {
+			payload := m.WrapperUtil.ErrorResponseWrap("internal server error", nil)
+			m.HttpUtil.WriteJson(w, http.StatusInternalServerError, payload)
+		}
+		return
+	}
+
+	responsePayload := m.WrapperUtil.SuccessResponseWrap(res)
+	m.HttpUtil.WriteSuccessJson(w, responsePayload)
+}
diff --git a/handler/quiz/type.go b/handler/quiz/type.go
index 2c9d3e03d76b678496942f6101f39a27b074d2a3..8c3bf6f5567cf7f04be9e42b67558279a0f6159d 100644
--- a/handler/quiz/type.go
+++ b/handler/quiz/type.go
@@ -5,4 +5,8 @@ import "net/http"
 type QuizHandler interface {
 	GetAllQuizes(w http.ResponseWriter, r *http.Request)
 	GetQuizDetail(w http.ResponseWriter, r *http.Request)
+
+	TakeQuiz(w http.ResponseWriter, r *http.Request)
+	GetQuizSolution(w http.ResponseWriter, r *http.Request)
+	FinishQuiz(w http.ResponseWriter, r *http.Request)
 }
diff --git a/middleware/guard/builder.go b/middleware/guard/builder.go
index 75850ebf45a8ef08662c76311156cd2a067a4ff3..c0f06a9e6c2324734c1db6f64e5b5eb8e34f46d8 100644
--- a/middleware/guard/builder.go
+++ b/middleware/guard/builder.go
@@ -10,7 +10,9 @@ import (
 )
 
 type GuardBuilder struct {
-	GuardMiddleware
+	token.TokenUtil
+	logger.Logger
+	wrapper.WrapperUtil
 }
 
 func NewBuilder(
@@ -19,25 +21,19 @@ func NewBuilder(
 	wrapper wrapper.WrapperUtil,
 ) *GuardBuilder {
 	return &GuardBuilder{
-		GuardMiddleware{
-			Token:       token,
-			Role:        []user.UserRole{},
-			Logger:      logger,
-			WrapperUtil: wrapper,
-		},
+		token,
+		logger,
+		wrapper,
 	}
 }
 
-func (g *GuardBuilder) AddRole(role ...user.UserRole) *GuardBuilder {
-	g.GuardMiddleware.Role = role
-	return g
-}
-
-func (g *GuardBuilder) Build() func(http.Handler) http.Handler {
-	return g.GuardMiddleware.Handle
-}
+func (g *GuardBuilder) Build(role ...user.UserRole) func(http.Handler) http.Handler {
+	handler := &GuardMiddleware{
+		Token:       g.TokenUtil,
+		Role:        role,
+		Logger:      g.Logger,
+		WrapperUtil: g.WrapperUtil,
+	}
 
-func (g *GuardBuilder) BuildSimple(role user.UserRole) func(http.Handler) http.Handler {
-	g.AddRole(role)
-	return g.Build()
+	return handler.Handle
 }
diff --git a/model/domain/quiz/answer.go b/model/domain/quiz/answer.go
deleted file mode 100644
index 477b2039d253b51934420202f7e1c34adbb23dac..0000000000000000000000000000000000000000
--- a/model/domain/quiz/answer.go
+++ /dev/null
@@ -1,8 +0,0 @@
-package quiz
-
-import "github.com/google/uuid"
-
-type Answer struct {
-	QuestionId uuid.UUID
-	OptionId   uuid.UUID
-}
diff --git a/model/domain/quiz/option.go b/model/domain/quiz/option.go
deleted file mode 100644
index 6f3af1fb082860285b9d141abb98245fe0d723f8..0000000000000000000000000000000000000000
--- a/model/domain/quiz/option.go
+++ /dev/null
@@ -1,9 +0,0 @@
-package quiz
-
-import "github.com/google/uuid"
-
-type Option struct {
-	Id       uuid.UUID `json:"id"`
-	Text     string    `json:"text"`
-	IsAnswer bool      `json:"is_answer"`
-}
diff --git a/model/domain/quiz/problem.go b/model/domain/quiz/problem.go
new file mode 100644
index 0000000000000000000000000000000000000000..7794b7f4355177f0ce5a948d11c6ff3f62aa89de
--- /dev/null
+++ b/model/domain/quiz/problem.go
@@ -0,0 +1,38 @@
+package quiz
+
+import "github.com/google/uuid"
+
+type QuizMedia struct {
+	Id   uuid.UUID `json:"id"`
+	Url  string    `json:"url"`
+	Type string    `json:"type"`
+}
+
+type AnswerOption struct {
+	Id         uuid.UUID   `json:"id"`
+	MediaId    []uuid.UUID `json:"media_id"`
+	Answer     string      `json:"answer"`
+	IsSolution *bool       `json:"is_solution"`
+}
+
+type QuizProblem struct {
+	Id       uuid.UUID      `json:"id"`
+	MediaId  []uuid.UUID    `json:"media_id"`
+	Question string         `json:"question"`
+	Answer   []AnswerOption `json:"answers"`
+}
+
+type QuizDetail struct {
+	Id          uuid.UUID     `json:"id"`
+	Name        string        `json:"name"`
+	CourseId    string        `json:"course_id"`
+	Description string        `json:"description"`
+	Help        string        `json:"help"`
+	Media       []QuizMedia   `json:"media"`
+	Problems    []QuizProblem `json:"problems"`
+}
+
+type Response struct {
+	ProblemId uuid.UUID `json:"problem_id"`
+	AnswerId  uuid.UUID `json:"answer_id"`
+}
diff --git a/model/domain/quiz/question.go b/model/domain/quiz/question.go
deleted file mode 100644
index d8b5fdfea2ca012266489b05e2ced985cbdb75d2..0000000000000000000000000000000000000000
--- a/model/domain/quiz/question.go
+++ /dev/null
@@ -1,9 +0,0 @@
-package quiz
-
-import "github.com/google/uuid"
-
-type Question struct {
-	Id          uuid.UUID `json:"id"`
-	Description string    `json:"string"`
-	Options     []Option  `json:"options"`
-}
diff --git a/model/domain/quiz/quiz.go b/model/domain/quiz/quiz.go
index 1300dbc89fddcec83976bbaa726125d1e7a13e86..896536cc66c3ffbca9840836c446019b139e8074 100644
--- a/model/domain/quiz/quiz.go
+++ b/model/domain/quiz/quiz.go
@@ -6,7 +6,7 @@ import (
 
 type Quiz struct {
 	Id           uuid.UUID `gorm:"primaryKey" json:"id"`
-	Name         string    `json:"name"`
+	Name         string    `json:"nama"`
 	CourseId     string    `json:"course_id"`
 	CreatorEmail string    `json:"creator_email"`
 	QuizPath     string    `json:"-"`
diff --git a/model/web/quiz/finish.go b/model/web/quiz/finish.go
new file mode 100644
index 0000000000000000000000000000000000000000..80c7335963d5977527460cf5ada30201865723e4
--- /dev/null
+++ b/model/web/quiz/finish.go
@@ -0,0 +1,7 @@
+package quiz
+
+import "gitlab.informatika.org/ocw/ocw-backend/model/domain/quiz"
+
+type FinishQuizPayload struct {
+	Data []quiz.Response `json:"data"`
+}
diff --git a/provider/storage/manager.go b/provider/storage/manager.go
index cc87edd73acda90734470345e5fd3ea1230a1280..cfeae57144fe4d23729a2382984360253e5d4659 100644
--- a/provider/storage/manager.go
+++ b/provider/storage/manager.go
@@ -9,3 +9,16 @@ import (
 func (s S3Storage) Delete(ctx context.Context, path string) error {
 	return s.minio.RemoveObject(ctx, s.env.BucketName, path, minio.RemoveObjectOptions{})
 }
+
+func (s S3Storage) Get(ctx context.Context, path string) ([]byte, error) {
+	result := []byte{}
+	obj, err := s.minio.GetObject(ctx, s.env.BucketName, path, minio.GetObjectOptions{})
+
+	if err != nil {
+		return result, err
+	}
+
+	_, err = obj.Read(result)
+
+	return result, err
+}
diff --git a/provider/storage/type.go b/provider/storage/type.go
index dc7cdd2f97597d8760d26aa2b75791989a12ff9f..19f2a46fb4d9044839660ba4234f47f5f661f0d2 100644
--- a/provider/storage/type.go
+++ b/provider/storage/type.go
@@ -9,4 +9,5 @@ type Storage interface {
 	CreatePutSignedLink(ctx context.Context, path string) (string, error)
 	CreateGetSignedLink(ctx context.Context, path string, reqParam url.Values) (string, error)
 	Delete(ctx context.Context, path string) error
+	Get(ctx context.Context, path string) ([]byte, error)
 }
diff --git a/repository/quiz/impl.go b/repository/quiz/impl.go
index 03665df4d4915b3c188da6e737bed27e7dc1582d..e51495422f1a10911dd47bf00b1764eb541446ab 100644
--- a/repository/quiz/impl.go
+++ b/repository/quiz/impl.go
@@ -86,3 +86,12 @@ func (q *QuizRepositoryImpl) GetAllTake(quizId uuid.UUID, userEmail string) ([]q
 
 	return result, err
 }
+
+func (q *QuizRepositoryImpl) GetLastTake(quizId uuid.UUID, userEmail string) (*quiz.QuizTake, error) {
+	result := &quiz.QuizTake{}
+	err := q.db.
+		Where("quiz_id = ? AND email = ?", quizId, userEmail).
+		Last(result).Error
+
+	return result, err
+}
diff --git a/repository/quiz/type.go b/repository/quiz/type.go
index 0fc33d4d153ff2f8eabaea5cc9b44be16be724e7..1b4e0cbeca391ec136dfc8c696d1c058d49e55e4 100644
--- a/repository/quiz/type.go
+++ b/repository/quiz/type.go
@@ -12,4 +12,5 @@ type QuizRepository interface {
 	NewTake(quizId uuid.UUID, userEmail string) (uuid.UUID, error)
 	IsActiveTake(quizId uuid.UUID, userEmail string) (bool, error)
 	GetAllTake(quizId uuid.UUID, userEmail string) ([]quiz.QuizTake, error)
+	GetLastTake(quizId uuid.UUID, userEmail string) (*quiz.QuizTake, error)
 }
diff --git a/routes/admin/route.go b/routes/admin/route.go
index d1ff589b86faa181e6e671bf7111ab3efed0b239..d1fe8e2213ad86d7b7bdd1ecf4fcac90ab8f60a5 100644
--- a/routes/admin/route.go
+++ b/routes/admin/route.go
@@ -14,7 +14,7 @@ type AdminRoutes struct {
 
 func (adr AdminRoutes) Register(r chi.Router) {
 	r.Route("/admin", func(r chi.Router) {
-		r.Use(adr.GuardBuilder.BuildSimple(user.Admin))
+		r.Use(adr.GuardBuilder.Build(user.Admin))
 
 		r.Get("/user", adr.AdminHandler.GetAllUser)
 		r.Get("/user/{email}", adr.AdminHandler.GetUserByEmail)
diff --git a/routes/course/route.go b/routes/course/route.go
index 23cb9f533b686bbf87655fcf1186ff319f1a0f6a..43a8305f4187ad99c9e7baadea375a59f373ad37 100644
--- a/routes/course/route.go
+++ b/routes/course/route.go
@@ -36,7 +36,7 @@ func (c CourseRoutes) Register(r chi.Router) {
 	})
 
 	r.Route("/course/{id}/material", func(r chi.Router) {
-		r.Use(c.BuildSimple(user.Contributor))
+		r.Use(c.Build(user.Contributor))
 		r.Post("/", c.MaterialHandler.CreateMaterial)
 	})
 }
diff --git a/routes/material/route.go b/routes/material/route.go
index 39a9408ee968113a716969bf0482b71e5073ccd9..41126ecf7b9b60c1f56f9bd77208e9486db51ef0 100644
--- a/routes/material/route.go
+++ b/routes/material/route.go
@@ -17,7 +17,7 @@ func (c MaterialRoutes) Register(r chi.Router) {
 		r.Get("/", c.DetailMaterial)
 
 		r.Route("/", func(r chi.Router) {
-			r.Use(c.GuardBuilder.BuildSimple(user.Contributor))
+			r.Use(c.GuardBuilder.Build(user.Contributor))
 
 			// Add
 			r.Post("/content", c.AddContent)
diff --git a/routes/quiz/route.go b/routes/quiz/route.go
index 58dbb0deb323c33a1138db79b8692b79aad0c5c0..b89269412c9add8ccc39a190a965f187a13c15b9 100644
--- a/routes/quiz/route.go
+++ b/routes/quiz/route.go
@@ -3,13 +3,37 @@ package quiz
 import (
 	"github.com/go-chi/chi/v5"
 	"gitlab.informatika.org/ocw/ocw-backend/handler/quiz"
+	"gitlab.informatika.org/ocw/ocw-backend/middleware/guard"
+	"gitlab.informatika.org/ocw/ocw-backend/model/domain/user"
 )
 
 type QuizRoutes struct {
 	quiz.QuizHandler
+	*guard.GuardBuilder
 }
 
 func (q QuizRoutes) Register(r chi.Router) {
 	r.Get("/course/{id}/quiz", q.QuizHandler.GetAllQuizes)
 	r.Get("/quiz/{id}", q.QuizHandler.GetQuizDetail)
+
+	guard := q.GuardBuilder.Build(
+		user.Student,
+		user.Contributor,
+		user.Admin,
+	)
+
+	r.Route("/quiz/{id}/take", func(r chi.Router) {
+		r.Use(guard)
+		r.Post("/", q.QuizHandler.TakeQuiz)
+	})
+
+	r.Route("/quiz/{id}/finish", func(r chi.Router) {
+		r.Use(guard)
+		r.Post("/", q.QuizHandler.FinishQuiz)
+	})
+
+	r.Route("/quiz/{id}/solution", func(r chi.Router) {
+		r.Use(guard)
+		r.Get("/", q.QuizHandler.GetQuizSolution)
+	})
 }
diff --git a/service/course/add.go b/service/course/add.go
index dc42d5698abbb725b15e52d533ffd7ef9c719226..a94a59b6e56c8d465adf46559d3877dff50b34e0 100644
--- a/service/course/add.go
+++ b/service/course/add.go
@@ -132,7 +132,7 @@ func (c CourseServiceImpl) AddFaculty(payload faculty.AddFacultyRequestPayload)
 
 	// Unauthorized Role
 	if claim.Role != user.Admin {
-		return web.NewResponseErrorFromError(err, web.UnauthorizedAccess)
+		return web.NewResponseError("user is not allowed to access this resources", web.UnauthorizedAccess)
 	}
 
 	id, err := uuid.NewUUID()
diff --git a/service/quiz/impl.go b/service/quiz/impl.go
index 5bf6171e4d6fd4535810463b454f7bae90b93c9c..3898cd448978c6604f71f68e7561077c9c396a00 100644
--- a/service/quiz/impl.go
+++ b/service/quiz/impl.go
@@ -1,13 +1,20 @@
 package quiz
 
 import (
+	"bytes"
+	"context"
+	"encoding/json"
+
 	"github.com/google/uuid"
 	"gitlab.informatika.org/ocw/ocw-backend/model/domain/quiz"
+	"gitlab.informatika.org/ocw/ocw-backend/model/web"
+	"gitlab.informatika.org/ocw/ocw-backend/provider/storage"
 	quizRepo "gitlab.informatika.org/ocw/ocw-backend/repository/quiz"
 )
 
 type QuizServiceImpl struct {
 	quizRepo.QuizRepository
+	storage.Storage
 }
 
 func (q QuizServiceImpl) ListAllQuiz(courseId string) ([]quiz.Quiz, error) {
@@ -17,3 +24,149 @@ func (q QuizServiceImpl) ListAllQuiz(courseId string) ([]quiz.Quiz, error) {
 func (q QuizServiceImpl) GetQuizDetail(quizId uuid.UUID) (*quiz.Quiz, error) {
 	return q.QuizRepository.GetQuizDetail(quizId)
 }
+
+func (q QuizServiceImpl) getQuizDetail(ctx context.Context, quizId uuid.UUID) (*quiz.QuizDetail, error) {
+	detail, err := q.QuizRepository.GetQuizDetail(quizId)
+
+	if err != nil {
+		return nil, err
+	}
+
+	payload, err := q.Storage.Get(ctx, detail.QuizPath)
+
+	if err != nil {
+		return nil, err
+	}
+
+	result := &quiz.QuizDetail{}
+
+	decoder := json.NewDecoder(bytes.NewReader(payload))
+	err = decoder.Decode(result)
+
+	return result, err
+}
+
+func (q QuizServiceImpl) DoTakeQuiz(ctx context.Context, quizId uuid.UUID, email string) (*quiz.QuizDetail, error) {
+	result, err := q.getQuizDetail(ctx, quizId)
+
+	if err != nil {
+		return nil, err
+	}
+
+	taken, err := q.IsActiveTake(quizId, email)
+
+	if err != nil {
+		return nil, err
+	}
+
+	if !taken {
+		_, err = q.NewTake(quizId, email)
+
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	for i := range result.Problems {
+		for j := range result.Problems[i].Answer {
+			result.Problems[i].Answer[j].IsSolution = nil
+		}
+	}
+
+	return result, nil
+}
+
+func (q QuizServiceImpl) GetSolutionQuiz(ctx context.Context, quizId uuid.UUID, email string) (*quiz.QuizDetail, error) {
+	result, err := q.getQuizDetail(ctx, quizId)
+
+	if err != nil {
+		return nil, err
+	}
+
+	_, err = q.GetLastTake(quizId, email)
+
+	if err != nil {
+		return nil, err
+	}
+
+	taken, err := q.IsActiveTake(quizId, email)
+
+	if err != nil {
+		return nil, err
+	}
+
+	if taken {
+		return nil, web.NewResponseError("user is not allow to access this data", "ERR_NOT_ALLOWED")
+	}
+
+	return result, nil
+}
+
+func (q QuizServiceImpl) checkAnswer(detail *quiz.QuizDetail, studentAnswer []quiz.Response) float64 {
+	answerDict := map[uuid.UUID][]uuid.UUID{}
+	totalProblem := len(detail.Problems)
+
+	for _, problem := range detail.Problems {
+		correctAnswerId := []uuid.UUID{}
+		for _, answer := range problem.Answer {
+			if *answer.IsSolution {
+				correctAnswerId = append(correctAnswerId, answer.Id)
+			}
+		}
+
+		answerDict[problem.Id] = correctAnswerId
+	}
+
+	correctAnswer := 0
+	for _, responseItem := range studentAnswer {
+		numCorrect := 0
+
+		for _, correctId := range answerDict[responseItem.ProblemId] {
+			if responseItem.AnswerId == correctId {
+				numCorrect++
+			}
+		}
+
+		if numCorrect == len(answerDict[responseItem.ProblemId]) {
+			correctAnswer++
+		}
+	}
+
+	return float64(correctAnswer) / float64(totalProblem) * 100
+}
+
+func (q QuizServiceImpl) DoFinishQuiz(ctx context.Context, quizId uuid.UUID, email string, studentAnswer []quiz.Response) (*quiz.QuizTake, error) {
+	taken, err := q.IsActiveTake(quizId, email)
+
+	if err != nil {
+		return nil, err
+	}
+
+	if !taken {
+		return nil, web.NewResponseError("user not yet do take the quiz", "NOT_TAKEN_QUIZ_YET")
+	}
+
+	result, err := q.getQuizDetail(ctx, quizId)
+
+	if err != nil {
+		return nil, err
+	}
+
+	score := q.checkAnswer(result, studentAnswer)
+
+	data, err := q.QuizRepository.GetLastTake(quizId, email)
+	data.IsFinished = true
+	data.Score = int(score)
+
+	if err != nil {
+		return nil, err
+	}
+
+	err = q.QuizRepository.UpdateScore(data.Id, int(score))
+
+	if err != nil {
+		return nil, err
+	}
+
+	return data, nil
+}
diff --git a/service/quiz/type.go b/service/quiz/type.go
index f7d0f72eb3a7a148c1e324a5ff800f99d38f5304..7c97e4965500fb25f75c19a4117c536559fcf9a8 100644
--- a/service/quiz/type.go
+++ b/service/quiz/type.go
@@ -1,6 +1,8 @@
 package quiz
 
 import (
+	"context"
+
 	"github.com/google/uuid"
 	"gitlab.informatika.org/ocw/ocw-backend/model/domain/quiz"
 )
@@ -8,4 +10,8 @@ import (
 type QuizService interface {
 	ListAllQuiz(courseId string) ([]quiz.Quiz, error)
 	GetQuizDetail(quizId uuid.UUID) (*quiz.Quiz, error)
+
+	DoTakeQuiz(ctx context.Context, quizId uuid.UUID, email string) (*quiz.QuizDetail, error)
+	DoFinishQuiz(ctx context.Context, quizId uuid.UUID, email string, studentAnswer []quiz.Response) (*quiz.QuizTake, error)
+	GetSolutionQuiz(ctx context.Context, quizId uuid.UUID, email string) (*quiz.QuizDetail, error)
 }