SnapPDF + Stripe
Post-payment webhook → auto-generate and compress invoices.
Every SaaS team that charges customers on Stripe hits the same wall: Stripe's default PDF invoices are functional but bland. The SnapPDF + Stripe integration listens for payment events, pulls Stripe's invoice, merges your branded cover + terms, applies watermarks or PAID stamps, compresses for email delivery, and fires the customer email. It replaces 200 lines of glue code with one Stripe webhook handler template we ship out of the box.
What you can build
- Listen to `invoice.paid`, `invoice.finalized`, `charge.refunded`, `checkout.session.completed`.
- Merge Stripe's auto-generated invoice with your cover page, terms, and receipt PDFs.
- Stamp PAID / REFUNDED / OVERDUE based on event type.
- Compress to <1MB for Gmail-safe attachment delivery.
- Emit a SnapPDF webhook on completion so downstream services (Resend, SES, HubSpot) can finalize.
Setup
- 01Configure Stripe webhookStripe dashboard → Developers → Webhooks → Add endpoint. URL: `https://api.snappdf.dev/api/v1/webhooks/stripe` (or your own handler).
- 02Select eventsPick `invoice.paid`, `invoice.finalized`, `charge.refunded`, `checkout.session.completed`. Fewer events = less quota burn.
- 03Copy the webhook signing secretStripe shows the `whsec_…` signing secret. Paste it into SnapPDF dashboard → Integrations → Stripe.
- 04Configure the flowSnapPDF dashboard → Stripe flow editor. Pick: merge with cover? apply watermark? compress? email via Resend?
- 05Link your Stripe account (optional)Use Stripe Connect to let SnapPDF read invoice PDFs directly — avoids needing you to provide a URL.
- 06Test with Stripe CLI`stripe trigger invoice.paid` against your endpoint. Verify the final PDF lands in the test customer's inbox.
Code example
Raw Stripe webhook handler wiring — what the integration does under the hood.
import Stripe from 'stripe';
import { SnapPDF } from '@snappdf/sdk';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
const snap = new SnapPDF({ apiKey: process.env.SNAPPDF_KEY! });
export async function POST(req: Request) {
const sig = req.headers.get('stripe-signature')!;
const event = stripe.webhooks.constructEvent(
await req.text(),
sig,
process.env.STRIPE_WEBHOOK_SECRET!,
);
if (event.type !== 'invoice.paid') return new Response('ok');
const inv = event.data.object as Stripe.Invoice;
const { pdf: merged } = await snap.pdf.merge({
files: [inv.invoice_pdf!, 'https://cdn.acme.com/legal/terms.pdf'],
});
const { pdf: stamped } = await snap.pdf.watermark({
file: merged, kind: 'text', text: 'PAID',
position: 'diagonal', opacity: 0.18, color: '#0f766e',
});
const { pdf: small } = await snap.pdf.compress({ file: stamped, level: 'high' });
await resend.emails.send({
to: inv.customer_email!,
from: 'billing@acme.com',
subject: `Invoice ${inv.number} — Paid`,
attachments: [{ filename: `${inv.number}.pdf`, content: small }],
});
return new Response('ok');
}Known limits
- · Stripe webhook delivery has a 30s timeout — long OCR must be routed to async.
- · Stripe Connect flows must set `Stripe-Account` header on each API call; our integration handles this automatically.
Pricing notes
Stripe integration free on every plan; invoice-volume ops are billed normally. High-volume shops usually sit on Business ($299/mo).
Available from the Free plan.
FAQ
Does this replace Stripe Invoices entirely?
No — we build on top of Stripe's canonical invoice PDF. You still get Stripe's tax calc, line-item logic, and legal-name formatting; we just layer your brand and policies on top.
What about refunds?
Configure a separate flow for `charge.refunded` — typically stamp REFUNDED and re-send the receipt.
Stripe Tax / VAT compliance?
Stripe's PDF is the legal record. We preserve it as-is and wrap additional pages around it. The stamped version remains legally equivalent in most jurisdictions; consult your counsel.
How does this interact with Stripe Connect?
Connected accounts can have their own SnapPDF flows. We scope the flow to the Stripe account ID.
Multi-currency?
All ops are currency-agnostic — we operate on the PDF bytes Stripe gives us.