diff --git a/api-backend/src/UNAM/Tupa/Backend/API/Endpoints/v1/funciones/funciones.php b/api-backend/src/UNAM/Tupa/Backend/API/Endpoints/v1/funciones/funciones.php
new file mode 100644
index 0000000000000000000000000000000000000000..e0fdc7a90a86fe2237182bc2e3241118ea177eae
--- /dev/null
+++ b/api-backend/src/UNAM/Tupa/Backend/API/Endpoints/v1/funciones/funciones.php
@@ -0,0 +1,386 @@
+<?php
+namespace UNAM\Tupa\Backend\API\Endpoints\v1\funciones;
+
+use SIUToba\rest\lib\rest_error;
+use SIUToba\rest\lib\rest_hidratador;
+use SIUToba\rest\lib\rest_validador;
+use SIUToba\rest\rest;
+
+use UNAM\Tupa\Core\Errors\ErrorTupa;
+use UNAM\Tupa\Backend\API\Factory;
+use UNAM\Tupa\Core\Filtros\Filtro;
+use UNAM\Tupa\Core\Negocio\SolicitudesServicios\Funcion;
+
+
+
+class funciones implements \SIUToba\rest\lib\modelable
+{
+    public static function _get_modelos()
+    {
+        $vigenciaFin = [
+            'vigencia_fin' => [
+                'type' => 'date',
+                '_validar' => [
+                    rest_validador::TIPO_DATE => [
+                        'format' => 'Y-m-d'
+                    ],
+                ],
+            ]         
+        ];
+
+        $funcionEdit = [
+            'nombre' => [
+                'type' => 'string',
+                'required' => true,
+                '_validar' => array(
+                    rest_validador::OBLIGATORIO,
+                ),
+            ],
+            'descripcion' => [
+                'type' => 'string',
+                'required' => true,
+                '_validar' => array(
+                    rest_validador::OBLIGATORIO,
+                ),
+            ],
+            'es_agrupador' => [
+                'type' => 'boolean',
+            ],
+            'vigencia_inicio' => [
+                'type' => 'date',
+                '_validar' => [
+                    rest_validador::TIPO_DATE => [
+                        'format' => 'Y-m-d'
+                    ],
+                ],
+            ],
+            'vigencia_fin' => [
+                'type' => 'date',
+                '_validar' => [
+                    rest_validador::TIPO_DATE => [
+                        'format' => 'Y-m-d'
+                    ],
+                ],
+            ],
+            'id_funcion_padre' => [
+                'type' => 'integer',
+            ],
+            'id_funcion_predecesor' => [
+                'type' => 'integer',
+            ],
+            'id_servicio' => [
+                'type' => 'integer',
+                'required' => true,
+                '_validar' => [
+                    rest_validador::OBLIGATORIO,
+                ],
+            ]  
+        ];
+
+        $funcion = array_merge(
+            array(
+                'id_funcion' => array(
+                    'type' => 'integer',
+                ),
+            ),
+            $funcionEdit
+        );
+
+        return $models = array(
+            'Funcion' => $funcion,
+            'FuncionEdit' => $funcionEdit,
+            'VigenciaFin' => $vigenciaFin
+        );
+    }
+
+    protected function get_spec_usuario($tipo = 'Funcion')
+    {
+        $m = $this->_get_modelos();
+
+        return $m[$tipo];
+    }
+
+    /**
+     * Se consume en GET /funciones/{id}.
+     *
+     * @summary Retorna datos de una funcion
+     * @responses 200 {"$ref": "Funcion"} Funcion
+     * @responses 404 No existe el recurso
+     * @responses 500 Error interno del servidor
+     */
+    public function get($id)
+    {
+        try {
+            $manager = Factory::getManagerFuncion();
+
+            $funcion = $manager->getFuncion($id);
+
+            $fila = rest_hidratador::hidratar_fila($this->get_spec_usuario('Funcion'), $funcion->toArray());
+
+            rest::response()->get($fila);
+        } catch (ErrorTupa $e) {
+            Factory::getMainLogger()->error($e->getMessage());
+            rest::response()->not_found();
+        } catch (\Exception $e) {
+            Factory::getMainLogger()->error($e->getMessage());
+            rest::response()->error_negocio('Error interno del servidor', 500);
+        }
+    }
+
+    /**
+     * Se consume en GET /funciones.
+     *
+     * @summary Retorna las funciones existentes
+     * @param_query $nombre string Se define como 'condicion;valor' donde 'condicion' puede ser contiene|no_contiene|comienza_con|termina_con|es_igual_a|es_distinto_de
+     * @param_query $descripcion string Se define como 'condicion;valor' donde 'condicion' puede ser es_menor_que|es_menor_igual_que|es_igual_a|es_distinto_de|es_mayor_igual_que|es_mayor_que|entre
+     * @param_query $id_servicio integer Se define como 'condicion;valor' donde 'condicion' puede ser es_menor_que|es_menor_igual_que|es_igual_a|es_distinto_de|es_mayor_igual_que|es_mayor_que|entre
+     * @param_query $id_funcion_padre string Se define como 'condicion;valor' donde 'condicion' puede ser es_menor_que|es_menor_igual_que|es_igual_a|es_distinto_de|es_mayor_igual_que|es_mayor_que|entre
+     * @param_query $id_funcion_predecesor string Se define como 'condicion;valor' donde 'condicion' puede ser es_menor_que|es_menor_igual_que|es_igual_a|es_distinto_de|es_mayor_igual_que|es_mayor_que|entre
+     * @param_query $vigencia_inicio string Se define como 'condicion;valor' donde 'condicion' puede ser es_menor_que|es_menor_igual_que|es_igual_a|es_distinto_de|es_mayor_igual_que|es_mayor_que|entre
+     * @param_query $vigencia_fin string Se define como 'condicion;valor' donde 'condicion' puede ser es_menor_que|es_menor_igual_que|es_igual_a|es_distinto_de|es_mayor_igual_que|es_mayor_que|entre
+     * @param_query $es_agrupador Boolean Es una funcion agrupadora de otras funciones
+     * @param_query $limit integer Limitar a esta cantidad de servicios
+     * @param_query $page integer Limitar desde esta pagina
+     * @param_query $order string +/-campo,...
+     * @responses 200 array {"$ref":"Funcion"}
+     * @responses 500 Error en los operadores ingresados para el filtro
+     */
+    public function get_list()
+    {
+        try {
+            $filtro = $this->get_filtro_get_list();
+
+            $filtro->setlimit(rest::request()->get('limit', null));
+            $filtro->setPage(rest::request()->get('page', null));
+            $filtro->setOrder(rest::request()->get('order', null));
+
+            $manager = Factory::getManagerFuncion();
+            $funciones = $manager->getFunciones($filtro);
+
+            $resultados = [];            
+            foreach ($funciones as $f) {
+                $resultados[] = $f->toArray();
+            }
+            
+            $registros = rest_hidratador::hidratar($this->get_spec_usuario('Funcion'), $resultados);
+
+            rest::response()->get($registros);
+        } catch (\Exception $e) {
+            Factory::getMainLogger()->error($e->getMessage());
+            rest::response()->error_negocio('Error interno del servidor', 500);
+        }
+    }
+
+    /**
+     * Se consume en GET /funciones/{id_funcion_padre}/hijas
+     *
+     * @summary Retorna las funciones hijas de una funcion padre
+     * @responses 200 array {"$ref":"Funcion"}
+     * @responses 500 Error en los operadores ingresados para el filtro
+     */
+    public function get_hijas_list($id)
+    {
+        try {
+            $filtro = $this->get_filtro_get_list();
+
+            $manager = Factory::getManagerFuncion();
+            $funciones = $manager->getFuncionesHijas($id);
+
+            $resultados = [];            
+            foreach ($funciones as $f) {
+                $resultados[] = $f->toArray();
+            }
+            
+            $registros = rest_hidratador::hidratar($this->get_spec_usuario('Funcion'), $resultados);
+
+            rest::response()->get($registros);
+        } catch (\Exception $e) {
+            Factory::getMainLogger()->error($e->getMessage());
+            rest::response()->error_negocio('Error interno del servidor', 500);
+        }
+    }
+
+    /**
+     * Se consume en GET /funciones/{id_funcion_predecesor}/sucesor
+     *
+     * @summary Retorna todas las funciones sucesoras de una funcion predecesora
+     * @responses 200 array {"$ref":"Funcion"}
+     * @responses 500 Error en los operadores ingresados para el filtro
+     */
+    public function get_sucesor_list($id)
+    {
+        try {
+            $filtro = $this->get_filtro_get_list();
+
+            $manager = Factory::getManagerFuncion();
+            $funciones = $manager->getFuncionesPredecesoras($id);
+
+            $resultados = [];            
+            foreach ($funciones as $f) {
+                $resultados[] = $f->toArray();
+            }
+            
+            $registros = rest_hidratador::hidratar($this->get_spec_usuario('Funcion'), $resultados);
+
+            rest::response()->get($registros);
+        } catch (\Exception $e) {
+            Factory::getMainLogger()->error($e->getMessage());
+            rest::response()->error_negocio('Error interno del servidor', 500);
+        }
+    }
+
+      /**
+     * Se consume en POST /funciones
+     *
+     * @summary Crea una nueva funcion
+     * @param_body $funciones FuncionEdit [required] los datos de la funcion
+     * @responses 201 {"string"} identificador de una funcion
+     * @responses 400 Funcion inválida
+     * @responses 500 Error interno
+     */
+    public function post_list()
+    {
+        // Valido y traduzco los datos al formato de mi modelo
+        $datos = $this->procesar_input_edicion('FuncionEdit',false);
+
+        try {
+            $manager = Factory::getManagerFuncion();
+ 
+            $funcion = new Funcion();
+            $funcion->loadFromDatos($datos);
+
+            $identificador = $manager->crear($funcion);
+     
+            $respuesta = [
+                'id_funcion' => $identificador[0]['id_funcion']
+            ];
+
+            rest::response()->post($respuesta);
+        } catch (rest_error $e) {
+            rest::response()->error_negocio($e->get_datalle(), 400);
+        } catch (\Exception $e) {
+            if ($e->getCode() >= 400 || $e->getCode() < 500) {
+                rest::response()->error_negocio([$e->getMessage()], 400);
+            } else {
+                rest::response()->error_negocio([$e->getMessage()], 500);
+            }
+        }
+    }
+
+      /**
+     * Se consume en PUT /funciones/{id}
+     *
+     * @summary Modifica una funcion
+     * @param_body $FuncinEdit FuncionEdit  [required] los datos a editar de una funcion
+     * @responses 204 El id es correcto
+     * @responses 400 El id no válido
+     * @responses 404 No existe el recurso
+     * @responses 500 Error interno
+     */
+    public function put($id)
+    {
+        $datos = $this->procesar_input_edicion('FuncionEdit');
+
+        try {
+            $manager = Factory::getManagerFuncion();
+            $funcion = $manager->getFuncion($id);
+            $funcion->loadFromDatos($datos);
+            $manager->actualizar($funcion);
+
+            rest::response()->put([ "respuesta" => true ]);
+        } catch (ErrorTupa $e) {
+            rest::response()->not_found();
+        } catch (\Exception $e) {
+            if ($e->getCode() >= 400 || $e->getCode() < 500) {
+                rest::response()->error_negocio([$e->getMessage()], 400);
+            } else {
+                rest::response()->error_negocio([$e->getMessage()], 500);
+            }
+        }
+    }
+
+    /**
+     * Se consume en PUT /funciones/{id}/baja.
+     *
+     * @summary Setea vigencia fin de una funcion
+     * @param_body $vigenciaFin VigenciaFin  [required] la fecha de fin de vigencia de la funcion
+     * @responses 200 Se seteo la baja correctamente
+     * @responses 404 No existe el recurso
+     * @responses 500 Error interno
+     */
+    public function put_baja_list($id)
+    {
+        $datos = $this->procesar_input_edicion('VigenciaFin');
+
+        try {
+            $manager = Factory::getManagerFuncion();
+            $funcion = $manager->getFuncion($id);
+
+            $fechaFin = $datos['vigencia_fin'] ?? date("Y-m-d");
+            $funcion->setVigenciaFin($fechaFin);
+
+            $manager->actualizar($funcion);
+
+            rest::response()->put([ "respuesta" => true ]);
+        } catch (ErrorTupa $e) {
+            Factory::getMainLogger()->error($e->getMessage());
+            rest::response()->not_found();
+        } catch (\Exception $e) {
+            Factory::getMainLogger()->error($e->getMessage());
+            if ($e->getCode() >= 400 || $e->getCode() < 500) {
+                rest::response()->error_negocio($e->getMessage(), 400);
+            } else {
+                rest::response()->error_negocio($e->getMessage(), 500);
+            }
+        }
+    }
+
+    /**
+     * @return Filtro
+     * @throws ErrorTupa
+     */
+    protected function get_filtro_get_list()
+    {
+        /* @var Filtro $filtro */
+        $filtro = new Filtro();
+        $filtro->agregarCampoRest('f.nombre', rest::request()->get('nombre', null));
+        $filtro->agregarCampoRest('f.descripcion', rest::request()->get('descripcion', null));
+        $filtro->agregarCampoRest('f.id_servicio', rest::request()->get('id_servicio', null));
+        $filtro->agregarCampoRest('f.id_funcion_padre', rest::request()->get('id_funcion_padre', null));
+        $filtro->agregarCampoRest('f.id_funcion_predecesor', rest::request()->get('id_funcion_predecesor', null));
+        $filtro->agregarCampoRest('f.vigencia_inicio', rest::request()->get('vigencia_inicio', null));
+        $filtro->agregarCampoRest('f.vigencia_fin', rest::request()->get('vigencia_fin', null));
+        if(rest::request()->get('es_agrupador', null)){
+            $filtro->agregarCampoRest('f.es_agrupador', 'es_igual_a;'.rest::request()->get('es_agrupador', null));
+        }
+        
+        $filtro->agregarCampoOrdenable('nombre');
+        $filtro->agregarCampoOrdenable('vigencia_inicio');
+
+        return $filtro;
+    }
+
+     /**
+     * $relajar_ocultos boolean no checkea campos obligatorios cuando no se especifican.
+     * @param string $modelo
+     * @param bool $relajar_ocultos
+     * @param array $datos
+     * @return array|string
+     * @throws rest_error
+     */
+    protected function procesar_input_edicion($modelo = 'FuncionEdit', $relajar_ocultos = false, $datos = null)
+    {
+        if (! $datos) {
+            $datos = rest::request()->get_body_json();
+        }
+
+        $spec_usuario = $this->get_spec_usuario($modelo);
+
+        rest_validador::validar($datos, $spec_usuario, $relajar_ocultos);
+
+        $resultado = rest_hidratador::deshidratar_fila($datos, $spec_usuario);
+
+        return Factory::getVarios()->arrayToUtf8($resultado);
+    }
+}
+
diff --git a/api-backend/src/UNAM/Tupa/Backend/API/Endpoints/v1/servicios/servicios.php b/api-backend/src/UNAM/Tupa/Backend/API/Endpoints/v1/servicios/servicios.php
new file mode 100644
index 0000000000000000000000000000000000000000..5a5b1b7fdca66f8db4b7a5bb8defe7d2603635e1
--- /dev/null
+++ b/api-backend/src/UNAM/Tupa/Backend/API/Endpoints/v1/servicios/servicios.php
@@ -0,0 +1,316 @@
+<?php
+
+namespace UNAM\Tupa\Backend\API\Endpoints\v1\servicios;
+
+use SIUToba\rest\lib\rest_error;
+use SIUToba\rest\lib\rest_hidratador;
+use SIUToba\rest\lib\rest_validador;
+use SIUToba\rest\rest;
+
+use UNAM\Tupa\Core\Errors\ErrorTupa;
+use UNAM\Tupa\Backend\API\Factory;
+use UNAM\Tupa\Core\Filtros\Filtro;
+use UNAM\Tupa\Core\Negocio\SolicitudesServicios\Servicio;
+
+
+class servicios implements \SIUToba\rest\lib\modelable
+{
+    public static function _get_modelos()
+    {
+        $vigenciaFin = [
+            'vigencia_fin' => [
+                'type' => 'date',
+                '_validar' => [
+                    rest_validador::TIPO_DATE => [
+                        'format' => 'Y-m-d'
+                    ],
+                ],
+            ]         
+        ];
+
+        $servicioEdit = array(
+            'nombre' => array(
+                'type' => 'string',
+                'required' => true,
+                '_validar' => array(
+                    rest_validador::OBLIGATORIO,
+                ),
+            ),
+            'descripcion' => array(
+                'type' => 'string',
+                'required' => true,
+                '_validar' => array(
+                    rest_validador::OBLIGATORIO,
+                ),
+            ),
+            'id_sistema_arai' => array(
+                'type' => 'string',
+                'required' => true,
+                '_validar' => array(
+                    rest_validador::OBLIGATORIO,
+                ),
+            ),
+            'vigencia_inicio' => [
+                'type' => 'date',
+                '_validar' => [
+                    rest_validador::OBLIGATORIO,
+                    rest_validador::TIPO_DATE => [
+                        'format' => 'Y-m-d'
+                    ],
+                ],
+            ]   
+        );
+
+        $servicio = array_merge(
+            array(
+                'id_servicio' => array(
+                    'type' => 'integer',
+                ),
+            ),
+            $servicioEdit,
+            $vigenciaFin
+        );
+        
+
+        return $models = array(
+            'Servicio' => $servicio,
+            'ServicioEdit' => $servicioEdit,
+            'VigenciaFin' => $vigenciaFin,
+        );
+    }
+
+    protected function get_spec_usuario($tipo = 'Servicio')
+    {
+        $m = $this->_get_modelos();
+
+        return $m[$tipo];
+    }
+
+    /**
+     * Se consume en GET /servicios/{id}.
+     *
+     * @summary Retorna datos de un servicio
+     * @responses 200 {"$ref": "Servicio"} Servicio
+     * @responses 404 No existe el recurso
+     * @responses 500 Error interno del servidor
+     */
+    public function get($id)
+    {
+        try {
+            $manager = Factory::getManagerServicio();
+
+            $servicio = $manager->getServicio($id);
+
+            $fila = rest_hidratador::hidratar_fila($this->get_spec_usuario('Servicio'), $servicio->toArray());
+
+            rest::response()->get($fila);
+        } catch (ErrorTupa $e) {
+            Factory::getMainLogger()->error($e->getMessage());
+            rest::response()->not_found();
+        } catch (\Exception $e) {
+            Factory::getMainLogger()->error($e->getMessage());
+            rest::response()->error_negocio('Error interno del servidor', 500);
+        }
+    }
+
+
+    /**
+     * Se consume en GET /servicios.
+     *
+     * @summary Retorna los servicios existentes
+     * @param_query $nombre string Se define como 'condicion;valor' donde 'condicion' puede ser contiene|no_contiene|comienza_con|termina_con|es_igual_a|es_distinto_de
+     * @param_query $descripcion string Se define como 'condicion;valor' donde 'condicion' puede ser es_menor_que|es_menor_igual_que|es_igual_a|es_distinto_de|es_mayor_igual_que|es_mayor_que|entre
+     * @param_query $id_sistema_arai string Se define como 'condicion;valor' donde 'condicion' puede ser es_menor_que|es_menor_igual_que|es_igual_a|es_distinto_de|es_mayor_igual_que|es_mayor_que|entre
+     * @param_query $vigencia_inicio string Se define como 'condicion;valor' donde 'condicion' puede ser es_menor_que|es_menor_igual_que|es_igual_a|es_distinto_de|es_mayor_igual_que|es_mayor_que|entre
+     * @param_query $vigencia_fin string Se define como 'condicion;valor' donde 'condicion' puede ser es_menor_que|es_menor_igual_que|es_igual_a|es_distinto_de|es_mayor_igual_que|es_mayor_que|entre
+     * @param_query $unidad_gestion string Se define como 'condicion;valor' donde 'condicion' puede ser es_menor_que|es_menor_igual_que|es_igual_a|es_distinto_de|es_mayor_igual_que|es_mayor_que|entre
+  
+     *
+     * @param_query $limit integer Limitar a esta cantidad de servicios
+     * @param_query $page integer Limitar desde esta pagina
+     * @param_query $order string +/-campo,...
+     * @responses 200 array {"$ref":"Servicio"}
+     * @responses 500 Error en los operadores ingresados para el filtro
+     */
+    public function get_list()
+    {
+        try {
+            $filtro = $this->get_filtro_get_list();
+            $filtro->setlimit(rest::request()->get('limit', null));
+            $filtro->setPage(rest::request()->get('page', null));
+            $filtro->setOrder(rest::request()->get('order', null));
+
+            $manager = Factory::getManagerServicio();
+            $servicios = $manager->getServicios($filtro);
+
+            $resultados = [];            
+            foreach ($servicios as $s) {
+                $resultados[] = $s->toArray();
+            }
+            
+            $registros = rest_hidratador::hidratar($this->get_spec_usuario('Servicio'), $resultados);
+
+            rest::response()->get($registros);
+        } catch (\Exception $e) {
+            Factory::getMainLogger()->error($e->getMessage());
+            rest::response()->error_negocio('Error interno del servidor', 500);
+        }
+    }
+
+
+    /**
+     * Se consume en POST /servicios
+     *
+     * @summary Crea un nuevo servicio
+     * @param_body $servicios ServicioEdit [required] los datos del servicio
+     * @responses 201 {"string"} identificador de un servicio
+     * @responses 400 Servicio inv�lido
+     * @responses 500 Error interno
+     */
+    public function post_list()
+    {
+        // Valido y traduzco los datos al formato de mi modelo
+        $datos = $this->procesar_input_edicion('ServicioEdit',false);
+
+        try {
+            $manager = Factory::getManagerServicio();
+
+            $servicio = new Servicio();
+
+            $servicio->loadFromDatos($datos);
+
+            $identificador = $manager->crear($servicio);
+
+            $respuesta = [
+                'id_servicio' => $identificador['id_servicio']
+            ];
+
+            rest::response()->post($respuesta);
+        } catch (rest_error $e) {
+            rest::response()->error_negocio($e->get_datalle(), 400);
+        } catch (\Exception $e) {
+            if ($e->getCode() >= 400 || $e->getCode() < 500) {
+                rest::response()->error_negocio([$e->getMessage()], 400);
+            } else {
+                rest::response()->error_negocio([$e->getMessage()], 500);
+            }
+        }
+    }
+
+    /**
+     * Se consume en PUT /servicios/{id}
+     *
+     * @summary Modifica un servicio
+     * @param_body $ServicioEdit ServicioEdit  [required] los datos a editar de un servicio
+     * @responses 204 El id es correcto
+     * @responses 400 El id no v�lido
+     * @responses 404 No existe el recurso
+     * @responses 500 Error interno
+     */
+    public function put($id)
+    {
+        $datos = $this->procesar_input_edicion('ServicioEdit');
+
+        try {
+            $manager = Factory::getManagerServicio();
+            $servicio = $manager->getServicio($id);
+            $servicio->loadFromDatos($datos);
+            $manager->actualizar($servicio);
+
+            rest::response()->put([ "respuesta" => true ]);
+        } catch (ErrorTupa $e) {
+            rest::response()->not_found();
+        } catch (\Exception $e) {
+            if ($e->getCode() >= 400 || $e->getCode() < 500) {
+                rest::response()->error_negocio([$e->getMessage()], 400);
+            } else {
+                rest::response()->error_negocio([$e->getMessage()], 500);
+            }
+        }
+    }
+
+    /**
+     * Se consume en PUT /servicios/{id}/baja.
+     *
+     * @summary Setea vigencia fin de un servicio
+     * @param_body $vigenciaFin VigenciaFin  [required] la fecha de fin de vigencia del servicio
+     * @responses 200 Se seteo la baja correctamente
+     * @responses 404 No existe el recurso
+     * @responses 500 Error interno
+     */
+    public function put_baja_list($id)
+    {
+        $datos = $this->procesar_input_edicion('VigenciaFin');
+
+        try {
+            $manager = Factory::getManagerServicio();
+            $servicio = $manager->getServicio($id);
+
+            if(!empty($datos['vigencia_fin'])){
+                $servicio->setVigenciaFin($datos['vigencia_fin']);
+            }else{
+                $servicio->setVigenciaFin(date("Y-m-d"));
+            }
+
+            $manager->actualizar($servicio);
+
+            rest::response()->put([ "respuesta" => true ]);
+        } catch (ErrorTupa $e) {
+            Factory::getMainLogger()->error($e->getMessage());
+            rest::response()->not_found();
+        } catch (\Exception $e) {
+            Factory::getMainLogger()->error($e->getMessage());
+            if ($e->getCode() >= 400 || $e->getCode() < 500) {
+                rest::response()->error_negocio($e->getMessage(), 400);
+            } else {
+                rest::response()->error_negocio($e->getMessage(), 500);
+            }
+        }
+    }
+
+
+     /**
+     * @return Filtro
+     * @throws ErrorTupa
+     */
+    protected function get_filtro_get_list()
+    {
+        /* @var Filtro $filtro */
+        $filtro = new Filtro();
+        $filtro->agregarCampoRest('s.nombre', rest::request()->get('nombre', null));
+        $filtro->agregarCampoRest('s.descripcion', rest::request()->get('descripcion', null));
+        $filtro->agregarCampoRest('s.id_sistema_arai', rest::request()->get('id_sistema_arai', null));
+        $filtro->agregarCampoRest('s.vigencia_inicio', rest::request()->get('vigencia_inicio', null));
+        $filtro->agregarCampoRest('s.vigencia_fin', rest::request()->get('vigencia_fin', null));
+        $filtro->agregarCampoRest('ug.id_unidad', rest::request()->get('unidad_gestion', null));
+        
+        $filtro->agregarCampoOrdenable('nombre');
+        $filtro->agregarCampoOrdenable('vigencia_inicio');
+
+        return $filtro;
+    }
+
+    /**
+     * $relajar_ocultos boolean no checkea campos obligatorios cuando no se especifican.
+     * @param string $modelo
+     * @param bool $relajar_ocultos
+     * @param array $datos
+     * @return array|string
+     * @throws rest_error
+     */
+    protected function procesar_input_edicion($modelo = 'ServicioEdit', $relajar_ocultos = false, $datos = null)
+    {
+        if (! $datos) {
+            $datos = rest::request()->get_body_json();
+        }
+
+        $spec_usuario = $this->get_spec_usuario($modelo);
+
+        rest_validador::validar($datos, $spec_usuario, $relajar_ocultos);
+
+        $resultado = rest_hidratador::deshidratar_fila($datos, $spec_usuario);
+
+        return Factory::getVarios()->arrayToUtf8($resultado);
+    }
+
+}
\ No newline at end of file
diff --git a/api-backend/src/UNAM/Tupa/Backend/API/Endpoints/v1/unidades_gestion/unidades_gestion.php b/api-backend/src/UNAM/Tupa/Backend/API/Endpoints/v1/unidades_gestion/unidades_gestion.php
new file mode 100644
index 0000000000000000000000000000000000000000..f84bf8a315eaa7148bd6919163f6b8af0b6ae700
--- /dev/null
+++ b/api-backend/src/UNAM/Tupa/Backend/API/Endpoints/v1/unidades_gestion/unidades_gestion.php
@@ -0,0 +1,417 @@
+<?php
+namespace UNAM\Tupa\Backend\API\Endpoints\v1\unidades_gestion;
+
+use SIUToba\rest\lib\rest_error;
+use SIUToba\rest\lib\rest_hidratador;
+use SIUToba\rest\lib\rest_validador;
+use SIUToba\rest\rest;
+
+use UNAM\Tupa\Core\Errors\ErrorTupa;
+use UNAM\Tupa\Core\Errors\UnidadGestionError;
+use UNAM\Tupa\Backend\API\Factory;
+use UNAM\Tupa\Core\Filtros\Filtro;
+use UNAM\Tupa\Core\Negocio\Organizacion\UnidadGestion;
+use UNAM\Tupa\Core\Negocio\SolicitudesServicios\Servicio;
+
+
+class unidadesGestion implements \SIUToba\rest\lib\modelable
+{
+    public static function _get_modelos()
+    {
+        $unidadGestionEdit = array(
+            'sigla' => array(
+                'type' => 'string',
+                'required' => true,
+                '_validar' => array(
+                    rest_validador::OBLIGATORIO,
+                ),
+            ),
+            'nombre' => array(
+                'type' => 'string',
+                'required' => true,
+                '_validar' => array(
+                    rest_validador::OBLIGATORIO,
+                ),
+            ),
+            'id_grupo_arai' => array(
+                'type' => 'string',
+                'required' => true,
+                '_validar' => array(
+                    rest_validador::OBLIGATORIO,
+                ),
+            ),
+            
+        );
+
+        $servicio = [
+            'id_servicio' => [
+                'type' => 'integer'
+            ],
+            'nombre' => array(
+                'type' => 'string',
+            ),
+            'descripcion' => array(
+                'type' => 'string',
+            ),
+            'id_sistema_arai' => array(
+                'type' => 'string',
+            ),
+            'vigencia_inicio' => [
+                'type' => 'date',
+            ],
+            'vigencia_fin' => [
+                'type' => 'date',
+            ]     
+        ];
+
+        $servicios = [
+            'servicios' => [
+                'type' => 'array',
+                'required' => true,
+                '_validar' => [ 
+                    rest_validador::OBLIGATORIO,
+                ],
+                'items' => [
+                    'type' => 'integer',
+                    'required' => true,
+                    '_validar' => [
+                        rest_validador::OBLIGATORIO,
+                    ]]
+            ]
+        ];
+
+
+        $unidadGestion = array_merge(
+            $unidadGestionEdit,
+            array(
+                'id_unidad' => array(
+                    'type' => 'integer',
+                ),
+            )
+        );
+        
+
+        return $models = array(
+            'UnidadGestion' => $unidadGestion,
+            'UnidadGestionEdit' => $unidadGestionEdit,
+            'Servicio' => $servicio,
+            'Servicios' => $servicios
+        );
+    }
+
+    protected function get_spec_usuario($tipo = 'UnidadGestion')
+    {
+        $m = $this->_get_modelos();
+
+        return $m[$tipo];
+    }
+
+    /**
+     * Se consume en GET /unidades_gestion/{id}.
+     *
+     * @summary Retorna datos de un unidad de gestion
+     * @responses 200 {"$ref": "UnidadGestion"} UnidadGestion
+     * @responses 404 No existe el recurso
+     * @responses 500 Error interno del servidor
+     */
+    public function get($id)
+    {
+        try {
+            $manager = Factory::getManagerUnidadGestion();
+
+            $unidadGestion = $manager->getUnidadGestion($id);
+
+            $fila = rest_hidratador::hidratar_fila($this->get_spec_usuario('UnidadGestionEdit'), $unidadGestion->toArray());
+
+            rest::response()->get($fila);
+        } catch (UnidadGestionError $e) {
+            Factory::getMainLogger()->error($e->getMessage());
+            rest::response()->not_found();
+        } catch (\Exception $e) {
+            Factory::getMainLogger()->error($e->getMessage());
+            rest::response()->error_negocio('Error interno del servidor', 500);
+        }
+    }
+
+     /**
+     * Se consume en GET /unidades-gestion.
+     *
+     * @summary Retorna las unidades de gestion existentes
+     * @param_query $sigla string Se define como 'condicion;valor' donde 'condicion' puede ser contiene|no_contiene|comienza_con|termina_con|es_igual_a|es_distinto_de
+     * @param_query $nombre string Se define como 'condicion;valor' donde 'condicion' puede ser es_menor_que|es_menor_igual_que|es_igual_a|es_distinto_de|es_mayor_igual_que|es_mayor_que|entre
+     * @param_query $id_grupo_arai string Se define como 'condicion;valor' donde 'condicion' puede ser es_menor_que|es_menor_igual_que|es_igual_a|es_distinto_de|es_mayor_igual_que|es_mayor_que|entre
+     *
+     * @param_query $limit integer Limitar a esta cantidad de términos y condiciones
+     * @param_query $page integer Limitar desde esta pagina
+     * @param_query $order string +/-campo,...
+     * @responses 200 array {"$ref":"UnidadesGestion"}
+     * @responses 500 Error en los operadores ingresados para el filtro
+     */
+    public function get_list()
+    {
+        try {
+            $filtro = $this->get_filtro_get_list();
+            $filtro->setlimit(rest::request()->get('limit', null));
+            $filtro->setPage(rest::request()->get('page', null));
+            $filtro->setOrder(rest::request()->get('order', null));
+
+            $manager = Factory::getManagerUnidadGestion();
+
+            $unidadesGestion = $manager->getUnidadesGestion($filtro);
+            $resultados = [];
+            foreach ($unidadesGestion as $ug) {
+                $resultados[] = $ug->toArray();
+            }
+            
+            $registros = rest_hidratador::hidratar($this->get_spec_usuario('UnidadGestion'), $resultados);
+
+            rest::response()->get($registros);
+        } catch (\Exception $e) {
+            Factory::getMainLogger()->error($e->getMessage());
+            rest::response()->error_negocio('Error interno del servidor', 500);
+        }
+    }
+
+     /**
+     * Se consume en GET /unidades-gestion/{id}/servicios.
+     *
+     * @summary Retorna los servicios asociados a una unidad de gestion
+     * @responses 200 {"$ref": "UnidadGestion"} UnidadGestion
+     * @responses 404 No existe el recurso
+     * @responses 500 Error interno del servidor
+     */
+    public function get_servicios_list($id)
+    {
+        try {            
+            $manager = Factory::getManagerServicio();
+
+            $servicios = $manager->getServiciosUnidadGestion($id);
+           
+            $resultados = [];
+            foreach ($servicios as $s) {
+                $resultados[] = $s->toArray();
+            }
+            
+            $registros = rest_hidratador::hidratar($this->get_spec_usuario('Servicio'), $resultados);
+
+            rest::response()->get($registros);
+        }catch (ErrorTupa $e) {
+            Factory::getMainLogger()->error($e->getMessage());
+            rest::response()->not_found($e->getMessage());
+        }catch (\Exception $e) {
+            Factory::getMainLogger()->error($e->getMessage());
+            rest::response()->error_negocio('Error interno del servidor', 500);
+        }
+    }
+
+     /**
+     * Se consume en POST /unidades-gestion/{id}/servicios.
+     *
+     * @summary Asocia distintos servicios a una unidad de gestion
+     * @param_body $servicios Servicios [required] array de ids de los servicios
+     * @responses 201 {"boolean"} exito
+     * @responses 400 unidad de gestion inválida
+     * @responses 500 Error interno
+     */
+    public function post_servicios_list($id)
+    {
+        // Valido y traduzco los datos al formato de mi modelo
+        $servicios = $this->procesar_input_edicion('Servicios');
+
+        try {
+            $manager = Factory::getManagerUnidadGestion();
+
+            $resultado = $manager->agregarServicios($id,$servicios);
+
+            rest::response()->post([ "respuesta" => $resultado ]);
+        } 
+        catch (UnidadGestionError $e) {
+            rest::response()->error_negocio([$e->getMessage()], 400);
+        } catch (\Exception $e) {
+            if ($e->getCode() >= 400 || $e->getCode() < 500) {
+                rest::response()->error_negocio([$e->getMessage()], 400);
+            } else {
+                rest::response()->error_negocio([$e->getMessage()], 500);
+            }
+        }
+    }
+
+     /**
+     * Se consume en POST /unidades-gestion
+     *
+     * @summary Crea una nueva unidad de géstion
+     * @param_body $unidadGestion UnidadGestionEdit [required] los datos de la unidad de gestion
+     * @responses 201 {"string"} identificador de unidad de gestion otorgado
+     * @responses 400 unidad de gestion inválidoa
+     * @responses 500 Error interno
+     */
+    public function post_list()
+    {
+        // Valido y traduzco los datos al formato de mi modelo
+        $datos = $this->procesar_input_edicion('UnidadGestion',false);
+
+        try {
+            $manager = Factory::getManagerUnidadGestion();
+
+            $ug = new UnidadGestion();
+
+            $ug->loadFromDatos($datos);
+
+            $identificador = $manager->crear($ug);
+
+            $respuesta = [
+                'id_unidad' => $identificador['id_unidad']
+            ];
+
+            rest::response()->post($respuesta);
+        } catch (rest_error $e) {
+            rest::response()->error_negocio($e->get_datalle(), 400);
+        } catch (\Exception $e) {
+            if ($e->getCode() >= 400 || $e->getCode() < 500) {
+                rest::response()->error_negocio([$e->getMessage()], 400);
+            } else {
+                rest::response()->error_negocio([$e->getMessage()], 500);
+            }
+        }
+    }
+
+    /**
+     * Se consume en PUT /unidades_gestion/{identificador}
+     *
+     * @summary Modifica una unidad de gestion
+     * @param_body $UnidadGestionEdit UnidadGestionEdit  [required] los datos a editar de la unidad de gestion
+     * @responses 204  el código es correcto
+     * @responses 400 Código no válido
+     * @responses 404 No existe el recurso
+     * @responses 500 Error interno
+     */
+    public function put($id)
+    {
+        $datos = $this->procesar_input_edicion('UnidadGestionEdit');
+
+        try {
+            $manager = Factory::getManagerUnidadGestion();
+            $ug = $manager->getUnidadGestion($id);
+            $ug->loadFromDatos($datos);
+            $manager->actualizar($ug);
+
+            rest::response()->put([ "respuesta" => true ]);
+        } catch (UnidadGestionError $e) {
+            rest::response()->not_found();
+        } catch (\Exception $e) {
+            if ($e->getCode() >= 400 || $e->getCode() < 500) {
+                rest::response()->error_negocio([$e->getMessage()], 400);
+            } else {
+                rest::response()->error_negocio([$e->getMessage()], 500);
+            }
+        }
+    }
+
+      /**
+     * Se consume en DELETE /unidades_gestion/{id}/servicios
+     *
+     * @summary Elimina los servicios asociados a una unidad de gestion
+     * @param_body $servicios Servicios [required] array de ids de los servicios
+     * @responses 200 Se elimino correctamente
+     * @responses 400 El id no existe
+     * @responses 404 No existe el recurso
+     * @responses 500 Error interno
+     */
+    public function delete_servicios_list($id)
+    {
+        $idServicios = $this->procesar_input_edicion('Servicios');
+
+        try {
+            $managerUG = Factory::getManagerUnidadGestion();
+            $managerServicio = Factory::getManagerServicio();
+            
+            $unidadGestion = $managerUG->getUnidadGestion($id);
+            
+            $filtro = new Filtro();
+            $filtro->agregarCampo('s.id_servicio',$filtro::DENTRO,$idServicios['servicios']);
+
+            $servicios = $managerServicio->getServicios($filtro);
+            
+            $managerUG->eliminarServicios($unidadGestion,$servicios);
+
+            rest::response()->put([ "respuesta" => true ]);
+        }catch (UnidadGestionError $e) {
+            rest::response()->error_negocio([$e->getMessage()], 400);
+        } 
+        catch (\Exception $e) {
+            Factory::getMainLogger()->error($e->getMessage());
+            if ($e->getCode() >= 400 || $e->getCode() < 500) {
+                rest::response()->error_negocio([$e->getMessage()], 400);
+            } else {
+                rest::response()->error_negocio([$e->getMessage()], 500);
+            }
+        }
+    }
+
+      /**
+     * Se consume en DELETE /unidades_gestion/{identificador}
+     *
+     * @summary Elimina una unidad de gestion
+     * @responses 204 Se elimino correctamente
+     * @responses 400 El id no existe
+     * @responses 404 No existe el recurso
+     * @responses 500 Error interno
+     */
+    public function delete($id)
+    {
+        try {
+            $manager = Factory::getManagerUnidadGestion();
+
+            $manager->eliminar($id);
+
+            rest::response()->put([ "respuesta" => true ]);
+        }catch (\Exception $e) {
+            if ($e->getCode() >= 400 || $e->getCode() < 500) {
+                rest::response()->error_negocio([$e->getMessage()], 400);
+            } else {
+                rest::response()->error_negocio([$e->getMessage()], 500);
+            }
+        }
+    }
+
+     /**
+     * @return Filtro
+     * @throws ErrorTupa
+     */
+    protected function get_filtro_get_list()
+    {
+        /* @var Filtro $filtro */
+        $filtro = new Filtro();
+        $filtro->agregarCampoRest('ug.nombre', rest::request()->get('nombre', null));
+        $filtro->agregarCampoRest('ug.sigla', rest::request()->get('sigla', null));
+        $filtro->agregarCampoRest('ug.id_grupo_arai', rest::request()->get('id_grupo_arai', null));
+
+        $filtro->agregarCampoOrdenable('nombre');
+        $filtro->agregarCampoOrdenable('sigla');
+
+        return $filtro;
+    }
+
+    /**
+     * $relajar_ocultos boolean no checkea campos obligatorios cuando no se especifican.
+     * @param string $modelo
+     * @param bool $relajar_ocultos
+     * @param array $datos
+     * @return array|string
+     * @throws rest_error
+     */
+    protected function procesar_input_edicion($modelo = 'UnidadGestionEdit', $relajar_ocultos = false, $datos = null)
+    {
+        if (! $datos) {
+            $datos = rest::request()->get_body_json();
+        }
+
+        $spec_usuario = $this->get_spec_usuario($modelo);
+
+        rest_validador::validar($datos, $spec_usuario, $relajar_ocultos);
+
+        $resultado = rest_hidratador::deshidratar_fila($datos, $spec_usuario);
+
+        return Factory::getVarios()->arrayToUtf8($resultado);
+    }
+}
diff --git a/api-backend/src/UNAM/Tupa/Backend/API/Factory.php b/api-backend/src/UNAM/Tupa/Backend/API/Factory.php
index e36d3c3552ef92ceb67896ff8fc51fc6ef040939..104953c33d9470f431881162bc21073de4835edd 100644
--- a/api-backend/src/UNAM/Tupa/Backend/API/Factory.php
+++ b/api-backend/src/UNAM/Tupa/Backend/API/Factory.php
@@ -26,8 +26,11 @@ use UNAM\Tupa\Core\Manager\ManagerTerminosCondiciones;
 use UNAM\Tupa\Core\Manager\ManagerVisitante;
 use UNAM\Tupa\Core\Manager\ManagerVisita;
 use UNAM\Tupa\Core\Manager\ManagerAutorizante;
+use UNAM\Tupa\Core\Manager\ManagerUnidadGestion;
 use UNAM\Tupa\Core\Manager\ManagerPermiso;
 use UNAM\Tupa\Core\Manager\ManagerSolicitud;
+use UNAM\Tupa\Core\Manager\ManagerServicio;
+use UNAM\Tupa\Core\Manager\ManagerFuncion;
 
 class Factory
 {
@@ -250,9 +253,17 @@ class Factory
             return new ManagerTerminosCondiciones($c['db-logger'], $c['db'], $c['codigo']);
         };
 
+        $container['manager-funcion'] = function ($c) {
+            return new ManagerFuncion($c['db-logger'], $c['db'], $c['codigo']);
+        };
+
         $container['manager-autorizante'] = function ($c) {
             return new ManagerAutorizante($c['db-logger'], $c['db'], $c['codigo']);
         };
+        
+        $container['manager-unidad-gestion'] = function ($c) {
+            return new ManagerUnidadGestion($c['db-logger'], $c['db'], $c['codigo']);
+        };
 
         $container['manager-solicitud'] = function ($c) {
             return new ManagerSolicitud($c['db-logger'], $c['db'], $c['codigo']);
@@ -262,6 +273,10 @@ class Factory
             return new ManagerPermiso($c['db-logger'], $c['db'], $c['codigo']);
         };
 
+        $container['manager-servicio'] = function ($c) {
+            return new ManagerServicio($c['db-logger'], $c['db'], $c['codigo']);
+        };
+
         $container['worker-redis'] = function ($c) {
             $config = new \SIU\Queue\Transport\Config\Redis();
 
@@ -342,6 +357,27 @@ class Factory
     {
         return self::getContainer()['manager-sede'];
     }
+    
+    /**
+     * Singleton de ManagerUnidadGestion
+     *
+     * @return ManagerUnidadGestion
+     */
+    public static function getManagerUnidadGestion()
+    {
+        return self::getContainer()['manager-unidad-gestion'];
+    }
+
+     /**
+     * Singleton de ManagerSede
+     *
+     * @return ManagerServicio
+     */
+    public static function getManagerServicio()
+    {
+        return self::getContainer()['manager-servicio'];
+    }
+
 
     /**
      * Singleton de ManagerTerminosCondiciones.
@@ -353,6 +389,16 @@ class Factory
         return self::getContainer()['manager-terminos-condiciones'];
     }
 
+     /**
+     * Singleton de ManagerSede
+     *
+     * @return ManagerFunciones
+     */
+    public static function getManagerFuncion()
+    {
+        return self::getContainer()['manager-funcion'];
+    }
+
     /**
      * Singleton de ManagerAutorizante
      *
diff --git "a/api-backend/tests/Integration/v1/collections\342\200\216/autorizantes/tupa_api_backend_autorizantes_test.postman_collection.json" b/api-backend/tests/Integration/v1/collections/autorizantes/tupa_api_backend_autorizantes_test.postman_collection.json
similarity index 100%
rename from "api-backend/tests/Integration/v1/collections\342\200\216/autorizantes/tupa_api_backend_autorizantes_test.postman_collection.json"
rename to api-backend/tests/Integration/v1/collections/autorizantes/tupa_api_backend_autorizantes_test.postman_collection.json
diff --git a/api-backend/tests/Integration/v1/collections/funciones/tupa_api_backend_funciones_test.postman_collection.json b/api-backend/tests/Integration/v1/collections/funciones/tupa_api_backend_funciones_test.postman_collection.json
new file mode 100644
index 0000000000000000000000000000000000000000..4c93b01a51f5fd641908e80873ab2fdaad9be7ae
--- /dev/null
+++ b/api-backend/tests/Integration/v1/collections/funciones/tupa_api_backend_funciones_test.postman_collection.json
@@ -0,0 +1,358 @@
+{
+	"info": {
+		"_postman_id": "da74add2-5ee3-464b-9be1-9fd6822f98c6",
+		"name": "Tupa API Backend Funciones",
+		"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
+		"_exporter_id": "16366966"
+	},
+	"item": [
+		{
+			"name": "V1",
+			"item": [
+				{
+					"name": "Funciones",
+					"item": [
+						{
+							"name": "Crea una nueva funcion",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"exec": [
+											"pm.test(\"Status code is 201\", () => {",
+											"    pm.response.to.have.status(201);",
+											"});",
+											"",
+											"const schema =  {",
+											"  \"nombre\": \"\",",
+											"  \"descripcion\": \"\",",
+											"  \"es_agrupador\": \"\",",
+											"  \"vigencia_inicio\": \"\",",
+											"  \"vigencia_fin\": \"\",",
+											"  \"id_funcion_padre\": \"\",",
+											"  \"id_funcion_predecesor\": \"\",",
+											"  \"id_servicio\": \"\"",
+											"}",
+											"",
+											"const body = JSON.parse(pm.request.body.raw);",
+											"const sameSchema = JSON.stringify(Object.keys(schema)) === JSON.stringify(Object.keys(body));",
+											"",
+											"pm.test('Estructura del body correcta', () => {",
+											"    pm.expect(true).to.be.eql(sameSchema);",
+											"}); ",
+											"",
+											"var respuesta = pm.response.json();",
+											"",
+											"pm.test(\"funcion creada con ID \" + respuesta.id_funcion, function () {",
+											"    pm.globals.set(\"idFuncion\", respuesta.id_funcion);",
+											"});"
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "POST",
+								"header": [],
+								"body": {
+									"mode": "raw",
+									"raw": "{\n  \"nombre\": \"{{$randomWord}}a\",\n  \"descripcion\": \"{{$randomWords}}a\",\n  \"es_agrupador\": true,\n  \"vigencia_inicio\": \"2020-01-01\",\n  \"vigencia_fin\": \"2020-01-01\",\n  \"id_funcion_padre\": null,\n  \"id_funcion_predecesor\": null,\n  \"id_servicio\": 1\n}",
+									"options": {
+										"raw": {
+											"language": "json"
+										}
+									}
+								},
+								"url": {
+									"raw": "{{baseUrl}}/v1/funciones",
+									"host": [
+										"{{baseUrl}}"
+									],
+									"path": [
+										"v1",
+										"funciones"
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "Retorna datos de una funcion",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"exec": [
+											"pm.test(\"Status code is 200\", () => {",
+											"    pm.response.to.have.status(200);",
+											"});",
+											"",
+											"",
+											"const response = pm.response.json();",
+											"const hasId = Object.keys(response).includes('id_funcion');",
+											"",
+											"pm.test(\"Funcion con id_funcion \" + response.id_funcion, function () {",
+											"    pm.expect(true).to.be.eql(hasId);",
+											"});",
+											""
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "GET",
+								"header": [],
+								"url": {
+									"raw": "{{baseUrl}}/v1/funciones/{{idFuncion}}",
+									"host": [
+										"{{baseUrl}}"
+									],
+									"path": [
+										"v1",
+										"funciones",
+										"{{idFuncion}}"
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "Retorna las funciones existentes",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"exec": [
+											"pm.test(\"Status code is 200\", () => {",
+											"    pm.response.to.have.status(200);",
+											"});",
+											"",
+											"const response = pm.response.json();",
+											"",
+											"pm.test(\"Se obtuvieron funciones \", function () {",
+											"    // Si existe al menos 1 servicio",
+											"    pm.expect(response.length).to.not.eql(0);",
+											"",
+											"    if(response.length > 0){",
+											"        const hasId = Object.keys(response[0]).includes('id_funcion');",
+											"",
+											"        // Si la funcion tiene un id_funcion",
+											"        pm.expect(true).to.be.eql(hasId);",
+											"    }",
+											"  ",
+											"});",
+											""
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "GET",
+								"header": [],
+								"url": {
+									"raw": "{{baseUrl}}/v1/funciones?nombre=contiene;a&descripcion=contiene;a&id_servicio=es_igual_a;1&vigencia_inicio=es_mayor_igual_que;2010-01-01&es_agrupador=true",
+									"host": [
+										"{{baseUrl}}"
+									],
+									"path": [
+										"v1",
+										"funciones"
+									],
+									"query": [
+										{
+											"key": "nombre",
+											"value": "contiene;a"
+										},
+										{
+											"key": "descripcion",
+											"value": "contiene;a"
+										},
+										{
+											"key": "id_funcion_padre",
+											"value": "es_igual_a;null",
+											"disabled": true
+										},
+										{
+											"key": "id_funcion_predecesor",
+											"value": "es_distinto_de;999",
+											"disabled": true
+										},
+										{
+											"key": "id_servicio",
+											"value": "es_igual_a;1"
+										},
+										{
+											"key": "vigencia_inicio",
+											"value": "es_mayor_igual_que;2010-01-01"
+										},
+										{
+											"key": "es_agrupador",
+											"value": "true"
+										}
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "Modifica una funcion",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"exec": [
+											"pm.test(\"Status code is 200\", () => {",
+											"    pm.response.to.have.status(200);",
+											"});",
+											"",
+											"const schema =  {",
+											"  \"nombre\": \"\",",
+											"  \"descripcion\": \"\",",
+											"  \"es_agrupador\": \"\",",
+											"  \"vigencia_inicio\": \"\",",
+											"  \"vigencia_fin\": \"\",",
+											"  \"id_funcion_padre\": \"\",",
+											"  \"id_funcion_predecesor\": \"\",",
+											"  \"id_servicio\": \"\"",
+											"}",
+											"",
+											"const body = JSON.parse(pm.request.body.raw);",
+											"const sameSchema = JSON.stringify(Object.keys(schema)) === JSON.stringify(Object.keys(body));",
+											"",
+											"pm.test('Estructura del body correcta', () => {",
+											"    pm.expect(true).to.be.eql(sameSchema);",
+											"}); ",
+											""
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "PUT",
+								"header": [],
+								"body": {
+									"mode": "raw",
+									"raw": "{\n  \"nombre\": \"{{$randomWord}}\",\n  \"descripcion\": \"{{$randomWords}}\",\n  \"es_agrupador\": true,\n  \"vigencia_inicio\": \"2020-02-01\",\n  \"vigencia_fin\": \"2025-01-01\",\n  \"id_funcion_padre\": null,\n  \"id_funcion_predecesor\": null,\n  \"id_servicio\": 1\n}",
+									"options": {
+										"raw": {
+											"language": "json"
+										}
+									}
+								},
+								"url": {
+									"raw": "{{baseUrl}}/v1/funciones/{{idFuncion}}",
+									"host": [
+										"{{baseUrl}}"
+									],
+									"path": [
+										"v1",
+										"funciones",
+										"{{idFuncion}}"
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "Setea vigencia fin de una funcion",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"exec": [
+											"pm.test(\"Status code is 200\", () => {",
+											"    pm.response.to.have.status(200);",
+											"});",
+											"",
+											"const schema =  {",
+											"  \"vigencia_fin\": \"\"",
+											"}",
+											"",
+											"const body = JSON.parse(pm.request.body.raw);",
+											"const sameSchema = JSON.stringify(Object.keys(schema)) === JSON.stringify(Object.keys(body));",
+											"",
+											"pm.test('Estructura del body correcta', () => {",
+											"    pm.expect(true).to.be.eql(sameSchema);",
+											"});"
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "PUT",
+								"header": [],
+								"body": {
+									"mode": "raw",
+									"raw": "{\n  \"vigencia_fin\": \"2028-01-01\"\n}",
+									"options": {
+										"raw": {
+											"language": "json"
+										}
+									}
+								},
+								"url": {
+									"raw": "{{baseUrl}}/v1/funciones/{{idFuncion}}/baja",
+									"host": [
+										"{{baseUrl}}"
+									],
+									"path": [
+										"v1",
+										"funciones",
+										"{{idFuncion}}",
+										"baja"
+									]
+								}
+							},
+							"response": []
+						}
+					]
+				}
+			]
+		}
+	],
+	"auth": {
+		"type": "basic",
+		"basic": [
+			{
+				"key": "password",
+				"value": "admin",
+				"type": "string"
+			},
+			{
+				"key": "username",
+				"value": "admin",
+				"type": "string"
+			}
+		]
+	},
+	"event": [
+		{
+			"listen": "prerequest",
+			"script": {
+				"type": "text/javascript",
+				"exec": [
+					""
+				]
+			}
+		},
+		{
+			"listen": "test",
+			"script": {
+				"type": "text/javascript",
+				"exec": [
+					""
+				]
+			}
+		}
+	],
+	"variable": [
+		{
+			"key": "baseUrl",
+			"value": "http://localhost:9002/api"
+		}
+	]
+}
\ No newline at end of file
diff --git "a/api-backend/tests/Integration/v1/collections\342\200\216/permisos/tupa_api_backend_permisos_test.postman_collection.json" b/api-backend/tests/Integration/v1/collections/permisos/tupa_api_backend_permisos_test.postman_collection.json
similarity index 100%
rename from "api-backend/tests/Integration/v1/collections\342\200\216/permisos/tupa_api_backend_permisos_test.postman_collection.json"
rename to api-backend/tests/Integration/v1/collections/permisos/tupa_api_backend_permisos_test.postman_collection.json
diff --git a/api-backend/tests/Integration/v1/collections/servicios/tupa_api_backend_servicios_test.postman_collection.json b/api-backend/tests/Integration/v1/collections/servicios/tupa_api_backend_servicios_test.postman_collection.json
new file mode 100644
index 0000000000000000000000000000000000000000..f543607d921c066e6b19c37266f0430bb8e15f99
--- /dev/null
+++ b/api-backend/tests/Integration/v1/collections/servicios/tupa_api_backend_servicios_test.postman_collection.json
@@ -0,0 +1,359 @@
+{
+	"info": {
+		"_postman_id": "884ded69-9e28-4c50-b25b-a5035b6d4175",
+		"name": "Tupa API Backend Servicios",
+		"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
+		"_exporter_id": "16366966"
+	},
+	"item": [
+		{
+			"name": "V1",
+			"item": [
+				{
+					"name": "Servicios",
+					"item": [
+						{
+							"name": "Crear un servicio",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"exec": [
+											"pm.test(\"Status code is 201\", () => {",
+											"    pm.response.to.have.status(201);",
+											"});",
+											"",
+											"const servicioSchema =  {  ",
+											"  \"nombre\": '',",
+											"  \"descripcion\": '',",
+											"  \"id_sistema_arai\": '',",
+											"  \"vigencia_inicio\": '',",
+											"}",
+											"",
+											"const body = JSON.parse(pm.request.body.raw);",
+											"const sameSchema = JSON.stringify(Object.keys(servicioSchema)) === JSON.stringify(Object.keys(body));",
+											"",
+											"pm.test('Estructura del body correcta', () => {",
+											"    pm.expect(true).to.be.eql(sameSchema);",
+											"}); ",
+											"",
+											"var respuesta = pm.response.json();",
+											"",
+											"pm.test(\"Servicio creado con ID \" + respuesta.id_servicio, function () {",
+											"    pm.globals.set(\"idServicio\", respuesta.id_servicio);",
+											"});"
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "POST",
+								"header": [],
+								"body": {
+									"mode": "raw",
+									"raw": "{\n  \"nombre\": \"{{$randomJobTitle}}\",\n  \"descripcion\": \"{{$randomJobTitle}}\",\n  \"id_sistema_arai\": \"{{$randomUUID}}\",\n  \"vigencia_inicio\": \"2022-01-01\"\n}",
+									"options": {
+										"raw": {
+											"language": "json"
+										}
+									}
+								},
+								"url": {
+									"raw": "{{baseUrl}}/v1/servicios",
+									"host": [
+										"{{baseUrl}}"
+									],
+									"path": [
+										"v1",
+										"servicios"
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "Obtener un servicio",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"exec": [
+											"pm.test(\"Status code is 200\", () => {",
+											"    pm.response.to.have.status(200);",
+											"});",
+											"",
+											"const response = pm.response.json();",
+											"const hasId = Object.keys(response).includes('id_servicio');",
+											"",
+											"pm.test(\"Servicio con id_servicio \" + response.id_servicio, function () {",
+											"    pm.expect(true).to.be.eql(hasId);",
+											"});"
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "GET",
+								"header": [],
+								"url": {
+									"raw": "{{baseUrl}}/v1/servicios/{{idServicio}}",
+									"host": [
+										"{{baseUrl}}"
+									],
+									"path": [
+										"v1",
+										"servicios",
+										"{{idServicio}}"
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "Obtener servicios activos",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"exec": [
+											"pm.test(\"Status code is 200\", () => {",
+											"    pm.response.to.have.status(200);",
+											"});",
+											"",
+											"const fechaActual = new Date();",
+											"const year = fechaActual.getFullYear();",
+											"const month = fechaActual.getMonth() + 1; ",
+											"const day = fechaActual.getDate();",
+											"const fechaFormateada = `${year}-${month.toString().padStart(2, '0')}-${day.toString().padStart(2, '0')}`;",
+											"",
+											"const resp = pm.response.json();",
+											"const filteredResponse = resp.filter((obj) => obj.vigencia_fin > fechaFormateada || obj.vigencia_fin == null);",
+											"",
+											"pm.test('Hay un Servicio activo', () => {",
+											"    pm.expect(filteredResponse.length).to.not.eql(0);",
+											"});"
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "GET",
+								"header": [],
+								"url": {
+									"raw": "{{baseUrl}}/v1/servicios",
+									"host": [
+										"{{baseUrl}}"
+									],
+									"path": [
+										"v1",
+										"servicios"
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "Modificar un servicio",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"exec": [
+											"pm.test(\"Status code is 200\", () => {",
+											"    pm.response.to.have.status(200);",
+											"});",
+											"",
+											"const servicioSchema =  {  ",
+											"  \"nombre\": '',",
+											"  \"descripcion\": '',",
+											"  \"id_sistema_arai\": '',",
+											"  \"vigencia_inicio\": '',",
+											"}",
+											"",
+											"const body = JSON.parse(pm.request.body.raw);",
+											"const sameSchema = JSON.stringify(Object.keys(servicioSchema)) === JSON.stringify(Object.keys(body));",
+											"",
+											"pm.test('Estructura del body correcta', () => {",
+											"    pm.expect(true).to.be.eql(sameSchema);",
+											"}); ",
+											""
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "PUT",
+								"header": [],
+								"body": {
+									"mode": "raw",
+									"raw": "{\n    \"nombre\": \"Servicio Modificado\",\n    \"descripcion\": \"Esto es un Servicio Modificado\",\n    \"id_sistema_arai\": \"_0e5589b482dc77e8d983db51d7ed2f36a9daaa11b4\",\n    \"vigencia_inicio\": \"2050-12-01\"\n}",
+									"options": {
+										"raw": {
+											"language": "json"
+										}
+									}
+								},
+								"url": {
+									"raw": "{{baseUrl}}/v1/servicios/{{idServicio}}",
+									"host": [
+										"{{baseUrl}}"
+									],
+									"path": [
+										"v1",
+										"servicios",
+										"{{idServicio}}"
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "Inactivar un servicio",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"exec": [
+											"pm.test(\"Status code is 200\", () => {",
+											"    pm.response.to.have.status(200);",
+											"});",
+											"",
+											"const servicioSchema =  {  ",
+											"  \"vigencia_fin\": '',",
+											"}",
+											"",
+											"const body = JSON.parse(pm.request.body.raw);",
+											"const sameSchema = JSON.stringify(Object.keys(servicioSchema)) === JSON.stringify(Object.keys(body));",
+											"",
+											"pm.test('Estructura del body correcta', () => {",
+											"    pm.expect(true).to.be.eql(sameSchema);",
+											"}); "
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "PUT",
+								"header": [],
+								"body": {
+									"mode": "raw",
+									"raw": "{\n  \"vigencia_fin\": \"2023-01-01\"\n}",
+									"options": {
+										"raw": {
+											"language": "json"
+										}
+									}
+								},
+								"url": {
+									"raw": "{{baseUrl}}/v1/servicios/{{idServicio}}/baja",
+									"host": [
+										"{{baseUrl}}"
+									],
+									"path": [
+										"v1",
+										"servicios",
+										"{{idServicio}}",
+										"baja"
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "Obtener servicios",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"exec": [
+											"pm.test(\"Status code is 200\", () => {",
+											"    pm.response.to.have.status(200);",
+											"});",
+											"",
+											"const response = pm.response.json();",
+											"",
+											"pm.test(\"Se obtuvieron servicios \", function () {",
+											"    // Si existe al menos 1 servicio",
+											"    pm.expect(response.length).to.not.eql(0);",
+											"",
+											"    if(response.length > 0){",
+											"        const hasId = Object.keys(response[0]).includes('id_servicio');",
+											"",
+											"        // Si el servicio tiene un id_servicio",
+											"        pm.expect(true).to.be.eql(hasId);",
+											"    }",
+											"  ",
+											"});"
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "GET",
+								"header": [],
+								"url": {
+									"raw": "{{baseUrl}}/v1/servicios",
+									"host": [
+										"{{baseUrl}}"
+									],
+									"path": [
+										"v1",
+										"servicios"
+									]
+								}
+							},
+							"response": []
+						}
+					]
+				}
+			]
+		}
+	],
+	"auth": {
+		"type": "basic",
+		"basic": [
+			{
+				"key": "password",
+				"value": "admin",
+				"type": "string"
+			},
+			{
+				"key": "username",
+				"value": "admin",
+				"type": "string"
+			}
+		]
+	},
+	"event": [
+		{
+			"listen": "prerequest",
+			"script": {
+				"type": "text/javascript",
+				"exec": [
+					""
+				]
+			}
+		},
+		{
+			"listen": "test",
+			"script": {
+				"type": "text/javascript",
+				"exec": [
+					""
+				]
+			}
+		}
+	],
+	"variable": [
+		{
+			"key": "baseUrl",
+			"value": "http://localhost:9002/api"
+		}
+	]
+}
\ No newline at end of file
diff --git "a/api-backend/tests/Integration/v1/collections\342\200\216/solicitudes/tupa_api_backend_solicitudes_test.postman_collection.json" b/api-backend/tests/Integration/v1/collections/solicitudes/tupa_api_backend_solicitudes_test.postman_collection.json
similarity index 100%
rename from "api-backend/tests/Integration/v1/collections\342\200\216/solicitudes/tupa_api_backend_solicitudes_test.postman_collection.json"
rename to api-backend/tests/Integration/v1/collections/solicitudes/tupa_api_backend_solicitudes_test.postman_collection.json
diff --git a/api-backend/tests/Integration/v1/collections/unidad-gestion/tupa_api_backend_unidad_gestion_test.postman_collection.json b/api-backend/tests/Integration/v1/collections/unidad-gestion/tupa_api_backend_unidad_gestion_test.postman_collection.json
new file mode 100644
index 0000000000000000000000000000000000000000..82f750ab50a7374f92535b2c2d1c5e208d63e16c
--- /dev/null
+++ b/api-backend/tests/Integration/v1/collections/unidad-gestion/tupa_api_backend_unidad_gestion_test.postman_collection.json
@@ -0,0 +1,374 @@
+{
+	"info": {
+		"_postman_id": "414381a0-51a4-429f-a4c1-82e5a8754f14",
+		"name": "Tupa API Backend Unidades Gestion",
+		"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
+		"_exporter_id": "25165965"
+	},
+	"item": [
+		{
+			"name": "V1",
+			"item": [
+				{
+					"name": "Unidad Gestión",
+					"item": [
+						{
+							"name": "Crear unidad de gestión",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"exec": [
+											"pm.test(\"Status code is 201\", () => {",
+											"    pm.response.to.have.status(201);",
+											"});",
+											"",
+											"const servicioSchema =  {  ",
+											"  \"sigla\": '',",
+											"  \"nombre\": '',",
+											"  \"id_grupo_arai\": ''",
+											"}",
+											"",
+											"const body = JSON.parse(pm.request.body.raw);",
+											"const sameSchema = JSON.stringify(Object.keys(servicioSchema)) === JSON.stringify(Object.keys(body));",
+											"",
+											"pm.test('Estructura del body correcta', () => {",
+											"    pm.expect(true).to.be.eql(sameSchema);",
+											"}); ",
+											"",
+											"var respuesta = pm.response.json();",
+											"",
+											"pm.test(\"unidad de gestion creada con ID \" + respuesta.id_unidad, function () {",
+											"    pm.globals.set(\"idUnidadGestion\", respuesta.id_unidad);",
+											"});"
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "POST",
+								"header": [],
+								"body": {
+									"mode": "raw",
+									"raw": "{\n  \"sigla\": \"{{$randomWord}}\",\n  \"nombre\": \"{{$randomWords}}\",\n  \"id_grupo_arai\": \"{{$randomUUID}}\"\n}",
+									"options": {
+										"raw": {
+											"language": "json"
+										}
+									}
+								},
+								"url": {
+									"raw": "{{baseUrl}}/v1/unidades-gestion",
+									"host": [
+										"{{baseUrl}}"
+									],
+									"path": [
+										"v1",
+										"unidades-gestion"
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "Obtener unidad de gestión",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"exec": [
+											"pm.test(\"Status code is 200\", () => {",
+											"    pm.response.to.have.status(200);",
+											"});",
+											"",
+											"/*",
+											"const response = pm.response.json();",
+											"const hasId = Object.keys(response).includes('id_unidad');",
+											"",
+											"pm.test(\"Servicio con id_unidad \" + response.id_unidad, function () {",
+											"    pm.expect(true).to.be.eql(hasId);",
+											"});",
+											"*/"
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "GET",
+								"header": [],
+								"url": {
+									"raw": "{{baseUrl}}/v1/unidades-gestion/{{idUnidadGestion}}",
+									"host": [
+										"{{baseUrl}}"
+									],
+									"path": [
+										"v1",
+										"unidades-gestion",
+										"{{idUnidadGestion}}"
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "Modificar unidad de gestión",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"exec": [
+											"pm.test(\"Status code is 200\", () => {",
+											"    pm.response.to.have.status(200);",
+											"});",
+											"",
+											"const unidadGestionSchema =  {",
+											"  \"sigla\": \"\",",
+											"  \"nombre\": \"\",",
+											"  \"id_grupo_arai\": \"\"",
+											"}",
+											"",
+											"const body = JSON.parse(pm.request.body.raw);",
+											"const sameSchema = JSON.stringify(Object.keys(unidadGestionSchema)) === JSON.stringify(Object.keys(body));",
+											"",
+											"pm.test('Estructura del body correcta', () => {",
+											"    pm.expect(true).to.be.eql(sameSchema);",
+											"}); ",
+											""
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "PUT",
+								"header": [],
+								"body": {
+									"mode": "raw",
+									"raw": "{\n  \"sigla\": \"UG-MOD\",\n  \"nombre\": \"UG Modificada\",\n  \"id_grupo_arai\": \"123456789\"\n}",
+									"options": {
+										"raw": {
+											"language": "json"
+										}
+									}
+								},
+								"url": {
+									"raw": "{{baseUrl}}/v1/unidades-gestion/{{idUnidadGestion}}",
+									"host": [
+										"{{baseUrl}}"
+									],
+									"path": [
+										"v1",
+										"unidades-gestion",
+										"{{idUnidadGestion}}"
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "Obtener servicios asociados a una unidad de gestion",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"exec": [
+											"pm.test(\"Status code is 200\", () => {",
+											"    pm.response.to.have.status(200);",
+											"});",
+											"",
+											"pm.test(\"Se obtuvieron servicios \", function () {",
+											"    var jsonData = pm.response.json();",
+											"    ",
+											"    if(jsonData.length > 0){",
+											"        pm.expect(jsonData.length).to.be.above(0);",
+											"",
+											"        const hasId = Object.keys(jsonData[0]).includes('id_servicio');",
+											"        // Si el servicio tiene un id_servicio",
+											"        pm.expect(true).to.be.eql(hasId);",
+											"    }else{",
+											"        pm.expect(jsonData.length).to.be.equal(0);",
+											"    }    ",
+											"});"
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "GET",
+								"header": [],
+								"url": {
+									"raw": "{{baseUrl}}/v1/unidades-gestion/{{idUnidadGestion}}/servicios",
+									"host": [
+										"{{baseUrl}}"
+									],
+									"path": [
+										"v1",
+										"unidades-gestion",
+										"{{idUnidadGestion}}",
+										"servicios"
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "Obtener unidades de gestion",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"exec": [
+											"pm.test(\"Status code is 200\", () => {",
+											"    pm.response.to.have.status(200);",
+											"});",
+											"",
+											"const jsonData = pm.response.json();",
+											"",
+											"pm.test(\"Obtener unidades de gestion \", function () {    ",
+											"    if(jsonData.length > 0){",
+											"        pm.expect(jsonData.length).to.be.above(0);",
+											"",
+											"        const hasId = Object.keys(jsonData[0]).includes('id_unidad');",
+											"        // Si el servicio tiene un id_servicio",
+											"        pm.expect(true).to.be.eql(hasId);",
+											"    }else{",
+											"        pm.expect(jsonData.length).to.be.equal(0);",
+											"    }    ",
+											"});",
+											"",
+											"",
+											"const plantillaUA =  {  ",
+											"  \"sigla\": '',",
+											"  \"nombre\": '',",
+											"  \"id_grupo_arai\": '',",
+											"  \"id_unidad\": ''",
+											"};",
+											"",
+											"pm.test('Estructura de la respuesta correcta', () => {",
+											"    if(jsonData.length > 0){",
+											"        const sameSchema = JSON.stringify(Object.keys(plantillaUA)) === JSON.stringify(Object.keys(jsonData[0]));",
+											"        pm.expect(true).to.be.eql(sameSchema);",
+											"    }else{",
+											"        const sameSchema = JSON.stringify([]) === JSON.stringify(jsonData);",
+											"        pm.expect(true).to.be.eql(sameSchema);",
+											"    }  ",
+											"}); "
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "GET",
+								"header": [],
+								"url": {
+									"raw": "{{baseUrl}}/v1/unidades-gestion",
+									"host": [
+										"{{baseUrl}}"
+									],
+									"path": [
+										"v1",
+										"unidades-gestion"
+									]
+								}
+							},
+							"response": []
+						},
+						{
+							"name": "Elimina una unidad de gestion",
+							"event": [
+								{
+									"listen": "test",
+									"script": {
+										"exec": [
+											"pm.test(\"Status code is 200\", () => {",
+											"    pm.response.to.have.status(200);",
+											"});",
+											"",
+											"var respuesta = pm.response.json();",
+											"",
+											"pm.test(\"Eliminado correctamente\", function () {",
+											"    var jsonData = pm.response.json();",
+											"    pm.expect(jsonData.respuesta).to.eql(true);",
+											"});"
+										],
+										"type": "text/javascript"
+									}
+								}
+							],
+							"request": {
+								"method": "DELETE",
+								"header": [],
+								"body": {
+									"mode": "raw",
+									"raw": "",
+									"options": {
+										"raw": {
+											"language": "json"
+										}
+									}
+								},
+								"url": {
+									"raw": "{{baseUrl}}/v1/unidades-gestion/{{idUnidadGestion}}",
+									"host": [
+										"{{baseUrl}}"
+									],
+									"path": [
+										"v1",
+										"unidades-gestion",
+										"{{idUnidadGestion}}"
+									]
+								}
+							},
+							"response": []
+						}
+					]
+				}
+			]
+		}
+	],
+	"auth": {
+		"type": "basic",
+		"basic": [
+			{
+				"key": "password",
+				"value": "admin",
+				"type": "string"
+			},
+			{
+				"key": "username",
+				"value": "admin",
+				"type": "string"
+			}
+		]
+	},
+	"event": [
+		{
+			"listen": "prerequest",
+			"script": {
+				"type": "text/javascript",
+				"exec": [
+					""
+				]
+			}
+		},
+		{
+			"listen": "test",
+			"script": {
+				"type": "text/javascript",
+				"exec": [
+					""
+				]
+			}
+		}
+	],
+	"variable": [
+		{
+			"key": "baseUrl",
+			"value": "http://localhost:9002/api"
+		}
+	]
+}
\ No newline at end of file
diff --git a/api-backend/www/api.php b/api-backend/www/api.php
index 4ffb60d8e3b898495b95d93fe9c5f8c0649b68cb..c94e828ec990c7dfcb89ee3562a1f313b01be805 100644
--- a/api-backend/www/api.php
+++ b/api-backend/www/api.php
@@ -21,7 +21,7 @@ $settings = array(
     'prefijo_controladores' => '',
     'api_version' => $api_version,
     'api_titulo' => 'Tupa (backend)',
-    'url_protegida' => '/pases|registros|sedes|terminos-condiciones|visitantes|visitas/',
+    'url_protegida' => '/pases|registros|sedes|terminos-condiciones|visitantes|visitas|servicios|unidades-gestion|funciones/',
     'debug' => true,
 );
 
diff --git a/core/src/UNAM/Tupa/Core/Errors/UnidadGestionError.php b/core/src/UNAM/Tupa/Core/Errors/UnidadGestionError.php
new file mode 100644
index 0000000000000000000000000000000000000000..0ff310c3c58626f4b04612395cba969156641c25
--- /dev/null
+++ b/core/src/UNAM/Tupa/Core/Errors/UnidadGestionError.php
@@ -0,0 +1,12 @@
+<?php declare(strict_types=1);
+
+namespace UNAM\Tupa\Core\Errors;
+
+/**
+ * Sede 
+ *
+ * @codeCoverageIgnore
+ */
+class UnidadGestionError extends ErrorTupa
+{
+}
\ No newline at end of file
diff --git a/core/src/UNAM/Tupa/Core/Manager/ManagerFuncion.php b/core/src/UNAM/Tupa/Core/Manager/ManagerFuncion.php
new file mode 100644
index 0000000000000000000000000000000000000000..86d89fdee99d34995f692809c55e40d78c64e2bd
--- /dev/null
+++ b/core/src/UNAM/Tupa/Core/Manager/ManagerFuncion.php
@@ -0,0 +1,314 @@
+<?php
+
+declare(strict_types=1);
+
+namespace UNAM\Tupa\Core\Manager;
+
+use UNAM\Tupa\Core\Errors\ErrorTupa;
+use UNAM\Tupa\Core\Filtros\Filtro;
+use UNAM\Tupa\Core\Negocio\SolicitudesServicios\Funcion;
+
+class ManagerFuncion extends Manager
+{
+    /**
+     * @param $id
+     * @return Funcion|null
+     * @throws ErrorTupa No se pudo recuperar el servicio
+     */
+    public function getFuncion($id)
+    {
+        $params = [
+            "id" => $id
+        ];
+
+        $sql = "SELECT  id_funcion,
+                        nombre,
+                        descripcion,
+                        es_agrupador,
+                        id_funcion_padre,
+                        id_funcion_predecesor,
+                        vigencia_inicio,
+                        vigencia_fin,
+                        id_servicio "
+            . "FROM funciones s "
+            . "WHERE id_funcion = :id";
+
+        $result = $this->db->sentencia_consultar_fila($sql, $params);
+
+        if (!$result) {
+            throw new ErrorTupa("No se pudo recuperar la funcion '$id'");
+        }
+
+        return $this->hidratarFuncion($result);
+    }
+
+    /**
+     * @param Filtro|null $filtro
+     * @param bool $hidratar
+     * @return Funcion[]
+     */
+    public function getFunciones(Filtro $filtro = null, $hidratar = true)
+    {
+        $where = $this->getSqlWhere($filtro);
+        $orderBy = $this->getSqlOrderBy($filtro);
+        $limit = $this->getSqlLimit($filtro);
+
+        $sql = sprintf("
+        SELECT  f.id_funcion,
+                f.nombre,
+                f.descripcion,
+                f.es_agrupador,
+                f.id_funcion_padre,
+                f.id_funcion_predecesor,
+                f.vigencia_inicio,
+                f.vigencia_fin,
+                f.id_servicio 
+        from funciones f
+            %s
+            %s
+            %s;", $where, $orderBy, $limit);
+
+        $result = $this->db->consultar($sql);
+
+        if ($hidratar) {
+            $result = $this->hidratarFunciones($result);
+        }
+
+        return $result;
+    }
+
+    /**
+     * @param Funcion $funcion
+     * @return bool|string
+     * @throws ErrorTupa No se pudo crear el servicio
+     */
+    public function crear(Funcion $funcion)
+    {
+        $sql = "INSERT INTO funciones (nombre, descripcion, es_agrupador, vigencia_inicio, id_funcion_padre, id_funcion_predecesor, id_servicio)
+                VALUES (:nombre, :descripcion, :es_agrupador, :vigencia_inicio, :id_funcion_padre, :id_funcion_predecesor, :id_servicio) RETURNING id_funcion";
+
+        $sqlParams = [
+            "nombre" => $funcion->getNombre(),
+            "descripcion" => $funcion->getDescripcion(),
+            "es_agrupador" => $funcion->getEsAgrupador() ? 1 : 0,
+            "vigencia_inicio" => $funcion->getVigenciaInicio(),
+            "id_funcion_padre" => is_object($funcion->getFuncionPadre()) ? $funcion->getFuncionPadre()->getId() : null,
+            "id_funcion_predecesor" => is_object($funcion->getFuncionPredecesor()) ? $funcion->getFuncionPredecesor()->getId() : null,
+            "id_servicio" => $funcion->getServicio()->getId()
+        ];
+
+        $result = $this->db->sentencia_consultar($sql, $sqlParams);
+
+        if (!$result) {
+            throw new ErrorTupa("No se pudo crear el servicio");
+        }
+
+        return $result;
+    }
+
+    /**
+     * @param Funcion $funcion
+     * @return mixed
+     */
+    public function actualizar($funcion)
+    {
+        $params = [
+            "id_funcion" => $funcion->getId(),
+            "nombre" => $funcion->getNombre(),
+            "descripcion" => $funcion->getDescripcion(),
+            "es_agrupador" => $funcion->getEsAgrupador() ? 1 : 0,
+            "vigencia_inicio" => $funcion->getVigenciaInicio(),
+            "vigencia_fin" => $funcion->getVigenciaFin(),
+            "id_funcion_padre" => is_object($funcion->getFuncionPadre()) ? $funcion->getFuncionPadre()->getId() : null,
+            "id_funcion_predecesor" => is_object($funcion->getFuncionPredecesor()) ? $funcion->getFuncionPredecesor()->getId() : null,
+            "id_servicio" => $funcion->getServicio()->getId()
+        ];
+
+        $sql = "UPDATE funciones
+                SET    nombre = :nombre,
+                       descripcion = :descripcion,
+                       es_agrupador = :es_agrupador,
+                       vigencia_inicio = :vigencia_inicio,
+                       vigencia_fin = :vigencia_fin,
+                       id_funcion_padre = :id_funcion_padre,
+                       id_funcion_predecesor = :id_funcion_predecesor,
+                       id_servicio = :id_servicio
+                WHERE  id_funcion = :id_funcion";
+
+        return $this->db->sentencia_ejecutar($sql, $params);
+    }
+
+
+    /**
+     * Retorna todas las funciones que son hijas de una funcion
+     * @param $id
+     * @return Funcion|null
+     */
+    public function getFuncionesHijas($idFuncionPadre, $hidratar = true)
+    {
+        $sql = sprintf(
+            "WITH RECURSIVE cte_padres_hijos(
+                id_funcion, 
+                nombre, 
+                descripcion,
+                es_agrupador,
+                id_funcion_predecesor,
+                id_funcion_padre, 
+                vigencia_inicio,
+                vigencia_fin,
+                nivel) AS (
+            SELECT 
+                id_funcion, 
+                nombre, 
+                descripcion,
+                es_agrupador,
+                id_funcion_predecesor,
+                id_funcion_padre, 
+                vigencia_inicio,
+                vigencia_fin,
+                1 as nivel
+            FROM funciones 
+            WHERE id_funcion_padre = %s -- obtener los nodos raíz
+            UNION ALL
+            SELECT 
+                funciones.id_funcion, 
+                funciones.nombre, 
+                funciones.descripcion,
+                funciones.es_agrupador,
+                funciones.id_funcion_predecesor,
+                funciones.id_funcion_padre, 
+                funciones.vigencia_inicio,
+                funciones.vigencia_fin,
+                cte_padres_hijos.nivel + 1
+            FROM funciones
+            JOIN cte_padres_hijos ON funciones.id_funcion_padre = cte_padres_hijos.id_funcion
+        )
+        SELECT 
+            id_funcion, 
+            nombre, 
+            descripcion,
+            es_agrupador,
+            id_funcion_predecesor,
+            id_funcion_padre, 
+            vigencia_inicio,
+            vigencia_fin,
+            nivel
+        FROM cte_padres_hijos
+        ORDER BY nivel, id_funcion;",
+            $idFuncionPadre
+        );
+
+        $result = $this->db->consultar($sql);
+
+        if ($hidratar) {
+            $result = $this->hidratarFunciones($result);
+        }
+
+        return $result;
+    }
+
+    /**
+     * Retorna todas las funciones sucesoras de una funcion predecesora
+     * 
+     * @param $id
+     * @return Funcion|null
+     */
+    public function getFuncionesPredecesoras($idFuncionPredecesor, $hidratar = true)
+    {
+        $sql = sprintf(
+            "WITH RECURSIVE cte_predecesores(
+                    id_funcion, 
+                    nombre, 
+                    descripcion,
+                    es_agrupador,
+                    id_funcion_predecesor,
+                    id_funcion_padre, 
+                    vigencia_inicio,
+                    vigencia_fin,
+                    nivel) AS (
+                SELECT 
+                    id_funcion, 
+                    nombre, 
+                    descripcion,
+                    es_agrupador,
+                    id_funcion_predecesor,
+                    id_funcion_padre, 
+                    vigencia_inicio,
+                    vigencia_fin,
+                    1 as nivel
+                FROM funciones
+                WHERE id_funcion_predecesor = %s -- obtener los nodos raíz
+                    
+                UNION ALL
+                    
+                SELECT 
+                    funciones.id_funcion, 
+                    funciones.nombre, 
+                    funciones.descripcion,
+                    funciones.es_agrupador,
+                    funciones.id_funcion_predecesor,
+                    funciones.id_funcion_padre, 
+                    funciones.vigencia_inicio,
+                    funciones.vigencia_fin,
+                    cte_predecesores.nivel + 1
+                FROM funciones
+                JOIN cte_predecesores ON funciones.id_funcion_predecesor = cte_predecesores.id_funcion
+            )
+                
+            SELECT 
+                id_funcion, 
+                nombre, 
+                descripcion,
+                es_agrupador,
+                id_funcion_predecesor,
+                id_funcion_padre, 
+                vigencia_inicio,
+                vigencia_fin,
+                nivel
+            FROM cte_predecesores
+            ORDER BY nivel, id_funcion;",
+            $idFuncionPredecesor
+        );
+
+        $result = $this->db->consultar($sql);
+
+        if ($hidratar) {
+            $result = $this->hidratarFunciones($result);
+        }
+
+        return $result;
+    }
+
+
+    /**
+     * @param $datos
+     * @return Funcion
+     */
+    protected function hidratarFuncion($datos)
+    {
+        $funcion = new Funcion();
+
+        $funcion->loadFromDatos($datos);
+
+        return $funcion;
+    }
+
+    /**
+     * @param $datos
+     * @return Funcion[] colección de Funciones
+     */
+    protected function hidratarFunciones($datos)
+    {
+        $funciones = [];
+
+        if (count($datos) < 1) {
+            return $funciones;
+        }
+
+        foreach ($datos as $dato) {
+            $funciones[] = $this->hidratarFuncion($dato);
+        }
+
+        return $funciones;
+    }
+}
diff --git a/core/src/UNAM/Tupa/Core/Manager/ManagerServicio.php b/core/src/UNAM/Tupa/Core/Manager/ManagerServicio.php
new file mode 100644
index 0000000000000000000000000000000000000000..bbf6b89734fb613ce2dbfa1340ebd69dcf2a873f
--- /dev/null
+++ b/core/src/UNAM/Tupa/Core/Manager/ManagerServicio.php
@@ -0,0 +1,178 @@
+<?php declare(strict_types=1);
+
+namespace UNAM\Tupa\Core\Manager;
+
+use UNAM\Tupa\Core\Errors\ErrorTupa;
+use UNAM\Tupa\Core\Filtros\Filtro;
+use UNAM\Tupa\Core\Negocio\SolicitudesServicios\Servicio;
+
+class ManagerServicio extends Manager
+{
+    /**
+     * @param $id
+     * @return Servcio|null
+     * @throws ErrorTupa No se pudo recuperar el servicio
+     */
+    public function getServicio($id)
+    {
+        $params = [
+            "id" => $id
+        ];
+
+        $sql = "SELECT id_servicio, nombre, descripcion, id_sistema_arai, vigencia_inicio,vigencia_fin "
+            . "FROM servicios s "
+            . "WHERE id_servicio = :id";
+
+        $result = $this->db->sentencia_consultar_fila($sql, $params);
+
+        if (!$result) {
+            throw new ErrorTupa("No se pudo recuperar el servicio '$id'");
+        }
+
+        return $this->hidratarServicio($result);
+    }
+
+     /**
+     * @param Filtro|null $filtro
+     * @param bool $hidratar
+     * @return Servicio[]
+     */
+    public function getServicios(Filtro $filtro = null, $hidratar = true)
+    {
+        $where = $this->getSqlWhere($filtro);
+        $orderBy = $this->getSqlOrderBy($filtro);
+        $limit = $this->getSqlLimit($filtro);
+
+        $sql = sprintf("
+        SELECT S.ID_SERVICIO,
+               S.NOMBRE,
+               S.DESCRIPCION,
+               S.ID_SISTEMA_ARAI,
+               S.VIGENCIA_INICIO,
+               S.VIGENCIA_FIN
+        FROM SERVICIOS S
+        LEFT JOIN SERVICIOS_UNIDAD_GESTION SUG ON S.ID_SERVICIO = SUG.ID_SERVICIO
+        LEFT JOIN UNIDADES_GESTION UG ON SUG.ID_UNIDAD = UG.ID_UNIDAD
+            %s
+            %s
+            %s;", $where, $orderBy, $limit);
+
+        $result = $this->db->consultar($sql);
+        
+        if ($hidratar) {
+            $result = $this->hidratarServicios($result);
+        }
+
+        return $result;
+    }
+
+     /**
+     * @param Servicio $servicio
+     * @return bool|string
+     * @throws ErrorTupa No se pudo crear el servicio
+     */
+    public function crear(Servicio $servicio)
+    {
+        $sql = "INSERT INTO servicios (nombre, descripcion, id_sistema_arai,vigencia_inicio) VALUES (:nombre, :descripcion, :id_sistema_arai,:vigencia_inicio)";
+
+        $sqlParams = [
+            "nombre" => $servicio->getNombre(),
+            "descripcion" => $servicio->getDescripcion(),
+            "id_sistema_arai" => $servicio->getIdSistemaArai(),
+            "vigencia_inicio" => $servicio->getVigenciaInicio()
+        ];
+
+        $result = $this->db->sentencia_ejecutar($sql, $sqlParams);
+        
+        if (!$result) {
+            throw new ErrorTupa("No se pudo crear el servicio");
+        }
+
+        $sql = "SELECT id_servicio FROM servicios 
+                WHERE nombre = :nombre
+                AND descripcion = :descripcion
+                AND vigencia_inicio = :vigencia_inicio
+                AND id_sistema_arai = :id_sistema_arai";
+   
+        return $this->db->sentencia_consultar_fila($sql, $sqlParams);
+    }
+
+    /**
+     * @param Servicio $servicio
+     * @return mixed
+     */
+    public function actualizar($servicio)
+    {
+        $params = [
+            "nombre" => $servicio->getNombre(),
+            "descripcion" => $servicio->getDescripcion(),
+            "id_sistema_arai" => $servicio->getIdSistemaArai(),
+            "vigencia_inicio" => $servicio->getVigenciaInicio(),
+            "vigencia_fin" => $servicio->getVigenciaFin(),
+            "id" => $servicio->getId(),
+        ];
+
+        $sql = "UPDATE servicios
+                SET    nombre = :nombre,
+                       descripcion = :descripcion,
+                       id_sistema_arai = :id_sistema_arai,
+                       vigencia_inicio = :vigencia_inicio,
+                       vigencia_fin = :vigencia_fin
+                WHERE  id_servicio = :id";
+
+        return $this->db->sentencia_ejecutar($sql, $params);
+    }
+    
+    public function getServiciosUnidadGestion($id_unidad){
+        $params = [
+            "id" => $id_unidad
+        ];
+
+        $sql = "SELECT s.id_servicio,s.nombre,descripcion,id_sistema_arai,vigencia_inicio,vigencia_fin
+                FROM UNIDADES_GESTION UG
+                INNER JOIN SERVICIOS_UNIDAD_GESTION SUG ON UG.ID_UNIDAD = SUG.ID_UNIDAD
+                INNER JOIN SERVICIOS S ON S.ID_SERVICIO = SUG.ID_SERVICIO
+                WHERE ug.id_unidad = :id";
+
+
+        $result = $this->db->sentencia_consultar($sql,$params);
+
+        if (!$result) {
+            return [];
+        }
+
+        return $this->hidratarServicios($result);
+    }
+
+    /**
+     * @param $datos
+     * @return Servicio
+     */
+    protected function hidratarServicio($datos)
+    {
+        $servicio = new Servicio();
+        
+        $servicio->loadFromDatos($datos);
+
+        return $servicio;
+    }
+
+    /**
+     * @param $datos
+     * @return Servicio[] colección de Servicios
+     */
+    protected function hidratarServicios($datos)
+    {
+        $servicios = [];
+
+        if (count($datos) < 1) {
+            return $servicios;
+        }
+
+        foreach ($datos as $dato) {
+            $servicios[] = $this->hidratarServicio($dato);
+        }
+        
+        return $servicios;
+    }
+}
diff --git a/core/src/UNAM/Tupa/Core/Manager/ManagerUnidadGestion.php b/core/src/UNAM/Tupa/Core/Manager/ManagerUnidadGestion.php
new file mode 100644
index 0000000000000000000000000000000000000000..7f55e30e6f25b7e56b78f0f00d4b1e2b573f8789
--- /dev/null
+++ b/core/src/UNAM/Tupa/Core/Manager/ManagerUnidadGestion.php
@@ -0,0 +1,234 @@
+<?php declare(strict_types=1);
+
+namespace UNAM\Tupa\Core\Manager;
+
+use UNAM\Tupa\Core\Errors\UnidadGestionError;
+use UNAM\Tupa\Core\Filtros\Filtro;
+use UNAM\Tupa\Core\Negocio\Organizacion\UnidadGestion;
+use UNAM\Tupa\Backend\API\Factory;
+
+class ManagerUnidadGestion extends Manager
+{
+    /**
+     * @param $id
+     * @return UnidadGestion|null
+     * @throws UnidadGestionError No se pudo recuperar la Unidad de gestion
+     */
+    public function getUnidadGestion($id)
+    {
+        $params = [
+            "id" => $id
+        ];
+
+        $sql = "SELECT id_unidad, sigla, nombre, id_grupo_arai "
+            . "FROM unidades_gestion ug "
+            . "WHERE id_unidad = :id";
+
+        $result = $this->db->sentencia_consultar_fila($sql, $params);
+
+        if (!$result) {
+            throw new UnidadGestionError("No se pudo recuperar la unidad de gestion '$id'");
+        }
+
+        return $this->hidratarUnidadGestion($result);
+    }
+
+     /**
+     * @param Filtro|null $filtro
+     * @param bool $hidratar
+     * @return UnidadesGestion[]
+     */
+    public function getUnidadesGestion(Filtro $filtro = null, $hidratar = true)
+    {
+        $where = $this->getSqlWhere($filtro);
+        $orderBy = $this->getSqlOrderBy($filtro);
+        $limit = $this->getSqlLimit($filtro);
+
+        $sql = sprintf("
+            SELECT	
+                ug.id_unidad, ug.nombre, ug.sigla, ug.id_grupo_arai
+            FROM 
+                 unidades_gestion ug
+            %s
+            %s
+            %s;", $where, $orderBy, $limit);
+
+        $result = $this->db->consultar($sql);
+ 
+        if ($hidratar) {
+            $result = $this->hidratarUnidaesdGestion($result);
+        }
+
+        return $result;
+    }
+
+     /**
+     * @param UnidadGestion $ug
+     * @return bool|string
+     * @throws UnidadGestionError No se pudo crear la unidad de gestion
+     */
+    public function crear(UnidadGestion $ug)
+    {
+        $sql = "INSERT INTO unidades_gestion (nombre, sigla, id_grupo_arai) VALUES (:nombre, :sigla, :id_grupo_arai)";
+
+        $sqlParams = [
+            "nombre" => $ug->getNombre(),
+            "sigla" => $ug->getSigla(),
+            "id_grupo_arai" => $ug->getIdGrupoArai(),
+        ];
+
+        $result = $this->db->sentencia_ejecutar($sql, $sqlParams);
+
+        if (!$result) {
+            throw new UnidadGestionError("No se pudo crear la unidad de gestion");
+        }
+
+        $sql = "SELECT id_unidad FROM unidades_gestion 
+                WHERE nombre = :nombre
+                AND sigla = :sigla 
+                AND id_grupo_arai = :id_grupo_arai";
+   
+        return $this->db->sentencia_consultar_fila($sql, $sqlParams);
+    }
+
+    /**
+     * @param UnidadGestion $unidadGestion
+     * @return mixed
+     */
+    public function actualizar(UnidadGestion $ug)
+    {
+        $params = [
+            "sigla" => $ug->getSigla(),
+            "nombre" => $ug->getNombre(),
+            "id_grupo_arai" => $ug->getIdGrupoArai(),
+            "id" => $ug->getId(),
+        ];
+
+        $sql = " UPDATE unidades_gestion
+                SET    nombre = :nombre,
+                       sigla = :sigla,
+                       id_grupo_arai = :id_grupo_arai
+                WHERE  id_unidad = :id";
+
+        return $this->db->sentencia_ejecutar($sql, $params);
+    }
+
+    /**
+     * @param $id
+     * @return bool|null
+     * @throws UnidadGestionError No se pudo eliminar la Unidad de gestion
+     */
+    public function eliminar($id)
+    {
+        $params = [
+            "id" => $id
+        ];
+
+        $sql = "DELETE FROM unidades_gestion "
+            . "WHERE id_unidad = :id";
+
+        $result = $this->db->sentencia_ejecutar($sql, $params);
+
+        if (!$result) {
+            throw new UnidadGestionError("No se pudo eliminar la unidad de gestion '$id'");
+        }
+
+        return $result;
+    }
+
+    /**
+     * @param int $idUnidad id de la unidad de gestion
+     * @param array $servicios id de los servicios que se van a asociar a la ug 
+     * @return bool
+     * @throws UnidadGestionError 
+     */
+    public function agregarServicios($idUnidad, $servicios)
+    {
+        try{            
+            $sql = "INSERT INTO servicios_unidad_gestion VALUES (:id_unidad_gestion,:id_servicio)";
+            
+            $this->db->abrir_transaccion();
+            foreach($servicios['servicios'] as $idServicio){
+                $params = [
+                    'id_unidad_gestion' => $idUnidad,
+                    'id_servicio' => $idServicio
+                ];    
+
+                $this->db->sentencia_ejecutar($sql, $params);    
+            }
+            $this->db->cerrar_transaccion();
+            return true;            
+        }catch(\Exception $e){
+            $this->db->abortar_transaccion();
+            Factory::getMainLogger()->error($e->getMessage());
+            throw new UnidadGestionError("No se pudo agregar el servicio a la unidad $idUnidad");
+        }  
+        return false;     
+    }
+
+    /**
+     * @param int $idUnidad id de la unidad de gestion
+     * @param array $servicios id de los servicios que se van a eliminar de laug 
+     * @return bool
+     * @throws UnidadGestionError 
+     */
+    public function eliminarServicios($unidadGestion, $servicios)
+    {
+        try{            
+            $sql = "DELETE FROM servicios_unidad_gestion WHERE id_unidad = :id_unidad_gestion and id_servicio = :id_servicio";
+            
+            $this->db->abrir_transaccion();
+            foreach($servicios as $servicio){
+                $params = [
+                    'id_unidad_gestion' => $unidadGestion->getId(),
+                    'id_servicio' => $servicio->getId()
+                ];    
+                
+                $resultado = $this->db->sentencia_ejecutar($sql, $params);    
+                
+                if(!$resultado){
+                    throw new \Exception('No se encontro el servicio para esta UG');
+                }
+            }
+            $this->db->cerrar_transaccion();
+            return true;            
+        }catch(\Exception $e){
+            $this->db->abortar_transaccion();
+            Factory::getMainLogger()->error($e->getMessage());
+            throw new UnidadGestionError("No se pudo eliminar el/los servicio de la unidad $idUnidad");
+        }  
+        return false;     
+    }
+
+    /**
+     * @param $datos
+     * @return UnidadGestion
+     */
+    protected function hidratarUnidadGestion($datos)
+    {
+        $ug = new UnidadGestion();
+        
+        $ug->loadFromDatos($datos);
+
+        return $ug;
+    }
+
+    /**
+     * @param $datos
+     * @return UnidadGestion[] colección de Unidades de gestion
+     */
+    protected function hidratarUnidaesdGestion($datos)
+    {
+        $ug = [];
+
+        if (count($datos) < 1) {
+            return $ug;
+        }
+
+        foreach ($datos as $dato) {
+            $ug[] = $this->hidratarUnidadGestion($dato);
+        }
+        
+        return $ug;
+    }
+}
diff --git a/core/src/UNAM/Tupa/Core/Negocio/Organizacion/UnidadGestion.php b/core/src/UNAM/Tupa/Core/Negocio/Organizacion/UnidadGestion.php
new file mode 100644
index 0000000000000000000000000000000000000000..326a911d43b8710d8c1776ce80d9d5bbfddc654f
--- /dev/null
+++ b/core/src/UNAM/Tupa/Core/Negocio/Organizacion/UnidadGestion.php
@@ -0,0 +1,92 @@
+<?php declare(strict_types=1);
+
+namespace UNAM\Tupa\Core\Negocio\Organizacion;
+
+
+class UnidadGestion {
+
+    private int $id;
+    private string $sigla;
+    private string $nombre;
+    private string $idGrupoArai;
+    private ?array $servicios;
+
+    public function getId():int{
+        return $this->id;
+    }
+
+    public function getSigla():string{
+        return $this->sigla;
+    }
+
+    public function getNombre():string{
+        return $this->nombre;
+    }
+
+    public function getIdGrupoArai():string{
+        return $this->idGrupoArai;
+    }
+
+    public function getServicios():?array{
+        return $this->servicios ?? null;
+    }
+
+    public function setId(int $id){
+        $this->id = $id;
+    }
+
+    public function setSigla(string $sigla):void {
+        $this->sigla = $sigla;
+    }
+
+    public function setNombre(string $nombre):void{
+        $this->nombre = $nombre;
+    }
+
+    public function setIdGrupoArai(string $idGrupo):void{
+        $this->idGrupoArai = $idGrupo;
+    }
+
+    public function setServicios(array $servicios){
+        $this->servicios = $servicios;
+    }
+
+    /**
+     * Hidrata los atributos del objeto a partir de $datos
+     *
+     * @param array $datos inicializar directamente con un set de datos
+     */
+    public function loadFromDatos(array $datos)
+    {
+        if (isset($datos['id_unidad'])) {
+            $this->setId($datos['id_unidad']);
+        }
+        if (isset($datos['sigla'])) {
+            $this->setSigla($datos['sigla']);
+        }
+        if (isset($datos['nombre'])) {
+            $this->setNombre($datos['nombre']);
+        }
+        if (isset($datos['id_grupo_arai'])) {
+            $this->setIdGrupoArai($datos['id_grupo_arai']);
+        }
+        if (isset($datos['servicios'])) {
+            $this->setServicios($datos['servicios']);
+        }
+    }
+    
+    /**
+     * @return array
+     */
+    public function toArray(): array
+    {
+        return [
+            'id_unidad' => $this->getId(),
+            'sigla' => $this->getSigla(),
+            'nombre' => $this->getNombre(),
+            'id_grupo_arai' => $this->getIdGrupoArai(),
+            'servicios' => $this->getServicios(),
+        ];
+    }
+}
+
diff --git a/core/src/UNAM/Tupa/Core/Negocio/SolicitudesServicios/Funcion.php b/core/src/UNAM/Tupa/Core/Negocio/SolicitudesServicios/Funcion.php
new file mode 100644
index 0000000000000000000000000000000000000000..9f4def59172d198b71361843381adbc3ec88ada2
--- /dev/null
+++ b/core/src/UNAM/Tupa/Core/Negocio/SolicitudesServicios/Funcion.php
@@ -0,0 +1,157 @@
+<?php  declare(strict_types=1);
+
+namespace UNAM\Tupa\Core\Negocio\SolicitudesServicios;
+
+use UNAM\Tupa\Core\Negocio\SolicitudesServicios\Servicio;
+
+class Funcion {
+    private int $id;
+    private string $nombre;
+    private string $descripcion;
+    private bool $esAgrupador;
+    private Funcion $funcionPadre;
+    private Funcion $funcionPredecesor;
+    private string $vigenciaInicio;    
+    private string $vigenciaFin;    
+    private Servicio $servicio;    
+
+    //Getter
+    public function getId():int {
+        return $this->id;
+    }
+
+    public function getNombre():string {
+        return $this->nombre;
+    }
+
+    public function getDescripcion():string {
+        return $this->descripcion;
+    }
+
+    public function getEsAgrupador():bool {
+        return $this->esAgrupador;
+    }
+
+    public function getFuncionPadre():?Funcion {
+        return $this->funcionPadre ?? null;
+    }
+
+    public function getFuncionPredecesor():?Funcion {
+        return $this->funcionPredecesor ?? null;
+    }
+
+    public function getVigenciaInicio():string {
+        return $this->vigenciaInicio;
+    }
+
+    public function getVigenciaFin():?string {
+        return $this->vigenciaFin ?? null;
+    }
+    
+    public function getServicio():?Servicio {
+        return $this->servicio ?? null;
+    }
+
+    //Setter
+    public function setId($id):void {
+        $this->id = $id;
+    }
+
+    public function setNombre(string $nombre):void {
+        $this->nombre = $nombre;
+    }
+
+    public function setDescripcion(string $descripcion):void {
+        $this->descripcion = $descripcion;
+    }
+
+    public function setEsAgrupador(bool $esAgrupador):void {
+        $this->esAgrupador = $esAgrupador;
+    }
+
+    public function setFuncionPadre(Funcion $funcionPadre):void {
+        $this->funcionPadre = $funcionPadre;
+    }
+
+    public function setFuncionPredecesor(Funcion $funcionPredecesor):void {
+        $this->funcionPredecesor = $funcionPredecesor;
+    }
+
+    public function setVigenciaInicio(string $vigenciaInicio):void {
+        $this->vigenciaInicio = $vigenciaInicio;
+    }
+
+    public function setVigenciaFin(string $vigenciaFin):void {
+        $this->vigenciaFin = $vigenciaFin;
+    }
+    
+    public function setServicio(Servicio $servicio):void {
+        $this->servicio =  $servicio;
+    }
+
+    /**
+     * Hidrata los atributos del objeto a partir de $datos
+     *
+     * @param array $datos inicializar directamente con un set de datos
+     */
+    public function loadFromDatos(array $datos)
+    {
+        if (isset($datos['id_funcion'])) {
+            $this->setId($datos['id_funcion']);
+        }
+
+        if (isset($datos['nombre'])) {
+            $this->setNombre($datos['nombre']);
+        }
+
+        if (isset($datos['descripcion'])) {
+            $this->setDescripcion($datos['descripcion']);
+        }
+
+        if (isset($datos['es_agrupador'])) {
+            $this->setEsAgrupador($datos['es_agrupador']);
+        }
+
+        if (isset($datos['id_funcion_padre'])) {
+            $funcionPadre = new Funcion();
+            $funcionPadre->setId($datos['id_funcion_padre']);
+            $this->setFuncionPadre($funcionPadre);
+        }
+
+        if (isset($datos['id_funcion_predecesor'])) {
+            $funcionPredecesor = new Funcion();
+            $funcionPredecesor->setId($datos['id_funcion_predecesor']);
+            $this->setFuncionPredecesor($funcionPredecesor);
+        }
+
+        if (isset($datos['vigencia_inicio'])) {
+            $this->setVigenciaInicio($datos['vigencia_inicio']);
+        }
+
+        if (isset($datos['vigencia_fin'])) {
+            $this->setVigenciaFin($datos['vigencia_fin']);
+        }
+
+        if (isset($datos['id_servicio'])) {
+            $servicio = new Servicio();
+            $servicio->setId($datos['id_servicio']);
+            $this->setServicio($servicio);
+        }
+    }
+
+    public function toArray(): array
+    {
+        return [
+            'id_funcion' => $this->getId(),
+            'nombre' => $this->getNombre(),
+            'descripcion' => $this->getDescripcion(),
+            'es_agrupador' => $this->getEsAgrupador(),
+            'id_funcion_padre' => is_object($this->getFuncionPadre()) ? $this->getFuncionPadre()->getId() : null,
+            'id_funcion_predecesor' => is_object($this->getFuncionPredecesor()) ? $this->getFuncionPredecesor()->getId() : null,
+            'vigencia_inicio' => $this->getVigenciaInicio(),
+            'vigencia_fin' => $this->getVigenciaFin(),
+            'id_servicio' => is_object($this->getServicio()) ? $this->getServicio()->getId() : null
+        ];
+    }
+}
+
diff --git a/core/src/UNAM/Tupa/Core/Negocio/SolicitudesServicios/Servicio.php b/core/src/UNAM/Tupa/Core/Negocio/SolicitudesServicios/Servicio.php
new file mode 100644
index 0000000000000000000000000000000000000000..66ee2d10359064c516ef41cbf1174db8a134ceae
--- /dev/null
+++ b/core/src/UNAM/Tupa/Core/Negocio/SolicitudesServicios/Servicio.php
@@ -0,0 +1,100 @@
+<?php  declare(strict_types=1);
+
+namespace UNAM\Tupa\Core\Negocio\SolicitudesServicios;
+
+class Servicio {
+    private int $idServicio;
+    private string $nombre;
+    private ?string $descripcion;
+    private string $idServicioArai;
+    private string $vigenciaInicio;
+    private ?string $vigenciaFin;
+
+    public function getId():int {
+        return $this->idServicio;
+    }
+
+    public function getNombre():string {
+        return $this->nombre;
+    }
+
+    public function getDescripcion():string {
+        return $this->descripcion;
+    }
+
+    public function getIdSistemaArai():string {
+        return $this->idServicioArai;
+    }
+
+    public function getVigenciaInicio():string {
+        return $this->vigenciaInicio;
+    }
+
+    public function getVigenciaFin():?string {
+        return $this->vigenciaFin ?? null;
+    }
+
+    public function setId(int $idServicio):void {
+        $this->idServicio = $idServicio;
+    }
+
+    public function setNombre(string $nombre):void {
+        $this->nombre = $nombre;
+    }
+
+    public function setDescripcion(?string $descripcion):void {
+        $this->descripcion = $descripcion;
+    }
+
+    public function setIdServicioArai(string $idServicioArai):void {
+        $this->idServicioArai = $idServicioArai;
+    }
+
+    public function setVigenciaInicio(string $vigenciaInicio):void {
+        $this->vigenciaInicio = $vigenciaInicio;
+    }
+
+    public function setVigenciaFin(?string $vigenciaFin):void {
+        $this->vigenciaFin = $vigenciaFin;
+    }
+
+    /**
+     * Hidrata los atributos del objeto a partir de $datos
+     *
+     * @param array $datos inicializar directamente con un set de datos
+     */
+    public function loadFromDatos(array $datos)
+    {
+        if (isset($datos['id_servicio'])) {
+            $this->setId($datos['id_servicio']);
+        }
+        if (isset($datos['nombre'])) {
+            $this->setNombre($datos['nombre']);
+        }
+        if (isset($datos['descripcion'])) {
+            $this->setDescripcion($datos['descripcion']);
+        }
+        if (isset($datos['id_sistema_arai'])) {
+            $this->setIdServicioArai($datos['id_sistema_arai']);
+        }
+        if (isset($datos['vigencia_inicio'])) {
+            $this->setVigenciaInicio($datos['vigencia_inicio']);
+        }
+        if (isset($datos['vigencia_fin'])) {
+            $this->setVigenciaFin($datos['vigencia_fin']);
+        }
+    }
+
+    public function toArray(): array
+    {
+        return [
+            'id_servicio' => $this->getId(),
+            'nombre' => $this->getNombre(),
+            'descripcion' => $this->getDescripcion(),
+            'id_sistema_arai' => $this->getIdSistemaArai(),
+            'vigencia_inicio' => $this->getVigenciaInicio(),
+            'vigencia_fin' => $this->getVigenciaFin()
+        ];
+    }
+
+}
\ No newline at end of file