Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 

README.md

@harder-labs/vendure-plugin-printful

Vendure 3.6+ plugin for Printful print-on-demand integration.

What it does

  • Idempotent fulfillment submission — exactly-once outbound calls to Printful's POST /orders driven by a BullMQ job with a deterministic jobId, backed by a PrintfulSubmissionState table with lease-based atomic claims.
  • Raw-body HMAC webhook/printful/webhook registered with beforeListen: true so HMAC verification runs against the original request bytes. Webhook dedupe via PrintfulWebhookDedupe.
  • Sync record cache — caches Printful sync products so storefront variant lookups don't round-trip to Printful on every request.
  • Admin retry mutationprintfulRetrySubmission(fulfillmentId) re-enqueues via the order service (preserving the jobId guardrail) for manual recovery.
  • Stub / live API client toggle — outbound calls go to a stub when apiToken is unset (dev default), live when set (prod).

Install

yarn add @harder-labs/vendure-plugin-printful
# peer:
yarn add @vendure/core

Usage

import { PrintfulPlugin } from '@harder-labs/vendure-plugin-printful';

const config: VendureConfig = {
    plugins: [
        PrintfulPlugin.init({
            apiToken: process.env.PRINTFUL_API_TOKEN,
            storeId: process.env.PRINTFUL_STORE_ID
                ? +process.env.PRINTFUL_STORE_ID
                : undefined,
            webhookSecret: process.env.PRINTFUL_WEBHOOK_SECRET,
            confirmOrders: process.env.PRINTFUL_CONFIRM_ORDERS !== 'false',
        }),
    ],
};

Custom fields contributed

Entity Field Purpose
ProductVariant printfulVariantId (number) links a Vendure variant to a Printful catalog variant
ProductVariant printfulSyncProductId (number) links to the Printful sync product
ProductVariant printCostCents (number) Printful's print cost for margin-floor checks
ProductVariant mockupUrl (string) preview image for storefront cards
Channel minimumMarginCents (number) floor that POD lines can't sell below — enforced by the platform's margin-floor OrderProcess
Fulfillment printfulOrderId (number) Printful's order id (post-submit)
Fulfillment printfulStatus (string) last-seen status from webhook

Env contract

Var Required for prod? Purpose
PRINTFUL_API_TOKEN yes Printful API token; unset → stub client
PRINTFUL_STORE_ID yes Printful store id for the channel
PRINTFUL_WEBHOOK_SECRET yes HMAC verification secret for /printful/webhook
PRINTFUL_CONFIRM_ORDERS optional (default true) whether to confirm orders on submit; false leaves them as drafts

Hooks

  • EventBus subscriber on OrderStateTransitionEvent (PaymentSettled → submit)
  • OnApplicationBootstrap — BullMQ queue ownership lives in PrintfulOrderService so admin retries don't bypass the jobId guardrail.

Provenance

Extracted from the vendure-platform in-tree implementation (Phase 0 tasks #7 + #14). Two gpt-5.4 review rounds hardened the lease-claim + admin-retry paths and split the webhook error taxonomy. See CHANGELOG.md.