Printful Integration
Status
⬜ Planned — API client exists (lib/printful.ts), wiring is in progress.
API versions
| Version | Use 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_keyfield in POST response). Store immediately asPRINTFUL_WEBHOOK_SECRETin Portainer. The GET endpoint only exposespublic_key. - Webhook signing:
secret_keyis a hex string — decode withBuffer.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.