diff --git a/Bedelia/.dockerignore b/Bedelia/.dockerignore
new file mode 100644
index 0000000000000000000000000000000000000000..2e9693ed1a9619a49dcd4c7f3e9ea26541ff27d7
--- /dev/null
+++ b/Bedelia/.dockerignore
@@ -0,0 +1,2 @@
+obj
+bin
\ No newline at end of file
diff --git a/Bedelia/Bedelia.csproj b/Bedelia/Bedelia.csproj
new file mode 100644
index 0000000000000000000000000000000000000000..e107ff40f0cf5a3da92284e01c9a03c54dc97595
--- /dev/null
+++ b/Bedelia/Bedelia.csproj
@@ -0,0 +1,18 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+
+  <PropertyGroup>
+    <TargetFramework>net5.0</TargetFramework>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.0" NoWarn="NU1605" />
+    <PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="5.0.0" NoWarn="NU1605" />
+    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.0">
+      <PrivateAssets>all</PrivateAssets>
+      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+    </PackageReference>
+    <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="5.0.0" />
+    <PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
+  </ItemGroup>
+
+</Project>
diff --git a/Bedelia/Bedelia.csproj.user b/Bedelia/Bedelia.csproj.user
new file mode 100644
index 0000000000000000000000000000000000000000..da34dfb3c7dfbdf3398ff0bdb2f5d654da7d56a9
--- /dev/null
+++ b/Bedelia/Bedelia.csproj.user
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Controller_SelectedScaffolderID>ApiControllerWithActionsScaffolder</Controller_SelectedScaffolderID>
+    <Controller_SelectedScaffolderCategoryPath>root/Common/Api</Controller_SelectedScaffolderCategoryPath>
+    <WebStackScaffolding_ControllerDialogWidth>600</WebStackScaffolding_ControllerDialogWidth>
+  </PropertyGroup>
+</Project>
\ No newline at end of file
diff --git a/Bedelia/Bedelia.sln b/Bedelia/Bedelia.sln
new file mode 100644
index 0000000000000000000000000000000000000000..67548d1d30f7b5f4772d28987a29323225a72553
--- /dev/null
+++ b/Bedelia/Bedelia.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30717.126
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bedelia", "Bedelia.csproj", "{BB028517-233A-466B-A46C-420FC942BA48}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{BB028517-233A-466B-A46C-420FC942BA48}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{BB028517-233A-466B-A46C-420FC942BA48}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{BB028517-233A-466B-A46C-420FC942BA48}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{BB028517-233A-466B-A46C-420FC942BA48}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {53DA0290-A5A4-422B-A6DD-837A8FFCF354}
+	EndGlobalSection
+EndGlobal
diff --git a/Bedelia/Controllers/CoursesController.cs b/Bedelia/Controllers/CoursesController.cs
new file mode 100644
index 0000000000000000000000000000000000000000..56e4e8da60d9f5a601fd17532cc672a8a2fc0ee7
--- /dev/null
+++ b/Bedelia/Controllers/CoursesController.cs
@@ -0,0 +1,151 @@
+using Bedelia.Dtos;
+using Bedelia.EF;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Bedelia.Controllers
+{
+    [Route("api/[controller]")]
+    [ApiController]
+    public class CoursesController : ControllerBase
+    {
+        private readonly BedeliaContext _context;
+
+        public CoursesController(BedeliaContext context)
+        {
+            _context = context;
+        }
+
+        [HttpGet]
+        public async Task<IActionResult> Get()
+        {
+            var courses = await _context.Courses.ToListAsync();
+            return Ok(courses);
+        }
+
+        [HttpGet("{name}")]
+        public async Task<IActionResult> Get(string name)
+        {
+            var course = await _context.Courses.FirstOrDefaultAsync(x => x.Name == name);
+
+            if (course == null)
+            {
+                return BadRequest(string.Format("el curso con nombre {0} no existe", name));
+            }
+
+            return Ok(course);
+        }
+
+        [HttpPost]
+        public async Task<IActionResult> Post([FromBody] string courseName)
+        {
+            var course = new Course()
+            {
+                Name = courseName
+            };
+
+            _context.Courses.Add(course);
+            await _context.SaveChangesAsync();
+
+            return Ok(course);
+        }
+
+        [HttpPost("loadData")]
+        public async Task<IActionResult> Post([FromBody] List<string> courseNames)
+        {
+            var dbCourses = await _context.Courses
+                .Where(x=>courseNames.Contains(x.Name))
+                .ToListAsync();
+
+            var courses = new List<Course>();
+            foreach (var courseName in courseNames)
+            {
+                var dbCourse = dbCourses.FirstOrDefault(x => x.Name == courseName);
+                if (dbCourse == null)
+                {
+                    courses.Add(new Course()
+                    {
+                        Name = courseName
+                    });
+                }
+            }
+
+            _context.Courses.AddRange(courses);
+            await _context.SaveChangesAsync();
+
+            return Ok(courses);
+        }
+
+        [HttpPut("{id}")]
+        public async Task<IActionResult> Put(int id, [FromBody] Course course)
+        {
+            var dbCourse = await _context.Courses.FirstOrDefaultAsync(x => x.Id == id);
+
+            if (dbCourse == null)
+            {
+                return BadRequest(string.Format("el curso con id {0} no existe en bedelia", id));
+            }
+
+            dbCourse.Name = course.Name;
+            await _context.SaveChangesAsync();
+
+            return Ok(dbCourse);
+        }
+
+        [HttpDelete("{id}")]
+        public async Task<IActionResult> Delete(int id)
+        {
+            var course = await _context.Courses.FirstOrDefaultAsync(x => x.Id == id);
+
+            _context.Courses.Remove(course);
+            await _context.SaveChangesAsync();
+
+            return Ok();
+        }
+
+        [HttpPost("closeRecord")]
+        public async Task<IActionResult> CloseRecord(CloseRecordDto closeRecord)
+        {
+            var now = DateTime.Now;
+            var course = await _context.Courses
+                .FirstOrDefaultAsync(x => x.Name == closeRecord.CourseName);
+
+            if (course == null)
+            {
+                return BadRequest(string.Format(@"No existe el curso con nombre {0} en bedelia", closeRecord.CourseName));
+            }
+
+            var userIdentityCards = closeRecord.UserGrades.Select(x => x.IdentityCard);
+
+            var users = await _context.Users
+                .Where(x => userIdentityCards.Contains(x.IdentityCard))
+                .ToListAsync();
+
+            var userCourses = new List<UserCourse>();
+            foreach (var user in users)
+            {
+                var grade = closeRecord.UserGrades
+                    .Where(x => x.IdentityCard == user.IdentityCard)
+                    .Select(x => x.Grade)
+                    .FirstOrDefault();
+
+                userCourses.Add(new UserCourse()
+                {
+                    CourseId = course.Id,
+                    UserId = user.Id,
+                    Grade = grade,
+                    GradeDate = now
+                });
+            }
+
+            _context.UserCourses.AddRange(userCourses);
+            await _context.SaveChangesAsync();
+
+            return Ok();
+        }
+    }
+}
diff --git a/Bedelia/Controllers/UsersController.cs b/Bedelia/Controllers/UsersController.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3a384a373dccfb51aa1fab7f5af02d77dcb99e7f
--- /dev/null
+++ b/Bedelia/Controllers/UsersController.cs
@@ -0,0 +1,139 @@
+using Bedelia.Dtos;
+using Bedelia.EF;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Bedelia.Controllers
+{
+    [Route("api/[controller]")]
+    [ApiController]
+    public class UsersController : ControllerBase
+    {
+        private readonly BedeliaContext _context;
+
+        public UsersController(BedeliaContext context)
+        {
+            _context = context;
+        }
+
+        [HttpGet]
+        public async Task<IActionResult> Get()
+        {
+            var users = await _context.Users.ToListAsync();
+            return Ok(users);
+        }
+
+        [HttpGet("{identityCard}")]
+        public async Task<IActionResult> Get(string identityCard)
+        {
+            var user = await _context.Users.FirstOrDefaultAsync(x => x.IdentityCard == identityCard);
+
+            if (user == null)
+            {
+                return BadRequest(string.Format("el usuario con cedula {0} no existe en bedelia", identityCard));
+            }
+
+            return Ok(user);
+        }
+
+        [HttpPost]
+        public async Task<IActionResult> Post([FromBody] UserCreateDto userDto)
+        {
+            var user = new User()
+            {
+                IdentityCard = userDto.IdentityCard,
+                Name = userDto.Name,
+                Password = userDto.Password
+            };
+
+            _context.Users.Add(user);
+            await _context.SaveChangesAsync();
+
+            return Ok(user);
+        }
+
+        [HttpPost("loadData")]
+        public async Task<IActionResult> Post([FromBody] List<UserCreateDto> userDtos)
+        {
+            var userIdentityCards = userDtos.Select(x => x.IdentityCard);
+
+            var dbUsers = await _context.Users
+                .Where(x => userIdentityCards.Contains(x.IdentityCard))
+                .ToListAsync();
+
+            var users = new List<User>();
+            foreach (var userDto in userDtos)
+            {
+                var dbUser = dbUsers.FirstOrDefault(x => x.IdentityCard == userDto.IdentityCard);
+                if (dbUser == null)
+                {
+                    users.Add(new User()
+                    {
+                        IdentityCard = userDto.IdentityCard,
+                        Name = userDto.Name,
+                        Password = userDto.Password
+                    });
+                }
+            }
+
+            _context.Users.AddRange(users);
+            await _context.SaveChangesAsync();
+
+            return Ok(users);
+        }
+
+        [HttpPut("{id}")]
+        public async Task<IActionResult> Put(int id, [FromBody] User user)
+        {
+            var dbUser = await _context.Users.FirstOrDefaultAsync(x => x.Id == id);
+
+            if (dbUser == null)
+            {
+                return BadRequest(string.Format("el usuario con id {0} no existe en bedelia", id));
+            }
+
+            dbUser.IdentityCard = user.IdentityCard;
+            dbUser.Name = user.Name;
+            dbUser.Password = user.Password;
+
+            await _context.SaveChangesAsync();
+
+            return Ok(dbUser);
+        }
+
+        [HttpDelete("{id}")]
+        public async Task<IActionResult> Delete(int id)
+        {
+            var user = await _context.Users.FirstOrDefaultAsync(x => x.Id == id);
+
+            _context.Users.Remove(user);
+            await _context.SaveChangesAsync();
+
+            return Ok();
+        }
+
+        [HttpGet("userNotes")]
+        public async Task<IActionResult> UserNotes()
+        {
+            var result = await (from user in _context.Users
+                                join userCourse in _context.UserCourses
+                                    on user.Id equals userCourse.UserId
+                                join course in _context.Courses
+                                    on userCourse.CourseId equals course.Id
+                                select new
+                                {
+                                    User = user.IdentityCard,
+                                    Course = course.Name,
+                                    Grade = userCourse.Grade,
+                                    GradeDate = userCourse.GradeDate
+                                }).ToListAsync();
+
+            return Ok(result);
+        }
+
+    }
+}
diff --git a/Bedelia/Dockerfile b/Bedelia/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..b4f2d55aa9108c20dcde071e65b879717b85d25f
--- /dev/null
+++ b/Bedelia/Dockerfile
@@ -0,0 +1,16 @@
+FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
+WORKDIR /app
+
+WORKDIR /src
+COPY *.csproj ./
+RUN dotnet restore ./Bedelia.csproj
+
+COPY . ./
+WORKDIR /src
+RUN dotnet publish -c release -o /app/publish
+
+FROM mcr.microsoft.com/dotnet/sdk:5.0
+WORKDIR /app
+COPY --from=build /app/publish .
+EXPOSE 5000
+ENTRYPOINT ["dotnet", "Bedelia.dll"]
\ No newline at end of file
diff --git a/Bedelia/Dtos/CloseRecordDto.cs b/Bedelia/Dtos/CloseRecordDto.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0b308b8185efc01ec83f2f6851987bad2f02aac9
--- /dev/null
+++ b/Bedelia/Dtos/CloseRecordDto.cs
@@ -0,0 +1,14 @@
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+
+namespace Bedelia.Dtos
+{
+    public class CloseRecordDto
+    {
+        [Required]
+        public string CourseName { get; set; }
+
+        [Required]
+        public List<UserGradeDto> UserGrades { get; set; }
+    }
+}
diff --git a/Bedelia/Dtos/CourseCreateDto.cs b/Bedelia/Dtos/CourseCreateDto.cs
new file mode 100644
index 0000000000000000000000000000000000000000..65119ee161ce38b9dcb7a26abad126092c2d99ff
--- /dev/null
+++ b/Bedelia/Dtos/CourseCreateDto.cs
@@ -0,0 +1,10 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace Bedelia
+{
+    public class CourseCreateDto
+    {
+        [Required]
+        public string Name { get; set; }
+    }
+}
diff --git a/Bedelia/Dtos/UserCreateDto.cs b/Bedelia/Dtos/UserCreateDto.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7c6cca67f99a53993111f7b2ea970f68e0884aae
--- /dev/null
+++ b/Bedelia/Dtos/UserCreateDto.cs
@@ -0,0 +1,16 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace Bedelia.Dtos
+{
+    public class UserCreateDto
+    {
+        [Required]
+        public string IdentityCard { get; set; }
+
+        [Required]
+        public string Name { get; set; }
+
+        [Required]
+        public string Password { get; set; }
+    }
+}
diff --git a/Bedelia/Dtos/UserGradeDto.cs b/Bedelia/Dtos/UserGradeDto.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e113b38530e4a7a936e74f9202bd8b4d900cb268
--- /dev/null
+++ b/Bedelia/Dtos/UserGradeDto.cs
@@ -0,0 +1,13 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace Bedelia.Dtos
+{
+    public class UserGradeDto
+    {
+        [Required]
+        public string IdentityCard { get; set; }
+
+        [Required]
+        public int Grade { get; set; }
+    }
+}
diff --git a/Bedelia/EF/BedeliaContext.cs b/Bedelia/EF/BedeliaContext.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3104af5b6de497e058331952b06f52096df92364
--- /dev/null
+++ b/Bedelia/EF/BedeliaContext.cs
@@ -0,0 +1,65 @@
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Bedelia.EF
+{
+    public class BedeliaContext : DbContext
+    {
+        public DbSet<User> Users { get; set; }
+        public DbSet<Course> Courses { get; set; }
+        public DbSet<UserCourse> UserCourses { get; set; }
+
+        public BedeliaContext(DbContextOptions options) : base(options) { }
+
+        protected override void OnModelCreating(ModelBuilder modelBuilder)
+        {
+            modelBuilder.Entity<User>(e =>
+            {
+                e.HasKey(x => x.Id);
+
+                e.HasIndex(x => x.IdentityCard)
+                    .IsUnique();
+
+                e.HasIndex(x => x.Name)
+                    .IsUnique();
+
+                e.Property(x => x.IdentityCard)
+                    .IsRequired()
+                    .HasMaxLength(50);
+
+                e.Property(x => x.Name)
+                    .IsRequired()
+                    .HasMaxLength(50);
+
+                e.Property(x => x.Password)
+                    .IsRequired()
+                    .HasMaxLength(255);
+            });
+
+            modelBuilder.Entity<Course>(e =>
+            {
+                e.HasKey(x => x.Id);
+
+                e.Property(x => x.Name)
+                .IsRequired()
+                .HasMaxLength(50);
+            });
+
+            modelBuilder.Entity<UserCourse>(e =>
+            {
+                e.HasKey(x => new { x.UserId, x.CourseId });
+
+                e.HasOne(x => x.Course)
+                    .WithMany(x => x.UserCourses)
+                    .HasForeignKey(x => x.CourseId);
+
+                e.HasOne(x => x.User)
+                    .WithMany(x => x.UserCourses)
+                    .HasForeignKey(x => x.UserId);
+            });
+        }
+    }
+}
diff --git a/Bedelia/EF/Course.cs b/Bedelia/EF/Course.cs
new file mode 100644
index 0000000000000000000000000000000000000000..65a6b5a6bf1e37b5204881a5a82e169190aa65a1
--- /dev/null
+++ b/Bedelia/EF/Course.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Bedelia.EF
+{
+    public class Course
+    {
+        public int Id { get; set; }
+        public string Name { get; set; }
+
+        public ICollection<UserCourse> UserCourses { get; set; }
+    }
+}
diff --git a/Bedelia/EF/User.cs b/Bedelia/EF/User.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4cfc40133510e9343554ac796aa152f1c95e8418
--- /dev/null
+++ b/Bedelia/EF/User.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Bedelia.EF
+{
+    public class User
+    {
+        public int Id { get; set; }
+        public string IdentityCard { get; set; }
+        public string Name { get; set; }
+        public string Password { get; set; }
+
+        public ICollection<UserCourse> UserCourses { get; set; }
+    }
+}
diff --git a/Bedelia/EF/UserCourse.cs b/Bedelia/EF/UserCourse.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0b52e7c4c4d3895fe88ec952b8cb5c91b6d8b8c8
--- /dev/null
+++ b/Bedelia/EF/UserCourse.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Bedelia.EF
+{
+    public class UserCourse
+    {
+        public int UserId { get; set; }
+        public int CourseId { get; set; }
+        public int Grade { get; set; }
+        public DateTime GradeDate { get; set; }
+
+        public User User { get; set; }
+        public Course Course { get; set; }
+    }
+}
diff --git a/Bedelia/Migrations/20201128224417_initial.Designer.cs b/Bedelia/Migrations/20201128224417_initial.Designer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1879039ae8918655176d06d108b0ce4de436ded4
--- /dev/null
+++ b/Bedelia/Migrations/20201128224417_initial.Designer.cs
@@ -0,0 +1,58 @@
+// <auto-generated />
+using Bedelia.EF;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+namespace Bedelia.Migrations
+{
+    [DbContext(typeof(BedeliaContext))]
+    [Migration("20201128224417_initial")]
+    partial class initial
+    {
+        protected override void BuildTargetModel(ModelBuilder modelBuilder)
+        {
+#pragma warning disable 612, 618
+            modelBuilder
+                .UseIdentityByDefaultColumns()
+                .HasAnnotation("Relational:MaxIdentifierLength", 63)
+                .HasAnnotation("ProductVersion", "5.0.0");
+
+            modelBuilder.Entity("Bedelia.EF.User", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer")
+                        .UseIdentityByDefaultColumn();
+
+                    b.Property<string>("IdentityCard")
+                        .IsRequired()
+                        .HasMaxLength(50)
+                        .HasColumnType("character varying(50)");
+
+                    b.Property<string>("Password")
+                        .IsRequired()
+                        .HasMaxLength(255)
+                        .HasColumnType("character varying(255)");
+
+                    b.Property<string>("Username")
+                        .IsRequired()
+                        .HasMaxLength(50)
+                        .HasColumnType("character varying(50)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("IdentityCard")
+                        .IsUnique();
+
+                    b.HasIndex("Username")
+                        .IsUnique();
+
+                    b.ToTable("Users");
+                });
+#pragma warning restore 612, 618
+        }
+    }
+}
diff --git a/Bedelia/Migrations/20201128224417_initial.cs b/Bedelia/Migrations/20201128224417_initial.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9dffea5c79d1ac3380c3e3b88fa4c9d3f8d3d385
--- /dev/null
+++ b/Bedelia/Migrations/20201128224417_initial.cs
@@ -0,0 +1,44 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+namespace Bedelia.Migrations
+{
+    public partial class initial : Migration
+    {
+        protected override void Up(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.CreateTable(
+                name: "Users",
+                columns: table => new
+                {
+                    Id = table.Column<int>(type: "integer", nullable: false)
+                        .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+                    IdentityCard = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: false),
+                    Username = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: false),
+                    Password = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_Users", x => x.Id);
+                });
+
+            migrationBuilder.CreateIndex(
+                name: "IX_Users_IdentityCard",
+                table: "Users",
+                column: "IdentityCard",
+                unique: true);
+
+            migrationBuilder.CreateIndex(
+                name: "IX_Users_Username",
+                table: "Users",
+                column: "Username",
+                unique: true);
+        }
+
+        protected override void Down(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.DropTable(
+                name: "Users");
+        }
+    }
+}
diff --git a/Bedelia/Migrations/20201128235147_courses.Designer.cs b/Bedelia/Migrations/20201128235147_courses.Designer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..05bcced32a524d9b4a8d5d063ff5f067eaf6589e
--- /dev/null
+++ b/Bedelia/Migrations/20201128235147_courses.Designer.cs
@@ -0,0 +1,126 @@
+// <auto-generated />
+using System;
+using Bedelia.EF;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+namespace Bedelia.Migrations
+{
+    [DbContext(typeof(BedeliaContext))]
+    [Migration("20201128235147_courses")]
+    partial class courses
+    {
+        protected override void BuildTargetModel(ModelBuilder modelBuilder)
+        {
+#pragma warning disable 612, 618
+            modelBuilder
+                .UseIdentityByDefaultColumns()
+                .HasAnnotation("Relational:MaxIdentifierLength", 63)
+                .HasAnnotation("ProductVersion", "5.0.0");
+
+            modelBuilder.Entity("Bedelia.EF.Course", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer")
+                        .UseIdentityByDefaultColumn();
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasMaxLength(50)
+                        .HasColumnType("character varying(50)");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("Courses");
+                });
+
+            modelBuilder.Entity("Bedelia.EF.User", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer")
+                        .UseIdentityByDefaultColumn();
+
+                    b.Property<string>("IdentityCard")
+                        .IsRequired()
+                        .HasMaxLength(50)
+                        .HasColumnType("character varying(50)");
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasMaxLength(50)
+                        .HasColumnType("character varying(50)");
+
+                    b.Property<string>("Password")
+                        .IsRequired()
+                        .HasMaxLength(255)
+                        .HasColumnType("character varying(255)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("IdentityCard")
+                        .IsUnique();
+
+                    b.HasIndex("Name")
+                        .IsUnique();
+
+                    b.ToTable("Users");
+                });
+
+            modelBuilder.Entity("Bedelia.EF.UserCourse", b =>
+                {
+                    b.Property<int>("UserId")
+                        .HasColumnType("integer");
+
+                    b.Property<int>("CourseId")
+                        .HasColumnType("integer");
+
+                    b.Property<int>("Grade")
+                        .HasColumnType("integer");
+
+                    b.Property<DateTime>("GradeDate")
+                        .HasColumnType("timestamp without time zone");
+
+                    b.HasKey("UserId", "CourseId");
+
+                    b.HasIndex("CourseId");
+
+                    b.ToTable("UserCourses");
+                });
+
+            modelBuilder.Entity("Bedelia.EF.UserCourse", b =>
+                {
+                    b.HasOne("Bedelia.EF.Course", "Course")
+                        .WithMany("UserCourses")
+                        .HasForeignKey("CourseId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("Bedelia.EF.User", "User")
+                        .WithMany("UserCourses")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("Course");
+
+                    b.Navigation("User");
+                });
+
+            modelBuilder.Entity("Bedelia.EF.Course", b =>
+                {
+                    b.Navigation("UserCourses");
+                });
+
+            modelBuilder.Entity("Bedelia.EF.User", b =>
+                {
+                    b.Navigation("UserCourses");
+                });
+#pragma warning restore 612, 618
+        }
+    }
+}
diff --git a/Bedelia/Migrations/20201128235147_courses.cs b/Bedelia/Migrations/20201128235147_courses.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8203cc103960bf9eebbdd683ddc2f5c92e26304e
--- /dev/null
+++ b/Bedelia/Migrations/20201128235147_courses.cs
@@ -0,0 +1,85 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+namespace Bedelia.Migrations
+{
+    public partial class courses : Migration
+    {
+        protected override void Up(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.RenameColumn(
+                name: "Username",
+                table: "Users",
+                newName: "Name");
+
+            migrationBuilder.RenameIndex(
+                name: "IX_Users_Username",
+                table: "Users",
+                newName: "IX_Users_Name");
+
+            migrationBuilder.CreateTable(
+                name: "Courses",
+                columns: table => new
+                {
+                    Id = table.Column<int>(type: "integer", nullable: false)
+                        .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+                    Name = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_Courses", x => x.Id);
+                });
+
+            migrationBuilder.CreateTable(
+                name: "UserCourses",
+                columns: table => new
+                {
+                    UserId = table.Column<int>(type: "integer", nullable: false),
+                    CourseId = table.Column<int>(type: "integer", nullable: false),
+                    Grade = table.Column<int>(type: "integer", nullable: false),
+                    GradeDate = table.Column<DateTime>(type: "timestamp without time zone", nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_UserCourses", x => new { x.UserId, x.CourseId });
+                    table.ForeignKey(
+                        name: "FK_UserCourses_Courses_CourseId",
+                        column: x => x.CourseId,
+                        principalTable: "Courses",
+                        principalColumn: "Id",
+                        onDelete: ReferentialAction.Cascade);
+                    table.ForeignKey(
+                        name: "FK_UserCourses_Users_UserId",
+                        column: x => x.UserId,
+                        principalTable: "Users",
+                        principalColumn: "Id",
+                        onDelete: ReferentialAction.Cascade);
+                });
+
+            migrationBuilder.CreateIndex(
+                name: "IX_UserCourses_CourseId",
+                table: "UserCourses",
+                column: "CourseId");
+        }
+
+        protected override void Down(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.DropTable(
+                name: "UserCourses");
+
+            migrationBuilder.DropTable(
+                name: "Courses");
+
+            migrationBuilder.RenameColumn(
+                name: "Name",
+                table: "Users",
+                newName: "Username");
+
+            migrationBuilder.RenameIndex(
+                name: "IX_Users_Name",
+                table: "Users",
+                newName: "IX_Users_Username");
+        }
+    }
+}
diff --git a/Bedelia/Migrations/BedeliaContextModelSnapshot.cs b/Bedelia/Migrations/BedeliaContextModelSnapshot.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4e00a716072e9bcf6ffb73e32de70f318c6d7c8c
--- /dev/null
+++ b/Bedelia/Migrations/BedeliaContextModelSnapshot.cs
@@ -0,0 +1,124 @@
+// <auto-generated />
+using System;
+using Bedelia.EF;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+namespace Bedelia.Migrations
+{
+    [DbContext(typeof(BedeliaContext))]
+    partial class BedeliaContextModelSnapshot : ModelSnapshot
+    {
+        protected override void BuildModel(ModelBuilder modelBuilder)
+        {
+#pragma warning disable 612, 618
+            modelBuilder
+                .UseIdentityByDefaultColumns()
+                .HasAnnotation("Relational:MaxIdentifierLength", 63)
+                .HasAnnotation("ProductVersion", "5.0.0");
+
+            modelBuilder.Entity("Bedelia.EF.Course", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer")
+                        .UseIdentityByDefaultColumn();
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasMaxLength(50)
+                        .HasColumnType("character varying(50)");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("Courses");
+                });
+
+            modelBuilder.Entity("Bedelia.EF.User", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer")
+                        .UseIdentityByDefaultColumn();
+
+                    b.Property<string>("IdentityCard")
+                        .IsRequired()
+                        .HasMaxLength(50)
+                        .HasColumnType("character varying(50)");
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasMaxLength(50)
+                        .HasColumnType("character varying(50)");
+
+                    b.Property<string>("Password")
+                        .IsRequired()
+                        .HasMaxLength(255)
+                        .HasColumnType("character varying(255)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("IdentityCard")
+                        .IsUnique();
+
+                    b.HasIndex("Name")
+                        .IsUnique();
+
+                    b.ToTable("Users");
+                });
+
+            modelBuilder.Entity("Bedelia.EF.UserCourse", b =>
+                {
+                    b.Property<int>("UserId")
+                        .HasColumnType("integer");
+
+                    b.Property<int>("CourseId")
+                        .HasColumnType("integer");
+
+                    b.Property<int>("Grade")
+                        .HasColumnType("integer");
+
+                    b.Property<DateTime>("GradeDate")
+                        .HasColumnType("timestamp without time zone");
+
+                    b.HasKey("UserId", "CourseId");
+
+                    b.HasIndex("CourseId");
+
+                    b.ToTable("UserCourses");
+                });
+
+            modelBuilder.Entity("Bedelia.EF.UserCourse", b =>
+                {
+                    b.HasOne("Bedelia.EF.Course", "Course")
+                        .WithMany("UserCourses")
+                        .HasForeignKey("CourseId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("Bedelia.EF.User", "User")
+                        .WithMany("UserCourses")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("Course");
+
+                    b.Navigation("User");
+                });
+
+            modelBuilder.Entity("Bedelia.EF.Course", b =>
+                {
+                    b.Navigation("UserCourses");
+                });
+
+            modelBuilder.Entity("Bedelia.EF.User", b =>
+                {
+                    b.Navigation("UserCourses");
+                });
+#pragma warning restore 612, 618
+        }
+    }
+}
diff --git a/Bedelia/Program.cs b/Bedelia/Program.cs
new file mode 100644
index 0000000000000000000000000000000000000000..eaca41ffc496e6b136a31e9421f64d4e5797bba8
--- /dev/null
+++ b/Bedelia/Program.cs
@@ -0,0 +1,27 @@
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Bedelia
+{
+    public class Program
+    {
+        public static void Main(string[] args)
+        {
+            CreateHostBuilder(args).Build().Run();
+        }
+
+        public static IHostBuilder CreateHostBuilder(string[] args) =>
+            Host.CreateDefaultBuilder(args)
+                .ConfigureWebHostDefaults(webBuilder =>
+                {
+                    webBuilder.UseStartup<Startup>();
+                    webBuilder.UseUrls("http://*:5000/");
+                });
+    }
+}
diff --git a/Bedelia/Properties/launchSettings.json b/Bedelia/Properties/launchSettings.json
new file mode 100644
index 0000000000000000000000000000000000000000..f66813ed228f570421e7108adf6e4ec5b748833a
--- /dev/null
+++ b/Bedelia/Properties/launchSettings.json
@@ -0,0 +1,31 @@
+{
+  "$schema": "http://json.schemastore.org/launchsettings.json",
+  "iisSettings": {
+    "windowsAuthentication": false,
+    "anonymousAuthentication": true,
+    "iisExpress": {
+      "applicationUrl": "http://localhost:55438",
+      "sslPort": 0
+    }
+  },
+  "profiles": {
+    "IIS Express": {
+      "commandName": "IISExpress",
+      "launchBrowser": true,
+      "launchUrl": "swagger",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    },
+    "Bedelia": {
+      "commandName": "Project",
+      "dotnetRunMessages": "true",
+      "launchBrowser": true,
+      "launchUrl": "swagger",
+      "applicationUrl": "http://localhost:5000",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    }
+  }
+}
diff --git a/Bedelia/Startup.cs b/Bedelia/Startup.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f170f55c9a870dedf2ab815e79f9e651f79114f3
--- /dev/null
+++ b/Bedelia/Startup.cs
@@ -0,0 +1,70 @@
+using Bedelia.EF;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+using Microsoft.OpenApi.Models;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Bedelia
+{
+    public class Startup
+    {
+        public Startup(IConfiguration configuration, IWebHostEnvironment env)
+        {
+            Configuration = configuration;
+            _env = env;
+        }
+
+        public IConfiguration Configuration { get; }
+        private readonly IWebHostEnvironment _env;
+
+        // This method gets called by the runtime. Use this method to add services to the container.
+        public void ConfigureServices(IServiceCollection services)
+        {
+
+            services.AddControllers();
+            services.AddSwaggerGen(c =>
+            {
+                c.SwaggerDoc("v1", new OpenApiInfo { Title = "Bedelia", Version = "v1" });
+            });
+
+            var postgreSqlSection = _env.IsProduction() ? "PostgreSqlCloud" : "PostgreSql";
+
+            services.AddDbContext<BedeliaContext>(x => x.UseNpgsql(
+                Configuration.GetConnectionString(postgreSqlSection)));
+        }
+
+        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
+        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, BedeliaContext context)
+        {
+            context.Database.Migrate();
+
+            if (env.IsDevelopment())
+            {
+                app.UseDeveloperExceptionPage();
+            }
+
+            app.UseSwagger();
+            app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Bedelia v1"));
+
+            app.UseRouting();
+
+            app.UseCors(x => x.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
+
+            app.UseAuthorization();
+
+            app.UseEndpoints(endpoints =>
+            {
+                endpoints.MapControllers();
+            });
+        }
+    }
+}
diff --git a/Bedelia/appsettings.Development.json b/Bedelia/appsettings.Development.json
new file mode 100644
index 0000000000000000000000000000000000000000..8983e0fc1c5e2795ccfde0c771c6d66c88ef4a42
--- /dev/null
+++ b/Bedelia/appsettings.Development.json
@@ -0,0 +1,9 @@
+{
+  "Logging": {
+    "LogLevel": {
+      "Default": "Information",
+      "Microsoft": "Warning",
+      "Microsoft.Hosting.Lifetime": "Information"
+    }
+  }
+}
diff --git a/Bedelia/appsettings.json b/Bedelia/appsettings.json
new file mode 100644
index 0000000000000000000000000000000000000000..048c2f6d1e366b10da59de510dab3ecb86125fba
--- /dev/null
+++ b/Bedelia/appsettings.json
@@ -0,0 +1,14 @@
+{
+  "ConnectionStrings": {
+    "PostgreSql": "Host=localhost;Database=bedelia;Username=postgres;Password=111111",
+    "PostgreSqlCloud": "Host=db;Database=bedelia;Username=postgres;Password=postgres"
+  },
+  "Logging": {
+    "LogLevel": {
+      "Default": "Information",
+      "Microsoft": "Warning",
+      "Microsoft.Hosting.Lifetime": "Information"
+    }
+  },
+  "AllowedHosts": "*"
+}
diff --git a/Bedelia/docker-compose.yml b/Bedelia/docker-compose.yml
new file mode 100644
index 0000000000000000000000000000000000000000..430f5afafaa0bd15f5434c45042321deec30bfe4
--- /dev/null
+++ b/Bedelia/docker-compose.yml
@@ -0,0 +1,25 @@
+version: '3.8'
+
+services:
+  bedelia:
+    image: esantangelo/bedelia
+    container_name: bedelia
+    depends_on:
+      - db
+    ports: 
+      - 80:5000
+    restart: on-failure
+
+  db:
+    image: postgres
+    container_name: db
+    environment: 
+      POSTGRES_PASSWORD: postgres
+    ports:
+      - 5432:5432
+    volumes:
+      - db-data:/var/lib/postgresql/data
+    restart: on-failure
+
+volumes:
+  db-data:
\ No newline at end of file
diff --git a/Tsi1.Api/Tsi1.Api/Controllers/CourseController.cs b/Tsi1.Api/Tsi1.Api/Controllers/CourseController.cs
index 3778365e1fe2c75f2b53f505f789767a2e7cfac3..dd4de595a500ee8c7db2d63f7ea44554be2c910b 100644
--- a/Tsi1.Api/Tsi1.Api/Controllers/CourseController.cs
+++ b/Tsi1.Api/Tsi1.Api/Controllers/CourseController.cs
@@ -16,10 +16,14 @@ namespace Tsi1.Api.Controllers
     public class CourseController : ControllerBase
     {
         private readonly ICourseService _courseService;
+        private readonly IUserService _userService;
+        private readonly IBedeliaService _bedeliaService;
 
-        public CourseController(ICourseService courseService)
+        public CourseController(ICourseService courseService, IUserService userService, IBedeliaService bedeliaService)
         {
             _courseService = courseService;
+            _userService = userService;
+            _bedeliaService = bedeliaService;
         }
 
         [Authorize(Roles = UserTypes.Student + ", " + UserTypes.Professor)]
@@ -54,15 +58,20 @@ namespace Tsi1.Api.Controllers
             return Ok(result.Data);
         }
 
-
         [Authorize(Roles = UserTypes.Student)]
         [HttpPost("Matriculate/{courseId}")]
         public async Task<IActionResult> Matriculate(int courseId)
         {
             var userId = int.Parse(HttpContext.User.Claims.FirstOrDefault(x => x.Type == "Id").Value);
+            var user = await _userService.GetById(userId);
+
+            var response = await _bedeliaService.IsValidUser(user.Data.Student.IdentityCard);
+            if (response.HasError)
+            {
+                return BadRequest(response.Message);
+            }
 
             var result = await _courseService.Matriculate(userId, courseId);
-            
             if (result.HasError)
             {
                 return BadRequest(result.Message);
@@ -245,5 +254,33 @@ namespace Tsi1.Api.Controllers
 
             return Ok(result.Data);
         }
+
+        [Authorize(Roles = UserTypes.Professor)]
+        [HttpPost("CloseRecord/{courseId}")]
+        public async Task<IActionResult> CloseRecord(int courseId)
+        {
+            var courseResult = await _courseService.GetById(courseId);
+            if (courseResult.HasError)
+            {
+                return BadRequest(courseResult.Message);
+            }
+
+            var userResult = await _userService.GetUserGrades(courseId);
+            if (userResult.HasError)
+            {
+                return BadRequest(userResult.Message);
+            }
+
+            var courseName = courseResult.Data.Name;
+            var userGrades = userResult.Data;
+
+            var result = await _bedeliaService.CloseRecord(courseName, userGrades);
+            if (result.HasError)
+            {
+                return BadRequest(result.Message);
+            }
+
+            return Ok();
+        }
     }
 }
diff --git a/Tsi1.Api/Tsi1.Api/Startup.cs b/Tsi1.Api/Tsi1.Api/Startup.cs
index d27fa6ae2007f1b94d51e98e5f22d00c440ed32d..5718b4a826b7bb99f6b3183540f37e2dfb3855f4 100644
--- a/Tsi1.Api/Tsi1.Api/Startup.cs
+++ b/Tsi1.Api/Tsi1.Api/Startup.cs
@@ -46,17 +46,27 @@ namespace Tsi1.Api
         {
             string postgreSqlSection;
             string mongoDbSection;
+            string bedeliaBaseUrlSection;
+
             if (_env.IsProduction())
             {
                 postgreSqlSection = "PostgreSqlCloud";
                 mongoDbSection = "Tsi1DatabaseSettingsCloud";
+                bedeliaBaseUrlSection = "BedeliaBaseUrlCloud";
             }
             else
             {
                 postgreSqlSection = "PostgreSql";
                 mongoDbSection = "Tsi1DatabaseSettings";
+                bedeliaBaseUrlSection = "BedeliaBaseUrl";
             }
 
+            var bedeliaBaseUrl = Configuration.GetSection(bedeliaBaseUrlSection).Value;
+            services.AddHttpClient<IBedeliaService, BedeliaService>(configureClient =>
+            {
+                configureClient.BaseAddress = new Uri(bedeliaBaseUrl);
+            });
+
             services.AddControllers();
             
             services.AddSignalR();
diff --git a/Tsi1.Api/Tsi1.Api/appsettings.json b/Tsi1.Api/Tsi1.Api/appsettings.json
index aeffabd1acc0a4a5296e376e85c35a1114d2770e..d77c42f3c0bdefb6c97c4c38fd5163408ae997c3 100644
--- a/Tsi1.Api/Tsi1.Api/appsettings.json
+++ b/Tsi1.Api/Tsi1.Api/appsettings.json
@@ -28,6 +28,8 @@
     "Host": "smtp.gmail.com",
     "Port": 587
   },
+  "BedeliaBaseUrl": "http://localhost:55438/",
+  "BedeliaBaseUrlCloud": "http://tsi-bedelia.web.elasticloud.uy/",
   "Logging": {
     "LogLevel": {
       "Default": "Information",
diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CloseRecordDto.cs b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CloseRecordDto.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f0964b6f3c0480dd9452a2dd4ba25ef130a7a7b2
--- /dev/null
+++ b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CloseRecordDto.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Tsi1.BusinessLayer.Dtos
+{
+    public class CloseRecordDto
+    {
+        public string CourseName { get; set; }
+        public List<UserGradeDto> UserGrades { get; set; }
+    }
+}
diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/UserGradeDto.cs b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/UserGradeDto.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8018e6035c1f02da0609ef8a71a4bedcef5f4201
--- /dev/null
+++ b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/UserGradeDto.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Tsi1.BusinessLayer.Dtos
+{
+    public class UserGradeDto
+    {
+        public string IdentityCard { get; set; }
+        public int Grade { get; set; }
+    }
+}
diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Helpers/ErrorMessages.cs b/Tsi1.Api/Tsi1.BusinessLayer/Helpers/ErrorMessages.cs
index 1cffd0551686cd30f851493c7d64788b98fe0b2a..14da5d591e0f831251808c1033384f4b501a8d75 100644
--- a/Tsi1.Api/Tsi1.BusinessLayer/Helpers/ErrorMessages.cs
+++ b/Tsi1.Api/Tsi1.BusinessLayer/Helpers/ErrorMessages.cs
@@ -34,6 +34,7 @@ namespace Tsi1.BusinessLayer.Helpers
         public const string CourseDoesNotExist = "El curso con id '{0}' no existe";
         public const string DuplicateCourseName = "Ya existe un curso con nombre '{0}'";
         public const string CourseIsTemplate = "El curso con id '{0}' es un template";
+        public const string CourseHasNoStudents = "El curso con id '{0}' no tiene estudiantes";
 
         public const string TenantDoesNotExist = "La Facultad '{0}' no existe";
         public const string DuplicateTenantName = "Ya existe una Facultad con nombre '{0}'";
diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IBedeliaService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IBedeliaService.cs
new file mode 100644
index 0000000000000000000000000000000000000000..88a6f293779d4dd16356078565ec3010a95dfa37
--- /dev/null
+++ b/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IBedeliaService.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using Tsi1.BusinessLayer.Dtos;
+using Tsi1.BusinessLayer.Helpers;
+
+namespace Tsi1.BusinessLayer.Interfaces
+{
+    public interface IBedeliaService
+    {
+        Task<ServiceResult<bool>> IsValidUser(string identityCard);
+
+        Task<ServiceResult<bool>> CloseRecord(string courseName, List<UserGradeDto> userGrades);
+    }
+}
diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IUserService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IUserService.cs
index 1fa99023a8a11832ee567ce57fa10bbdfcf9286a..e3a89207701c5fb213da6b5365f9555bf446afca 100644
--- a/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IUserService.cs
+++ b/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IUserService.cs
@@ -34,5 +34,7 @@ namespace Tsi1.BusinessLayer.Interfaces
 
         Task<ServiceResult<List<UserPreviewDto>>> GetProfessors(int tenantId);
         Task<ServiceResult<List<UserPreviewDto>>> GetAdmins(int tenantId, string userType);
+
+        Task<ServiceResult<List<UserGradeDto>>> GetUserGrades(int courseId);
     }
 }
diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Services/BedeliaService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Services/BedeliaService.cs
new file mode 100644
index 0000000000000000000000000000000000000000..cd7a08a470c3107dcb49d35dbbe0255cbe4e7dae
--- /dev/null
+++ b/Tsi1.Api/Tsi1.BusinessLayer/Services/BedeliaService.cs
@@ -0,0 +1,61 @@
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Net;
+using System.Net.Http;
+using System.Text;
+using System.Threading.Tasks;
+using Tsi1.BusinessLayer.Dtos;
+using Tsi1.BusinessLayer.Helpers;
+using Tsi1.BusinessLayer.Interfaces;
+
+namespace Tsi1.BusinessLayer.Services
+{
+    public class BedeliaService : IBedeliaService
+    {
+        private readonly HttpClient _httpClient;
+
+        public BedeliaService(HttpClient httpClient)
+        {
+            _httpClient = httpClient;
+        }
+
+        public async Task<ServiceResult<bool>> IsValidUser(string identityCard)
+        {
+            var result = new ServiceResult<bool>();
+
+            var response = await _httpClient.GetAsync($"api/Users/{identityCard}");
+            if (response.StatusCode != HttpStatusCode.OK)
+            {
+                result.HasError = true;
+                var errorMessage = await response.Content.ReadAsStringAsync();
+                result.AddMessage(errorMessage);
+            }
+
+            return result;
+        }
+
+        public async Task<ServiceResult<bool>> CloseRecord(string courseName, List<UserGradeDto> userGrades)
+        {
+            var result = new ServiceResult<bool>();
+            var closeRecord = new CloseRecordDto()
+            {
+                CourseName = courseName,
+                UserGrades = userGrades
+            };
+
+            var jsonInString = JsonConvert.SerializeObject(closeRecord);
+            var model = new StringContent(jsonInString, Encoding.UTF8, "application/json");
+
+            var response = await _httpClient.PostAsync("api/Courses/closeRecord", model);
+            if (response.StatusCode != HttpStatusCode.OK)
+            {
+                result.HasError = true;
+                var errorMessage = await response.Content.ReadAsStringAsync();
+                result.AddMessage(errorMessage);
+            }
+
+            return result;
+        }
+    }
+}
diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Services/UserService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Services/UserService.cs
index 1536b9635bc33adbf87e259503498e3eec976906..e2ad8bbba442fde1f299dccb7743c39ba443f4f2 100644
--- a/Tsi1.Api/Tsi1.BusinessLayer/Services/UserService.cs
+++ b/Tsi1.Api/Tsi1.BusinessLayer/Services/UserService.cs
@@ -358,5 +358,31 @@ namespace Tsi1.BusinessLayer.Services
 
             return result;
         }
+
+        public async Task<ServiceResult<List<UserGradeDto>>> GetUserGrades(int courseId)
+        {
+            var result = new ServiceResult<List<UserGradeDto>>();
+
+            var course = await _context.Courses
+                .Include(x => x.StudentCourses)
+                    .ThenInclude(x => x.Student)
+                .FirstOrDefaultAsync(x => x.Id == courseId);
+
+            if (!course.StudentCourses.Any())
+            {
+                result.HasError = true;
+                result.AddMessage(string.Format(ErrorMessages.CourseHasNoStudents, courseId));
+                return result;
+            }
+
+            // TODO: obtain the grade from StudentCourses
+            result.Data = course.StudentCourses.Select(x => new UserGradeDto()
+            {
+                Grade = 10,
+                IdentityCard = x.Student.IdentityCard
+            }).ToList();
+
+            return result;
+        }
     }
 }
diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Tsi1.BusinessLayer.csproj b/Tsi1.Api/Tsi1.BusinessLayer/Tsi1.BusinessLayer.csproj
index a18735ed0c8c52887e85611f1b353106330f869f..d2c88dff5dce9ee2149d7e3b785110d593d0894d 100644
--- a/Tsi1.Api/Tsi1.BusinessLayer/Tsi1.BusinessLayer.csproj
+++ b/Tsi1.Api/Tsi1.BusinessLayer/Tsi1.BusinessLayer.csproj
@@ -11,6 +11,7 @@
     <PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="2.2.0" />
     <PackageReference Include="Microsoft.AspNetCore.Http.Features" Version="3.1.9" />
     <PackageReference Include="MimeKit" Version="2.9.2" />
+    <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
   </ItemGroup>
 
   <ItemGroup>