DEV Community

KunStudio
KunStudio

Posted on • Originally published at pod-shop.pages.dev

How I wired Printify's API to a PayPal-only checkout for a print-on-demand shop (no Shopify, no Stripe)

How I wired Printify's API to a PayPal-only checkout for a print-on-demand shop (no Shopify, no Stripe)

Most print-on-demand tutorials assume you're building on Shopify with the Printify Shopify app, or on WooCommerce, or accepting Stripe. I wanted none of those — a static storefront, PayPal as the only payment rail, and Printify purely as a fulfillment API, no platform lock-in.

Here's the actual wiring behind Inkwell & Co, a small graphic-tee shop built this way.

Why skip the Shopify/Printify app integration

The standard Printify + Shopify integration is genuinely easy to set up, which is exactly why I didn't want it for this project — it couples your storefront to Shopify's checkout, theme system, and monthly fee regardless of order volume. For a single small catalog:

  • Printify's REST API (api.printify.com/v1) exposes products, variants, and order creation directly — no app-store middleman needed.
  • PayPal's REST API (Orders v2 + webhooks) handles checkout and capture without needing a full commerce platform underneath it.
  • A static frontend + a couple of serverless functions is enough glue code to connect the two.

The order flow

customer checks out via PayPal (Orders v2 create + capture)
  → PayPal webhook fires on PAYMENT.CAPTURE.COMPLETED
  → webhook handler POSTs an order to Printify (/shops/{id}/orders.json)
    with the captured shipping address + line items
  → Printify handles print + fulfillment + shipping
  → order status polled back for customer-facing tracking
Enter fullscreen mode Exit fullscreen mode

The part that actually took iteration wasn't the happy path — it was getting the PayPal capture payload's shipping address mapped correctly onto Printify's expected order schema (Printify wants a fairly specific address object shape, and PayPal's capture response nests it differently depending on whether the buyer used a saved address or typed one in at checkout). Test both paths explicitly if you're building something similar; they don't look the same in the response.

What I'd do differently starting over

  • Log the full raw PayPal webhook payload before transforming it, not after. The one bug that cost real time was an address field silently going empty for guest checkouts specifically — invisible until you have the raw payload to diff against.
  • Printify's variant IDs are size/color-specific and not obvious from the product API alone — pull the full variants list once at setup and cache it, don't try to guess the mapping.
  • A webhook retry from PayPal (they do retry on non-2xx) can create a duplicate Printify order unless the handler is idempotent on PayPal's capture ID. Worth building that guard in from the start rather than after the first duplicate print run.

Live shop: https://pod-shop.pages.dev/

If you've wired Printify to a non-Shopify checkout and hit different edge cases, I'd like to compare notes in the comments.

Top comments (0)