diff --git a/CHANGELOG.md b/CHANGELOG.md
index f38ff0239e67d106fa4bb78a87c9f49bd1a2cf30..19a7a7f5abce9c9ed6a22323441d87b5a83c8c45 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Added
 - Button added to switch to dark theme. @rgiedryte
+- Allow filtering by job page by quarter @cedric-dev
 
 ### Changed
 
diff --git a/src/main/java/nl/tudelft/tam/controller/ApplicationController.java b/src/main/java/nl/tudelft/tam/controller/ApplicationController.java
index 87d200f408988493e8ff2c3510721bf7db26759e..66e2a1b6a3fe5258b5b6e4bfb67314e04cb19003 100644
--- a/src/main/java/nl/tudelft/tam/controller/ApplicationController.java
+++ b/src/main/java/nl/tudelft/tam/controller/ApplicationController.java
@@ -30,7 +30,9 @@ import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
 import org.springframework.web.bind.annotation.*;
+import org.springframework.web.util.UriComponentsBuilder;
 
+import nl.tudelft.labracore.api.dto.AcademicPeriodSummaryDTO;
 import nl.tudelft.labracore.api.dto.ProgramDetailsDTO;
 import nl.tudelft.labracore.lib.security.user.AuthenticatedPerson;
 import nl.tudelft.labracore.lib.security.user.Person;
@@ -61,6 +63,9 @@ public class ApplicationController {
 	@Autowired
 	ProgramService programService;
 
+	@Autowired
+	JobOfferService jobOfferService;
+
 	// endregion
 
 	// region view pages
@@ -80,8 +85,8 @@ public class ApplicationController {
 			@PageableDefault(value = 25) Pageable pageable,
 			Model model) {
 		List<ProgramDetailsDTO> programs = programService.getCoordinatingPrograms(person.getId());
-		if (filter.getProgram() == null) {
-			filter.setProgram(programs.get(0).getId());
+		if (filter.getPrograms() == null) {
+			filter.setPrograms(programs.stream().map(ProgramDetailsDTO::getId).toList());
 		}
 
 		List<Application> applications = applicationService
@@ -89,6 +94,7 @@ public class ApplicationController {
 
 		model.addAttribute("applications", PageUtil.toPage(pageable, applications));
 		model.addAttribute("programs", programs);
+		model.addAttribute("periods", jobOfferService.getAllAcademicPeriods());
 
 		return "application/all";
 	}
@@ -108,8 +114,8 @@ public class ApplicationController {
 			@PageableDefault(value = 25) Pageable pageable,
 			Model model) {
 		List<ProgramDetailsDTO> programs = programService.getCoordinatingPrograms(person.getId());
-		if (filter.getProgram() == null) {
-			filter.setProgram(programs.get(0).getId());
+		if (filter.getPrograms() == null) {
+			filter.setPrograms(programs.stream().map(ProgramDetailsDTO::getId).toList());
 		}
 
 		filter.setStatuses(List.of(Status.ACCEPTED));
@@ -118,8 +124,9 @@ public class ApplicationController {
 
 		model.addAttribute("applications", PageUtil.toPage(pageable, applications));
 		model.addAttribute("exports",
-				applicationService.getExportsForPersonAndProgram(person, filter.getProgram()));
+				applicationService.getExportsForPersonAndPrograms(person, filter.getPrograms()));
 		model.addAttribute("programs", programs);
+		model.addAttribute("periods", jobOfferService.getAllAcademicPeriods());
 
 		return "application/all_flexdelft";
 	}
@@ -134,13 +141,16 @@ public class ApplicationController {
 	 */
 	@GetMapping("my")
 	public String getApplications(@AuthenticatedPerson Person person,
+			@RequestParam(required = false, name = "period") List<Long> filterPeriods,
 			@RequestParam(required = false) String q, Model model) {
 		List<ApplicationDetailsJobOfferDTO> applications = applicationService
-				.getFilteredApplicationsForPerson(person.getId(), q)
-				.stream().filter(a -> a.getJobOffer().getEdition().getEndDate().isAfter(LocalDateTime.now()))
+				.getFilteredApplicationsForPerson(person.getId(), q).stream()
+				.filter(a -> a.getJobOffer().getEdition().getEndDate().isAfter(LocalDateTime.now()))
+				.filter(a -> filterPeriods == null || a.getJobOffer().getEdition().getPeriod() == null
+						|| filterPeriods.contains(a.getJobOffer().getEdition().getPeriod().getId()))
 				.toList();
-
 		model.addAttribute("applications", applications);
+		model.addAttribute("periods", jobOfferService.getAllAcademicPeriods());
 		return "application/view_many";
 	}
 
@@ -187,11 +197,20 @@ public class ApplicationController {
 	@PostMapping("submit")
 	@PreAuthorize("@authorisationService.canSubmitApplication(#create.jobOffer.id)")
 	public String submitApplication(@AuthenticatedPerson Person person, ApplicationCreateDTO create,
-			@RequestParam(required = false) String page, @RequestParam(required = false) Long program) {
+			@RequestParam(required = false) String page,
+			@RequestParam(required = false) String program,
+			@RequestParam(required = false, name = "period") List<AcademicPeriodSummaryDTO> filterPeriods) {
 		applicationService.submit(person.getId(), create);
 		String url = "applications".equals(page) ? "application/my" : "job-offer/open";
-		return "redirect:/"
-				+ (url + (program == null ? "" : "?program=" + program));
+
+		Map<String, List<String>> params = new HashMap<>();
+		if (program != null)
+			params.put("program", List.of(program));
+		if (filterPeriods != null)
+			params.put("period", filterPeriods.stream()
+					.map(AcademicPeriodSummaryDTO::getName).toList());
+
+		return "redirect:/" + url + buildURLParams(params);
 	}
 
 	/**
@@ -206,21 +225,22 @@ public class ApplicationController {
 	public String retractApplication(@AuthenticatedPerson Person person, @PathVariable Long id,
 			@RequestParam(required = false) String page,
 			@RequestParam(required = false) String q,
-			@RequestParam(required = false) String tab,
-			@RequestParam(required = false) String program) {
+			@RequestParam(required = false) String program,
+			@RequestParam(required = false, name = "period") List<AcademicPeriodSummaryDTO> filterPeriods) {
 		applicationService.retract(person.getId(), id);
 
 		String url = "applications".equals(page) ? "application/my" : "job-offer/open";
 
-		Map<String, String> params = new HashMap<>();
+		Map<String, List<String>> params = new HashMap<>();
 		if (q != null)
-			params.put("q", q);
-		if (tab != null)
-			params.put("tab", tab);
+			params.put("q", List.of(q));
 		if (program != null)
-			params.put("program", program);
+			params.put("program", List.of(program));
+		if (filterPeriods != null)
+			params.put("period", filterPeriods.stream().map(AcademicPeriodSummaryDTO::getName)
+					.toList());
 
-		return "redirect:/" + url + getURLParamsString(params);
+		return "redirect:/" + url + buildURLParams(params);
 	}
 
 	/**
@@ -324,31 +344,31 @@ public class ApplicationController {
 	public String acceptApplication(@AuthenticatedPerson Person person, @PathVariable Long id,
 			@RequestParam(required = false) String page,
 			@RequestParam(required = false) String q,
-			@RequestParam(required = false) String tab,
-			@RequestParam(required = false) String program) {
+			@RequestParam(required = false) String program,
+			@RequestParam(required = false) List<AcademicPeriodSummaryDTO> filterPeriods) {
 		applicationService.accept(person.getId(), id);
 
 		String url = "applications".equals(page) ? "application/my" : "job-offer/open";
 
-		Map<String, String> params = new HashMap<>();
+		Map<String, List<String>> params = new HashMap<>();
 		if (q != null)
-			params.put("q", q);
-		if (tab != null)
-			params.put("tab", tab);
+			params.put("q", List.of(q));
 		if (program != null)
-			params.put("program", program);
+			params.put("program", List.of(program));
+		if (filterPeriods != null)
+			params.put("period", filterPeriods.stream().map(AcademicPeriodSummaryDTO::getName).toList());
 
-		return "redirect:/" + url + getURLParamsString(params);
+		return "redirect:/" + url + buildURLParams(params);
 	}
 
-	private static String getURLParamsString(Map<String, String> params) {
-		StringBuilder result = new StringBuilder();
-		char sep = '?';
-		for (String param : params.keySet()) {
-			result.append(sep).append(param).append("=").append(params.get(param));
-			sep = '&';
+	private String buildURLParams(Map<String, List<String>> params) {
+		UriComponentsBuilder uriBuilder = UriComponentsBuilder.newInstance();
+		for (Map.Entry<String, List<String>> entry : params.entrySet()) {
+			for (String value : entry.getValue()) {
+				uriBuilder.queryParam(entry.getKey(), value);
+			}
 		}
-		return result.toString();
+		return uriBuilder.toUriString();
 	}
 
 	// endregion
@@ -360,7 +380,7 @@ public class ApplicationController {
 	 * @return        The export file as a resource
 	 */
 	@GetMapping("export")
-	@PreAuthorize("@authorisationService.isCoordinatorForProgram(#filter.program)")
+	@PreAuthorize("@authorisationService.isCoordinatorForPrograms(#filter.programs)")
 	public ResponseEntity<Resource> exportApplications(@AuthenticatedPerson Person person,
 			ApplicationFilterDTO filter)
 			throws IOException {
@@ -375,16 +395,18 @@ public class ApplicationController {
 	 * @return        The export file as a resource
 	 */
 	@GetMapping("flex-delft-export")
-	@PreAuthorize("@authorisationService.isCoordinatorForProgram(#filter.program)")
+	@PreAuthorize("@authorisationService.isCoordinatorForPrograms(#filter.programs)")
 	public ResponseEntity<Resource> exportApplicationsForFlexDelft(@AuthenticatedPerson Person person,
-			ApplicationFilterDTO filter, @RequestParam Integer batch)
+			ApplicationFilterDTO filter,
+			@RequestParam Integer batch)
 			throws IOException {
 		filter.setStatuses(List.of(Status.ACCEPTED));
-		List<Application> appList = applicationService.getFilteredCoordinatingApplications(person.getId(),
-				filter);
+		List<Application> appList = applicationService
+				.getFilteredCoordinatingApplications(person.getId(), filter).stream()
+				.toList();
 		return csvService
 				.getResponse(
-						applicationService.exportApplicationsForFlexDelft(person, filter.getProgram(), batch,
+						applicationService.exportApplicationsForFlexDelft(person, filter.getPrograms(), batch,
 								"applications", appList, filter.getUpdatedSince()));
 	}
 
diff --git a/src/main/java/nl/tudelft/tam/controller/JobOfferController.java b/src/main/java/nl/tudelft/tam/controller/JobOfferController.java
index 5b932159a411076627785dc0c037dec6f41efa34..940e386e106800c43e7306e306237171287a3767 100644
--- a/src/main/java/nl/tudelft/tam/controller/JobOfferController.java
+++ b/src/main/java/nl/tudelft/tam/controller/JobOfferController.java
@@ -129,7 +129,6 @@ public class JobOfferController {
 	 * Gets all open job offers
 	 *
 	 * @param  person The currently logged in person
-	 * @param  tab    The active tab
 	 * @param  q      The search query
 	 * @param  model  The model to add the data to
 	 * @return        The job offer page with all open job offers (or all applications) (depends on tab)
@@ -137,7 +136,7 @@ public class JobOfferController {
 	@GetMapping("open")
 	public String getOpenJobOffers(@AuthenticatedPerson Person person,
 			@RequestParam(required = false) Long program,
-			@RequestParam(required = false) String tab,
+			@RequestParam(required = false, name = "period") List<Long> filterPeriods,
 			@RequestParam(required = false) String q, Model model) {
 		List<ApplicationDetailsJobOfferDTO> applications = applicationService
 				.getFilteredApplicationsForPerson(person.getId(), q);
@@ -159,7 +158,10 @@ public class JobOfferController {
 					.collect(Collectors.toSet());
 			List<JobOfferSummaryDTO> offers = offerDetails.stream()
 					.filter(o -> coursesInProgram.contains(o.getEdition().getCourse().getId()))
-					.map(x -> (JobOfferSummaryDTO) x).collect(Collectors.toList());
+					// Assume that edition without period always gets displayed...
+					.filter(o -> filterPeriods == null || o.getEdition().getPeriod() == null
+							|| filterPeriods.contains(o.getEdition().getPeriod().getId()))
+					.map(x -> (JobOfferSummaryDTO) x).toList();
 
 			// Sort editions based on Cohort, exclude masters and add them to the end.
 			Comparator<EditionDetailsOffersWorkDTO> editionComparator = Comparator
@@ -174,13 +176,9 @@ public class JobOfferController {
 		Map<Long, ApplicationStatusSummaryDTO> appForOffer = applicationService
 				.getMapWithStatusAppOpenByIdForPerson(
 						person.getId(),
-						offerDetails.stream().map(JobOfferDetailsDTO::getId).collect(Collectors.toList()));
+						offerDetails.stream().map(JobOfferDetailsDTO::getId).toList());
 
-		if (tab == null || !List.of("offers", "applications").contains(tab)) {
-			tab = "offers";
-		}
-
-		model.addAttribute("tab", tab);
+		model.addAttribute("periods", jobOfferService.getAllAcademicPeriods());
 		model.addAttribute("applications", applications);
 		model.addAttribute("programs", programsWithJobOffers.stream()
 				.sorted(Comparator.comparing(ProgramSummaryDTO::getName)).toList());
@@ -502,5 +500,4 @@ public class JobOfferController {
 		return "redirect:/job-offer/" + id;
 	}
 	// endregion
-
 }
diff --git a/src/main/java/nl/tudelft/tam/dto/util/ApplicationFilterDTO.java b/src/main/java/nl/tudelft/tam/dto/util/ApplicationFilterDTO.java
index 472b020695aacd11a7ab50de615cedc603568f81..729d50db1c68bc7f7896775d808c9d30fe09ec31 100644
--- a/src/main/java/nl/tudelft/tam/dto/util/ApplicationFilterDTO.java
+++ b/src/main/java/nl/tudelft/tam/dto/util/ApplicationFilterDTO.java
@@ -35,7 +35,7 @@ import nl.tudelft.tam.enums.Status;
 @AllArgsConstructor
 public class ApplicationFilterDTO {
 
-	private Long program;
+	private List<Long> programs;
 
 	@DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
 	private LocalDateTime updatedSince;
@@ -46,6 +46,8 @@ public class ApplicationFilterDTO {
 	@DateTimeFormat(pattern = "yyyy-MM-dd")
 	private LocalDate contractStartBefore;
 
+	private List<Long> academicPeriods;
+
 	private List<Status> statuses;
 
 }
diff --git a/src/main/java/nl/tudelft/tam/repository/ApplicationExportRepository.java b/src/main/java/nl/tudelft/tam/repository/ApplicationExportRepository.java
index d012466e1fcd50c31582670680f8ba24550dfb7d..a9bc638090d31b6d2143d606f9b35853cf1480a5 100644
--- a/src/main/java/nl/tudelft/tam/repository/ApplicationExportRepository.java
+++ b/src/main/java/nl/tudelft/tam/repository/ApplicationExportRepository.java
@@ -38,7 +38,6 @@ public interface ApplicationExportRepository extends JpaRepository<ApplicationEx
 				.orElseThrow(() -> new ResourceNotFoundException("Application Export was not found: " + id));
 	}
 
-	List<ApplicationExport> findAllByExportedByAndProgramIdOrderByExportAtDesc(Long exportedBy,
-			Long programId);
-
+	List<ApplicationExport> findAllByExportedByAndProgramIdInOrderByExportAtDesc(Long exportedBy,
+			List<Long> programIds);
 }
diff --git a/src/main/java/nl/tudelft/tam/security/AuthorisationService.java b/src/main/java/nl/tudelft/tam/security/AuthorisationService.java
index 826b02d1632085e382d5abe2d54b4860922786ef..a5c51a1479c119027bacef56f2c9092534e56a83 100644
--- a/src/main/java/nl/tudelft/tam/security/AuthorisationService.java
+++ b/src/main/java/nl/tudelft/tam/security/AuthorisationService.java
@@ -135,6 +135,16 @@ public class AuthorisationService {
 						.anyMatch(c -> Objects.equals(c.getId(), getAuthPerson().getId()));
 	}
 
+	/**
+	 * Checks if the person is a coordinator for multiple programs
+	 *
+	 * @param  programIds The ids of the programs
+	 * @return            true if the authenticated person is a coordinator
+	 */
+	public boolean isCoordinatorForPrograms(List<Long> programIds) {
+		return isAdmin() || programIds.stream().allMatch(this::isCoordinatorForProgram);
+	}
+
 	/**
 	 * Checks if the person can edit the coordinators for a programme
 	 *
diff --git a/src/main/java/nl/tudelft/tam/service/ApplicationService.java b/src/main/java/nl/tudelft/tam/service/ApplicationService.java
index 95bd991d3cd41ee806c6daf585136ba532b463fd..5ba1f5dc0115eac7a5b821c760a02b8bec4b7365 100644
--- a/src/main/java/nl/tudelft/tam/service/ApplicationService.java
+++ b/src/main/java/nl/tudelft/tam/service/ApplicationService.java
@@ -120,6 +120,8 @@ public class ApplicationService {
 
 	@Autowired
 	DTOConverter converter;
+	@Autowired
+	private ProgramService programService;
 
 	// endregion
 
@@ -743,7 +745,7 @@ public class ApplicationService {
 	 */
 	public List<Application> getCoordinatingApplications(Long personId) {
 		List<Long> programIds = coordinatorService.findAllByPersonId(personId).stream()
-				.map(Coordinator::getProgramId).collect(Collectors.toList());
+				.map(Coordinator::getProgramId).toList();
 		return applicationRepository.findAll().stream()
 				.filter(e -> programIds.contains(courseService
 						.getOrThrow(
@@ -790,15 +792,15 @@ public class ApplicationService {
 	}
 
 	/**
-	 * Finds all the exports a person did for a program.
+	 * Finds all the exports a person did for a list of programs.
 	 *
 	 * @param  person    The person
-	 * @param  programId The id of the program
+	 * @param  programId The ids of the programs
 	 * @return           All exports done by the person
 	 */
-	public List<ApplicationExport> getExportsForPersonAndProgram(Person person, Long programId) {
-		return applicationExportRepository.findAllByExportedByAndProgramIdOrderByExportAtDesc(person.getId(),
-				programId);
+	public List<ApplicationExport> getExportsForPersonAndPrograms(Person person, List<Long> programIds) {
+		return applicationExportRepository
+				.findAllByExportedByAndProgramIdInOrderByExportAtDesc(person.getId(), programIds);
 	}
 
 	/**
@@ -810,8 +812,8 @@ public class ApplicationService {
 	 */
 	public List<Application> getFilteredCoordinatingApplications(Long personId,
 			ApplicationFilterDTO filter) {
-		List<Application> applications = getCoordinatingApplicationsForProgram(personId, filter.getProgram())
-				.stream()
+		List<Application> applications = filter.getPrograms().stream()
+				.flatMap(programId -> getCoordinatingApplicationsForProgram(personId, programId).stream())
 				.filter(a -> !editionService.getOrThrow(a.getJobOffer().getEditionId()).getIsArchived())
 				.toList();
 		return filterApplications(applications, filter);
@@ -835,6 +837,11 @@ public class ApplicationService {
 				.filter(app -> filter.getUpdatedSince() == null || !applicationChangeEventRepository
 						.findByApplicationIdAndChangedAtAfter(app.getId(), filter.getUpdatedSince())
 						.isEmpty())
+				.filter(a -> filter.getAcademicPeriods() == null ||
+						Optional.ofNullable(
+								editionService.getEditionById(a.getJobOffer().getEditionId()).getPeriod())
+								.map(period -> filter.getAcademicPeriods().contains(period.getId()))
+								.orElse(false))
 				.toList();
 	}
 
@@ -951,7 +958,7 @@ public class ApplicationService {
 	 * Exports a list of applications with FlexDelft specific fields
 	 *
 	 * @param  person       The person exporting
-	 * @param  programId    The program being exported for
+	 * @param  programIds   The programs being exported
 	 * @param  batch        The batch number
 	 * @param  name         The name of the file
 	 * @param  applications The list of applications
@@ -959,7 +966,8 @@ public class ApplicationService {
 	 * @return              The Path to the export file
 	 */
 	@Transactional
-	public Path exportApplicationsForFlexDelft(Person person, Long programId, Integer batch, String name,
+	public Path exportApplicationsForFlexDelft(Person person, List<Long> programIds, Integer batch,
+			String name,
 			List<Application> applications, LocalDateTime since)
 			throws IOException {
 		if (since != null) {
@@ -967,13 +975,18 @@ public class ApplicationService {
 					ApplicationFilterDTO.builder().updatedSince(since).build());
 		}
 
-		applicationExportRepository.save(ApplicationExport.builder().exportedBy(person.getId())
-				.programId(programId).batchNumber(batch).build());
+		programIds.forEach(programId -> {
+			applicationExportRepository.save(ApplicationExport.builder()
+					.exportedBy(person.getId())
+					.programId(programId)
+					.batchNumber(batch)
+					.build());
+		});
 
 		// Fetch all people and editions to cache and avoid many requests to core
 		personService.get(applications.stream().map(a -> a.getId().getPersonId()));
 		editionService.get(
-				applications.stream().map(a -> a.getJobOffer().getEditionId()).collect(Collectors.toList()));
+				applications.stream().map(a -> a.getJobOffer().getEditionId()).toList());
 
 		String[] headers;
 
diff --git a/src/main/java/nl/tudelft/tam/service/JobOfferService.java b/src/main/java/nl/tudelft/tam/service/JobOfferService.java
index f042681dc710653217225a1bba3deb6d67c0a55a..756a27fa556402024ac41e19577d24cd8659704f 100644
--- a/src/main/java/nl/tudelft/tam/service/JobOfferService.java
+++ b/src/main/java/nl/tudelft/tam/service/JobOfferService.java
@@ -36,6 +36,7 @@ import org.springframework.web.multipart.MultipartFile;
 import com.opencsv.exceptions.CsvValidationException;
 
 import jakarta.validation.constraints.NotNull;
+import nl.tudelft.labracore.api.AcademicPeriodControllerApi;
 import nl.tudelft.labracore.api.dto.*;
 import nl.tudelft.librador.dto.DTOConverter;
 import nl.tudelft.librador.dto.patch.Patch;
@@ -80,6 +81,9 @@ public class JobOfferService {
 	@Autowired
 	ProgramService programService;
 
+	@Autowired
+	AcademicPeriodControllerApi academicPeriodApi;
+
 	@Autowired
 	PersonService personService;
 
@@ -444,4 +448,13 @@ public class JobOfferService {
 		return roleService.getTAsAndHeadTAsById(id).stream()
 				.filter(x -> !applicationService.hasApplicationInEdition(x.getPerson().getId(), id)).toList();
 	}
+
+	/**
+	 * Get all academic periods from CORE
+	 *
+	 * @return all academic periods
+	 */
+	public List<AcademicPeriodDetailsDTO> getAllAcademicPeriods() {
+		return academicPeriodApi.getAll().collectList().block();
+	}
 }
diff --git a/src/main/resources/templates/application/all.html b/src/main/resources/templates/application/all.html
index de13d3856f28d1d37ed6a672aa29244492739cc5..4020e72951db1a473202d224720a8ecc984b78ae 100644
--- a/src/main/resources/templates/application/all.html
+++ b/src/main/resources/templates/application/all.html
@@ -50,14 +50,38 @@
                 method="get">
                 <div class="flex vertical gap-1">
                     <label for="export-program" th:text="#{jobOffer.export.program}"></label>
-                    <select class="textfield" id="export-program" name="program" required>
+                    <select
+                        class="textfield"
+                        id="export-program"
+                        name="programs"
+                        multiple
+                        data-select
+                        required>
                         <option
                             th:each="program : ${programs}"
-                            th:selected="${program.id.toString() == param.program?.toString()}"
+                            th:selected="${param.programs == null
+                            || #arrays.contains(#strings.arraySplit(param.programs, ','), program.id.toString())}"
                             th:value="${program.id}"
                             th:text="${program.name}"></option>
                     </select>
                 </div>
+                <div>
+                    <label for="period-select" class="mr-3">Select a period</label>
+                    <select
+                        id="period-select"
+                        class="textfield"
+                        name="academicPeriods"
+                        multiple
+                        data-select>
+                        <option
+                            th:each="period: ${periods}"
+                            th:value="${period.id}"
+                            th:text="${period.name}"
+                            th:selected="${param.period == null
+                            || #arrays.contains(
+                            #strings.arraySplit(param.period,','), period.id.toString())}" />
+                    </select>
+                </div>
                 <div class="flex vertical gap-1">
                     <label
                         for="contract-start-after"
diff --git a/src/main/resources/templates/application/all_flexdelft.html b/src/main/resources/templates/application/all_flexdelft.html
index 679e0b2dd17e57b394e998d1e5933a78c84a99e2..10498a0711b7002c759fa1b572e9bdd6afa894df 100644
--- a/src/main/resources/templates/application/all_flexdelft.html
+++ b/src/main/resources/templates/application/all_flexdelft.html
@@ -83,14 +83,38 @@
                 </div>
                 <div class="flex vertical gap-1">
                     <label for="export-program" th:text="#{jobOffer.export.program}"></label>
-                    <select class="textfield" id="export-program" name="program" required>
+                    <select
+                        class="textfield"
+                        id="export-program"
+                        name="programs"
+                        multiple
+                        data-select
+                        required>
                         <option
                             th:each="program : ${programs}"
-                            th:selected="${program.id.toString() == param.program?.toString()}"
+                            th:selected="${param.programs == null
+                            || #arrays.contains(#strings.arraySplit(param.programs, ','), program.id.toString())}"
                             th:value="${program.id}"
                             th:text="${program.name}"></option>
                     </select>
                 </div>
+                <div class="flex vertical gap-1">
+                    <label for="period-select" class="mr-3">Select a period</label>
+                    <select
+                        id="period-select"
+                        class="textfield"
+                        name="academicPeriods"
+                        multiple
+                        data-select>
+                        <option
+                            th:each="period: ${periods}"
+                            th:value="${period.id}"
+                            th:text="${period.name}"
+                            th:selected="${param.period == null
+                            || #arrays.contains(
+                            #strings.arraySplit(param.period,','), period.id.toString())}" />
+                    </select>
+                </div>
                 <div class="flex vertical gap-1">
                     <label
                         for="export-batch-number"
diff --git a/src/main/resources/templates/application/view_many.html b/src/main/resources/templates/application/view_many.html
index 82831356105f2691279005677ead1ce5e34b7f74..1187a999e1f89917b827a667154b7b6acb97694b 100644
--- a/src/main/resources/templates/application/view_many.html
+++ b/src/main/resources/templates/application/view_many.html
@@ -58,7 +58,20 @@
                     th:text="#{application.my}"></a>
             </div>
 
-            <div>
+            <div class="flex align-end justify-end | md:vertical md:align-stretch">
+                <div>
+                    <label for="period-select" class="mr-3">Select a period</label>
+                    <select id="period-select" class="textfield" multiple data-select>
+                        <option
+                            th:each="period: ${periods}"
+                            th:value="${period.id}"
+                            th:text="${period.name}"
+                            th:selected="${param.period == null
+                            || param.period.equals(period.id.toString())
+                            || #arrays.contains(
+                            #strings.arraySplit(param.period,','), period.id.toString())}" />
+                    </select>
+                </div>
                 <form class="search">
                     <input
                         name="q"
@@ -175,6 +188,13 @@
                         window.location = url.toString();
                     });
 
+                    $("#period-select").change(function () {
+                        let url = new URL(window.location);
+                        console.log($(this).val());
+                        url.searchParams.set("period", $(this).val());
+                        window.location = url.toString();
+                    });
+
                     $("#search-form").submit(function (event) {
                         event.preventDefault();
                         let url = new URL(window.location);
diff --git a/src/main/resources/templates/job_offer/view_many.html b/src/main/resources/templates/job_offer/view_many.html
index b36fe3a2c9882630b7b1d563f278080a68fbe91e..ec533f7b8c73025c2c4ee51aad722f46ead21b53 100644
--- a/src/main/resources/templates/job_offer/view_many.html
+++ b/src/main/resources/templates/job_offer/view_many.html
@@ -47,7 +47,7 @@
                     th:text="#{application.my}"></a>
             </div>
 
-            <div class="flex space-between align-center | md:vertical md:align-stretch">
+            <div class="flex space-between align-end | md:vertical md:align-stretch">
                 <div>
                     <label
                         for="program-select"
@@ -64,20 +64,32 @@
                             th:text="${program.name}"></option>
                     </select>
                 </div>
-
-                <form class="search" id="search-form">
-                    <input
-                        name="q"
-                        id="job-offer-search"
-                        th:aria-label="#{general.search}"
-                        type="search"
-                        th:value="${param.q}"
-                        th:placeholder="#{jobOffer.search}" />
-                    <button
-                        class="fa-solid fa-search"
-                        th:aria-label="#{general.search}"
-                        type="submit"></button>
-                </form>
+                <div class="flex space-between align-end">
+                    <div>
+                        <label for="period-select" class="mr-3">Select a period</label>
+                        <select id="period-select" class="textfield" multiple data-select>
+                            <option
+                                th:each="period: ${periods}"
+                                th:value="${period.id}"
+                                th:text="${period.name}"
+                                th:selected="${param.period == null
+                            || #arrays.contains(#strings.arraySplit(param.period,','), period.id.toString())}" />
+                        </select>
+                    </div>
+                    <form class="search" id="search-form">
+                        <input
+                            name="q"
+                            id="job-offer-search"
+                            th:aria-label="#{general.search}"
+                            type="search"
+                            th:value="${param.q}"
+                            th:placeholder="#{jobOffer.search}" />
+                        <button
+                            class="fa-solid fa-search"
+                            th:aria-label="#{general.search}"
+                            type="submit"></button>
+                    </form>
+                </div>
             </div>
 
             <table
@@ -291,6 +303,13 @@
                         window.location = url.toString();
                     });
 
+                    $("#period-select").change(function () {
+                        let url = new URL(window.location);
+                        console.log($(this).val());
+                        url.searchParams.set("period", $(this).val());
+                        window.location = url.toString();
+                    });
+
                     $("#search-form").submit(function (event) {
                         event.preventDefault();
                         let url = new URL(window.location);
diff --git a/src/test/java/nl/tudelft/tam/service/ApplicationServiceMockTest.java b/src/test/java/nl/tudelft/tam/service/ApplicationServiceMockTest.java
index 2434d7b58ef67fa1c3748257f2d9b5f1c5df70d9..9319f2789eb78e8f40a2dd08c780f441cb0dde19 100644
--- a/src/test/java/nl/tudelft/tam/service/ApplicationServiceMockTest.java
+++ b/src/test/java/nl/tudelft/tam/service/ApplicationServiceMockTest.java
@@ -758,7 +758,7 @@ class ApplicationServiceMockTest {
 
 		@SuppressWarnings("unchecked") ArgumentCaptor<List<String[]>> captor = ArgumentCaptor
 				.forClass(List.class);
-		service.exportApplicationsForFlexDelft(exporter, PROGRAM_ID, 1, name, applications, null);
+		service.exportApplicationsForFlexDelft(exporter, List.of(PROGRAM_ID), 1, name, applications, null);
 		verify(csvService).writeToCSV(captor.capture(), any(), eq(name + ".csv"));
 
 		assertThat(captor.getValue())
diff --git a/src/test/java/nl/tudelft/tam/service/JobOfferServiceTest.java b/src/test/java/nl/tudelft/tam/service/JobOfferServiceTest.java
index fa0605417c477563406a66c997865d6b324c5794..d28f728b5db0760cec56d4a40bef9266b9777dfb 100644
--- a/src/test/java/nl/tudelft/tam/service/JobOfferServiceTest.java
+++ b/src/test/java/nl/tudelft/tam/service/JobOfferServiceTest.java
@@ -39,6 +39,7 @@ import org.springframework.mock.web.MockMultipartFile;
 import org.springframework.transaction.annotation.Transactional;
 
 import application.test.TestTAMApplication;
+import nl.tudelft.labracore.api.AcademicPeriodControllerApi;
 import nl.tudelft.labracore.api.dto.*;
 import nl.tudelft.librador.dto.DTOConverter;
 import nl.tudelft.tam.dto.create.JobOfferCreateDTO;
@@ -52,6 +53,7 @@ import nl.tudelft.tam.model.Application;
 import nl.tudelft.tam.model.JobOffer;
 import nl.tudelft.tam.repository.JobOfferRepository;
 import nl.tudelft.tam.security.AuthorisationService;
+import reactor.core.publisher.Flux;
 
 @SpringBootTest(classes = TestTAMApplication.class)
 @Transactional
@@ -94,6 +96,10 @@ class JobOfferServiceTest {
 
 	@MockBean
 	private RoleService roleService;
+	@MockBean
+	private AcademicPeriodControllerApi academicPeriodControllerApi;
+	@Autowired
+	private DTOConverter dtoMapper;
 
 	@BeforeEach
 	void setUp() {
@@ -561,4 +567,14 @@ class JobOfferServiceTest {
 		verify(applicationService).hasApplicationInEdition(3L, editionId);
 	}
 
+	@Test
+	void getAllAcademicPeriodTest() {
+		var originalPeriods = List.of(new AcademicPeriodDetailsDTO().id(1L));
+		when(academicPeriodControllerApi.getAll()).thenReturn(Flux.fromIterable(originalPeriods));
+
+		var period = service.getAllAcademicPeriods();
+
+		assertThat(originalPeriods).isEqualTo(period);
+
+	}
 }