diff --git a/atdb/requirements/base.txt b/atdb/requirements/base.txt
index 38935ee2a06d85b69c5d5bafc3a26dfeb44da837..eb63b89a13274589c3866ed061fdba550b169cb4 100644
--- a/atdb/requirements/base.txt
+++ b/atdb/requirements/base.txt
@@ -18,3 +18,4 @@ requests-oauthlib==1.3.1
 six==1.15.0
 whitenoise==5.0.1
 pytz==2022.6
+xhtml2pdf==0.2.15
\ No newline at end of file
diff --git a/atdb/taskdatabase/urls.py b/atdb/taskdatabase/urls.py
index 8197a156896420b5850ab71f0036d5db6dc875e3..26a4b3a9912f2410f962d386a617c71df10a1434 100644
--- a/atdb/taskdatabase/urls.py
+++ b/atdb/taskdatabase/urls.py
@@ -104,6 +104,7 @@ urlpatterns = [
     # ancillary dataproducts endpoints (retrieved by archiver service for copy to LTA dcache).
     path('get_summary_html/<sas_id>', views.GetSummaryHtml, name='get-summary-html'),
     path('get_summary_json/<sas_id>', views.GetSummaryJson, name='get-summary-json'),
+    path('get_summary_pdf/<sas_id>', views.GetSummaryPdf, name='get-summary-pdf'),
 
     # --- controller resources ---
     path('tasks/<int:pk>/setstatus/<new_status>/<page>', views.TaskSetStatus, name='task-setstatus-view'),
diff --git a/atdb/taskdatabase/views.py b/atdb/taskdatabase/views.py
index de0520ad734d990c4060b5d6e5d50d01652ea73b..d77a03781f9bad89b00cf93ce41da6c53020c16a 100644
--- a/atdb/taskdatabase/views.py
+++ b/atdb/taskdatabase/views.py
@@ -15,6 +15,7 @@ from django.contrib.auth.decorators import login_required
 from django.views.generic import ListView
 from django.contrib import messages
 
+
 from rest_framework import generics
 from rest_framework.response import Response
 from django.http import JsonResponse, HttpResponse
@@ -26,9 +27,8 @@ from django_tables2.views import SingleTableMixin
 from django.shortcuts import render, redirect, reverse
 from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
 from django.contrib.admin.views.decorators import staff_member_required
-from django.db.models import Count, F, Func, ExpressionWrapper, DurationField
-from django.db.models.functions import TruncHour, TruncDay
-from django.db.models import IntegerField, DateTimeField
+from xhtml2pdf import pisa
+from io import BytesIO
 
 from rest_framework.request import Request
 #from silk.profiling.profiler import silk_profile
@@ -1716,6 +1716,15 @@ def GetSummaryHtml(request, sas_id):
         queryset = Task.objects.filter(sas_id=sas_id)
         task = queryset[0]
 
+        # this would be the django template way of combining a html template with context.
+        # but that didn't add any of the styling, so I did it the basic way (see below).
+        # TODO: remove the commented out code later
+
+        # template = get_template("taskdatabase/validation/summary.html")
+        # summary_html = algorithms.construct_summary(task)
+        # context = {'task': task, 'my_summary': summary_html}
+        # html = template.render(context)
+
         # add some basic layout without using the summary.html template
         head_html="""
             <head>
@@ -1751,6 +1760,63 @@ def GetSummaryHtml(request, sas_id):
         })
 
 
+def GetSummaryPdf(request, sas_id):
+    """
+    Construct and return a summary html structure for given sas_id
+    This is the same informtion and algorithm as used when the user clicks the SUM button on the Validation page.
+    See documentation: https://drive.google.com/file/d/16R8L06OFiKHFHBUA6FhrNVZVAaQBC2tU/view?usp=sharing
+
+    example: /atdb/get_summary_pdf/606942
+    """
+    try:
+
+        # use a trick to be able to use the existing task based code
+        queryset = Task.objects.filter(sas_id=sas_id)
+        task = queryset[0]
+
+        # add some basic layout without using the summary.html template
+        head_html = """
+            <head>
+               <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
+               <link href='https://fonts.googleapis.com/css?family=Raleway' rel='stylesheet' type='text/css'>
+            </head>
+        """
+
+        body_html = """
+            <html>
+                <body>
+                    <div class="container-fluid details-container">
+                        <div class='card'><table>
+                            <div class="card-body">
+                                <table class="table table-striped">
+        """
+
+        # create the core html
+        summary_html = algorithms.construct_summary(task)
+
+        # close all the tags
+        footer_html = "</table></div></div></div></body></html>"
+
+        # combine the html sections
+        html = head_html + body_html + summary_html + footer_html
+
+        # Create a BytesIO object to receive the PDF data
+        result = BytesIO()
+
+        # Convert HTML to PDF
+        # TODO: fonts zijn fout in dev (ook op production?)
+        pdf = pisa.pisaDocument(BytesIO(html.encode("UTF-8")), result)
+        pdf_name = sas_id + '_summary.pdf'
+        if not pdf.err:
+            # Return the PDF as a response
+            response = HttpResponse(result.getvalue(), content_type='application/pdf')
+            response['Content-Disposition'] = f'attachment; filename={pdf_name}'
+            return response
+
+    except:
+        return HttpResponse(f'Failed to generate PDF: {pdf.err}')
+
+
 def GetSummaryJson(request, sas_id):
     """
     Construct and return a summary json structure for given sas_id