Skip to main content
RapidDev - Software Development Agency
flutterflow-integrationsFlutterFlow API Call

Printful

Connect FlutterFlow to Printful using a FlutterFlow API Group with Bearer token authentication. Use GET calls for order production status and product catalog reads client-side, but proxy all order-creation and write calls through a Firebase Cloud Function — Printful's Bearer token can authorize real billable charges and must never be embedded in the compiled Flutter app.

What you'll learn

  • How to generate a Printful API token scoped to a specific store
  • How to configure a FlutterFlow API Group with Printful's Bearer auth and multi-store X-PF-Store-Id header
  • How to fetch order production and shipping status and display it in a ListView
  • How to implement the async mockup-generator task and poll for the result image URL
  • How to route order creation through a Firebase Cloud Function to keep the billing token off the device
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate14 min read40 minutesE-commerceLast updated July 2026RapidDev Engineering Team
TL;DR

Connect FlutterFlow to Printful using a FlutterFlow API Group with Bearer token authentication. Use GET calls for order production status and product catalog reads client-side, but proxy all order-creation and write calls through a Firebase Cloud Function — Printful's Bearer token can authorize real billable charges and must never be embedded in the compiled Flutter app.

Quick facts about this guide
FactValue
ToolPrintful
CategoryE-commerce
MethodFlutterFlow API Call
DifficultyIntermediate
Time required40 minutes
Last updatedJuly 2026

Build a Printful Order-Tracking and Mockup App in FlutterFlow

Printful is the most popular print-on-demand fulfillment backend for independent creators. It handles printing, packing, and shipping of custom products (T-shirts, mugs, phone cases, and more) only when an order comes in — no inventory required. The FlutterFlow use-case is typically an ops app: a founder wants to see where each order is in the production pipeline, check shipping tracking numbers, and generate product mockup images without leaving their phone.

Printful's REST API is straightforward — Bearer token auth, clean JSON responses, and endpoints for orders, products, sync variants, and the asynchronous mockup generator. The important detail for FlutterFlow is that a Printful Bearer token has full account access: it can create orders, which means real charges hit your credit card. That single fact determines the architecture. Read-only status calls (GET /orders, GET /orders/{id}) are safe to make from the Flutter client, but POST /orders must run through a server-side proxy. The Printful API currently caps traffic at around 120 requests per minute per token — verify the current limit in Printful's developer docs, as this may change.

The mockup generator is the most distinctive Printful feature you can surface in a FlutterFlow app. It is asynchronous: you POST a task, get back a task_key, and then poll GET /mockup-generator/task?task_key= until the status changes from waiting to completed, at which point the response contains your image URL. This two-call pattern requires a polling action loop in FlutterFlow's Action Flow Editor, which this guide walks through in detail.

Integration method

FlutterFlow API Call

FlutterFlow connects to Printful's REST API (base URL https://api.printful.com) using an API Group with a Bearer token in the Authorization header. Read-only calls for order status, shipping tracking, and product catalog browsing run from the Flutter client over HTTPS. Order creation — which triggers real fulfillment and billing — must be proxied through a Firebase Cloud Function that holds the Bearer token in environment variables, so the secret key never ships inside the compiled app.

Prerequisites

  • A Printful account with at least one store connected
  • A FlutterFlow project (any plan supports API Calls)
  • A Firebase project for the Cloud Function proxy (required for order creation)
  • Access to the Printful Dashboard at printful.com/dashboard
  • The store ID for your Printful store (found in the store URL or Settings)

Step-by-step guide

1

Generate a Printful API token

Log in to your Printful account and click your account name or avatar in the top-right corner of the dashboard. From the dropdown, select Settings, then click the Stores tab. Find the store you want to connect to FlutterFlow in the list and click the API link or the Manage button next to it. Scroll to the API section and click Generate Token (the button label may vary slightly between Printful dashboard versions). Printful will display your new Bearer token — copy it immediately and store it in a secure location like a password manager. Tokens are store-scoped, meaning each token is tied to a specific store. If you run multiple stores and need to access them all from your app, you will either need to generate a token per store or use Printful's multi-store header (X-PF-Store-Id) with a single account-level token. Note your store ID from the dashboard URL or the store settings page — you will need it for the X-PF-Store-Id header. Printful tokens do not expire but can be revoked at any time from the same settings page; treat them like a password.

Pro tip: If you have more than one Printful store, add the X-PF-Store-Id header to your API Group and supply the correct numeric store ID. Omitting this header on a multi-store account causes Printful to return data for the wrong store or return a 400 error.

Expected result: You have a Printful Bearer token saved securely and you know your numeric Printful store ID.

2

Create a Printful API Group in FlutterFlow

In your FlutterFlow project, click API Calls in the left navigation panel. Click + Add → Create API Group. Name the group Printful and set the Base URL to https://api.printful.com. Click the Headers tab and add the following headers. First, add Authorization with the value Bearer [your_token]. Because this is a secret key, do not paste the token as a literal string: click the variable icon next to the value field, create an App State variable named printfulToken (type String, initial value empty), and reference it here as FFAppState().printfulToken. You will set the token value at login or app start through a secure initialization action. Second, add Content-Type with the value application/json. If you are working with a multi-store account, add a third header X-PF-Store-Id and set its value to your numeric store ID (this can be a hardcoded string since it is not a secret). Click Save. The Printful API Group is now ready for individual endpoint calls.

api_group_config.json
1// Printful API Group configuration (reference)
2{
3 "group_name": "Printful",
4 "base_url": "https://api.printful.com",
5 "headers": [
6 {
7 "key": "Authorization",
8 "value": "Bearer [FFAppState().printfulToken]"
9 },
10 {
11 "key": "Content-Type",
12 "value": "application/json"
13 },
14 {
15 "key": "X-PF-Store-Id",
16 "value": "[your_store_id]"
17 }
18 ]
19}

Pro tip: Printful wraps all API responses in a result property. When mapping JSON paths, use $.result[*].id rather than $[*].id for list endpoints like /orders.

Expected result: The Printful API Group appears in the API Calls panel with the base URL, Bearer auth header, and Content-Type header configured.

3

Add order status and product GET calls and bind to a ListView

With the Printful API Group selected, click + Add API Call. Name the first call GetOrders and set the Method to GET. In the URL Path field, enter /orders. Click the Variables tab and add two optional variables: offset (integer, default 0) and limit (integer, default 20). Update the URL Path to /orders?offset={{offset}}&limit={{limit}}. Click the Response & Test tab, then click Test. Printful wraps responses in a result object, so your raw JSON will look like { "code": 200, "result": [...] }. Click Generate JSON Paths and look for paths like $.result[*].id, $.result[*].status, $.result[*].recipient.name, and $.result[*].shipping. Name these orderId, orderStatus, recipientName, and shippingCarrier. Create a second API Call named GetOrderDetail with URL Path /orders/{{orderId}}, adding orderId as a required variable. Create a third call named GetStoreProducts at /store/products with offset and limit variables, mapping $.result[*].id, $.result[*].name, $.result[*].thumbnail_url, and $.result[*].synced. In your FlutterFlow canvas, add a ListView and configure its Backend Query to use GetOrders. Add a ListTile widget inside the ListView, bind the title to recipientName and the subtitle to orderStatus. Add a color-coded Container behind the status badge: map 'fulfilled' to green, 'in_process' to amber, and 'canceled' to red using a conditional expression in the widget's background color property.

json_paths.txt
1// Printful JSON path mapping for /orders
2// All paths start with $.result because Printful wraps responses
3
4$.result[*].id orderId
5$.result[*].status orderStatus
6$.result[*].recipient.name recipientName
7$.result[*].recipient.email recipientEmail
8$.result[*].shipping shippingMethod
9$.result[*].created createdTimestamp
10$.result[*].shipments[0].tracking_url trackingUrl
11
12// /store/products paths
13$.result[*].id storeProductId
14$.result[*].name productName
15$.result[*].thumbnail_url thumbnailUrl
16$.result[*].synced isSynced

Pro tip: Printful order statuses follow a predictable progression: draft → pending → in_process → fulfilled. Map each status to a color and icon in your ListView for a clear visual pipeline.

Expected result: A ListView in your FlutterFlow app shows Printful orders with recipient names, production status badges, and shipping information pulled live from the API.

4

Proxy order creation through a Firebase Cloud Function

Creating a Printful order (POST /orders) triggers real fulfillment and billing. This call must never come from the Flutter client because the Bearer token would be embedded in the compiled app, giving anyone with a decompiler the ability to create unlimited billable orders on your account. Deploy a Firebase Cloud Function named createPrintfulOrder. The function authenticates the caller using Firebase Auth (reject unauthenticated requests with an HttpsError), reads the Printful Bearer token from environment variables, and POSTs the order payload to https://api.printful.com/orders. It returns the Printful order response JSON to FlutterFlow. In FlutterFlow, create a separate API Group named PrintfulProxy that points at your Cloud Function's HTTPS trigger URL. Add a Firebase Auth ID token header so only logged-in app users can call it. In the Action Flow Editor on your checkout screen, wire the Place Order button to call the PrintfulProxy API Call with the order details serialized as JSON. If the response contains a result.id, navigate to a confirmation screen showing the new Printful order ID.

index.js
1// Firebase Cloud Function: createPrintfulOrder/index.js
2const functions = require('firebase-functions');
3const fetch = require('node-fetch');
4
5exports.createPrintfulOrder = functions.https.onCall(async (data, context) => {
6 if (!context.auth) {
7 throw new functions.https.HttpsError('unauthenticated', 'Login required');
8 }
9
10 const token = process.env.PRINTFUL_TOKEN;
11 const storeId = process.env.PRINTFUL_STORE_ID;
12
13 const response = await fetch('https://api.printful.com/orders', {
14 method: 'POST',
15 headers: {
16 'Authorization': `Bearer ${token}`,
17 'Content-Type': 'application/json',
18 'X-PF-Store-Id': storeId,
19 },
20 body: JSON.stringify(data.order), // order payload from FlutterFlow
21 });
22
23 if (!response.ok) {
24 const error = await response.json();
25 throw new functions.https.HttpsError('internal', error.result || 'Printful error');
26 }
27
28 return await response.json();
29});

Pro tip: Set PRINTFUL_TOKEN and PRINTFUL_STORE_ID using Firebase environment config before deploying. Test with a Printful sandbox or a draft order (confirm=false in the body) before enabling live order creation.

Expected result: The Cloud Function deploys and is callable from FlutterFlow. Test orders are created in Printful (visible in the dashboard) without the Bearer token appearing anywhere in the Flutter app source.

5

Implement the async mockup generator with polling

The Printful mockup generator is one of the most useful features to surface in a FlutterFlow app. It is a two-step async process: first you submit a task, then you poll until it is complete. In your Printful API Group, create an API Call named SubmitMockupTask with Method POST and URL Path /mockup-generator/create-task/{{productId}}. Add productId as a required variable. The request body should contain a variant_ids array and a files array with your design image URL — see Printful's mockup generator docs for the exact body structure. Map the response path $.result.task_key to taskKey. Create a second API Call named PollMockupTask with Method GET and URL Path /mockup-generator/task?task_key={{taskKey}}, mapping $.result.status to taskStatus and $.result.mockups[0].mockup_url to mockupUrl. In your FlutterFlow Action Flow Editor, wire a Generate Mockup button to first call SubmitMockupTask and store the task_key in a page variable. Then add a Wait action (1–2 seconds) followed by a call to PollMockupTask. Use a Conditional Action to check if taskStatus equals 'completed': if yes, store mockupUrl in an App State variable and display the image; if no, loop back to the Wait + Poll sequence. Add a maximum iteration counter (e.g., 10 tries) to avoid an infinite loop if Printful is slow.

mockup_task.json
1// POST /mockup-generator/create-task/{productId} body example
2// Send this as the API Call body in FlutterFlow
3{
4 "variant_ids": [4012, 4013],
5 "files": [
6 {
7 "placement": "front",
8 "image_url": "https://yourcdn.com/design.png",
9 "position": {
10 "area_width": 1800,
11 "area_height": 2400,
12 "width": 1800,
13 "height": 1800,
14 "top": 300,
15 "left": 0
16 }
17 }
18 ],
19 "format": "jpg"
20}
21
22// Polling response when complete
23// $.result.status = "completed"
24// $.result.mockups[0].mockup_url = "https://mockup-generator.printful.com/..."

Pro tip: Respect Printful's rate limit (approximately 120 requests per minute — verify current limits in Printful's developer docs) when polling. Wait at least 2 seconds between poll calls and show a spinner with status text ('Generating mockup... attempt 3 of 10') so users know the app is working.

Expected result: The app submits a mockup task, polls until complete, and displays the rendered product image URL. The Image widget in FlutterFlow shows the mockup photo as soon as the task_key resolves to a completed status.

Common use cases

POD order tracking dashboard

Build a FlutterFlow app that shows all Printful orders with their production status (pending, in_process, fulfilled, canceled) and the carrier tracking URL. The app pulls from GET /orders filtered by status, displays a status badge with color coding, and opens the tracking URL in an in-app browser when the user taps Track Shipment.

FlutterFlow Prompt

Show me a list of my Printful orders with order ID, product name, current status (pending, in production, shipped), and a Track button that opens the shipping tracking link.

Copy this prompt to try it in FlutterFlow

Product mockup preview generator

Create a FlutterFlow screen where a seller selects a Printful product variant and uploads a design image. The app submits a mockup-generator task to a Firebase Cloud Function, then polls for completion and displays the rendered mockup image. This lets sellers preview new designs before listing them on their storefront.

FlutterFlow Prompt

Let me pick a Printful product and see a photo-realistic mockup with my design applied to it. Show a loading spinner while the mockup is being generated and display the final image when ready.

Copy this prompt to try it in FlutterFlow

Store catalog sync viewer

Build a FlutterFlow app that shows all products synced between a WooCommerce or Shopify store and Printful, including sync status (synced, unsynced, incomplete). Use GET /store/products to list the catalog and GET /store/products/{id} for variant details. Staff can flag items that need attention directly from the app.

FlutterFlow Prompt

Show all my synced Printful products with their sync status, thumbnail image, and number of variants. Let me filter by sync status and tap a product to see the individual variant details.

Copy this prompt to try it in FlutterFlow

Troubleshooting

401 Unauthorized on all Printful API calls

Cause: The Bearer token is incorrect, was revoked in the Printful dashboard, or the App State variable holding it was not initialized before the API call fired.

Solution: Verify the token in the Printful Dashboard → Settings → Stores → API. Confirm the printfulToken App State variable is set at app startup (e.g., in an initial Action on the app's entry page) before any API call fires. Regenerate the token if you suspect it was revoked.

400 Bad Request on all API calls, or data returned is from the wrong store

Cause: You have multiple Printful stores but the X-PF-Store-Id header is missing or contains the wrong store ID.

Solution: Find your numeric store ID in the Printful Dashboard URL (it appears as a number in the URL when you navigate to a specific store) or in Settings → Stores. Add or correct the X-PF-Store-Id header in your FlutterFlow API Group. Each store has a different ID.

429 Too Many Requests when polling the mockup generator rapidly

Cause: The mockup generator polling loop is firing too frequently, exceeding Printful's rate limit of approximately 120 requests per minute per token.

Solution: Add a Wait action of at least 2 seconds between each poll attempt in the Action Flow Editor. Implement a maximum retry counter (10 attempts) and show an error message if the mockup does not complete within that time, prompting the user to try again.

Mockup generator POST returns a task_key but polling always returns status 'waiting' and never 'completed'

Cause: The task_key variable was not correctly passed from the SubmitMockupTask response to the PollMockupTask request, or the polling API Call variable is not mapped to the correct page variable.

Solution: In the Action Flow Editor, after the SubmitMockupTask call, add an Update Page Variable action that sets taskKey to the value returned from the taskKey JSON path. Confirm the PollMockupTask API Call uses this page variable as its taskKey input. Test by checking the raw API response in FlutterFlow's API Call tester to confirm the task_key is in $.result.task_key.

Best practices

  • Never put the Printful Bearer token in a FlutterFlow API Call header as a hardcoded literal — store it in App State and initialize it securely at app startup, and keep Write-capable tokens exclusively in Firebase Cloud Function environment variables.
  • Proxy all POST /orders calls through a Firebase Cloud Function; a leaked token can drain your Printful balance with unauthorized orders.
  • Add the X-PF-Store-Id header to your API Group from the start, even if you only have one store now — it prevents silent data mix-ups if you add a second store later.
  • Respect Printful's rate limits when implementing mockup-generator polling — wait at least 2 seconds between poll calls and cap retries at 10 to avoid hammering the API.
  • Use Printful's draft order mode (add confirm: false to POST /orders) for testing, so orders are created in Printful but not sent to fulfillment until you explicitly confirm them.
  • Cache product catalog data in Firestore or local App State rather than re-fetching the full catalog on every screen load — product data changes infrequently and caching reduces API calls significantly.
  • Show clear loading states during mockup generation — the async two-step process can take 10–30 seconds, and users will assume the app is broken without a visible progress indicator.
  • Test on a real device or simulator for your final QA pass; FlutterFlow's web Run Mode is fine for API call testing but may behave differently for action loops and wait timers.

Alternatives

Frequently asked questions

Can I use Printful's API without a paid Printful plan?

Yes. Printful's API is free to use — you pay only when an order is fulfilled (print + shipping cost). There are no monthly API fees or subscription tiers for API access. The API token is generated from any Printful account, including the free tier.

Why do I need a Firebase Cloud Function just to create an order?

Because Printful's Bearer token authorizes real monetary charges. If you put the token in your Flutter app, anyone who decompiles the APK or IPA can extract it and place unlimited orders that bill to your payment method. The Cloud Function is a server that holds the token in environment variables (never in code) and only acts on authenticated requests from your app.

How long does the mockup generator take to return a result?

Typically between 5 and 30 seconds depending on server load and product complexity. Always implement a polling loop with a 2-second wait between calls and a maximum retry limit. Show a spinner and progress message so users know the app is working — the async latency is normal behavior, not an error.

Can my FlutterFlow app receive Printful webhooks for real-time order updates?

Not directly — FlutterFlow apps do not have a public inbound URL for webhooks. Configure Printful webhooks to send events to a Firebase Cloud Function, which writes the event to a Firestore collection. Your FlutterFlow app listens to that Firestore collection in real time using FlutterFlow's native Firebase integration and updates the UI when a new event document appears.

What is the X-PF-Store-Id header and do I always need it?

X-PF-Store-Id is required when your Printful account has more than one store connected. Without it, Printful may return data from the wrong store or return a 400 error. Even if you only have one store today, add the header to your API Group from the start so you do not need to refactor later if you expand.

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 FlutterFlow 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.