Skip to main content

Printful Integration

Status

⬜ Planned — API client exists (lib/printful.ts), wiring is in progress.

API versions

VersionUse for
V1 (https://api.printful.com)Orders, product sync
V2 (https://api.printful.com/v2)Webhook registration, store stats

Same API key works for both.

Key rules

  • Printful is source of truth for variants, pricing, availability. Never hardcode sizes or colors — always pull from Printful API.
  • Catalog product ID ≠ sync product ID. Sync product ID is your store-specific ID. Catalog product ID lives in sync_variant.product.product_id. Size guides use catalog ID: https://www.printful.com/size-guide/{catalogProductId}.
  • Webhook secret is returned only once — at registration (secret_key field in POST response). Store immediately as PRINTFUL_WEBHOOK_SECRET in Portainer. The GET endpoint only exposes public_key.
  • Webhook signing: secret_key is a hex string — decode with Buffer.from(secret, 'hex') before HMAC-SHA256. Sign the raw request body (request.text(), not .json()). Header: x-printful-signature.

Planned work

  • Variant UI on physical product pages
  • Cart carries full variant data (size, color, printful variant ID)
  • Webhook creates Printful orders automatically on checkout
  • Tracking email on shipment dispatch

Webhook re-registration

Run npm run register:webhooks and update PRINTFUL_WEBHOOK_SECRET in Portainer when webhook configs expire.