diff --git a/src/Meezi.API/Controllers/PrintAgentPairingController.cs b/src/Meezi.API/Controllers/PrintAgentPairingController.cs
new file mode 100644
index 0000000..150866d
--- /dev/null
+++ b/src/Meezi.API/Controllers/PrintAgentPairingController.cs
@@ -0,0 +1,63 @@
+using System.Security.Cryptography;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.EntityFrameworkCore;
+using Meezi.API.Hubs;
+using Meezi.API.Models.Printing;
+using Meezi.Infrastructure.Data;
+using Meezi.Shared;
+
+namespace Meezi.API.Controllers;
+
+///
+/// Anonymous endpoint the print-agent installer calls to redeem a pairing code for
+/// a long-lived token. The token is returned exactly once; only its hash is stored.
+///
+[ApiController]
+[AllowAnonymous]
+[Route("api/print-agent")]
+public class PrintAgentPairingController : ControllerBase
+{
+ private readonly AppDbContext _db;
+
+ public PrintAgentPairingController(AppDbContext db) => _db = db;
+
+ [HttpPost("claim")]
+ public async Task Claim([FromBody] ClaimAgentRequest request, CancellationToken ct)
+ {
+ if (string.IsNullOrWhiteSpace(request.Code))
+ return BadRequest(new ApiResponse