Trip-Insurance PDF eSIM QR: The 15-Minute Integration for Policy Admin Systems (2026)
The tactical walkthrough for embedding an eSIM QR + activation URL into a trip-insurance PDF at policy issuance. One webhook, one POST /v1/orders call, one PDF template variable. Same pattern works on Duck Creek, Guidewire, and Majesco. Total integration: ~90 lines of code, 2–3 engineer-weeks under standard vendor release cadence.
Summary
Embedding a QR + activation URL into a trip-insurance PDF at policy issuance: one webhook handler + one POST /v1/orders + one PDF template variable. Same pattern works on Duck Creek, Guidewire, and Majesco. ~90 lines total, 2–3 engineer-weeks under a standard PAS release cadence.
Integration flow (three nodes)
- PAS fires policy.issued webhook to your middleware.
- Your middleware extracts destination + dates, calls POST /v1/orders, gets back activationUrl + qrCodeUrl.
- Your PDF renderer injects the URL/QR into the policy PDF template + emails to policyholder.
Full handler (~40 lines)
// on-policy-issued.ts
import crypto from 'crypto';
export async function POST(req: Request) {
const raw = await req.text();
const sig = req.headers.get('x-pas-signature') ?? '';
const expected = crypto
.createHmac('sha256', process.env.PAS_WEBHOOK_SECRET!)
.update(raw)
.digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {
return new Response('bad signature', { status: 401 });
}
const event = JSON.parse(raw);
if (event.type !== 'policy.issued') return new Response('ok');
const destination = event.data.trip.destinationCountry; // 'ES'
const tripDays = event.data.trip.durationDays; // 10
const policyholder = event.data.policyholder.email;
const policyNumber = event.data.policyNumber;
// Provision the eSIM
const yonoRes = await fetch('https://api.yonosim.com/v1/orders', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.YONOSIM_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': `policy-${policyNumber}`,
},
body: JSON.stringify({
planId: pickRegionalPlan(destination, tripDays), // eu_5gb_30d for ES
customerEmail: policyholder,
metadata: { policyNumber, insurer: 'acme_ins' },
}),
});
const order = await yonoRes.json();
// Trigger PDF generation with the activation URL variable
await regeneratePolicyPdf(policyNumber, {
esimActivationUrl: order.activationUrl,
esimQrPngUrl: order.qrCodeUrl,
esimIccid: order.iccid,
});
return new Response('ok');
}PDF template snippet
In your PAS PDF template (Duck Creek, Guidewire, or plain HTML→PDF via Puppeteer/WeasyPrint), add a Schedule of Benefits section variable for the eSIM:
<!-- Schedule of Benefits — Connectivity Bundle -->
<h3>International Data Connectivity</h3>
<p>Your policy includes 5 GB of international mobile data
valid for 30 days at your destination.</p>
<div class="esim-activation">
<img src="{{esimQrPngUrl}}" alt="Install eSIM" width="180" height="180" />
<p>Scan QR to install, or visit:<br>
<strong>{{esimActivationUrl}}</strong></p>
<p class="fine-print">ICCID: {{esimIccid}}</p>
</div>Cancellation handling (~20 lines)
// on-policy-cancelled.ts
export async function POST(req: Request) {
// ... signature verification ...
const event = JSON.parse(raw);
if (event.type !== 'policy.cancelled') return new Response('ok');
const esimOrderId = await lookupEsimForPolicy(event.data.policyNumber);
if (!esimOrderId) return new Response('no esim to refund');
await fetch(`https://api.yonosim.com/v1/orders/${esimOrderId}/refund`, {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.YONOSIM_API_KEY}` },
});
// order.refunded webhook fires — insurer's ledger is credited
return new Response('ok');
}Total size + timeline
Policy-issued handler: 40 lines. Cancellation handler: 20 lines. PDF template variable: 10 lines. YonoSIM webhook listener for order.refunded → insurer ledger: 20 lines. Total: ~90 lines. Timeline: 2–3 engineer-weeks under standard PAS release cadence.
FAQ
QHow does the QR code get into the policy PDF?
ATwo paths. (1) Pre-generated in the API response — POST /v1/orders returns { id, activationUrl, qrCodeUrl } where qrCodeUrl is a hosted PNG. Insert as an <img> tag in your PDF template. (2) Generate client-side from the LPA string — POST /v1/orders returns { lpaString: 'LPA:1$smdp.example.com$activation-code' } which any standard QR library (qrcode-npm, ZXing, jsPDF) can render to inline SVG. Pattern 1 is simpler; pattern 2 gives more design control.
QWhen does the eSIM order get created relative to policy issuance?
AOn the policy-issued webhook. Sequence: (1) policyholder completes purchase, (2) PAS fires policy.issued event, (3) your middleware receives the event, extracts destination + trip dates, calls POST /v1/orders on YonoSIM, (4) YonoSIM returns activationUrl in ~180ms, (5) middleware injects the URL into the PDF template variables and triggers PDF generation, (6) generated PDF is emailed to policyholder alongside the standard policy confirmation.
QWhat if the PDF is generated by a legacy PAS that doesn't support runtime variable injection?
ATwo workarounds. (1) Generate the eSIM at issuance, store the activationUrl against the policy record, then use a follow-up email service (SendGrid, Resend) to deliver the QR + URL 24–48 hours before trip departure — bypasses the PDF template limitation entirely. (2) Post-generation PDF stamping via a service like PDFTron or Foxit — the eSIM QR is stamped onto the PDF after the PAS generates it. Pattern 1 is what most modern PAS integrations use; pattern 2 is what legacy PAS integrations use.
QDoes the eSIM QR expire?
AThe QR code itself is a permanent artifact — it encodes the LPA string that stays valid until the eSIM is installed. The eSIM ORDER expires per YonoSIM's provisioning rules: typically 90 days for auto-cancellation on non-installation, 30 days for auto-refund on non-usage. For a trip-insurance bundle, this means the policyholder has ~3 months to install the eSIM before the order lapses — usually more than enough runway even for policies bought far in advance.
QHow do we handle policyholder cancellations before the trip?
AOn the policy.cancelled webhook, your middleware calls POST /v1/orders/:id/refund on the corresponding eSIM order. YonoSIM cancels the eSIM upstream and credits the insurer's balance. If the policyholder already installed the eSIM but hadn't used it, the standard 30-day no-usage sweep would auto-refund anyway. Either way, the insurer's ledger is preserved.
QWhat's the total engineering commitment?
A~90 lines of code across three components: (1) policy-issued webhook handler with signature verification (~40 lines), (2) POST /v1/orders call with destination + policy metadata (~20 lines), (3) PDF template variable + email follow-up trigger (~30 lines). Under a standard PAS vendor release cadence (Duck Creek, Guidewire, Majesco all run 4–6 week release cycles), that's 2–3 engineer-weeks of the vendor's team, or same duration if the insurer's internal team builds against the vendor's outbound-webhook framework.
Bottom line
Adding an eSIM to a trip-insurance policy PDF is ~90 lines of code and 2–3 engineer-weeks — well within a single PAS release cycle. The sandbox at api.yonosim.com/docs lets you validate the full lifecycle including auto-refund before writing the integration ticket. Back to the Travel insurance hub.