Skip to main content
RapidDev - Software Development Agency
retool-integrationsREST API Resource

How to Integrate Retool with Printful

Connect Retool to Printful by creating a REST API Resource with Printful's API token authentication. Use Printful's API to build a print-on-demand operations dashboard that tracks order production status, monitors fulfillment timelines, manages product catalogs, and estimates shipping costs — all from a centralized Retool panel without switching between storefronts.

What you'll learn

  • How to generate a Printful API token and configure a REST API Resource in Retool
  • How to query Printful orders, products, and fulfillment status from Retool's query editor
  • How to build a print-on-demand operations dashboard tracking production and delivery timelines
  • How to use JavaScript transformers to reshape Printful API responses for Retool Tables and status indicators
  • How to estimate shipping costs and manage product catalog data from a Retool panel
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner15 min read20 minutesE-commerceLast updated April 2026RapidDev Engineering Team
TL;DR

Connect Retool to Printful by creating a REST API Resource with Printful's API token authentication. Use Printful's API to build a print-on-demand operations dashboard that tracks order production status, monitors fulfillment timelines, manages product catalogs, and estimates shipping costs — all from a centralized Retool panel without switching between storefronts.

Quick facts about this guide
FactValue
ToolPrintful
CategoryE-commerce
MethodREST API Resource
DifficultyBeginner
Time required20 minutes
Last updatedApril 2026

Build a Printful Order Tracking and Operations Dashboard in Retool

Printful handles the production and fulfillment side of print-on-demand businesses, but store owners and operations managers often need a unified view of order status across all their connected storefronts — Shopify, Etsy, WooCommerce, and direct API orders combined. Retool provides this unified operations panel by connecting directly to Printful's API, giving teams real-time visibility into production queues, fulfillment timelines, and shipping status without switching between multiple dashboards.

With a Retool-Printful integration, your operations team can view all orders across connected stores with current production status, identify orders stuck in processing or on hold, track shipping confirmation timelines, and monitor which products are most frequently ordered. When combined with your Shopify or WooCommerce data in the same Retool app, you can create a complete order-to-delivery tracking panel that spans the entire fulfillment chain.

Printful's API uses token-based authentication and returns clean JSON responses. The API covers order management, product catalog (sync products and sync variants), shipping rate estimation, store management, and warehouse inventory — all the data operations teams need for day-to-day fulfillment management.

Integration method

REST API Resource

Printful connects to Retool through a REST API Resource using an API token sent as a Bearer token in the Authorization header. All requests are proxied server-side through Retool, keeping your Printful API token secure and eliminating CORS issues. You configure the base URL and authentication once at the resource level, then build individual queries for orders, products, shipping rates, and store status.

Prerequisites

  • A Printful account with at least one connected store (Shopify, Etsy, WooCommerce, or manual API store)
  • A Printful API token (Printful Dashboard → Settings → Stores → API → Generate Token, or account-level API settings)
  • A Retool account with permission to create Resources
  • Familiarity with Retool's query editor and Table component
  • Optional: access to your connected storefront's database or API for cross-system order joining

Step-by-step guide

1

Generate a Printful API token and create a Retool Resource

First, generate your Printful API token. Log into your Printful dashboard and navigate to Settings → Stores, then select the store you want to connect. Look for the API section and click Generate Token. Alternatively, for an account-level token that covers all stores, go to your Printful account Settings → API. Copy the generated API token — it's a long alphanumeric string. Keep this secure; it grants full API access to your Printful account. Now go to the Resources tab in your Retool instance and click Add Resource. Select REST API from the resource type list. Name the resource 'Printful API'. In the Base URL field, enter https://api.printful.com. This is Printful's API v1 base URL — all endpoint paths will be appended to this. For authentication, Printful uses Bearer token authentication. In the Authentication section, select Bearer Token from the dropdown and enter your Printful API token in the Token field. For better security, store your token as a Retool configuration variable first: navigate to Settings → Configuration Variables, create a variable named PRINTFUL_API_TOKEN marked as Secret, then use {{ retoolContext.configVars.PRINTFUL_API_TOKEN }} in the Bearer Token field. Click Save Changes to create the resource.

Pro tip: Printful issues store-specific tokens and account-level tokens. Use an account-level token in Retool if you manage multiple stores under one Printful account — this way a single Retool resource can query orders and products across all your stores. Use the store_id URL parameter to filter by specific store when needed.

Expected result: A Printful API REST Resource is saved in your Retool Resources list with Bearer token authentication configured. The resource name 'Printful API' appears in the resource selector when creating queries.

2

Query Printful orders and production status

Create your first query to fetch orders from Printful. In your app's Code panel, click + to add a new query. Name it getOrders and select the Printful API resource. Set Method to GET. In the Path field, enter /orders. Add URL parameters to filter the results: - key = status, value = {{ dropdown_status.value || '' }} (filter by order status) - key = limit, value = 100 - key = offset, value = {{ (pagination.page - 1) * 100 || 0 }} - key = store_id, value = {{ dropdown_store.value || '' }} (if you have multiple stores) Printful order statuses include: draft, failed, pending, canceled, inprocess, onhold, partial, fulfilled. Create a second query named getOrderById that fetches full details for a selected order. Set Method to GET, Path to /orders/{{ table_orders.selectedRow.id }}. Run this on table row selection (set it to trigger from table_orders' row click event). Create a third query named getStores (GET, /stores) to populate a store filter dropdown. Run this on page load. Bind the result to a Dropdown component so operations staff can filter by specific connected storefront. For tracking information, Printful includes shipment data nested inside the order object. The order detail response includes a shipments array with carrier, tracking_number, and tracking_url fields.

transformer.js
1// JavaScript transformer — flatten Printful orders for Table display
2const orders = data.result || [];
3return orders.map(order => ({
4 id: order.id,
5 external_id: order.external_id || 'N/A',
6 status: order.status,
7 status_label: {
8 draft: 'Draft',
9 pending: 'Pending',
10 inprocess: 'In Production',
11 onhold: 'On Hold',
12 partial: 'Partially Shipped',
13 fulfilled: 'Fulfilled',
14 canceled: 'Canceled',
15 failed: 'Failed'
16 }[order.status] || order.status,
17 recipient: order.recipient
18 ? `${order.recipient.name || 'N/A'} (${order.recipient.country_code || ''})`
19 : 'N/A',
20 item_count: Array.isArray(order.items) ? order.items.length : 0,
21 created: order.created
22 ? new Date(order.created * 1000).toLocaleDateString('en-US', {
23 year: 'numeric', month: 'short', day: 'numeric'
24 })
25 : 'N/A',
26 retail_costs: order.retail_costs
27 ? `$${parseFloat(order.retail_costs.total || 0).toFixed(2)}`
28 : 'N/A',
29 tracking: order.shipments?.[0]?.tracking_number || 'Not shipped'
30}));

Pro tip: Printful uses Unix timestamps (seconds since epoch) for date fields — use new Date(timestamp * 1000) in JavaScript transformers to convert to readable dates. This is different from ISO 8601 timestamps used by most modern APIs.

Expected result: The getOrders query returns a list of Printful orders with production status, recipient details, item count, and tracking numbers. The transformer maps status codes to human-readable labels. The Table is populated and filterable by status.

3

Create order item detail and shipping tracking view

When operations staff click an order in the main table, they should see full item details — which products, quantities, print files, and shipping tracking. Build this detail view using the getOrderById query. Configure getOrderById to run whenever table_orders.selectedRow changes. In the Code panel, find getOrderById and set it to trigger on the selectedRow change event, or use Run on event handler from the table's row selection setting. Bind the item details to a second Table component named table_items. Set its Data property to {{ getOrderById.data.result.items }}. Configure columns to show name, quantity, retail_price, and status. For shipping tracking, add a Link component that opens the tracking URL in a new tab: use {{ getOrderById.data.result.shipments?.[0]?.tracking_url }} as the href value. Add a TextInput next to it showing the tracking number: {{ getOrderById.data.result.shipments?.[0]?.tracking_number }}. Add stat card components at the top of the detail panel showing: production status, number of items, retail total, and fulfillment date (if available). Use Retool's Stat component or custom Container + Text components for these. Create a query named cancelOrder (DELETE, /orders/{{ table_orders.selectedRow.id }}) and add a Cancel Order button with a confirmation modal. Only show this button when order status is 'draft' or 'pending' — use component visibility conditions to hide it for in-production or fulfilled orders. For complex POD operations integrations spanning multiple platforms, RapidDev's team can help build a unified fulfillment panel that combines Printful data with Shopify, Etsy, and WooCommerce order data.

transformer.js
1// JavaScript transformer — format order items for detail table
2const order = data.result || {};
3const items = order.items || [];
4return items.map(item => ({
5 name: item.name || item.variant_name || 'Unknown Product',
6 quantity: item.quantity || 1,
7 sku: item.sku || 'N/A',
8 retail_price: item.retail_price
9 ? `$${parseFloat(item.retail_price).toFixed(2)}`
10 : 'N/A',
11 status: item.status || 'pending',
12 product_id: item.product?.product_id || 'N/A',
13 variant_id: item.product?.variant_id || 'N/A',
14 files: Array.isArray(item.files)
15 ? item.files.map(f => f.type).join(', ')
16 : 'None'
17}));

Pro tip: Printful's order detail response includes a costs object with breakdown of fulfillment cost, shipping cost, and tax for your internal records — distinct from the retail_costs (what the customer paid). Display both if you're building a profitability dashboard alongside the order tracker.

Expected result: Clicking an order row loads the full item detail in the secondary table, showing product names, quantities, and print file types. The tracking number and tracking URL link are visible in the shipping section. The Cancel Order button appears only for cancelable orders.

4

Build a shipping rate estimation query

Create a shipping cost estimation tool so customer service staff can quickly answer shipping questions. This requires a POST request to Printful's shipping rates endpoint. Add form components to your app: a TextInput for recipient country code (e.g., 'US'), a TextInput for postal code, a Select for state/region (for US orders), and a product variant selector populated from your sync products. Create a query named estimateShipping. Set Method to POST. Path = /shipping/rates. Set Body type to JSON. The request body must include a recipient address object and items array: The items array needs the sync_variant_id for each product and the quantity. Populate the product selector from a getProducts query (GET, /sync/products) that runs on page load. After running estimateShipping, the response includes a result array of shipping options. Each option has a name (carrier/service), rate (cost in USD), minDeliveryDays, and maxDeliveryDays. Bind these to a Table component showing all available options sorted by rate. Add a 'Copy Rate' button column that copies the selected rate to the clipboard — useful for customer service staff quoting shipping costs over email or chat.

shipping_rates_body.json
1{
2 "recipient": {
3 "country_code": "{{ textInput_country.value }}",
4 "state_code": "{{ textInput_state.value || '' }}",
5 "zip": "{{ textInput_zip.value }}",
6 "city": "{{ textInput_city.value || '' }}"
7 },
8 "items": [
9 {
10 "quantity": {{ numberInput_qty.value || 1 }},
11 "variant_id": {{ select_variant.value }}
12 }
13 ],
14 "currency": "USD",
15 "locale": "en_US"
16}

Pro tip: Printful's shipping rate API requires a valid combination of country, state (for US), and postal code. If you get a 'recipient address is invalid' error, verify the country_code is the 2-letter ISO code (US, GB, DE) and that US state codes use the 2-letter abbreviation (CA, NY, TX) rather than the full state name.

Expected result: Filling in the destination address and selecting a product variant, then clicking 'Get Shipping Rates' populates a table showing all available carrier options with their costs and delivery time ranges.

5

Monitor synced products and catalog health

Build a product catalog monitoring panel that shows all synced products across your connected stores and flags any with configuration issues — missing print files, unlinked variants, or pricing gaps. Create a query named getSyncProducts (GET, /sync/products) with URL parameter limit = 100. This returns all synchronized products from your connected storefronts. Create a follow-up query named getSyncProductDetail (GET, /sync/products/{{ table_products.selectedRow.id }}) that loads full variant details when a product row is clicked. Create a JavaScript transformer that analyzes each product's sync health: Bind the health analysis to the products table with color-coded indicators: green checkmark for healthy products, yellow warning for incomplete configurations, red alert for broken sync. Add a summary banner showing total products, healthy count, and products needing attention. Use a Retool Stats component or custom container to display these at the top of the catalog panel. For products needing attention, add an action button that links directly to Printful's product editor using the external_id: {{ 'https://www.printful.com/dashboard/products/' + table_products.selectedRow.id }}. This gives operations staff a one-click path to fix configuration issues without manually searching in Printful's dashboard.

catalog_health.js
1// JavaScript transformer — catalog health analysis
2const products = data.result || [];
3return products.map(product => {
4 const variants = product.sync_variants || [];
5 const unlinkedVariants = variants.filter(v => !v.synced).length;
6 const missingFiles = variants.filter(v =>
7 !v.files || v.files.length === 0
8 ).length;
9
10 let health = 'Healthy';
11 let health_code = 'good';
12 if (unlinkedVariants > 0 || missingFiles > 0) {
13 health = `${unlinkedVariants} unlinked, ${missingFiles} missing files`;
14 health_code = 'warning';
15 }
16 if (variants.length === 0) {
17 health = 'No variants';
18 health_code = 'error';
19 }
20
21 return {
22 id: product.id,
23 external_id: product.external_id,
24 name: product.name || 'Unnamed',
25 store_id: product.store_id,
26 variant_count: variants.length,
27 synced_variants: variants.filter(v => v.synced).length,
28 health,
29 health_code,
30 thumbnail_url: product.thumbnail_url || ''
31 };
32});

Pro tip: Printful's sync product API paginates at 100 products per page. If your store has more than 100 synced products, implement pagination using the offset parameter and a 'Load More' button, or build a Retool Workflow that fetches all pages and caches results in a Retool Database table for fast dashboard loading.

Expected result: The products table shows all synced products with a health status indicator per row. Products with unlinked variants or missing files are highlighted. Clicking a product row loads full variant details including file types and pricing. The summary banner shows the total catalog health at a glance.

Common use cases

Build a production status tracking dashboard

Create a Retool app that shows all Printful orders with their current production status, creation date, estimated fulfillment date, and tracking information. Add color-coded status indicators (pending=gray, confirmed=blue, fulfilled=green, canceled=red) and filter controls for status, store, and date range.

Retool Prompt

Build a POD order tracker that queries /orders from Printful with status and date filters, shows order_id, status, recipient name, and items_count in a color-coded Table, and triggers a detail panel when a row is selected showing item names, quantities, and current tracking number.

Copy this prompt to try it in Retool

Shipping cost estimator panel

Build a shipping rate estimation tool where operations staff enter a destination country and postal code, select products, and see all available shipping options with costs and estimated delivery times. This helps customer service staff answer shipping questions and helps operations managers choose preferred carriers.

Retool Prompt

Create a shipping estimator panel with country/zip inputs and a product selector, that POSTs to Printful's /shipping/rates endpoint with the recipient address and items array, then displays the returned shipping options in a Table sorted by cost with carrier name, rate, and min/max delivery days.

Copy this prompt to try it in Retool

Product sync and catalog management panel

Build a product management dashboard that shows all synchronized products from your connected storefronts, their Printful variants, print areas, and pricing. Include a sync status indicator showing which products are properly configured and which have missing variant mappings that need attention.

Retool Prompt

Build a product sync panel that queries /sync/products to show all synced products with their store origin, variant count, and sync status, with a drilldown into /sync/products/{id} showing individual variant details including print files, retail price, and Printful production cost.

Copy this prompt to try it in Retool

Troubleshooting

All API requests return 401 Unauthorized

Cause: The Bearer token is invalid, expired, or the resource is configured with the wrong authentication method. Printful tokens are store-specific or account-level — using a store token to query another store's data will fail.

Solution: Verify your API token is valid by navigating to Printful Dashboard → Settings → API and checking if the token exists. If you need cross-store access, generate an account-level token rather than a store-specific one. In your Retool resource, confirm the Authentication type is set to Bearer Token (not Basic Auth or API Key header).

Order dates display as large numbers instead of readable dates

Cause: Printful uses Unix timestamps (seconds since epoch) for date fields like 'created' and 'updated'. Without conversion, these appear as numbers like 1710000000 in Retool Tables.

Solution: In your JavaScript transformer, convert Printful timestamps using new Date(timestamp * 1000).toLocaleDateString(). The multiplication by 1000 converts from seconds (Printful's format) to milliseconds (JavaScript's Date constructor expectation).

typescript
1// Convert Printful Unix timestamp to readable date
2// In your transformer:
3created: new Date(order.created * 1000).toLocaleDateString('en-US', {
4 year: 'numeric',
5 month: 'short',
6 day: 'numeric'
7})

Shipping rate estimation returns 'recipient address is invalid' error

Cause: The country_code, state_code, or zip format doesn't match Printful's expected values. Printful requires ISO 2-letter country codes and 2-letter US state codes.

Solution: Verify the country_code is a 2-letter ISO 3166-1 alpha-2 code (US, GB, DE, CA, AU). For US destinations, ensure state_code is the 2-letter postal abbreviation (CA, NY, TX) not the full state name. Zip codes must be valid for the given country and state combination.

Sync products query returns an empty result array despite products existing in Printful

Cause: The account-level API token may not have access to the specific store's products, or the store_id filter is set incorrectly. Alternatively, the store may not have completed the sync process.

Solution: First, query GET /stores to confirm which store IDs are accessible with your API token. Then add a store_id URL parameter to the /sync/products query matching one of the returned store IDs. If using a store-specific token, it can only access products from its own store.

Best practices

  • Store your Printful API token as a Secret configuration variable in Retool Settings → Configuration Variables — never paste it directly into the Bearer Token field as a plain string.
  • Use an account-level API token rather than a store-specific token if you manage multiple Printful stores, so a single Retool resource can query all stores using the store_id parameter.
  • Always convert Printful's Unix timestamps (seconds) to JavaScript Date objects using new Date(timestamp * 1000) in transformers — Printful does not use ISO 8601 format.
  • Add production status color coding to your orders table using Retool's column formatting rules — green for fulfilled, yellow for in-process, red for failed or on-hold orders.
  • Paginate your order and product queries using Printful's limit and offset parameters — large accounts with thousands of orders will time out without pagination.
  • Combine Printful order data with your storefront (Shopify, WooCommerce, Etsy) data in the same Retool app to create a complete order-to-delivery tracking panel without switching platforms.
  • Add a 'View in Printful' link column to your orders table using the Printful dashboard URL pattern so operations staff can jump directly to a specific order for complex issues.
  • Use Retool Workflows with a scheduled trigger to check Printful for new failed or on-hold orders and send Slack notifications to your operations team for immediate attention.

Alternatives

Frequently asked questions

Does Retool have a native connector for Printful?

No, Printful does not have a native connector in Retool. You connect via a REST API Resource with Bearer token authentication. All of Printful's core operations — orders, products, shipping rates, and stores — are accessible through their REST API, so a REST API Resource gives you full access to the data you need for operational dashboards.

Can I create Printful orders from Retool?

Yes, Printful's API supports creating orders via POST to /orders. You need to provide the recipient's address, items with variant IDs and quantities, and shipping method. Creating orders via Retool is useful for manual order processing, wholesale orders, or sample requests that don't go through your connected storefront. Use Retool's Form components to collect the order details before submitting.

How do I track which Printful orders came from which storefront?

Printful includes a store_id field on every order identifying which connected store it came from. Use the GET /stores endpoint to build a map of store IDs to store names, then join this with your orders data in a JavaScript transformer to display the store name (Shopify Store, Etsy Shop, etc.) alongside each order. Filter the orders table using a store selector dropdown populated from the stores list.

Can Retool receive webhooks from Printful when order status changes?

Yes, Printful supports webhooks for order status events including order creation, order status updates, and shipment tracking updates. Create a Retool Workflow with a webhook trigger to get a unique URL, then configure Printful's webhook settings (Dashboard → Settings → Webhooks) to send events to that URL. The workflow can update a Retool Database with current order status, send Slack alerts for failed orders, or trigger other automated actions.

What's the difference between Printful's order costs and retail costs in the API?

Printful's API returns two cost objects: 'costs' represents what Printful charges you for production and shipping (your fulfillment cost), and 'retail_costs' represents what your customer paid on your storefront. The difference between these is your profit margin per order. Build a profitability column in your Retool dashboard by subtracting costs.total from retail_costs.total for each order.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Integrations are where projects stall

We wire Retool integrations like this one every week — auth, webhooks, edge cases included. Fixed-price builds from $13K, delivered in 6–10 weeks.

Talk to an integration engineer

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.