diff --git a/aleksis/apps/kort/api.py b/aleksis/apps/kort/api.py
index 1ddeae48ec5b47f7d5af6121b72ded0cab0a3ca5..5179acf9a46240b18110decf532ea94eeee95ab5 100644
--- a/aleksis/apps/kort/api.py
+++ b/aleksis/apps/kort/api.py
@@ -2,8 +2,11 @@ from django.contrib import admin
 from django.shortcuts import get_object_or_404
 from django.utils import timezone
 
+from celery.result import allow_join_result
+from celery.states import SUCCESS
 from oauth2_provider.contrib.rest_framework import TokenHasScope
 from rest_framework import generics, permissions, serializers
+from rest_framework.exceptions import APIException, ValidationError
 from rest_framework.permissions import BasePermission
 from rest_framework.response import Response
 from rest_framework.views import APIView
@@ -79,6 +82,12 @@ class CardPrintJobStatusSerializer(serializers.ModelSerializer):
         fields = ("id", "status", "status_text")
 
 
+class CardChipNumberSerializer(serializers.ModelSerializer):
+    class Meta:
+        model = Card
+        fields = ("chip_number",)
+
+
 class CardPrinterDetails(generics.RetrieveAPIView):
     """Show details about the card printer."""
 
@@ -135,3 +144,39 @@ class CardPrintJobUpdateStatusView(generics.UpdateAPIView):
     required_scopes = ["card_printer"]
     serializer_class = CardPrintJobStatusSerializer
     queryset = CardPrintJob.objects.all()
+
+
+class CardPrintJobSetChipNumberView(generics.UpdateAPIView):
+    """Update the status of the card printer."""
+
+    permission_classes = [permissions.IsAuthenticated, TokenHasScope, CorrectJobPrinterPermission]
+    required_scopes = ["card_printer"]
+    serializer_class = CardChipNumberSerializer
+    queryset = CardPrintJob.objects.all()
+
+    def update(self, request, *args, **kwargs):
+        instance = self.get_object()
+        card = instance.card
+
+        if card.chip_number:
+            raise ValidationError
+
+        serializer = self.get_serializer(card, data=request.data)
+        serializer.is_valid(raise_exception=True)
+        self.perform_update(serializer)
+
+        result = instance.card.generate_pdf()
+
+        with allow_join_result():
+            result.wait()
+            card.refresh_from_db()
+
+        if result.status == SUCCESS and card.pdf_file:
+            serializer = CardPrintJobSerializer(instance)
+            instance.refresh_from_db()
+
+            return Response(serializer.data)
+        else:
+            card.chip_number = None
+            card.save()
+            raise APIException("Error while generating PDF file")
diff --git a/aleksis/apps/kort/models.py b/aleksis/apps/kort/models.py
index 7889cb33a6def26a994653b546965377a832244c..eac8c3bf0211296c6f6d34704ace0db9eb3bb505 100644
--- a/aleksis/apps/kort/models.py
+++ b/aleksis/apps/kort/models.py
@@ -6,6 +6,7 @@ from django.conf import settings
 from django.core.exceptions import ValidationError
 from django.core.validators import FileExtensionValidator
 from django.db import models
+from django.db.models import Q
 from django.template import Context, Template
 from django.utils import timezone
 from django.utils.translation import gettext as _
@@ -148,6 +149,21 @@ class CardPrinter(ExtensibleModel):
             printer.check_online_status()
 
     def get_next_print_job(self) -> Optional["CardPrintJob"]:
+        if not self.generate_number_on_server:
+            print(
+                self.jobs.filter(card__pdf_file=""),
+                self.jobs.filter(card__pdf_file="").exclude(card__chip_number=""),
+            )
+            self.jobs.filter(
+                (Q(card__pdf_file="") & ~Q(card__chip_number=""))
+                | Q(status=PrintStatus.IN_PROGRESS)
+            ).update(status=PrintStatus.FAILED)
+            Card.objects.filter(
+                jobs__in=self.jobs.filter(status=PrintStatus.FAILED), chip_number=""
+            ).update(chip_number="")
+        else:
+            self.jobs.filter(status=PrintStatus.IN_PROGRESS).update(status=PrintStatus.FAILED)
+
         jobs = self.jobs.order_by("created").filter(status=PrintStatus.REGISTERED)
         if self.generate_number_on_server:
             jobs = jobs.filter(card__pdf_file__isnull=False)
@@ -248,7 +264,9 @@ class CardPrintJob(TimeStampedModel, ExtensibleModel):
     printer = models.ForeignKey(
         CardPrinter, on_delete=models.CASCADE, verbose_name=_("Printer"), related_name="jobs"
     )
-    card = models.ForeignKey(Card, on_delete=models.CASCADE, verbose_name=_("Card"))
+    card = models.ForeignKey(
+        Card, on_delete=models.CASCADE, verbose_name=_("Card"), related_name="jobs"
+    )
 
     status = models.CharField(
         max_length=255,
diff --git a/aleksis/apps/kort/urls.py b/aleksis/apps/kort/urls.py
index a0c9f5de6dd709e91913dc206fa5226c8401092e..1cc3abcde975474cf37c389060e2a7dc1ea0544d 100644
--- a/aleksis/apps/kort/urls.py
+++ b/aleksis/apps/kort/urls.py
@@ -45,4 +45,9 @@ urlpatterns = [
         api.CardPrintJobUpdateStatusView.as_view(),
         name="api_update_job_status",
     ),
+    path(
+        "api/v1/jobs/<int:pk>/chip_number/",
+        api.CardPrintJobSetChipNumberView.as_view(),
+        name="api_set_chip_number",
+    ),
 ]