diff --git a/src/main.rs b/src/main.rs
index 976144819d6df23875539d9d50664b54e5c37426..2b314144ebc12410a71a55b6cbee438975048a45 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -63,7 +63,9 @@ async fn main() -> std::io::Result<()> {
                             .service(service::get_page_data)
                             .service(service::update_page)
                             .service(service::files::post_files)
-                            .service(service::files::delete_static_file),
+                            .service(service::files::delete_static_file)
+                            .service(service::add_template)
+                            .service(service::update_template),
                     ),
             )
             .service(service::files::favicon)
diff --git a/src/service/website.rs b/src/service/website.rs
index a7242a3b5a8cb3736e56159123f3d90d44206f01..1c5f1da042dedbccb475bb47f3d314762da26807 100644
--- a/src/service/website.rs
+++ b/src/service/website.rs
@@ -1,4 +1,4 @@
-use crate::website::{Page, WebSite};
+use crate::website::{Page, PageTemplate, WebSite};
 use actix_web::{
     get, post, put,
     web::{Data, Json},
@@ -23,7 +23,7 @@ pub async fn add_page(
         .expect("Couldn't acquire website write lock")
         .add_page(add_page_data.parent_page_id, add_page_data.new_page.clone())
     {
-        Ok(()) => HttpResponse::Ok().finish(),
+        Ok(()) => HttpResponse::Created().finish(),
         Err(msg) => {
             HttpResponse::BadRequest().body(format!("Error adding new page to website - {}", msg))
         }
@@ -53,11 +53,11 @@ pub async fn update_page(
     updated_page: Json<Page>,
 ) -> HttpResponse {
     let id = id.into_inner();
-    let updated_page = updated_page.into_inner();
+
     match website
         .write()
         .expect("Couldn't acquire website write lock")
-        .update_page(id, updated_page)
+        .update_page(id, updated_page.into_inner())
     {
         Ok(page) => HttpResponse::Ok().json(page),
         Err(msg) => {
@@ -65,3 +65,46 @@ pub async fn update_page(
         }
     }
 }
+
+#[post("/add-template")]
+pub async fn add_template(
+    website: Data<RwLock<WebSite>>,
+    new_template: Json<PageTemplate>,
+) -> HttpResponse {
+    match website
+        .write()
+        .expect("Couldn't acquire website write lock")
+        .add_template(new_template.into_inner())
+    {
+        Ok(template) => HttpResponse::Created().json(template),
+        Err(msg) => HttpResponse::BadRequest().body(format!("Error adding new template {}", msg)),
+    }
+}
+
+#[post("/update-template")]
+pub async fn update_template(
+    website: Data<RwLock<WebSite>>,
+    updated_template: Json<PageTemplate>,
+) -> HttpResponse {
+    let updated = {
+        let mut ws = website
+            .write()
+            .expect("Couldn't acquire website write lock");
+        match ws.update_template(updated_template.into_inner()) {
+            Ok(template) => template.clone(),
+            Err(msg) => {
+                return HttpResponse::BadRequest().body(format!("Error updating template {}", msg))
+            }
+        }
+    };
+
+    WebSite::update_page_rec_after_template_update(
+        &mut website
+            .write()
+            .expect("Couldn't acquire website write lock")
+            .root_page,
+        &updated,
+    );
+
+    HttpResponse::Ok().json(updated)
+}
diff --git a/src/website/mod.rs b/src/website/mod.rs
index c1c6ad901df80cf18aef76011857b658ab59c3cf..19c8a3fe3d294136b4e906832a6bb4896409b663 100644
--- a/src/website/mod.rs
+++ b/src/website/mod.rs
@@ -3,5 +3,5 @@ mod html;
 mod page;
 mod website;
 
-pub use page::Page;
+pub use page::*;
 pub use website::*;
diff --git a/src/website/page.rs b/src/website/page.rs
index cc95c8857eb642b9b806b7aab59d5cc91f97da0b..34fc43b977e954cd77affb61ff7b3ac006f4c0a1 100644
--- a/src/website/page.rs
+++ b/src/website/page.rs
@@ -249,6 +249,17 @@ impl Page {
         Ok(())
     }
 
+    pub fn update_template(&mut self, template: &PageTemplate) {
+        self.template = Some(template.clone());
+        self.template_name = template.name.to_owned();
+    }
+
+    pub fn update_template_if_same_name(&mut self, template: &PageTemplate) {
+        if self.template_name.eq(&template.name) {
+            self.update_template(template);
+        }
+    }
+
     pub fn set_template(&mut self, template: PageTemplate) {
         self.template = Some(template);
     }
@@ -286,6 +297,7 @@ impl Page {
             .find(|t| t.name == self.template_name)
             .expect("Page template not found")
     }
+
     fn write_to_static_file(
         &self,
         url: &PathBuf,
diff --git a/src/website/website.rs b/src/website/website.rs
index 2de39e99cd48f4341b02f34380f20b20ca4a09e8..946c180a32717c12e8a40db0358038918131ce22 100644
--- a/src/website/website.rs
+++ b/src/website/website.rs
@@ -19,7 +19,7 @@ pub struct WebSiteBuilder(WebSiteData);
 #[derive(Debug, Clone)]
 pub struct WebSite {
     last_generated_page_id: usize,
-    root_page: Page,
+    pub root_page: Page,
     pub static_files_manager: StaticFilesManager,
     templates: Vec<PageTemplate>,
 }
@@ -229,6 +229,83 @@ impl WebSite {
             None => Err(format!("Page with id {} was not found", id)),
         }
     }
+
+    fn validate_add_template(&self, template: &PageTemplate) -> Result<(), String> {
+        if !self.get_template(&template.name).is_none() {
+            return Err(format!(
+                "A template named \"{}\" already exists",
+                template.name
+            ));
+        }
+
+        if PageTemplate::get_page_body_placeholder(&mut template.clone().contents).is_err() {
+            return Err(format!(
+                "Page body container was not found in template named \"{}\"",
+                template.name
+            ));
+        }
+
+        Ok(())
+    }
+
+    fn validate_update_template(&self, template: &PageTemplate) -> Result<(), String> {
+        if self.get_template(&template.name).is_none() {
+            return Err(format!(
+                "Templated named \"{}\" was not found.",
+                template.name
+            ));
+        }
+
+        if PageTemplate::get_page_body_placeholder(&mut template.clone().contents).is_err() {
+            return Err(format!(
+                "Page body container was not found in template named \"{}\"",
+                template.name
+            ));
+        }
+
+        Ok(())
+    }
+
+    fn get_template(&self, name: &String) -> Option<&PageTemplate> {
+        self.templates.iter().find(|t| t.name.eq(name))
+    }
+
+    fn get_template_mut(&mut self, name: &String) -> Option<&mut PageTemplate> {
+        self.templates.iter_mut().find(|t| t.name.eq(name))
+    }
+
+    pub fn add_template(&mut self, new_template: PageTemplate) -> Result<&PageTemplate, String> {
+        match self.validate_add_template(&new_template) {
+            Ok(()) => {
+                let name = new_template.name.to_owned();
+                self.templates.push(new_template);
+                Ok(self.get_template(&name).unwrap())
+            }
+            Err(msg) => Err(msg),
+        }
+    }
+
+    pub fn update_template(
+        &mut self,
+        updated_template: PageTemplate,
+    ) -> Result<&PageTemplate, String> {
+        match self.validate_update_template(&updated_template) {
+            Ok(()) => {
+                let template = self.get_template_mut(&updated_template.name).unwrap();
+                *template = updated_template;
+
+                Ok(template)
+            }
+            Err(msg) => Err(msg),
+        }
+    }
+
+    pub fn update_page_rec_after_template_update(page: &mut Page, template: &PageTemplate) {
+        page.update_template_if_same_name(template);
+        for sp in page.sub_pages.iter_mut() {
+            Self::update_page_rec_after_template_update(sp, template);
+        }
+    }
 }
 
 #[cfg(test)]
@@ -320,4 +397,79 @@ mod test_website {
 
         remove_test_dir(&test_dir);
     }
+
+    #[test]
+    fn add_template() {
+        let test_template: &'static str = "
+{
+    \"name\": \"TEST ADD TEMPLATE\",
+    \"layout\": {},
+    \"contents\": [
+        {
+            \"tag\": \"div\",
+            \"attrs\": {
+                \"class\": \"page-template\"
+            },
+            \"contents\": [
+                {
+                    \"tag\": \"header\",
+                    \"contents\": [
+                        {
+                            \"tag\": \"nav\"
+                        }
+                    ]
+                },
+                {
+                    \"tag\": \"div\",
+                    \"attrs\": {
+                        \"id\": \"page-body\"
+                    }
+                },
+                {
+                    \"tag\": \"footer\"
+                }
+            ]
+        }
+    ]
+}
+        ";
+
+        let test_dir = PathBuf::from("./test");
+        let mut ws = test_website(&test_dir);
+
+        let new_template: PageTemplate = serde_json::from_str(test_template).unwrap();
+
+        let add_template_res = ws.add_template(new_template);
+        assert!(add_template_res.is_ok());
+
+        let added_template = add_template_res.unwrap();
+        assert_eq!(added_template.name, "TEST ADD TEMPLATE");
+
+        remove_test_dir(&test_dir);
+    }
+
+    #[test]
+    fn test_update_template() {
+        let test_dir = PathBuf::from("./test");
+        let ws = test_website(&test_dir);
+        let (updated, mut ws) = {
+            let mut ws = ws;
+            let mut template = ws
+                .get_template(&"TEST TEMPLATE".to_string())
+                .unwrap()
+                .clone();
+
+            template.contents[0].tag = "changed_tag".to_owned();
+
+            let updated = ws.update_template(template).unwrap();
+            assert_eq!(updated.contents[0].tag, "changed_tag");
+            (updated.clone(), ws)
+        };
+
+        WebSite::update_page_rec_after_template_update(&mut ws.root_page, &updated);
+        for p in ws.get_all_pages_as_vec() {
+            assert_eq!(p.template.as_ref().unwrap().contents[0].tag, "changed_tag");
+        }
+        remove_test_dir(&test_dir);
+    }
 }