diff --git a/src/main/java/com/sarapis/orservice/controller/ProgramController.java b/src/main/java/com/sarapis/orservice/controller/ProgramController.java
new file mode 100644
index 0000000..cdf690b
--- /dev/null
+++ b/src/main/java/com/sarapis/orservice/controller/ProgramController.java
@@ -0,0 +1,56 @@
+package com.sarapis.orservice.controller;
+
+import com.sarapis.orservice.dto.ProgramDTO;
+import com.sarapis.orservice.service.ProgramService;
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/api/programs")
+public class ProgramController {
+  public final ProgramService programService;
+
+  @Autowired
+  public ProgramController(ProgramService programService) {
+    this.programService = programService;
+  }
+
+  @GetMapping
+  public ResponseEntity<List<ProgramDTO>> getAllPrograms() {
+    List<ProgramDTO> programDTOs = this.programService.getAllPrograms();
+    return ResponseEntity.ok(programDTOs);
+  }
+
+  @GetMapping("/{id}")
+  public ResponseEntity<ProgramDTO> getProgramById(@PathVariable String id) {
+    ProgramDTO programDTO = this.programService.getProgramDTOById(id);
+    return ResponseEntity.ok(programDTO);
+  }
+
+  @PostMapping
+  public ResponseEntity<ProgramDTO> createProgram(@RequestBody ProgramDTO programDTO) {
+    ProgramDTO createdProgramDTO = this.programService.createProgram(programDTO);
+    return ResponseEntity.ok(createdProgramDTO);
+  }
+
+  @PutMapping("/{id}")
+  public ResponseEntity<ProgramDTO> updateProgram(@PathVariable String id, @RequestBody ProgramDTO programDTO) {
+    ProgramDTO updatedProgramDTO = this.programService.updateProgram(id, programDTO);
+    return ResponseEntity.ok(updatedProgramDTO);
+  }
+
+  @DeleteMapping("/{id}")
+  public ResponseEntity<Void> deleteProgram(@PathVariable String id) {
+    this.programService.deleteProgram(id);
+    return ResponseEntity.noContent().build();
+  }
+}
diff --git a/src/main/java/com/sarapis/orservice/repository/ProgramRepository.java b/src/main/java/com/sarapis/orservice/repository/ProgramRepository.java
new file mode 100644
index 0000000..b1bb163
--- /dev/null
+++ b/src/main/java/com/sarapis/orservice/repository/ProgramRepository.java
@@ -0,0 +1,28 @@
+package com.sarapis.orservice.repository;
+
+import com.sarapis.orservice.entity.Attribute;
+import com.sarapis.orservice.entity.Metadata;
+import com.sarapis.orservice.entity.Program;
+import jakarta.transaction.Transactional;
+import java.util.List;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+
+public interface ProgramRepository extends JpaRepository<Program, String> {
+  @Query("SELECT new Attribute(id, linkId, linkType, linkEntity, value, taxonomyTerm, label) FROM Attribute WHERE linkId = ?1")
+  List<Attribute> getAttributes(String organizationId);
+
+  @Query("SELECT new Metadata(id, resourceId, resourceType, lastActionDate, lastActionType, fieldName, previousValue, replacementValue, updatedBy) FROM Metadata WHERE resourceId = ?1")
+  List<Metadata> getMetadata(String organizationId);
+
+  @Modifying
+  @Transactional
+  @Query("DELETE FROM Attribute WHERE linkId = ?1")
+  void deleteAttributes(String organizationId);
+
+  @Modifying
+  @Transactional
+  @Query("DELETE FROM Metadata WHERE resourceId =?1")
+  void deleteMetadata(String organizationId);
+}
diff --git a/src/main/java/com/sarapis/orservice/service/ProgramService.java b/src/main/java/com/sarapis/orservice/service/ProgramService.java
new file mode 100644
index 0000000..e604af6
--- /dev/null
+++ b/src/main/java/com/sarapis/orservice/service/ProgramService.java
@@ -0,0 +1,16 @@
+package com.sarapis.orservice.service;
+
+import com.sarapis.orservice.dto.ProgramDTO;
+import java.util.List;
+
+public interface ProgramService {
+  List<ProgramDTO> getAllPrograms();
+
+  ProgramDTO getProgramDTOById(String id);
+
+  ProgramDTO createProgram(ProgramDTO programDTO);
+
+  ProgramDTO updateProgram(String id, ProgramDTO programDTO);
+
+  void deleteProgram(String id);
+}
diff --git a/src/main/java/com/sarapis/orservice/service/ProgramServiceImpl.java b/src/main/java/com/sarapis/orservice/service/ProgramServiceImpl.java
new file mode 100644
index 0000000..ade5ce6
--- /dev/null
+++ b/src/main/java/com/sarapis/orservice/service/ProgramServiceImpl.java
@@ -0,0 +1,87 @@
+package com.sarapis.orservice.service;
+
+import com.sarapis.orservice.dto.AttributeDTO;
+import com.sarapis.orservice.dto.MetadataDTO;
+import com.sarapis.orservice.dto.ProgramDTO;
+import com.sarapis.orservice.entity.Attribute;
+import com.sarapis.orservice.entity.Metadata;
+import com.sarapis.orservice.entity.Program;
+import com.sarapis.orservice.repository.AttributeRepository;
+import com.sarapis.orservice.repository.MetadataRepository;
+import com.sarapis.orservice.repository.ProgramRepository;
+import java.util.List;
+import org.springframework.stereotype.Service;
+
+@Service
+public class ProgramServiceImpl implements ProgramService {
+  private final ProgramRepository programRepository;
+  private final AttributeRepository attributeRepository;
+  private final MetadataRepository metadataRepository;
+
+  public ProgramServiceImpl(ProgramRepository programRepository, AttributeRepository attributeRepository, MetadataRepository metadataRepository) {
+    this.programRepository = programRepository;
+    this.attributeRepository = attributeRepository;
+    this.metadataRepository = metadataRepository;
+  }
+
+  @Override
+  public List<ProgramDTO> getAllPrograms() {
+    List<ProgramDTO> programDTOs = this.programRepository.findAll().stream().map(Program::toDTO).toList();
+    programDTOs.forEach(this::addRelatedData);
+    return programDTOs;
+  }
+
+  @Override
+  public ProgramDTO getProgramDTOById(String id) {
+    Program program = this.programRepository.findById(id).orElseThrow(
+        () -> new RuntimeException("Program not found.")
+    );
+    ProgramDTO programDTO = program.toDTO();
+    this.addRelatedData(programDTO);
+    return programDTO;
+  }
+
+  @Override
+  public ProgramDTO createProgram(ProgramDTO programDTO) {
+    Program program = this.programRepository.save(programDTO.toEntity());
+    for (AttributeDTO attributeDTO : programDTO.getAttributes()) {
+      this.attributeRepository.save(attributeDTO.toEntity(program.getId()));
+    }
+
+    for (MetadataDTO metadataDTO : programDTO.getMetadata()) {
+      this.metadataRepository.save(metadataDTO.toEntity(program.getId()));
+    }
+
+    ProgramDTO savedProgramDTO = this.programRepository.save(program).toDTO();
+    this.addRelatedData(savedProgramDTO);
+    return savedProgramDTO;
+  }
+
+  @Override
+  public ProgramDTO updateProgram(String id, ProgramDTO programDTO) {
+    Program oldProgram = this.programRepository.findById(id).orElseThrow(
+        () -> new RuntimeException("Program not found."));
+    oldProgram.setId(programDTO.getId());
+    oldProgram.setName(programDTO.getName());
+    oldProgram.setAlternateName(programDTO.getAlternateName());
+    oldProgram.setDescription(programDTO.getDescription());
+
+    Program updatedProgram = this.programRepository.save(oldProgram);
+    return updatedProgram.toDTO();
+  }
+
+  @Override
+  public void deleteProgram(String id) {
+    Program program = this.programRepository.findById(id).orElseThrow(() -> new RuntimeException("Program not found."));
+    this.programRepository.deleteAttributes(program.getId());
+    this.programRepository.deleteMetadata(program.getId());
+    this.programRepository.delete(program);
+  }
+
+  private void addRelatedData(ProgramDTO programDTO) {
+    programDTO.getAttributes().addAll(this.programRepository.getAttributes(programDTO.getId()).stream().map(
+        Attribute::toDTO).toList());
+    programDTO.getMetadata().addAll(this.programRepository.getMetadata(programDTO.getId()).stream().map(
+        Metadata::toDTO).toList());
+  }
+}