API Documentation v2 | Printful (2.0.0-beta)

Download OpenAPI specification:Download

About the Printful API

Welcome to API v2 BETA

  • We’re excited to inform you that the new major version of our API just went live, and we want to invite you to participate in the Open Beta test. Please keep in mind that this release is still in BETA, although all presented endpoints can be used in a production environment. Since this is a BETA release, we are keen on adopting any changes to our API (which we encourage you to pass via this feedback form). We do not expect to introduce any breaking changes to the current form of endpoints, although the final form of each endpoint might slightly vary from the current version.

  • How to use new endpoints? Create or use an already created private token for authorization. Unless it's stated otherwise, the v2 version of Printful API may be used like the v1 version. All v2 endpoints use /v2 prefix and the specifics of each endpoint are explained in a dedicated section.

  • Test and provide feedback: Explore the new features, experiment with the enhancements, and share your feedback through our dedicated feedback form.

What is new in the V2s

  • The flexibility of order creation with itemized order building (read more).
  • Simplifying embroidery orders: auto thread color detection as default, simplified thread colors definition on the layer level.
  • New, powerful design creation with multiple design layers support and positioning for order items and sync variants (read more).
  • New, more secure Webhooks by enforcing HTTPS, added expiration date, and request signing.
  • More flexibility in webhook per event configuration.
  • New webhook events – a new event for catalog price change, and the stock update event is now real-time with a refresh rate every 5 minutes (previously every 24h).
  • More information in the Catalog about the products (images, discounted pricing, placement information).
  • More flexibility in the catalog (extensive filtering and sorting options, DSR support, pagination).
  • More information on the order shipment level – more precise EDT, departure country, and shipment tracking events.
  • Standardization of returned time in API – standardized format according to ISO 8601, UTC time zone.
  • Standardization of returned price formats in API. Prices are displayed as a string with up to 2 decimal points.
  • Uniform pagination parameters across all endpoints.
  • Performance improvements for all endpoints.

Migration Guide

How to switch from V1 to V2 endpoints

  • Update the Base URL: Ensure your requests use the updated V2 base path. For V2, endpoints include the prefix /v2 ( e.g., https://api.printful.com/v2/orders).
  • Authentication: Both V1 and V2 use private tokens for authorization. Confirm your token is still valid and configured for your store. No major changes are required here.
  • Leverage New Features: V2 introduces several enhancements, including:
    • Improved order creation flexibility, allowing itemized order building.
    • Simplified embroidery orders with features like auto thread color detection.
    • New webhooks for real-time updates on events like stock changes.
    • Standardized returned time (ISO 8601) and price formats.
  • Handle Pagination and Rate Limiting: V2 implements uniform pagination parameters and adopts a leaky bucket algorithm for rate limiting. The X-Ratelimit-* headers indicate usage and reset times. Adjust your application to handle these changes effectively.
  • Test the Endpoints: Create a separate store to test scenarios in production cautiously. Provide feedback on any anomalies using Printful’s feedback form linked in their documentation.
  • Explore Documentation for Changes: Thoroughly review the updated API reference to understand the specifics of V2 endpoints, parameters, and expected responses. Adjust your code for endpoints where behavior or parameters have changed compared to V1.

Errors

The errors in the API are formatted following the RFC 9457: Problem Details for HTTP APIs. The content type of error responses is application/problem+json and the response is a JSON object with the members:

type string A URL that identifies the type of error. The URL can be followed to get more information about the error in our documentation.
status integer The status code of the response that returned the error.
title string A short human-readable summary of the problem.
detail string A human-readable explanation of the problem.
instance string A unique identifier of a specific instance of the error. You can send it when you contact our support team so that it's easier for us to find the logs for your specific request.

This member may not be present for all error types.

Some error types may include some other additional information. For example, validation errors will contain the problem that was detected and a pointer to the invalid data.

An example of a response would be:

{
    "type": "https://developers.printful.com/docs/v2-beta/#errors/not-found",
    "status" : 404,
    "title" : "Not Found",
    "detail" : "The resource that you tried to access does not exist."
}

General Errors

Internal Server Error

This error is returned when the server encounters an unexpected problem to complete the requested operation. Since this is usually an error on our end, resending the request will probably result in getting the error again.

You don't need to do any action to solve this since we are notified when this error happens. However, if you want, you can contact us through our support channels. If you decide to contact us, providing the returned instance will help us to identify the problem.

Validation Errors

This error is returned when the server encounters an unexpected or incorrect value provided by the user. Usually the request can be corrected by providing the correct values specified in valid_values property on an error.

Retired Resources

Sync endpoints and Product templates endpoints

Product management, with sync products or product templates, is not available in version 2 of the API yet.

FAQ

How can I access the new API?

To access the new API (V2), update your endpoint URLs to include the /v2 prefix ( e.g., https://api.printful.com/v2/orders). You’ll also need a valid private token for authorization. The V2 API supports the same authentication method as V1, so you can continue using your existing token unless it has expired. Ensure that your applications are updated to use the V2 endpoints, as these include several new features and enhancements.

What happens if I don't migrate?

While the V1 API will continue to function for now, it is essential to migrate to V2 to take advantage of new features and optimizations. V2 includes enhancements like real-time webhook updates, better performance, standardized formats, and improved functionalities. Staying on V1 means missing out on these improvements and could lead to challenges as support for V1 may be phased out in the future. It’s strongly recommended to migrate to ensure compatibility and optimal performance.

How can I get help with my migration?

For migration assistance, you can:

  • Refer to the V2 API documentation, which provides detailed information about endpoints, parameters, and response formats.
  • Contact Printful Developer Support at devsupport@printful.com for specific questions or troubleshooting help.

Are there any changes to API Rate Limits?

Yes, there are changes to the rate-limiting mechanism in V2. Unlike the simple limit-reset system in V1, V2 implements a leaky bucket algorithm:

  • The headers X-Ratelimit-Limit, X-Ratelimit-Remaining, X-Ratelimit-Reset, and X-Ratelimit-Policy provide detailed rate-limit information.
  • V2 allows smoother traffic bursts by gradually refilling the bucket over time, improving performance and reducing the impact of hitting the limit.
  • Default limits remain similar (120 requests per minute), but the reset mechanism is now more dynamic, reflecting the real-time refill process.
  • These changes aim to provide more predictable behavior and better utilization of API resources. Adjust your application to handle the revised rate-limiting system effectively.

Use Cases

Order Management

This section outlines practical use cases to help you estimate, create, update, and track orders effectively. Whether you're calculating shipment costs, determining potential custom fees, or leveraging webhooks for real-time updates, these use cases are designed to streamline your order workflows.

Key topics include:

  • Estimating Shipments: Learn how to estimate shipment costs, types, and determine whether custom fees will apply.
  • Order Estimation: Understand how to calculate the costs and details of an order before placing it.
  • Creating Orders from Catalog Source: Discover how to create new orders using items directly from the catalog.
  • Order Modifications: Includes deleting individual order items and updating existing orders.
  • Order Confirmation: How to confirm yout orders and initiate fulfillment.
  • Order Updates and Tracking: Access tools for receiving updates via webhook events, retrieving detailed order information through the API, and tracking shipments with precise shipping details.

These use cases are tailored to provide actionable insights for efficiently managing your Printful orders, ensuring a smooth integration experience.

Estimating orders

The cost of the order can be estimated before even placing the order by using the order estimation endpoint. The estimation is an asynchronous process so the response won’t contain the estimation data right away, but instead the task ID will be returned.

{
  "data": {
    "id": "fc959efb-b3a0-4c12-9cc6-f54d3158291d",
    "status": "pending",
    "costs": null,
    "retail_costs": null,
    "failure_reasons": []
  }
}

The task ID fc959efb-b3a0-4c12-9cc6-f54d3158291d can be then used to retrieve the result of the estimation with https://api.printful.com/v2/order-estimation-tasks?id=fc959efb-b3a0-4c12-9cc6-f54d3158291d.

The estimation task has 3 different statuses:

  • pending
  • failed
  • completed

If the estimation fails the task status will be set to the failed and the reason will be included in the failure_reasons

Estimating Shipments

Shipping rates can be estimated by using the Estimating orders endpoint as it also returns the shipping cost.

{
  "data": {
    "id": "fc959efb-b3a0-4c12-9cc6-f54d3158291d",
    "status": "completed",
    "costs": {
      ...
      "shipping": "4.79",
      ...
    }
  }
}

That shipping cost however is always calculated for the standard shipping method.

How to estimate the shipment cost and type

To display the different shipping methods the shipping rates endpoint needs to be used. Three main things are required to correctly calculate the shipping costs:

  • Recipient data
  • Product variant + quantity
  • Currency

The response will contain all the available shipment methods:

{
  "data": [
    {
      "shipping": "STANDARD",
      "shipping_method_name": "Flat Rate (Estimated delivery: May 19–24) ",
      "rate": "13.60",
      "currency": "EUR",
      "min_delivery_days": 4,
      "max_delivery_days": 7,
      "min_delivery_date": "2022-10-17",
      "max_delivery_date": "2022-10-20",
      "shipments": [
        {
          "departure_country": "US",
          "shipment_items": [
            {
              "catalog_variant_id": 4011,
              "quantity": 3
            }
          ],
          "customs_fees_possible": true
        }
      ]
    }
  ]
}

How to determine if the custom fees will be applied

Depending on where the shipment is shipped from and where it will be shipped the additional taxes and duties might apply. To check if the custom fees might apply the customs_fees_possible parameter from the shipping rates endpoint can be used to determine that.

{
  "data": [
    {
      ...
      "shipments": [
        {
          ...
          "customs_fees_possible": true
        }
      ]
    }
  ]
}

Creating order from catalog source

To create the order the recipient address and the catalog product with the designs needs to be specified. Order will be created with the draft status and the pending costs calculations.

Orders with the draft status won’t be charged, and they won’t be picked up by our fulfillment facilities. In order to mark the order as ready for fulfillment the order confirmation endpoint needs to be used.

Orders can be also created without specifying any items at first. In that case just the recipient address can be provided:

{
  "recipient": {
    "name": "John Smith",
    "address1": "19749 Dearborn St",
    "city": "Chatsworth",
    "country_code": "US",
    "state_code": "CA",
    "zip": "91311"
  }
}

The item creation endpoint can be then used in such order to add different products that should be included in the order. This functionality might be useful when implementing a user cart.

Deleting an order item

Individual items can be removed from the order by using the delete order item endpoint but only if the order is in either draft or failed state.

Updating an order

Order can be updated only in the draft and failed state. An entire order can be updated or just a specific item.

The updates in the V2 of the API use the PATCH method protocol. This means that only the values provided in the request will be updated. For example, sending a request with an empty body will not perform any changes to the order.

Example of updating a recipient name: PATCH https://api.printful.com/v2/orders/{order_id}

{
  "recipient": {
    "name": "John Smith"
  }
}

Some values can’t be updated separately, attempting to update an array's values requires sending a whole array. For example updating just the item design placement is not possible and will result in an error.

{
  "items": [
    {
      "placements": [
        {
          "placement": "front"
        }
      ]
    }
  ]
}

In such case a whole valid design data needs to be provided:

{
  "items": [
    {
      "quantity": 1,
      "catalog_variant_id": 4011,
      "source": "catalog",
      "placements": [
        {
          "placement": "front",
          "technique": "dtg",
          "layers": [
            {
              "type": "file",
              "url": "{{image_url}}"
            }
          ]
        }
      ]
    }
  ]
}

Order Confirmation

In V2 API the orders cannot be created immediately in a confirmed state. In order to confirm an order it first needs to be created in the draft state. Or if the order failed e.g. due to payment method missing it can be confirmed again.

If the order cost calculations are still calculating or they have failed to calculate then the order won’t be possible to be confirmed.

Example of order cost still calculating:

...
"costs": {
            "calculation_status": "calculating",
            "currency": null,
            "subtotal": null,
            "discount": null,
            "shipping": null,
            "digitization": null,
            "additional_fee": null,
            "fulfillment_fee": null,
            "retail_delivery_fee": null,
            "tax": null,
            "vat": null,
            "total": null
        },
...

Webhook events

To get the notifications about the order status, the webhook events endpoint can be used to subscribe to various webhook events e.g.:

  • Order created
  • Order updated
  • Order failed
  • Order cancelled
  • Order put on hold
  • Order put on hold approved
  • Order removed from hold
  • Order refunded

Get endpoints

The order list can be retrieved using the retrieve a list of orders endpoint. There is also an endpoint for retrieving the single order and the endpoint to retrieve a specific order item.

Shipping information

After an order is made it is split into shipments, meaning that a single order can have multiple shipments. You can retrieve the status of these shipments using the shipments endpoint.

The main use case of this endpoint is in providing tracking details about each shipment. Providing information about the status of the shipment and what events have occurred so far.

{
  ...
      "shipment_status": "canceled",
      "shipped_at": "2023-06-15T16:35:35Z",
      "delivery_status": "unknown",
      "delivered_at": "2023-06-15T16:35:35Z",
      "departure_address": {
        "country_name": "United States",
        "country_code": "US",
        "state_code": "CA"
      },
      "tracking_url": "​https://myorders.com/tracking/39925631",
      "tracking_events": [
        {
          "triggered_at": "2023-06-15T19:15:05Z",
          "description": "Arrived At Destination"
        }
      ],
...

Another important usage of this endpoint is in providing delivery time estimates:

{
  ...
  "estimated_delivery": {
    "from_date": "2023-06-15",
    "to_date": "2023-06-15",
    "calculated_at": "2023-06-15T16:35:35Z"
  },
  ...
}

Given that not all orders can fit in a single shipment it may be necessary to indicate which shipment will contain which item. The shipments endpoint can be used to link ordered items back to physical items.

{
  ...
  "shipment_items": [
    {
      "id": 10,
      "order_item_id": 20,
      "order_item_external_id": "item-external-id",
      "order_item_name": "Item name",
      "quantity": 1,
      "_links": {
        "order_item": {
          "href": "​https://api.printful.com/v2/orders/2/order-items/20"
        }
      }
    }
  ],
  ...
}

Building a product catalog

Product options, placements and techniques

In order to create order items and other designs it's important to know the specification of the product. The catalog products endpoints offers a way to expose these options so that designs can be created dynamically from blank Printful products.

Displaying the product

A request to https://api.printful.com/v2/catalog-products will provide a paged list of products along with descriptions and images of products to help users identify the product they would like.

[
  {
    "id": 294,
    "type": "T-SHIRT",
    "main_category_id": 7,
    "name": "Unisex Pullover Hoodie | Bella + Canvas 3719",
    "brand": "Bella + Canvas",
    "model": "3719",
    "image": "https://s3-printful.stage.printful.dev/upload/product-catalog-img/35/352d4f3cc9fbac9ee9173467bc7f200e_l",
    "variant_count": 20,
    "is_discontinued": false,
    "description": "A soft and comfy unisex hoodie that fits all your hoodie needs. The fleece fabric makes it a great partner all year round, be it a summer evening on the beach, or a Christmas dinner in a mountain cabin.\n\n• 52% airlume combed ring-spun cotton, 48% poly fleece\n• Heather colors are 60% airlume combed ring-spun cotton, 40% poly fleece\n• Fabric weight: 6.5 oz/yd² (220.4 g/m²)\n• Regular fit\n• Side-seamed construction\n• Blank product sourced from Honduras, Nicaragua or the US"
  },
  {
    "id": 262,
    "type": "CUT-SEW",
    "main_category_id": 49,
    "name": "All-Over Print Drawstring Bag",
    "brand": null,
    "model": null,
    "image": "https://s3-printful.stage.printful.dev/upload/product-catalog-img/0f/0f04d73474287ef01d6f5541c3a63de2_l",
    "variant_count": 1,
    "is_discontinued": false,
    "description": "Combine your love for vibrant prints and a sporty style with a cool drawstring bag. It's a must-have gym essential that can be worn as a backpack with drawstring closure at top, and narrow, contrasting shoulder straps. \n\n• 100% polyester\n• One size: 15″ × 17″ (38.1 cm × 43.2 cm)\n• Fabric weight (may vary by 5%): 6.64 oz/yd² (225 g/m²)\"\n• Maximum weight limit: 33 lbs (15 kg)\n• Twin cotton handles\n• Drawstring closure\n• Blank product components sourced from Israel",
  }
]

Selecting the product and creating a design

Once the product is selected additional information is needed in order to create a design with the blank product. The following is a valid item

{
  "quantity": 1,
  "catalog_variant_id": 4011,
  "source": "catalog",
  "placements": [
    {
      "placement": "front",
      "technique": "dtg",
      "layers": [
        {
          "type": "file",
          "url": "{{image_url}}"
        }
      ]
    }
  ]
}

A lot of the information in the above request depend on information taken from the catalog.

https://api.printful.com/v2/catalog-products/294

{
  "id": 294,
  "techniques": [
    {
      "key": "dtg",
      "display_name": "DTG printing",
      "is_default": true
    },
    {
      "key": "embroidery",
      "display_name": "Embroidery",
      "is_default": false
    }
  ],
  "placements": [
    {
      "placement": "embroidery_chest_left",
      "technique": "embroidery",
      "layers": [
        {
          "type": "file",
          "layer_options": [
            {
              "name": "thread_colors",
              "techniques": [
                "embroidery"
              ],
              "type": "array",
              "values": {
                "#FFFFFF": "1801 White",
                "#000000": "1800 Black",
                "#96A1A8": "1718 Grey",
                "#A67843": "1672 Old Gold",
                "#FFCC00": "1951 Gold",
                "#E25C27": "1987 Orange",
                "#CC3366": "1910 Flamingo",
                "#CC3333": "1839 Red",
                "#660000": "1784 Maroon",
                "#333366": "1966 Navy",
                "#005397": "1842 Royal",
                "#3399FF": "1695 Aqua/Teal",
                "#6B5294": "1832 Purple",
                "#01784E": "1751 Kelly Green",
                "#7BA35A": "1848 Kiwi Green"
              }
            }
          ]
        }
      ],
      "placement_options": []
    },
    {
      "placement": "front",
      "technique": "dtg",
      "layers": [
        {
          "type": "file",
          "layer_options": []
        }
      ],
      "placement_options": []
    },
    ...
  ],
  ...
}

The example above gives us most of the information necessary to design the item, it provides the techiques, placements and layers available for the product.

Mapped onto an item these values would look like this:

{
  "placements": [
    {
      "placement": "front",
      "technique": "dtg",
      "layers": [
        {
          "type": "file",
          "url": "{{image_url}}"
        }
      ]
    }
  ]
}

It also offers alternative options, for example the same product could use embroidery thread colors if embroidery placements are selected.

{
  "placements": [
    {
      "placement": "embroidery_chest_left",
      "technique": "embroidery",
      "layers": [
        {
          "type": "file",
          "layer_options": [
            {
              "name": "thread_colors",
              "value": [
                "#FFFFFF",
                "#000000"
              ]
            }
          ],
          "url": "{{image_url}}"
        }
      ]
    }
  ]
}

What's missing from this is the catalog_variant_id, the variant can be found using https://api.printful.com/v2/catalog-products/294/catalog-variants. Each variant is different in color and size and the user can view an image of each to help select their variant.

[
  {
    "id": 9224,
    "catalog_product_id": 294,
    "name": "Bella + Canvas 3719 Unisex Fleece Pullover Hoodie (White / XL)",
    "size": "XL",
    "color": "White",
    "color_code": "#ffffff",
    "color_code2": null,
    "image": "https://s3-printful.stage.printful.dev/products/294/9220_1526986863.jpg",
    ...
  },
  ...
]

With the catalog variant selected the design can be finished, and creating an item is just a matter of selecting the quantity and source of the design.

{
  "quantity": 1,
  "catalog_variant_id": 9224,
  "source": "catalog",
  "placements": [
    {
      "placement": "embroidery_chest_left",
      "technique": "embroidery",
      "layers": [
        {
          "type": "file",
          "layer_options": [
            {
              "name": "thread_colors",
              "value": [
                "#FFFFFF",
                "#000000"
              ]
            }
          ],
          "url": "{{image_url}}"
        }
      ]
    }
  ]
}

Getting the pricing information

The catalog API can also be used to indicate to the end customer what the price of the product will be.

https://api.printful.com/v2/catalog-variants/9224/prices

{
  "data": {
    "currency": "EUR",
    "product": {
      "id": 294,
      "placements": [
        {
          "id": "embroidery_chest_left",
          "title": "Left chest",
          "type": "Embroidery",
          "technique_key": "embroidery",
          "placement_options": [],
          "price": "2.95",
          "discounted_price": "2.95",
          "layers": [
            {
              "type": "file",
              "additional_price": "0.00",
              "layer_options": []
            }
          ]
        },
        {
          "id": "front",
          "title": "Front print",
          "type": "DTG printing",
          "technique_key": "dtg",
          "placement_options": [],
          "price": "5.75",
          "discounted_price": "5.75",
          "layers": [
            {
              "type": "file",
              "additional_price": "0.00",
              "layer_options": []
            }
          ]
        }
      ]
    },
    "variant": {
      "id": 9224,
      "techniques": [
        {
          "technique_key": "dtg",
          "technique_display_name": "DTG printing",
          "price": "28.95",
          "discounted_price": "28.95"
        },
        {
          "technique_key": "embroidery",
          "technique_display_name": "Embroidery",
          "price": "30.75",
          "discounted_price": "30.75"
        }
      ]
    },
    "discount_tiers": [
      {
        "quantity": 25,
        "bulk_discount_percentage": 0.08
      },
      ...
    ]
  },
}

The price of the product will depend upon the technique, the variant, the placement and the quantity of the product ordered. Furthermore, the first placement will be discounted by the discounted_price.

For more information on pricing please follow this link: https://www.printful.com/pricing

Price changed webhook

It may also be useful that a system can react to changes in product pricing, the Catalog Price Changed (catalog_price_changed) webhook can be used to handle this use case.

Getting the images for the products

The images provided in the catalog products and variants are only very simple. For more complex use cases where a larger variety of mockups of a single product may need to be displayed, the catalog product images and variant images endpoints can help. Note however, that these require additional work, Printful doesn't provide images for every color so most images on those endpoints are transparent and require the developer to overlay them on top of the color defined on the resource.

Getting the availability of products (stock information)

Stock of products changes daily at Printful so it's important to make sure to display this availability to the end customers.

One way to make sure end customers only see the products available in their region is to filter by selling region https://api.printful.com/v2/catalog-products?selling_region_name=brazil.

If more detailed availability information is needed it can be taken from the variant and product availability endpoints.

https://api.printful.com/v2/catalog-products/294/availability

{
  "data": [
    {
      "catalog_variant_id": 9231,
      "techniques": [
        {
          "technique": "dtg",
          "selling_regions": [
            {
              "name": "usa",
              "availability": "in stock",
              "placement_option_availability": []
            }
          ]
        },
        {
          "technique": "embroidery",
          "selling_regions": [
            {
              "name": "usa",
              "availability": "in stock",
              "placement_option_availability": []
            }
          ]
        }
        ...
      ]

This may be important in cases where the stock availability of specific techniques is important.

Stock updated webhook

It may also be useful that a system can react to changes in product availability, the catalog stock updated (catalog_stock_updated) webhook can be used to handle this use case.~~

How to create mockups

Defining mockup styles

When creating a mockup a style first needs to be selected for the given product.

https://api.printful.com/v2/catalog-products/294/mockup-styles

{
  "data": [
    {
      "placement": "front",
      "display_name": "Front print",
      "technique": "dtg",
      "print_area_width": 12.0,
      "print_area_height": 12.0,
      "print_area_type": "simple",
      "dpi": 150,
      "mockup_styles": [
        {
          "id": 16652,
          "category_name": "Flat",
          "view_name": "Front",
          "restricted_to_variants": null
        },
        ...

These styles contain a view and category and are limited by placement to help select the correct style.

Creating mockups

Once the style is retrieved creating a mockup is very similar to creating an order item. All of this data from the order item created above can be reused to create a mockup

{
  "source": "catalog",
  "placements": [
    {
      "placement": "embroidery_chest_left",
      "technique": "embroidery",
      "layers": [
        {
          "type": "file",
          "layer_options": [
            {
              "name": "thread_colors",
              "value": [
                "#FFFFFF",
                "#000000"
              ]
            }
          ],
          "url": "{{image_url}}"
        }
      ]
    }
  ]
}

The placements are all that is needed to create a design. A mockup also needs these properties

{
  "mockup_style_ids": [
    16652 # The style selected before
  ],
  "catalog_product_id": 1, # The catalog product
  "catalog_variant_ids": [ # A list of catalog variants
    16365
  ],
  ...
}

The mockup generator can then take a list of products in order to create multiple mockups at a time.

{
  "format": "jpg",
  "products": [
    {
      "source": "catalog",
      "mockup_style_ids": [
        16652
      ],
      "catalog_product_id": 294,
      "catalog_variant_ids": [
        9231
      ],
      "placements": [
        {
          "placement": "embroidery_chest_left",
          "technique": "embroidery",
          "layers": [
            {
              "type": "file",
              "layer_options": [
                {
                  "name": "thread_colors",
                  "value": [
                    "#FFFFFF",
                    "#000000"
                  ]
                }
              ],
              "url": "{{image_url}}"
            }
          ]
        }
      ]
    }
  ]
}

Fetching the mockup task

The response of the above request will look something like this:

{
  "id": 752213059,
  "status": "pending",
  "catalog_variant_mockups": [],
  "failure_reasons": [],
  "_links": {
    "self": {
      "href": "https://api.printful.com/v2/mockup-tasks?id=752213059"
    }
  }
}

Mockups are generated asynchronously so they will not be present right after making the request.

Webhook events

When the mockup is finished processing a webhook will be triggered which can be listened to using the Mockup task finished webhook (mockup_task_finished).

GET endpoint

It may not be possible to set up webhooks in some systems, or it may simply be too complicated for the scope of a given project. If this is the case the mockup can also be retrieved by polling the endpoint to retrieve mockup tasks, e.g. https://api.printful.com/v2/mockup-tasks?id=752213059.

Even if a system uses webhook events, the GET endpoint should still be used as a backup in case the message is never received from the webhook. Setting a server up to automatically check the process of mockup tasks can improve the reliability of an integration.

Rate Limiting

Printful implements rate limiting to ensure the stability of the API while keeping it fair for all users. Rate limiting is handled differently depending on the version and endpoint being used.

Header values

Printful uses the following header values to communicate rate limits:

X-Ratelimit-Limit
X-Ratelimit-Remaining
X-Ratelimit-Reset
X-Ratelimit-Policy

However, the meaning of these values changes depending on the algorithm used.

V1 Rate limitting

V1 used a very simple rate limiting mechanism, you had a limit of 120, every request would reduce that limit by 1, if it hits 0 you would receive a 429 error, every minute the limit of 120 would be restored. See: V1 Rate Limits.

This system is good, because it's easy to understand for most users. However, we found it had a number of disadvantages both for users and for Printful.

  • A burst in traffic could lead to 120 requests in the first second. This is harmful for Printful and will lead to a bad user experience as all end users wait for the rate limit to be reset.
  • Some users will have close to 120 requests a minute, but most sites don't have such uniform traffic.

V2 Rate Limiting

Leaky Bucket

In V2 of the API Printful implements a Leaky Bucket rate limiting algorithm.

Note: The algorithm does not implement any queuing mechanisms in its current form so it can also be described as a Token Bucket algorithm.

Like with the old rate limiting algorithm, when you make a request to the API, the X-Ratelimit-Remaining header value will go down by one. However, the X-Ratelimit-Reset does not work the same, it states how long it will take to "refill the bucket". The bucket will be refilled one drop at a time instead of all at once, so the X-Ratelimit-Reset will be much smaller after the first request.

By default, after the first request the headers will look like this:

X-Ratelimit-Policy: 120;w=60;
X-Ratelimit-Limit: 120
X-Ratelimit-Remaining: 119
X-Ratelimit-Reset: 0.5

This means 120 requests can be made in a single burst, one request has already been made and X-Ratelimit-Remaining will reach 120 again in 0.5 seconds. The X-Ratelimit-Policy header indicates that in a window of 60 seconds 120 tokens (or "quota units") will be added to the bucket.

The headers are inspired by the format in RateLimit header fields for HTTP Internet-Draft.

What is rate-limited in V2

All endpoints are rate-limited with the leaky bucket rate limiter and the defaults. However, it is planned for future endpoints to have higher or lower limits depending on usage and the capacity of the API.

Using the leaky bucket effectively

There are a number of strategies you can use to take advantage of rate limiting.

  • When receiving a 429 you can use the retry-after header to check when the next request can be made, then schedule a request to trigger at that time.
  • You can implement a queue that only sends out requests at the rate indicated in the policy. You can calculate the rate of requests using the X-Ratelimit-Policy 120 ÷ 60 = 0.5, so the queue should send requests out at a rate of once every 500 milliseconds.
  • Some combination of the two, for example, allow requests to trigger at any rate, start queuing after the first 429, then turn off the queue after no new requests are sent and the X-Ratelimit-Reset time has been met.

Localisation

Some of the resources returned by the API are translated into several languages. By default, they are returned in English in the API responses.

If you want to get a response with texts in another language, you can use the X-PF-Language HTTP header. Its value should be the long version of the locale to use (e.g. es_ES for Spanish). Possible localisation parameters:

  • en_US
  • en_GB
  • en_CA
  • es_ES
  • fr_FR
  • de_DE
  • it_IT
  • ja_JP

Example

Product details (GET https://api.printful.com/products/71) response with default locale (en_US):

{
    "code": 200,
    "result": {
        "product": {
            "type_name": "T-Shirt",
            "title": "Unisex Staple T-Shirt | Bella + Canvas 3001",
            ...
        }
    }
}

Product details response with Spanish locale (X-PF-Language: es_ES):

{
    "code": 200,
    "result": {
        "product": {
            ...
            "type_name": "Camiseta",
            "title": "Camiseta esencial unisex | Bella + Canvas 3001",
            ...
        }
    }
}

OAuth Scopes v2

OAuth API allows receiving data for token

Retrieve OAuth scopes

This endpoint will retrieve all OAuth scopes associated with the used token

Authorizations:
OAuth

Responses

Response Schema: application/json
required
Array of objects (OAuthScope)
required
object

HATEOAS links

Response samples

Content type
application/json
{}

Catalog v2

What is a catalog product?

A catalog product refers to a blank product and its variants. Each variant can be used as the base for custom designs. Catalog product consists of multiple catalog variants each of which might be a combination of size and color or it might be a variation with e.g. tear away label. The entire hierarchy is shown in the diagram below:

Catalog product diagram

What is a catalog variant?

Catalog variant might be a combination of size and color associated with the catalog product or additional variation of a product with certain features like tear away label. It can be thought of as an actual physical blank product. For example T-shirt Bella Canvas 3001 in White color and size M is considered to be a single variant. Catalog variants can have different availability as different regions could have different stock of some product colors and sizes.

Catalog variant diagram

Printful has a substantial catalog of blank Products and Variants. A Product can describe a specific type, model and manufacturer of the item, while the Variant specifies the more detailed attributes of the product like the exact size/color of a T-shirt or the dimensions of a poster. Moreover, each item in the Printful Catalog has a unique Variant ID. When managing Sync Products or orders, you will need to specify the Variant ID of the specific blank item, hence you can use this API resource to find the needed Variant ID.

It is critically important to always refer to the Variant IDs (NOT Product IDs) when creating products or orders. Mixing up and using the Product ID instead of the Variant ID can lead to an entirely different product created or item ordered. The Product entity is only meant to allow of easier browsing of what Printful offers.

You can also use this API resource to find out the types of print files. A product can be configured for as well as the additional price each print file would cost (e.g. the back print or inside label print for T-shirts). Moreover, some product types allow for additional options (e.g. embroidery type and thread colors) – these options are listed in the responses as well.

Important: Jewelry products are not supported via API.

Rate limiting: Up to 120 requests per 60 seconds. A 60 seconds lockout is applied if request count is exceeded.

Catalog general information

General introduction

This resource contains the list of all the products that are available in Printful for purchase and fulfillment. Apart from basic product data and availability it also contains the information about:

Catalog diagram

Filtering options

Filters can be used to search for particular set of products based on the provided values. Multiple filters can be used at the same time.

Filtering option name Description Where to find
colors Filters products by variants containing specified colors data[].color Catalog variants
new Filters products that are new -
placements Filters products by available placements specified in the list data[].placements[].placement Catalog products
category_ids Filters products by specified product categories data[].id Catalog categories
techniques Filters products by specified techniques data[].techniques[].key Catalog products
types Filters products by specified types of product e.g. T-Shirt. data[].type Catalog products
bestseller Filters products that are bestsellers -

Sorting

Requires providing two parameters in the URL: sort_type And sort_direction. Sort type determines a type of sorting that will be used e.g. sort by price and the sort direction determines if the result should be sorted ascending or descending. Only one sort type can be used at a time.

Sorting option name Description
new Sorts resulting catalog products starting with new ones
rating Sorts resulting catalog products by their user-rating
price Sorts resulting catalog products by their base price
bestseller Sorts resulting catalog products starting with bestsellers

DSR

  • What is DSR? – DSR (Default Selling Region) is an option that lets you limit the results of a product catalog to products that could be shipped within a specified region. When choosing Worldwide, we'll display the entire Product Catalog. Delivery times depend on end-customer location and selected product.
  • Where DSR can be set and how it affects response? – DSR can be currently set in Catalog products and Product Prices.
  • Available DSRs
Region name Region name value
Worldwide worldwide
North America north_america
Canada canada
Europe europe
Spain spain
Latvia latvia
United Kingdom uk
France france
Germany germany
Australia australia
Japan japan
New Zealand new_zealand
Italy italy
Brazil brazil
Southeast Asia southeast_asia
Republic of Korea republic_of_korea

Size guides

Size guides diagram

Get Product Size Guide endpoint will return size guides for the specified product.

There are three types of size tables available, as described by the following table:

Table type API name Description
Measure yourself measure_yourself Measurements of the product to measure the body provided by the supplier.
Product measurements product_measure Measurements of the product provided by the supplier.
International size conversion international International size conversion – e.g. US, EU or UK sizes corresponding to the product sizes.

Not each table type might be available for the selected product. See examples

Categories

Catalog categories are used to group products with similar characteristics such as t-shirts, hats etc.

Categories have purely informational purposes and cannot be edited by the customers. Categories can be nested e.g.

  • Men’s clothing
    • All shirts
      • T-Shirts
      • Polo shirts
    • Jackets & vests

Apart from display purposes they can be also used for filtering the products in the API see Filtering options

Retrieve a list of catalog products

This endpoint retrieves a list of the products available in Printful's catalog. The list is paginated and can be filtered using various filters. The information returned includes details on how each product can be designed, such as the available placements, techniques, and additional options. For a visual representation of the design data, please see the following diagram: Design data diagram

Authorizations:
OAuth
query Parameters
category_ids
Array of integers
Examples:
  • category_ids=4 - Using a single category ID
  • category_ids=4,7 - Multiple category IDs

One or more category IDs to return only products in those categories. The IDs can be found in the response of the operation Get Categories.

colors
Array of strings
Examples:
  • colors=grey - Grey.
  • colors=heather%20grey - Heather grey color.
  • colors=grey,heather%20grey - Grey or heather grey color

One or more color names to return only products with variants of one the those colors.

limit
integer [ 1 .. 100 ]
Default: 20

The number of results to return per page.

new
boolean
Default: false
Examples:
  • new=true - Return only new products

If true only new Products will be returned.

offset
integer >= 0
Default: 0
Examples:
  • offset=100 - Return results after the initial 100

The number of results to not include in the response starting from the beginning of the list.

This can be used to return results after the initial 100. For example, sending offset 100

placements
Array of strings
Examples:
  • placements=front - Return products with variants that have front placement.
  • placements=front,back - Return products with variants that have front or back placement.

One or more identifiers of a placement to return only products with variants that have that placement. The complete list of placements can be found here.

selling_region_name
string
Default: "worldwide"
Enum: "worldwide" "north_america" "canada" "europe" "spain" "latvia" "uk" "france" "germany" "australia" "japan" "new_zealand" "italy" "brazil" "southeast_asia" "republic_of_korea" "all"

Only returns the products that can be sold in the specified region. If is set to 'all' returns each region availability for specified product.

sort_direction
string
Default: "descending"
Enum: "ascending" "descending"

This parameter only is used if sort_type is also present and it changes the order of the returned products. The exact meaning varies depending on the value of sort_type:

  • sort_type=new
    • ascending sorts from newest to oldest.
    • descending sorts from oldest to newest.
  • sort_type=rating
    • ascending from lowest to highest rated.
    • descending from highest to lowest rated.
  • sort_type=price
    • ascending from lowest to highest price.
    • descending from highest to lowest price.
  • sort_type=bestseller
    • ascending from non bestsellers to bestsellers.
    • descending from bestsellers to non bestsellers.
sort_type
string
Enum: "new" "rating" "price" "bestseller"

The sorting strategy to use when sorting the result. When it's not present, no specific order is guaranteed.

techniques
Array of strings (TechniqueEnum)
Items Enum: "dtg" "digital" "cut-sew" "uv" "embroidery" "sublimation" "dtfilm"
Examples:
  • techniques=digital - Products with variants that can be printed using the technique digital.
  • techniques=digital,embroidery - Products with variants that can be printed using the techniques digital or embroidery.

One or more techniques to return only products with variants that can be printed using one of the techniques.

destination_country
string

The ISO 3166-1 alpha-2 country code for the destination country. Only products shippable to the specified country will be returned.

header Parameters
X-PF-Language
string

Use this to specify which locale you would like to use in the responses, for some endpoints this can affect translations.

Responses

Response Schema: application/json
required
Array of objects (Product)
required
object (Paging)

Paging information

required
object (Product links)

HATEOAS links

Response samples

Content type
application/json
{}

Retrieve a single catalog product

Returns information about a single specified catalog product. See catalog product

Authorizations:
OAuth
path Parameters
id
required
integer

Product ID.

query Parameters
selling_region_name
string
Default: "worldwide"
Enum: "worldwide" "north_america" "canada" "europe" "spain" "latvia" "uk" "france" "germany" "australia" "japan" "new_zealand" "italy" "brazil" "southeast_asia" "republic_of_korea" "all"

Only returns the products that can be sold in the specified region. If is set to 'all' returns each region availability for specified product.

header Parameters
X-PF-Language
string

Use this to specify which locale you would like to use in the responses, for some endpoints this can affect translations.

Responses

Response Schema: application/json
required
object (Product)

Information about the Catalog Product

Response samples

Content type
application/json
{}

Retrieve information about specific catalog variant

Returns information about single specified catalog variant. See catalog variant

Authorizations:
OAuth
path Parameters
id
required
integer

Variant ID

header Parameters
X-PF-Language
string

Use this to specify which locale you would like to use in the responses, for some endpoints this can affect translations.

Responses

Response Schema: application/json
required
object (Variant)
required
object

HATEOAS links

Response samples

Content type
application/json
{}

Retrieve information about catalog product variants

Returns information about all catalog variants associated with the specified catalog product. See catalog variant

Authorizations:
OAuth
path Parameters
id
required
integer

Product ID.

header Parameters
X-PF-Language
string

Use this to specify which locale you would like to use in the responses, for some endpoints this can affect translations.

Responses

Response Schema: application/json
required
Array of objects (Variant)
required
object (Paging)

Paging information

required
object

HATEOAS links

Response samples

Content type
application/json
{}

Retrieve a list of catalog categories

Returns list of all categories that are present in the catalog. The categories specify the type of the product that is associated with it. For example, the category "Men’s T-shirts" indicates that the product is a subgroup of T-shirts specifically targeted at Men. Categories can be used to filter the product list by specific tags See categories_ids

Authorizations:
OAuth

Responses

Response Schema: application/json
required
Array of objects (Category)
required
object

HATEOAS links

Retrieve information about specific category

Returns information about a specific catalog category. The categories specify the type of the product that is associated with it. For example, the category "Men’s T-shirts" indicates that the product is a subgroup of T-shirts specifically targeted at Men. Categories can be used to filter the product list by specific tags See categories_ids

Authorizations:
OAuth
path Parameters
id
required
integer

Category ID

Responses

Response Schema: application/json
required
object (Category)

Information about the Category

required
object

HATEOAS links

Response samples

Content type
application/json
{}

Retrieve a list of catalog product categories

To retrieve information about a particular products categories, use this feature. It returns details about the catalog categories associated with the catalog product. Categories help identify the type of product associated with them. For instance, the category "Men's T-shirts" denotes that the product is a subgroup of T-shirts intended for men.

Authorizations:
OAuth
path Parameters
id
required
integer

Product ID.

query Parameters
selling_region_name
string
Default: "worldwide"
Enum: "worldwide" "north_america" "canada" "europe" "spain" "latvia" "uk" "france" "germany" "australia" "japan" "new_zealand" "italy" "brazil" "southeast_asia" "republic_of_korea" "all"

Only returns the products that can be sold in the specified region. If is set to 'all' returns each region availability for specified product.

Responses

Response Schema: application/json
required
Array of objects (Category)
required
object (Paging)

Paging information

required
object

HATEOAS links

Response samples

Retrieve size guide for a catalog product

Returns information about the size guide for a specific product.

Authorizations:
OAuth
path Parameters
id
required
integer

Product ID.

query Parameters
unit
string
Example: unit=inches,cm

A comma-separated list of measurement unit in which size tables are to be returned (inches or cm). The default value is determined based on the locale country. The inches are used for United States, Liberia and Myanmar, for other countries the unit defaults to centimeters.

header Parameters
X-PF-Language
string

Use this to specify which locale you would like to use in the responses, for some endpoints this can affect translations.

Responses

Response Schema: application/json
required
object (ProductSizeGuide)

Size Guide information for the Product

required
object

HATEOAS links

Response samples

Content type
application/json
{
  • "data": {
    },
}

Retrieve catalog product prices

Calculates prices for specific catalog product based on selling region and specified currency. Calculations also include Store discounts. Selling region is used to specify product production currency, that is the price that the product is natively manufactured in. Different selling regions might affect the overall price amount. Currency parameter is used only to define the currency that the prices will be displayed in.

For more information on product pricing please refer to the information provided at https://www.printful.com/pricing

When developing against either API be sure to inform your customers that a placement will be included in the price of the product. If one placement is provided that placement will be included in the price, if multiple are provided the included placement will generally be the placement that comes earliest in the list of placements at `/v2/catalog-products/71` (though the discount will generally be up to the price of the first placement in that list). Certain placements come with additional service fees, such as large embroidery, this additional price will never be included even if the only placement is large embroidery.

There is a minor difference in the handling of prices for placements between V1 and V2. In V1 the price of the first placement is always null, this is because there is always a placement included in the price of each product. In V2 the price of placements is always displayed even if it is included in the price of the product because any placement can be included.

Authorizations:
OAuth
path Parameters
id
required
integer

Product ID.

query Parameters
selling_region_name
string
Example: selling_region_name=worldwide

Specifies the region production currency that the product prices will be calculated in

currency
string
Example: currency=USD

The currency (3-letter code) used to determine currency in which the prices will be displayed. The store currency will be used by default. The format is compliant with ISO 4217 standard.

header Parameters
X-PF-Language
string

Use this to specify which locale you would like to use in the responses, for some endpoints this can affect translations.

Responses

Response Schema: application/json
required
object (ProductPrice)

Product prices information

required
object (Paging)

Paging information

required
object

HATEOAS links

Response samples

Content type
application/json
{}

Retrieve pricing information for the catalog variant

Return pricing information from a single variant and the parent product

Authorizations:
OAuth
path Parameters
id
required
integer

Variant ID

query Parameters
selling_region_name
string
Example: selling_region_name=worldwide

Specifies the region production currency that the product prices will be calculated in

currency
string
Example: currency=USD

The currency (3-letter code) used to determine currency in which the prices will be displayed. The store currency will be used by default. The format is compliant with ISO 4217 standard.

header Parameters
X-PF-Language
string

Use this to specify which locale you would like to use in the responses, for some endpoints this can affect translations.

Responses

Response Schema: application/json
required
object (VariantPrice)

Variant prices information

required
object

HATEOAS links

Response samples

Content type
application/json
{
  • "data": {
    },
}

Retrieve blank images for a catalog product

This feature helps to fetch blank images for a catalog product. These blank images are always white and semi-transparent and can be colored by the user on the client-side as per the specified color in the data.images.background_color field. For some mockups the data.images.background_image could apply. The endpoint allows filtering of the result based on the type of the mockup, the placement, and the color of the product.

Authorizations:
OAuth
path Parameters
id
required
integer

Product ID.

query Parameters
mockup_style_ids
integer
Example: mockup_style_ids=1, 2, 3

Used to specify style of images For example:

colors
string
Example: colors=black,red

String values separated by comma. You can specify multiple variant colors filters.

placement
string
Example: placement=front

Filters result by specified placement

header Parameters
X-PF-Language
string

Use this to specify which locale you would like to use in the responses, for some endpoints this can affect translations.

Responses

Response Schema: application/json
required
Array of objects (VariantImages)
required
object (Paging)

Paging information

required
object

HATEOAS links

Response samples

Content type
application/json
{}

Retrieve the shipping countries for a Product

Retrieve the list of countries the Catalog Product can be shipped to.

Authorizations:
OAuth
path Parameters
id
required
integer

Product ID.

header Parameters
X-PF-Language
string

Use this to specify which locale you would like to use in the responses, for some endpoints this can affect translations.

Responses

Response Schema: application/json
required
Array of objects (Country)

Response samples

Content type
application/json
{
  • "data": [
    ]
}

Retrieve blank images for a catalog variant

Returns images for a specified Variant.

Authorizations:
OAuth
path Parameters
id
required
integer

Variant ID

query Parameters
mockup_style_ids
integer
Example: mockup_style_ids=1, 2, 3

Used to specify style of images For example:

placement
string
Example: placement=front

Filters result by specified placement

header Parameters
X-PF-Language
string

Use this to specify which locale you would like to use in the responses, for some endpoints this can affect translations.

Responses

Response Schema: application/json
required
Array of objects (VariantImages)
required
object

HATEOAS links

Response samples

Content type
application/json
{}

Retrieve catalog product mockup styles

Returns information about available mockup styles for specified catalog product.

Authorizations:
OAuth
path Parameters
id
required
integer

Product ID.

query Parameters
placements
Array of strings
Examples:
  • placements=front - Return mockup styles that match a specific placement.
  • placements=front,back - Return mockup styles that match a list of placements.

One or more placement idenitifiers used to filter in mockup styles that match a given placement. The complete list of placements can be found here.

selling_region_name
string
Default: "worldwide"
Enum: "worldwide" "north_america" "canada" "europe" "spain" "latvia" "uk" "france" "germany" "australia" "japan" "new_zealand" "italy" "brazil" "southeast_asia" "republic_of_korea" "all"

Only returns the products that can be sold in the specified region. If is set to 'all' returns each region availability for specified product.

offset
integer

Result set offset

limit
integer

Number of items per page (max 100)

header Parameters
X-PF-Language
string

Use this to specify which locale you would like to use in the responses, for some endpoints this can affect translations.

Responses

Response Schema: application/json
required
Array of objects (MockupStyles)
required
object (Paging)

Paging information

required
object

HATEOAS links

Response samples

Content type
application/json
{}

Retrieve catalog product mockup templates

Returns positional data for specified catalog product mockups. The data from this endpoint could be used to generate your own mockups without the need to use Printful's mockup generator. Mockup template

Authorizations:
OAuth
path Parameters
id
required
integer

Product ID.

query Parameters
placements
Array of strings
Examples:
  • placements=front - Return products with variants that have front placement.
  • placements=front,back - Return products with variants that have front or back placement.

One or more identifiers of a placement to return only products with variants that have that placement. The complete list of placements can be found here.

selling_region_name
string
Default: "worldwide"
Enum: "worldwide" "north_america" "canada" "europe" "spain" "latvia" "uk" "france" "germany" "australia" "japan" "new_zealand" "italy" "brazil" "southeast_asia" "republic_of_korea" "all"

Only returns the products that can be sold in the specified region. If is set to 'all' returns each region availability for specified product.

limit
integer [ 1 .. 100 ]
Default: 20

The number of results to return per page.

offset
integer >= 0
Default: 0
Examples:
  • offset=100 - Return results after the initial 100

The number of results to not include in the response starting from the beginning of the list.

This can be used to return results after the initial 100. For example, sending offset 100

header Parameters
X-PF-Language
string

Use this to specify which locale you would like to use in the responses, for some endpoints this can affect translations.

Responses

Response Schema: application/json
required
Array of objects (MockupTemplates)
object (Paging)

Paging information

required
object

HATEOAS links

Response samples

Content type
application/json
{}

Retrieve catalog product stock availability

Provides information about the catalog product stock status. Stock availability is grouped by variants → techniques → selling regions.

Authorizations:
OAuth
path Parameters
id
required
integer

Product ID.

query Parameters
techniques
Array of strings (TechniqueEnum)
Items Enum: "dtg" "digital" "cut-sew" "uv" "embroidery" "sublimation" "dtfilm"
Examples:
  • techniques=digital - Products with variants that can be printed using the technique digital.
  • techniques=digital,embroidery - Products with variants that can be printed using the techniques digital or embroidery.

One or more techniques to return only products with variants that can be printed using one of the techniques.

selling_region_name
string
Default: "worldwide"
Enum: "worldwide" "north_america" "canada" "europe" "spain" "latvia" "uk" "france" "germany" "australia" "japan" "new_zealand" "italy" "brazil" "southeast_asia" "republic_of_korea" "all"

Only returns the products that can be sold in the specified region. If is set to 'all' returns each region availability for specified product.

limit
integer [ 1 .. 100 ]
Default: 20

The number of results to return per page.

offset
integer >= 0
Default: 0
Examples:
  • offset=100 - Return results after the initial 100

The number of results to not include in the response starting from the beginning of the list.

This can be used to return results after the initial 100. For example, sending offset 100

header Parameters
X-PF-Language
string

Use this to specify which locale you would like to use in the responses, for some endpoints this can affect translations.

Responses

Response Schema: application/json
required
Array of objects (VariantStockAvailability)
required
object (Paging)

Paging information

required
Array of objects (FilterSettings)

The list of the filters that were used in the request

required
object

HATEOAS links

Response samples

Content type
application/json
{}

Retrieve catalog variant stock availability

Provides information about the catalog variant stock status. Stock availability is grouped by variants → techniques → selling regions.

Authorizations:
OAuth
path Parameters
id
required
integer

Variant ID

query Parameters
techniques
Array of strings (TechniqueEnum)
Items Enum: "dtg" "digital" "cut-sew" "uv" "embroidery" "sublimation" "dtfilm"
Examples:
  • techniques=digital - Products with variants that can be printed using the technique digital.
  • techniques=digital,embroidery - Products with variants that can be printed using the techniques digital or embroidery.

One or more techniques to return only products with variants that can be printed using one of the techniques.

selling_region_name
string
Default: "worldwide"
Enum: "worldwide" "north_america" "canada" "europe" "spain" "latvia" "uk" "france" "germany" "australia" "japan" "new_zealand" "italy" "brazil" "southeast_asia" "republic_of_korea" "all"

Only returns the products that can be sold in the specified region. If is set to 'all' returns each region availability for specified product.

header Parameters
X-PF-Language
string

Use this to specify which locale you would like to use in the responses, for some endpoints this can affect translations.

Responses

Response Schema: application/json
required
object (VariantStockAvailability)

Stock availability data for a specific catalog variant

required
Array of objects (FilterSettings)

The list of the filters that were used in the request

required
object

HATEOAS links

Response samples

Content type
application/json
{}

Orders v2

Order Building

You can create a draft order without order items but you won’t be able to confirm it until at least one order item are added to that order. With this approach, you can create a draft order with all necessary recipient data and add items to it as you go (similar to a shopping cart) by using Create Order Item. After every order item addition, the order cost will be re-calculated.

A minimal DRAFT order can be created with just the address:

POST https://api.printful.com/v2/orders
Authorization: Bearer {{bearer_token}}
{
  "recipient": {
    "address1": "19749 Dearborn St",
    "city": "Chatsworth",
    "state_code": "CA",
    "state_name": "California",
    "country_code": "US",
    "country_name": "United States",
    "zip": "91311"
  }
}

After the order is created the order items can be added one by one.

POST https://api.printful.com/v2/orders/{{order_id}}/order-items
Authorization: Bearer {{bearer_token}}
{
    "catalog_variant_id": 4011,
    "source": "catalog",
    "quantity": 1,
    "placements": [
        {
            "placement": "front",
            "technique": "dtg",
            "layers": [
                {
                    "type": "file",
                    "url": "https://www.printful.com/static/images/layout/printful-logo.png"
                }
            ]
        }
    ]
}

It is also possible to create an order with all order items in a single request.

POST https://api.printful.com/v2/orders
Authorization: Bearer {{bearer_token}}
{
  "recipient": {
    "address1": "19749 Dearborn St",
    "city": "Chatsworth",
    "state_code": "CA",
    "state_name": "California",
    "country_code": "US",
    "country_name": "United States",
    "zip": "91311"
  },
  "order_items": [
    {
      "catalog_variant_id": 4011,
      "source": "catalog",
      "quantity": 1,
      "placements": [
        {
          "placement": "front",
          "technique": "dtg",
          "layers": [
            {
              "type": "file",
              "url": "https://www.printful.com/static/images/layout/printful-logo.png"
            }
          ]
        }
      ]
    }
  ]
}

Order life cycle and statuses

draft At this stage, the order has been created but has not yet been submitted for fulfillment. It can be freely edited, changed, or deleted at this stage. The order will not charged or fulfilled until it has been confirmed.
pending The order has been submitted for fulfillment and it will be charged in this stage, but is not yet accepted for fulfillment. The order can be cancelled at this stage so long as it has not been charged yet.
failed Order was submitted for fulfillment but it had some errors preventing it from being fulfilled (problem with the address, missing printfiles, failed to charge the wallet, etc.).
canceled The order has been canceled and can no longer be processed. If the order was already charged then the cost of the order will be returned to your store.
inprocess The order is being fulfilled and can no longer be canceled or modified. Contact customer support if there are any issues with the order at this point.
onhold The order has encountered a problem during the fulfillment that needs to be resolved together with Printful customer service before fulfillment can continue.
partial The order is partially fulfilled (some items are shipped already, the rest will follow).
fulfilled All items have been shipped successfully.

You are only charged for orders when they have been confirmed with the “Confirm Order” operation and have the status “pending” Confirm Order. If the order encounters a problem after it has been confirmed, then it is moved to the failed state so that the problem can be fixed and the order can be resubmitted.

For order status updates please subscribe to one of the webhook events following webhook events:

Order items

Order items are representations of the actual products that will come with an order.

In the sections below we explain each order item source and provide examples of how a simple request might look like for each source.

Catalog Source

Catalog products are blank products available in Printful. Since they are blank you’ll need to specify design data during the order creation. This flow is intended if you allow your customers to specify their own designs which means that every order is unique.

The following example request shows how an item structure might look in JSON.

POST https://api.printful.com/v2/orders/{{order_id}}/order-items
Authorization: Bearer {{bearer_token}}
{
    "catalog_variant_id": 4012,
    "source": "catalog",
    "quantity": 1,
    "placements": [
        {
            "placement": "front",
            "technique": "dtg",
            "layers": [
                {
                    "type": "file",
                    "url": "https://www.printful.com/static/images/layout/printful-logo.png"
                }
            ]
        }
    ]
}
Example of order item mockup

Design specification

Design data is the information used to customize the product. A design consists of placements, layers and unique product options. Placements refer to where a design will be printed, for example, a T-Shirt might have the placements front and left_sleeve. Placements can also constrict what techniques can be used in that area of the product, for example a product might have both front and embroidery_front and embroidery can only be used in the second placement. A layer is constrained to the print area of the placement that you’ve chosen. A design that is outside of the print area won’t be visible.

Depending on the product, placement, and technique different layers might be available.

You can check which layers are available using the Retrieve a single catalog product operation.

The design data structure is the same regardless of the flow (making orders, creating sync products etc.). So the solution can be re-used in the different endpoints.

Design data

Placements

The product placement is the part of the product where design layers will be printed, different placements will also offer different options and techniques, they will also have different limitations. The available placement list will vary depending on the product. To get the available placements of a product use the Retrieve a single catalog product endpoint with the product ID that you want to check.

Front placement:
Front design data placement
Left sleeve placement:
Left sleeve design data placement
Note depending on the type and quantity of the placement additional fees might apply.

Layers

Layers are what is printed in each placement, and there can be up to 5 of them per one placement. The layers are printed on top of each other with the 0th layer being the furthest back and the 4th element being on top of all other layers.

API supports only one layer type - file.

Layer diagram

Layers are defined as an array per placement:

...
  "layers": [
    {
      "type": "file",
      "url": "https://picsum.photos/200",
      "layer_options": [
        {
          "name": "thread_colors",
          "value": [
            "#FFFFFF"
          ]
        }
      ],
      "position": {
        "width": 640,
        "height": 640,
        "left": 0,
        "top": 0
      }
    }
  ]
...

Layer Positioning

You can specify the image position inside the print area by providing a position object.

Each print area has specific dimensions, by default our system will assume that your file has to fit into those limitations and not exceed them. The (0,0) point is always located in the top left corner of the print area.

Note all values are in inches.

Example of positioning the 450x450 image on the front placement

Position Mockup Payload
Top left Top left mockup
  "position": {
    "area_width": 1800,
    "area_height": 2400,
    "width": 450,
    "height": 450,
    "top": 0,
    "left": 0
  }
Top middle Top left mockup
"position": {
  "area_width": 1800,
  "area_height": 2400,
  "width": 450,
  "height": 450,
  "top": 0,
  "left": 675
}
Top right Top left mockup
"position": {
  "area_width": 1800,
  "area_height": 2400,
  "width": 450,
  "height": 450,
  "top": 0,
  "left": 1350
}
Middle Top left mockup
"position": {
  "area_width": 1800,
  "area_height": 2400,
  "width": 450,
  "height": 450,
  "top": 975,
  "left": 675
}
Bottom left Top left mockup
"position": {
  "area_width": 1800,
  "area_height": 2400,
  "width": 450,
  "height": 450,
  "top": 1950,
  "left": 0
}
Bottom middle Top left mockup
"position": {
  "area_width": 1800,
  "area_height": 2400,
  "width": 450,
  "height": 450,
  "top": 1950,
  "left": 675
}
Bottom right Top left mockup
"position": {
  "area_width": 1800,
  "area_height": 2400,
  "width": 450,
  "height": 450,
  "top": 1950,
  "left": 1350
}

Options

Apart from placement and layers you can also specify options.

# Example of option data.
{
  "name": "unlimited_color",
  "value": true
}

Option always consist of the name of the option and the value. Value of the option can be different depending on the option type but they are always predefined for the specified product. You can always check what options and what values are available for a specific product by checking Retrieve a single catalog product

Options can be specified on three levels:

  • Product options - Those options specify additional design options for an entire product. E.g. inside_pocket allows you to define if a product should be fulfilled with an additional inside pocket. Or stitch_color lets you choose the stitch colors that will be used to stitch back All-Over print products.
  • Placement options - They specify options for an entire placement. Currently, the only placement option is unlimited_color which if specified causes the placement to be fulfilled using Unlimited Color embroidery
  • Layer options - Specify additional parameters for a single layer. E.g. 3d_puff option if set to true causes that particular layer to use 3D puff embroidery.

Order Customization

Packing Slip Customization

The packing slip information can be customized according to the store’s specific requirements. Some of the options are: a custom logo, the name of the store, customer service email/phone, and more.

The packing slip fields can be configured at the store level (in the Dashboard at Settings > Stores > Branding > Packing slip section.) and overridden for a specific order.

To override the packing slip settings for the order, you can use packing_slip fields for each order.

POST https://api.printful.com/v2/orders
Authorization: Bearer {{bearer_token}}
{
    "recipient": {
        "address1": "19749 Dearborn St",
        "city": "Chatsworth",
        "state_code": "CA",
        "state_name": "California",
        "country_code": "US",
        "zip": "91311"
    },
    "customization": {
        "packing_slip": {
            "email": "[email protected]",
            "phone": "+48000000000",
            "message": "this is a message",
            "logo_url": "https://example.com/image.jpg",
            "store_name": "a store"
        }
    }
}

Below you can find an example or a packing slip for a shipment with explained fields.

packing slip

Field annotations:

  • (1) Barcode unique for the shipment.
  • (2) Store logo defined in the store settings or overridded using packing_slip.logo_url field.
  • (3) The date of the shipment.
  • (4) Packing slip number consisting of order and shipment IDs in Printful database, divided with a hyphen.
  • (5) The country from which the shipment is made. If the recipient is in the United States, this field will be absent.
  • (6) Recipient address with phone, without email address.
  • (7) Store name. This can be overridden using packing_slip.store_name.
  • (8) The address to which the shipment should be returned. By default it will be a Printful’s return address, but you can set your own address in the store settings (Settings > Stores > Returns > Return address section).
  • (9) The customer service phone number defined in the store settings or overridden using packing_slip.phone field.
  • (10) The customer service email address defined in the store settings or overridden using packing_slip.email field.
  • (11) Gift message. This is only present if the gift field was provided in the order request.
  • (12) The order creation date.
  • (13) Printful Order ID which can be overridden using packing_slip.custom_order_id field.
  • (14) The list of order items with quantities. The items’ display names are localized, using the recipient’s country and include variant information such as color and size e.g. „Unisex Staple T-Shirt | Bella + Canvas 3001 ( Lilac / M)”.
  • (15) The packing slip message defined in the store settings or overridden using packing_slip.message field.

Gift

The order gift option is part of the order customization and contains two properties: subject and message. This option allows users to add a custom note that will be seen by the final customer who receives the product.

POST https://api.printful.com/v2/orders
Authorization: Bearer {{bearer_token}}
{
    "recipient": {
        "address1": "19749 Dearborn St",
        "city": "Chatsworth",
        "state_code": "CA",
        "state_name": "California",
        "country_code": "US",
        "zip": "91311"
    },
    "customization": {
        "gift": {
            "subject": "To John",
            "message": "Happy birthday!"
        }
    }
}

Notes for Beta

The Orders endpoints for the V2 Beta are incomplete. Some V1 endpoints will still need to be used to achieve certain functionality.

Order Cost Calculations

Order costs are calculated asynchronously. This means when you create or update an order you are likely to see a response from the API with costs and retail_costs fields set to null and "calculation_status": "calculating".

"costs": {
  "calculation_status": "calculating",
  "currency": null,
  "subtotal": null,
  "discount": null,
  "shipping": null,
  "digitization": null,
  "additional_fee": null,
  "fulfillment_fee": null,
  "retail_delivery_fee": null,
  "tax": null,
  "vat": null,
  "total": null
},
"retail_costs": {
  "calculation_status": "calculating",
  "currency": "USD",
  "subtotal": "0.00",
  "discount": "1.00",
  "shipping": "0.00",
  "tax": "0.00",
  "vat": "0.00",
  "total": null
},

Once the costs and retail costs are calculated the "calculation_status" will change the status to "done"

"costs": {
  "calculation_status": "done",
  "currency": "USD",
  "subtotal": "107.50",
  "discount": "0.00",
  "shipping": "14.84",
  "digitization": "0.00",
  "additional_fee": "0.00",
  "fulfillment_fee": "0.00",
  "retail_delivery_fee": "0.00",
  "tax": "11.20",
  "vat": "0.00",
  "total": "133.54"
},
"retail_costs": {
  "calculation_status": "done",
  "currency": "USD",
  "subtotal": "0.00",
  "discount": "1.00",
  "shipping": "0.00",
  "tax": "0.00",
  "vat": "0.00",
  "total": "134.54"
},

If you are subscribed to the order_updated webhook event, you will receive an event when the calculation is finished.

Retrieve a list of orders

Retrieve a list of orders from a specific store. The order list will be paginated with twenty items per page by default.

Authorizations:
OAuth
query Parameters
limit
integer [ 1 .. 100 ]
Default: 20

The number of results to return per page.

offset
integer >= 0
Default: 0
Examples:
  • offset=100 - Return results after the initial 100

The number of results to not include in the response starting from the beginning of the list.

This can be used to return results after the initial 100. For example, sending offset 100

header Parameters
X-PF-Store-Id
string

Use this to specify which store you want to use (required only for account level token).

The store IDs can be retrieved with the Get basic information about stores endpoint.

Responses

Response Schema: application/json
required
Array of objects (OrderSummary)
required
object (Paging)

Paging information

required
object

HATEOAS links

Response samples

Content type
application/json
{}

Create a new order

This endpoint allows the creation of a new order in which the default status will be draft.

Authorizations:
OAuth
header Parameters
X-PF-Store-Id
string

Use this to specify which store you want to use (required only for account level token).

The store IDs can be retrieved with the Get basic information about stores endpoint.

Request Body schema: application/json

POST request body

external_id
string

Order ID from the external system

shipping
string

Shipping method. Defaults to 'STANDARD'

required
object (Address)

The recipient data.

required
Array of any

Array of order items

object (Customization)

The Order's customization values

object (RetailCosts-2)

Retail costs

Responses

Response Schema: application/json
required
object (Order)

Order

Request samples

Content type
application/json
{
  • "external_id": "4235234213",
  • "shipping": "STANDARD",
  • "recipient": {
    },
  • "order_items": [
    ],
  • "customization": {
    },
  • "retail_costs": {
    }
}

Response samples

Content type
application/json
{
  • "data": {
    }
}

Retrieve a single order

Retrieve a single order from the specified store. The result object will contain links to the same resource, order items, and shipments.

Authorizations:
OAuth
path Parameters
required
integer or string

Order ID (integer) or Order External ID (string prepended with "@" symbol)

header Parameters
X-PF-Store-Id
string

Use this to specify which store you want to use (required only for account level token).

The store IDs can be retrieved with the Get basic information about stores endpoint.

Responses

Response Schema: application/json
required
object (Order)

Order

Response samples

Content type
application/json
{
  • "data": {
    }
}

Delete an order

Warning: The DELETE HTTP method in version 2 of order in the API will delete the order if the order can be deleted. This is distinct from version 1 where the DELETE method will actually cancel the order rather than delete it. Please, keep this in mind if you are migrating to version 2 from version 1

Delete the order if it can be deleted. An order can be deleted if it's status is draft, failed or cancelled. The order must also have not been charged yet and there must be no payments pending.

Authorizations:
OAuth
path Parameters
required
integer or string

Order ID (integer) or Order External ID (string prepended with "@" symbol)

header Parameters
X-PF-Store-Id
string

Use this to specify which store you want to use (required only for account level token).

The store IDs can be retrieved with the Get basic information about stores endpoint.

Responses

Response samples

Content type
application/json
{
  • "code": 401,
  • "result": "Malformed Authorization header.",
  • "error": {
    }
}

Update an order

Make a partial update of an order.

Authorizations:
OAuth
path Parameters
required
integer or string

Order ID (integer) or Order External ID (string prepended with "@" symbol)

header Parameters
X-PF-Store-Id
string

Use this to specify which store you want to use (required only for account level token).

The store IDs can be retrieved with the Get basic information about stores endpoint.

Request Body schema: application/json

PATCH request body

external_id
string

Order ID from the external system

shipping
string

Shipping method. Defaults to 'STANDARD'

object (Address)

The recipient data.

Array of any

Array of order items

object (Customization)

The Order's customization values

object

Retail costs

Responses

Response Schema: application/json
required
object (Order)

Order

Request samples

Content type
application/json
{
  • "external_id": "4235234213",
  • "shipping": "STANDARD",
  • "recipient": {
    },
  • "order_items": [
    ],
  • "customization": {
    },
  • "retail_costs": {
    }
}

Response samples

Content type
application/json
{
  • "data": {
    }
}

Confirm an order

This endpoint allows customers to confirm the order and start the fulfillment in the production facility.

Authorizations:
OAuth
path Parameters
required
integer or string

Order ID (integer) or Order External ID (string prepended with "@" symbol)

header Parameters
X-PF-Store-Id
string

Use this to specify which store you want to use (required only for account level token).

The store IDs can be retrieved with the Get basic information about stores endpoint.

Responses

Response Schema: application/json
required
object (Order)

Order

required
object

HATEOAS links

Response samples

Content type
application/json
{}

Retrieve a list of order items

This endpoint retrieves the list of items that belong to the order.

Authorizations:
OAuth
path Parameters
required
integer or string

Order ID (integer) or Order External ID (string prepended with "@" symbol)

query Parameters
type
string

Type of items returned (order_item, branding_item). By default all items are returned.

limit
integer [ 1 .. 100 ]
Default: 20

The number of results to return per page.

offset
integer >= 0
Default: 0
Examples:
  • offset=100 - Return results after the initial 100

The number of results to not include in the response starting from the beginning of the list.

This can be used to return results after the initial 100. For example, sending offset 100

header Parameters
X-PF-Store-Id
string

Use this to specify which store you want to use (required only for account level token).

The store IDs can be retrieved with the Get basic information about stores endpoint.

Responses

Response Schema: application/json
required
Array of any
required
object

HATEOAS links

Response samples

Content type
application/json
{}

Create a new order item

This endpoint allows the creation of a new item that will be added to an existing order.

Authorizations:
OAuth
path Parameters
required
integer or string

Order ID (integer) or Order External ID (string prepended with "@" symbol)

header Parameters
X-PF-Store-Id
string

Use this to specify which store you want to use (required only for account level token).

The store IDs can be retrieved with the Get basic information about stores endpoint.

Request Body schema: application/json
required

POST request body

source
required
string

Catalog source

catalog_variant_id
required
integer

ID of catalog variant

external_id
string or null (ItemExternalId)

Item user specified external ID

quantity
integer

Item quantity

retail_price
string

Item retail price

name
string

Item custom name

required
Array of objects (PlacementsList)

Each entry in this list represents a placement on the physical product and the design that will be printed in that location.

Array of any (ProductOptions)

List of product options

Responses

Response Schema: application/json
required
Array of any
required
object

HATEOAS links

Request samples

Content type
application/json
Example
{
  • "source": "catalog",
  • "catalog_variant_id": 4011,
  • "external_id": "123_abc",
  • "quantity": 1,
  • "retail_price": "10.00",
  • "name": "Custom name",
  • "placements": [
    ],
  • "product_options": [
    ]
}

Response samples

Content type
application/json
{}

Retrieve a single order item

This endpoint will retrieve a single order item specified in the request.

Authorizations:
OAuth
path Parameters
required
integer or string

Item ID (integer) or Item External ID (string prepended with "@" symbol)

required
integer or string

Order ID (integer) or Order External ID (string prepended with "@" symbol)

header Parameters
X-PF-Store-Id
string

Use this to specify which store you want to use (required only for account level token).

The store IDs can be retrieved with the Get basic information about stores endpoint.

Responses

Response Schema: application/json
required
any
required
object

HATEOAS links

Response samples

Content type
application/json
{
  • "data": {
    },
}

Update an order item

Make a partial update of an order item. NOTE that the source of the order item can't be changed via a PATCH request, to create an order item from another source you must delete the current one and add a new one.

path Parameters
required
integer or string

Item ID (integer) or Item External ID (string prepended with "@" symbol)

required
integer or string

Order ID (integer) or Order External ID (string prepended with "@" symbol)

header Parameters
X-PF-Store-Id
string

Use this to specify which store you want to use (required only for account level token).

The store IDs can be retrieved with the Get basic information about stores endpoint.

Request Body schema: application/json
required

PATCH request body

source
required
string

Catalog source

catalog_variant_id
required
integer

ID of catalog variant

external_id
string or null (ItemExternalId)

Item user specified external ID

quantity
integer

Item quantity

retail_price
string

Item retail price

name
string

Item custom name

required
Array of objects (PlacementsList)

Each entry in this list represents a placement on the physical product and the design that will be printed in that location.

Array of any (ProductOptions)

List of product options

Responses

Response Schema: application/json
required
Array of any
required
object

HATEOAS links

Request samples

Content type
application/json
Example
{
  • "source": "catalog",
  • "catalog_variant_id": 4011,
  • "external_id": "123_abc",
  • "quantity": 1,
  • "retail_price": "10.00",
  • "name": "Custom name",
  • "placements": [
    ],
  • "product_options": [
    ]
}

Response samples

Content type
application/json
{}

Delete Order Item

Remove a single item from the order.

Authorizations:
OAuth
path Parameters
required
integer or string

Item ID (integer) or Item External ID (string prepended with "@" symbol)

required
integer or string

Order ID (integer) or Order External ID (string prepended with "@" symbol)

header Parameters
X-PF-Store-Id
string

Use this to specify which store you want to use (required only for account level token).

The store IDs can be retrieved with the Get basic information about stores endpoint.

Responses

Response samples

Content type
application/json
{
  • "code": 400,
  • "result": "Missing required parameters",
  • "error": {
    }
}

Retrieve a list of shipments

Shipments contain information about how and when your orders items will be delivered and fulfilled.

Authorizations:
OAuth
path Parameters
required
integer or string

Order ID (integer) or Order External ID (string prepended with "@" symbol)

query Parameters
limit
integer [ 1 .. 100 ]
Default: 20

The number of results to return per page.

offset
integer >= 0
Default: 0
Examples:
  • offset=100 - Return results after the initial 100

The number of results to not include in the response starting from the beginning of the list.

This can be used to return results after the initial 100. For example, sending offset 100

header Parameters
X-PF-Store-Id
string

Use this to specify which store you want to use (required only for account level token).

The store IDs can be retrieved with the Get basic information about stores endpoint.

Responses

Response Schema: application/json
required
Array of objects (Shipment)
required
object
required
object (Paging)

Paging information

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "_links": {
    },
  • "paging": {
    }
}

Retrieve an invoice

Returns the invoice for an order as a base64 encoded document. Decoding the base64 content can be different depending on the client, for most browsers this format will alow you to view and display the invoice data:application/pdf;base64,{the_base_64_content_string}.

Authorizations:
OAuth
path Parameters
required
integer or string

Order ID (integer) or Order External ID (string prepended with "@" symbol)

header Parameters
X-PF-Store-Id
string

Use this to specify which store you want to use (required only for account level token).

The store IDs can be retrieved with the Get basic information about stores endpoint.

Responses

Response Schema: application/json
required
object

Response samples

Content type
application/json
{}

Retrieve an order estimation task

Retrieve an order cost estimation task from a specific store. Estimation results are only available for one hour after cost estimation task is done.

Authorizations:
OAuth
query Parameters
id
required
string

Order estimation task ID.

header Parameters
X-PF-Store-Id
string

Use this to specify which store you want to use (required only for account level token).

The store IDs can be retrieved with the Get basic information about stores endpoint.

Responses

Response Schema: application/json
required
object (OrderEstimationTaskSummary)

Order estimation task summary

Response samples

Content type
application/json
{
  • "data": {
    }
}

Create a new order estimation task

Use this endpoint to estimate orders with items.

Authorizations:
OAuth
header Parameters
X-PF-Store-Id
string

Use this to specify which store you want to use (required only for account level token).

The store IDs can be retrieved with the Get basic information about stores endpoint.

Request Body schema: application/json

POST request body

required
object (Address)

The recipient data.

required
Array of any

Array of order items

object (RetailCosts-2)

Retail costs

Responses

Response Schema: application/json
required
object (OrderEstimationTaskSummary)

Order estimation task summary

Request samples

Content type
application/json
{
  • "recipient": {
    },
  • "order_items": [
    ],
  • "retail_costs": {
    }
}

Response samples

Content type
application/json
{
  • "data": {
    }
}

Files v2

To avoid the need to upload every file again when the same item is ordered, your print files are stored in the File Library and can be reused.

You can use this API to directly add files to the library, and later use File IDs when creating orders. However, the more convenient way is to specify the files by URL at the same time the order is created.

Most probably you will never need to use this API - just specify the file URL when creating orders and the files will be added automatically.

File processing can be very time-consuming, so they are processed asynchronously. After you add a file, it is saved with the status waiting and downloaded and processed later. Afterward, the status is changed to ok if the file was loaded successfully and was a valid image file or failed if the process did not succeed. Some file metadata fields like dimensions and resolution are only filled in after the file has been processed.

If an order with a file has been confirmed before the file was processed, and the file turns out to be invalid, then the order is reverted to a failed state and needs to be corrected and confirmed again.

If you try to add a file that has an identical URL to an already existing file, then no new file is created, and the system returns the old one without refreshing its contents.

Remember
If you have changed the original, make sure that the URL is changed as well for future orders, otherwise the old version will be reused.

You can add a “last modified” timestamp to the end of the URL to ensure that the URL is different for changed files.

Files that are added through the API can be set not to show up in the File library on the web, just set the visible attribute to false when creating them.

Caution: API endpoint "Get list of files" (/files) is removed and can no longer be used. Calling this endpoint will return a HTTP 410 (Gone) response.

Add a new file

Adds a new File to the library by providing URL of the file.

If a file with identical URL already exists, then the original file is returned. If a file does not exist, a new file is created.

See examples

Authorizations:
OAuth
header Parameters
X-PF-Store-Id
string

Use this to specify which store you want to use (required only for account level token).

The store IDs can be retrieved with the Get basic information about stores endpoint.

Request Body schema: application/json
required

POST request body

role
string
Default: "printfile"
Enum: "printfile" "label" "preview"

Role of the file

url
required
string

Source URL where the file is to be downloaded from. The use of .ai, .psd, and .tiff files has been deprecated, if your application uses these file types or accepts these types from users you will need to add validation.

filename
string

If the filename is not provided, and something looking like a filename is present in the URL (e.g. "something.jpg"), it will be used. Otherwise, it will default to {file_id}.{file_extension}, with file extension determined based on the media type of the file.

visible
boolean
Default: true

Show file in the Printfile Library

Responses

Response Schema: application/json
required
object (File)

Information about the File

Request samples

Content type
application/json
{
  • "role": "printfile",
  • "url": "​https://www.example.com/files/tshirts/example.png",
  • "filename": "shirt1.png",
  • "visible": true
}

Response samples

Content type
application/json
{}

Retrieve a single file from the file library

Get basic information about the file stored in the file library

Authorizations:
OAuth
path Parameters
id
required
integer

File ID.

Responses

Response Schema: application/json
required
object (File)

Information about the File

Response samples

Content type
application/json
{}

Countries v2

To create an order, you have to use country and state codes to specify the recipient address. Both country code and state code are mandatory for orders to the USA, Canada and Australia. For other countries only the country code is needed to create an order.

Country codes are based on the ISO 3166-1 alpha-2 standard and are two letters long.

State codes are based on the ISO 3166-2 standard by omitting the country code part of the code and are used only for the USA, Canada, Japan and Australia.

All state/country codes that Printful accepts can be listed by this API.

Retrieve a list of countries

Get information about all countries where Printful is available

Authorizations:
OAuth
query Parameters
offset
integer >= 0
Default: 0
Examples:
  • offset=100 - Return results after the initial 100

The number of results to not include in the response starting from the beginning of the list.

This can be used to return results after the initial 100. For example, sending offset 100

limit
integer [ 1 .. 250 ]
Default: 20

The number of results to return per page.

Responses

Response Schema: application/json
required
Array of objects (Country)
required
object (Paging)

Paging information

required
object

HATEOAS links

Response samples

Content type
application/json
{}

Shipping Rates v2

Rate limiting: The default rate limit is 120 requests per 60 seconds.

Warning: If the summary item quantity count exceeds 100 then the rate limit is changed to 5 requests per 60 seconds.

A 60 seconds lockout is applied if request count is exceeded.

Recipient in shipping rates estimates

When making a shipping rates estimate the only data that is necessary is the country code, and state code in the case of the case of the United States, Canada, and Australia. This allows for an estimate to be retrieved for a customer before their address is known, however the more information provided the more accurate the estimate will be.

Calculate Shipping Rates

Returns available shipping options and rates for the given list of products.

Authorizations:
OAuth
header Parameters
X-PF-Store-Id
string

Use this to specify which store you want to use (required only for account level token).

The store IDs can be retrieved with the Get basic information about stores endpoint.

X-PF-Language
string

Use this to specify which locale you would like to use in the responses, for some endpoints this can affect translations.

Request Body schema: application/json

POST request body

required
object (Address)

The recipient data.

required
Array of any

Array of order items

currency
string

Currency code in which the rate is returned. If not provided will use the default currency for the store.

Responses

Response Schema: application/json
required
Array of objects

Request samples

Content type
application/json
{
  • "recipient": {
    },
  • "order_items": [
    ],
  • "currency": "string"
}

Response samples

Content type
application/json
{
  • "data": [
    ]
}

Warehouse Products v2

Warehouse Products v2

Retrieve a list of warehouse products

This endpoint returns paginated results containing detailed information about warehouse products, including their variants, stock levels, and dimensions.

Authorizations:
OAuth
query Parameters
filter[name*]
string

Wildcard match of the name value. Note that the value will be matched if the name property contains the value anywhere in the string.

limit
integer [ 1 .. 100 ]
Default: 20

The number of results to return per page.

offset
integer >= 0
Default: 0
Examples:
  • offset=100 - Return results after the initial 100

The number of results to not include in the response starting from the beginning of the list.

This can be used to return results after the initial 100. For example, sending offset 100

header Parameters
X-PF-Store-Id
string

Use this to specify which store you want to use (required only for account level token).

The store IDs can be retrieved with the Get basic information about stores endpoint.

Responses

Response Schema: application/json
required
Array of objects
required
object (Paging)

Paging information

required
object

HATEOAS links

Response samples

Content type
application/json
{}

Retrieve a single warehouse product

Get information about a single warehouse product with it's stock location.

Authorizations:
OAuth
path Parameters
warehouse_product_id
required
integer

Warehouse Product ID.

header Parameters
X-PF-Store-Id
string

Use this to specify which store you want to use (required only for account level token).

The store IDs can be retrieved with the Get basic information about stores endpoint.

Responses

Response Schema: application/json
required
object

Response samples

Content type
application/json
{}

Mockup Generator v2

This resource is used to visualize how the designed products will look like. Since this is a resource-heavy operation we process the requests asynchronously. That means that you won't get the results immediately, and instead you will get task ID which you could use to retrieve the mockups once they are done using Retrieve mockup generator tasks. You can also subscribe to a webhook Mockup generator task finished event to be notified once the tasks finish processing.

To create a mockup you need to specify:

While placements specifies how the catalog product should look like, the mockup_style_ids define how the mockups themselves should look like. You can find available mockup styles for a product by requesting Retrieve catalog product mockup styles.

To give a little bit more context on how to use product mockup styles see the table below:

The example product is Bella Canvas 3001 with ID 71.

Mockup styles Mockups
    {
        "style_id": 1115,
        "style_name": "Men's",
        "view_name": "Front"
    }
Men's front mockup
    {
        "style_id": 1103,
        "style_name": "Men's",
        "view_name": "Left sleeve"
    }
Men's left sleeve mockup
    {
        "style_id": 1117,
        "style_name": "Women's",
        "view_name": "Front"
    }
Women's front mockup
    {
        "style_id": 1107,
        "style_name": "Women's",
        "view_name": "Left sleeve"
    }
Women's left sleeve mockup
    {
        "style_id": 768,
        "style_name": "Women's Lifestyle",
        "view_name": "Front"
    }
Women's lifestyle front mockup
    {
        "style_id": 770,
        "style_name": "Women's Lifestyle",
        "view_name": "Left"
    }
Women's lifestyle left mockup
    {
        "style_id": 849,
        "style_name": "Flat",
        "view_name": "Front"
    }
Flat front mockup
    {
        "style_id": 931,
        "style_name": "On hanger",
        "view_name": "Front"
    }
On hanger front mockup

Mockups from the product templates

Instead of creating a mockups from catalog variants data you can generate them from a product template. In that case all you need is:

Important: All the catalog variants specified in the request must also be defined in the product template, otherwise an error will be returned.

Throttling and daily file limit

An account is allowed to make a number of mockup generation requests per minute. The limit is:

  • 2 requests per minute for new stores;
  • 10 requests per minute for stores with at least $10.00 worth of fulfilled orders.

Additionally, there is a limit of 20,000 files that can be generated daily by each environment.

Number of generated files

There will be one mockup file returned for each valid combination of Catalog Variant, mockup style and placement within one product object.

If the same file would be generated for two or more combinations (for example, for different sizes of a T-Shirt in the same color), it will only be generated once and the same URL will be returned for each of these combinations. If only one file is generated it will count as one file toward the daily limit.

Create Mockup Generator tasks

Create Mockup Generator tasks

Authorizations:
OAuth
header Parameters
X-PF-Store-Id
string

Use this to specify which store you want to use (required only for account level token).

The store IDs can be retrieved with the Get basic information about stores endpoint.

Request Body schema: application/json

This action schedules asynchronous mockup generation tasks. In the response of this request id will be returned which can be used to retrieve the result of the tasks Retrieve mockup generator tasks. In addition, the webhook event will be sent informing about the task completion, if the correct webhook has been subscribed to Mockup generator task finished event. You can subscribe to webhook events by using Set up event configuration.

format
string
Enum: "jpg" "png"

Generated file format. PNG will have a transparent background, JPG will have a smaller file size.

required
Array of objects (MockupProduct)

Responses

Response Schema: application/json
required
Array of objects (MockupGeneratorTask)
required
object

HATEOAS links

Request samples

Content type
application/json
{
  • "format": "jpg",
  • "products": [
    ]
}

Response samples

Content type
application/json
{}

Retrieve Mockup Generator tasks

Returns result of Mockup Generator tasks

Authorizations:
OAuth
query Parameters
id
required
Array of strings
Examples:
  • id=421699980 - Return single specified mockup generator task result.
  • id=421699980,421699981 - Return multiple specified mockup generator task results.

One or more mockup generator task IDs to return only specified tasks. The IDs can be found in the response of the operation Create mockup generator tasks.

limit
integer [ 1 .. 100 ]
Default: 20

The number of results to return per page.

offset
integer >= 0
Default: 0
Examples:
  • offset=100 - Return results after the initial 100

The number of results to not include in the response starting from the beginning of the list.

This can be used to return results after the initial 100. For example, sending offset 100

Responses

Response Schema: application/json
required
Array of objects (MockupGeneratorTask)
required
object (Paging)

Paging information

required
object

HATEOAS links

Response samples

Content type
application/json
{}

Webhook v2

Webhooks are an API feature that allows your system to receive notifications about certain events.

When an event occurs, for example one of the products you use comes back in stock, the Printful server will make a POST request to your defined URL that will contain a JSON object in the request body. Your server has to respond with HTTP status 2xx OK, otherwise, the request will be retried in increasing intervals (after 1, 4, 16, 64, 256 and 1024 minutes).

The JSON object will always contain these attributes:

type string Event type
occurred_at timestamp Event time
retries integer Number of previous attempts to deliver this webhook event
store_id integer ID of the store that the event occurred to
data Object Additional data, depending on the event type

Currently, our Webhook Simulator doesn't support the v2 webhooks.

Event signing

Since the webhook URL used to accept the events needs to be publicly availably, it's important to be able to verify if the event originates from our servers or was sent by someone else who knows the URL.

That's why we introduced event signing in Webhook v2.

Webhook settings are associated with a public and a secret key. The public key is used to identify the specific settings (you may use the same URL for different configurations) and the secret key is used to generate and verify the event signature.

We're using HMAC-SHA256 hash to create the signature. For tests, you may find an online or offline tool and check if you get the same hash for the event data you receive and the configuration's secret key.

Please note that in the secret_key field we return the hexadecimal representation of the secret key. It means that you need to decode it before passing it to the tool or method that calculates the signature, unless it supports keys in hexadecimal format.

For actual usage, we strongly recommend to incorporate the signature verification in the event handling process.

If you find that you receive an event with invalid or missing signature, you should ignore the event.

You may investigate the situation, starting with verifying if your configuration is correct. It's possible you used wrong secret key to generate the signature on your side or generated it for the formatted event content instead of the raw content etc.

If you didn't find an explanation, you may contact us with the event details (content, your URL, event time) so we can check if we sent such an event and find out why the signature is invalid.

Expiration time

It's possible to specify the expiration time of the configuration. If you decide to use this option, you will be forced to resubscribe which will generate a new key pair. You may simply send the GET request when the configuration is still valid and use the returned data to create the new configuration.

If the configuration is already expired and you don't have the data saved somewhere, a regular GET request will result in a 404 Not Found response with a message explaining what needs to be done: "The settings are expired. To view them, please use query param show_expired with value true."

You may then use show_expired param with value true to retrieve the configuration and use it to resubscribe.

Please note that once the new configuration is saved, the new secret key will be used to sign the events. It needs to be updated in your code as soon as possible to avoid invalid signature warnings.

Shipment sent Webhook

Is called when a shipment with all or part of the ordered items is shipped.

If the order is shipped in multiple shipments, this event will be called for every shipment sent.

If some items are reshipped, a shipping notification will be sent again for the same items.

Request Body schema: application/json

Shipment sent.

type
required
string
Value: "shipment_sent"

Event type

occurred_at
required
string <date-time>

Event time

retries
required
integer

Number of previous attempts to deliver this webhook event

store_id
required
integer

ID of the store that the event occurred to

required
object (ShipmentInfo)

Shipment and order data

Responses

Request samples

Content type
application/json
{
  • "type": "shipment_sent",
  • "occurred_at": "2023-04-05T06:07:08Z",
  • "retries": 2,
  • "store_id": 12,
  • "data": {
    }
}

Shipment returned Webhook

Is called when a shipment is processed as returned to the fulfillment facility. To learn more about the reasons why a shipment might be returned, take a look at Printful's Return Policy

Request Body schema: application/json

Shipment returned.

type
required
string
Value: "shipment_returned"

Event type

occurred_at
required
string <date-time>

Event time

retries
required
integer

Number of previous attempts to deliver this webhook event

store_id
required
integer

ID of the store that the event occurred to

required
object (ReturnInfo)

Shipment and order data

Responses

Request samples

Content type
application/json
{
  • "type": "shipment_returned",
  • "occurred_at": "2023-04-05T06:07:08Z",
  • "retries": 2,
  • "store_id": 12,
  • "data": {
    }
}

Shipment out of stock Webhook

Is called when a shipment goes out of stock (is_out_of_stock = true) or comes back in stock (is_out_of_stock = false).

Authorizations:
OAuth
Request Body schema: application/json

Shipment out of stock/back in stock.

type
required
string
Value: "shipment_out_of_stock"

Event type

occurred_at
required
string <date-time>

Event time

retries
required
integer

Number of previous attempts to deliver this webhook event

store_id
required
integer

ID of the store that the event occurred to

required
object (ShipmentOutOfStockInfo)

Shipment and order data

Responses

Request samples

Content type
application/json
{
  • "type": "shipment_out_of_stock",
  • "occurred_at": "2023-04-05T06:07:08Z",
  • "retries": 2,
  • "store_id": 12,
  • "data": {
    }
}

Order created Webhook

Is called when the order is first created.

Request Body schema: application/json

Order created.

type
required
string

Event type

occurred_at
required
string <date-time>

Event time

retries
required
integer

Number of previous attempts to deliver this webhook event

store_id
required
integer

ID of the store that the event occurred to

required
object (CreateInfo)

Created order data

Responses

Request samples

Content type
application/json
{
  • "type": "order_created",
  • "occurred_at": "2023-04-05T06:07:08Z",
  • "retries": 2,
  • "store_id": 12,
  • "data": {
    }
}

Order updated Webhook

Is called when an existing order gets updated for any reason - including things that are covered with other webhooks like order_canceled.

Request Body schema: application/json

Order updated.

type
required
string

Event type

occurred_at
required
string <date-time>

Event time

retries
required
integer

Number of previous attempts to deliver this webhook event

store_id
required
integer

ID of the store that the event occurred to

required
object (UpdateInfo)

Updated order data

Responses

Request samples

Content type
application/json
{
  • "type": "order_updated",
  • "occurred_at": "2023-04-05T06:07:08Z",
  • "retries": 2,
  • "store_id": 12,
  • "data": {
    }
}

Order failed Webhook

Is called when a confirmed order changes its status to failed.

It can happen, for example, if printfiles can not be downloaded, are not valid image files or when there is a payment failure.

Request Body schema: application/json

Order failed.

type
required
string

Event type

occurred_at
required
string <date-time>

Event time

retries
required
integer

Number of previous attempts to deliver this webhook event

store_id
required
integer

ID of the store that the event occurred to

required
object (FailureInfo)

Failure reason and order data

Responses

Request samples

Content type
application/json
{
  • "type": "order_failed",
  • "occurred_at": "2023-04-05T06:07:08Z",
  • "retries": 2,
  • "store_id": 12,
  • "data": {
    }
}

Order canceled Webhook

Is called when a confirmed order changes its status to canceled.

It can happen when a submitted order is canceled from the dashboard or through the API or when the order is canceled by the Printful staff.

Request Body schema: application/json

Order canceled.

type
required
string

Event type

occurred_at
required
string <date-time>

Event time

retries
required
integer

Number of previous attempts to deliver this webhook event

store_id
required
integer

ID of the store that the event occurred to

required
object (CancelInfo)

Cancel reason and order data

Responses

Request samples

Content type
application/json
{
  • "type": "order_canceled",
  • "occurred_at": "2023-04-05T06:07:08Z",
  • "retries": 2,
  • "store_id": 12,
  • "data": {
    }
}

Catalog stock updated Webhook

Is called when stock is updated for some of a product's variants.

Contains information about the availability of product variants that have changed.

Request Body schema: application/json

Catalog stock updated.

type
required
string
Value: "catalog_stock_updated"

Event type

occurred_at
required
string <date-time>

Event time

retries
required
integer

Number of previous attempts to deliver this webhook event

store_id
required
integer

ID of the store that the event occurred to

required
Array of objects (ChangedAvailabilities)

Responses

Request samples

Content type
application/json
{
  • "type": "catalog_stock_updated",
  • "occurred_at": "2023-04-05T06:07:08Z",
  • "retries": 2,
  • "store_id": 12,
  • "data": [
    ]
}

Catalog price changed Webhook

Is called when a catalog product price has changed.

This webhook is related to the pricing endpoint.

Request Body schema: application/json

Catalog price changed.

type
required
string
Value: "catalog_price_changed"

Event type

occurred_at
required
string <date-time>

Event time

retries
required
integer

Number of previous attempts to deliver this webhook event

store_id
required
integer

ID of the store that the event occurred to

required
object (ProductPriceChangedInfo)

Information about products which catalog product prices changed

Responses

Request samples

Content type
application/json
{
  • "type": "catalog_price_changed",
  • "occurred_at": "2023-04-05T06:07:08Z",
  • "retries": 2,
  • "store_id": 12,
  • "data": {
    }
}

Order put hold Webhook

Is called when order is put on hold.

Request Body schema: application/json

Order put on hold.

type
required
string

Event type

occurred_at
required
string <date-time>

Event time

retries
required
integer

Number of previous attempts to deliver this webhook event

store_id
required
integer

ID of the store that the event occurred to

required
object (OrderStatusChange)

Responses

Request samples

Content type
application/json
{
  • "type": "order_put_hold",
  • "occurred_at": "2023-04-05T06:07:08Z",
  • "retries": 2,
  • "store_id": 12,
  • "data": {
    }
}

Order put hold approval Webhook

Is called when order is put on hold and there are changes that must be approved by the customer before fulfillment. Will contain a confirm hash that can be used to approve changes with the Approval Sheets Api.

Request Body schema: application/json

Order put on hold because it needs customer approval. You will receive an approval sheet with suggested changes and a confirmation hash so you can approve the changes if you agree with them.

type
required
string

Event type

occurred_at
required
string <date-time>

Event time

retries
required
integer

Number of previous attempts to deliver this webhook event

store_id
required
integer

ID of the store that the event occurred to

required
object (OrderRequiresApproval)

Responses

Request samples

Content type
application/json
{}

Order remove hold Webhook

Is called when order is removed from hold.

Request Body schema: application/json

Order removed from on hold.

type
required
string

Event type

occurred_at
required
string <date-time>

Event time

retries
required
integer

Number of previous attempts to deliver this webhook event

store_id
required
integer

ID of the store that the event occurred to

required
object (OrderStatusChange)

Responses

Request samples

Content type
application/json
{
  • "type": "order_remove_hold",
  • "occurred_at": "2023-04-05T06:07:08Z",
  • "retries": 2,
  • "store_id": 12,
  • "data": {
    }
}

Order refunded Webhook

Is called when a confirmed order has been refunded.

Request Body schema: application/json

Order refunded.

type
required
string

Event type

occurred_at
required
string <date-time>

Event time

retries
required
integer

Number of previous attempts to deliver this webhook event

store_id
required
integer

ID of the store that the event occurred to

required
object (RefundInfo)

Refunded amount and order data

Responses

Request samples

Content type
application/json
{
  • "type": "order_refunded",
  • "occurred_at": "2023-04-05T06:07:08Z",
  • "retries": 2,
  • "store_id": 12,
  • "data": {
    }
}

Mockup task finished Webhook

Is called when a Mockup task is finished.

This doesn't necessarily mean that the task has successfully finished

it could also mean that the task has failed to generate.

Request Body schema: application/json

Mockup task finished processing.

type
required
string
Value: "mockup_task_finished"

Event type

occurred_at
required
string <date-time>

Event time

retries
required
integer

Number of previous attempts to deliver this webhook event

store_id
required
integer

ID of the store that the event occurred to

required
object (MockupGeneratorTask)

Result of mockup generator task

Responses

Request samples

Content type
application/json
{}

Shipment put hold Webhook

Is called when a shipment is put on hold

Request Body schema: application/json

Shipment put on hold.

type
required
string

Event type

occurred_at
required
string <date-time>

Event time

retries
required
integer

Number of previous attempts to deliver this webhook event

store_id
required
integer

ID of the store that the event occurred to

object (ShipmentPutOnHold)

Responses

Request samples

Content type
application/json
{
  • "type": "shipment_put_hold",
  • "occurred_at": "2023-04-05T06:07:08Z",
  • "retries": 2,
  • "store_id": 12,
  • "data": {
    }
}

Shipment put hold approval Webhook

Is called when shipment is put on hold and there are changes that must be approved by the customer before fulfillment.

Request Body schema: application/json

Shipment put on hold because it needs customer approval. You will receive an approval sheet with suggested changes and a confirmation hash so you can approve the changes if you agree with them.

type
required
string

Event type

occurred_at
required
string <date-time>

Event time

retries
required
integer

Number of previous attempts to deliver this webhook event

store_id
required
integer

ID of the store that the event occurred to

object (ShipmentRequiresApproval)

Responses

Request samples

Content type
application/json
{}

Shipment remove hold Webhook

Is called when shipment is removed from hold.

Request Body schema: application/json

Shipment removed from on hold.

type
required
string

Event type

occurred_at
required
string <date-time>

Event time

retries
required
integer

Number of previous attempts to deliver this webhook event

store_id
required
integer

ID of the store that the event occurred to

object (ShipmentRemovedHold)

Responses

Request samples

Content type
application/json
{
  • "type": "shipment_remove_hold",
  • "occurred_at": "2023-04-05T06:07:08Z",
  • "retries": 2,
  • "store_id": 12,
  • "data": {
    }
}

Get webhook configuration

Returns a configured webhook URL and a list of webhook event types enabled for the store

Authorizations:
OAuth
query Parameters
show_expired
boolean

If this parameter is passed with value true, expired settings will be returned instead of a 404 warning.

header Parameters
X-PF-Store-Id
string

Use this to specify which store you want to use (required only for account level token).

The store IDs can be retrieved with the Get basic information about stores endpoint.

Responses

Response Schema: application/json
code
integer

Response status code 200

object (WebhookInfo)

Request samples

curl --location --request GET 'https://api.printful.com/v2/webhooks' \
--header 'Authorization: Bearer {oauth_token}'

Response samples

Content type
application/json
{
  • "code": 200,
  • "result": {
    }
}

Set up webhook configuration

Use this endpoint to enable a webhook URL for a store and select webhook event types that will be sent to this URL.

Note that only one webhook configuration can be active for each private OAuth token or app, calling this method will disable the previous webhook configuration.

Setting up the Catalog stock updated webhook requires passing products (currently only IDs are taken into account).

Stock update webhook (catalog_stock_updated) will only include information for the products specified in the products param.

Configuring all other events require the same set of fields with no parameters.

Authorizations:
OAuth
header Parameters
X-PF-Store-Id
string

Use this to specify which store you want to use (required only for account level token).

The store IDs can be retrieved with the Get basic information about stores endpoint.

Request Body schema: application/json
required

POST request body

default_url
string or null

Webhook URL (HTTPS-only) that will receive store's event notifications if no URL is set for the event.

expires_at
string or null <date-time>

Date-time indicating when the configuration should expire. The default value is null meaning it won't expire.

required
Array of objects (EventConfiguration)

Array of enabled webhook event configurations

Responses

Response Schema: application/json
code
integer

Response status code 200

object (WebhookInfo)

Request samples

Content type
application/json
{
  • "default_url": "​https://www.example.com/printful/webhook",
  • "expires_at": "2023-04-05T06:07:08Z",
  • "events": [
    ]
}

Response samples

Content type
application/json
{
  • "code": 200,
  • "result": {
    }
}

Disable webhook support

Removes the webhook URL and all event types from the store.

Authorizations:
OAuth
header Parameters
X-PF-Store-Id
string

Use this to specify which store you want to use (required only for account level token).

The store IDs can be retrieved with the Get basic information about stores endpoint.

Responses

Request samples

curl --location --request DELETE 'https://api.printful.com/v2/webhooks' \
--header 'Content-Type: application/json'

Response samples

Content type
application/json
{
  • "code": 401,
  • "result": "Malformed Authorization header.",
  • "error": {
    }
}

Get event configuration

Returns event configuration for store

Authorizations:
OAuth
path Parameters
eventType
required
string

Event type

query Parameters
show_expired
boolean

If this parameter is passed with value true, expired settings will be returned instead of a 404 warning.

header Parameters
X-PF-Store-Id
string

Use this to specify which store you want to use (required only for account level token).

The store IDs can be retrieved with the Get basic information about stores endpoint.

Responses

Response Schema: application/json
code
integer

Response status code 200

object (EventConfiguration)

Request samples

curl --location --request GET 'https://api.printful.com/v2/webhooks/shipment_sent' \
--header 'Authorization: Bearer {oauth_token}'

Response samples

Content type
application/json
{
  • "code": 200,
  • "result": {
    }
}

Set up event configuration

Use this endpoint to create or replace specific event configuration for a store.

Setting up the Catalog stock updated webhook requires passing products (currently only IDs are taken into account).

Stock update webhook will only include information for the products specified in the products param.

Authorizations:
OAuth
path Parameters
eventType
required
string

Event type

header Parameters
X-PF-Store-Id
string

Use this to specify which store you want to use (required only for account level token).

The store IDs can be retrieved with the Get basic information about stores endpoint.

Request Body schema: application/json
required

POST request body

type
required
string

Event type. The dropdown shows values required for webhook event configuration. During the setup of a new webhook event please check this dropdown if the event does not require additional parameters to be set.

url
string or null

Webhook URL (HTTPS-only) that will receive the event notifications.

required
Array of any

Responses

Response Schema: application/json
code
integer

Response status code 200

object (EventConfiguration)

Request samples

Content type
application/json
Example
{
  • "type": "catalog_stock_updated",
  • "url": "​https://www.example.com/printful/webhook",
  • "params": [
    ]
}

Response samples

Content type
application/json
{
  • "code": 200,
  • "result": {
    }
}

Disable support for event

Disables the event for a store and clears its configuration, leaving other webhooks intact.

Authorizations:
OAuth
path Parameters
eventType
required
string

Event type

header Parameters
X-PF-Store-Id
string

Use this to specify which store you want to use (required only for account level token).

The store IDs can be retrieved with the Get basic information about stores endpoint.

Responses

Request samples

curl --location --request DELETE 'https://api.printful.com/v2/webhooks/shipment_sent' \
--header 'Content-Type: application/json'

Response samples

Content type
application/json
{
  • "code": 401,
  • "result": "Malformed Authorization header.",
  • "error": {
    }
}

Stores v2

Stores v2

Retrieve a single store

Get information about a single store.

Authorizations:
OAuth
path Parameters
store_id
required
integer (InternalId)
Example: 1234

Store ID

header Parameters
X-PF-Store-Id
string

Use this to specify which store you want to use.

The store IDs can be retrieved with the Get basic information about stores endpoint.

Responses

Response Schema: application/json
required
object (StoreSchema)

Information about the Store

Response samples

Content type
application/json
{
  • "data": {
    }
}

Retrieves a list of stores

Retrieves a list of all stores available to the token. If the token is a store level token it will return only the one store, if it is an account level token it will return all stores available to the account.

Authorizations:
OAuth
header Parameters
X-PF-Store-Id
string

Use this to specify which store you want to use.

The store IDs can be retrieved with the Get basic information about stores endpoint.

Responses

Response Schema: application/json
required
Array of objects (StoreSchema)
required
object
required
object (Paging)

Paging information

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "_links": {
    },
  • "paging": {
    }
}

Retrieve statistics for a single store

Returns statistics for specified report types.

You need to specify the report types you want to retrieve in the report_types query parameter as a comma-separated list, e.g. report_types=sales_and_costs,profit.

Note: You cannot get statistics for a period longer than 6 months.

Example

To get statistics in the default currency of a store for sales_and_costs and profit reports for August 2022, you can use the following URL: https://api.printful.com/v2/stores/{id}/statistics?report_types=sales_and_costs,profit&date_from=2022-08-01&date_to=2022-08-31.

Report types

Currently, the following report types are available:

Report type Description
sales_and_costs Detailed information on sales and costs grouped by date.
sales_and_costs_summary Short information on sales and costs grouped by date.
printful_costs Amount paid to Printful for fulfillment and shipping.
profit Profit in the specified period.
total_paid_orders The number of paid orders in the specified period.
costs_by_amount Information on costs by amount grouped by date.
costs_by_product Information on costs grouped by product.
costs_by_variant Information on costs grouped by variant.
average_fulfillment_time Average time it took Printful to fulfill your orders.

The response structure for the specific reports is documented in the response schema (result.store_statistics.[reportName]).

Authorizations:
OAuth
path Parameters
store_id
required
integer

Use this to specify which store you want to use. The store IDs can be retrieved with the Get basic information about stores endpoint.

query Parameters
date_from
required
string <date>
Example: date_from=2022-08-01

The beginning of the period to get the statistics from (date in Y-m-d format).

date_to
required
string <date>
Example: date_to=2022-08-31

The end of the period to get the statistics from (date in Y-m-d format).

currency
string
Example: currency=USD

The currency (3-letter code) to return the statistics in. The store currency will be used by default.

report_types
required
string
Enum: "sales_and_costs" "profit" "average_fulfillment_type" "costs_by_amount" "costs_by_product" "costs_by_variant" "printful_costs" "sales_and_costs_summary" "total_paid_orders"

A comma-separated list of report types to be retrieved.

Responses

Response Schema: application/json
required
object (StoreStatistics)

Statistics for a single store

Response samples

Content type
application/json
{
  • "data": {
    }
}

Approval Sheets v2

Get information about approval sheets.

Retrieve a list of approval sheets

Retrieve a list of approval sheets confirming suggested changes to files of on hold orders.

Authorizations:
OAuth
query Parameters
order_id
integer

Order ID.

header Parameters
X-PF-Store-Id
string

Use this to specify which store you want to use (required only for account level token).

The store IDs can be retrieved with the Get basic information about stores endpoint.

Responses

Response Schema: application/json
required
Array of objects (ApprovalSheet)
required
object (Approval sheet links)

HATEOAS links

Response samples

Content type
application/json
{}

Examples

Catalog API examples

Using size guides

In this example, we'll fetch the size guides for the "Women's Basic Organic T-Shirt | SOL'S 02077" product (ID: 561).

We use the default en_US locale and don't provide the unit parameter, so the measurement values will be returned in inches.

URL: https://api.printful.com/v2/catalog-products/561/sizes

Whole response body
{
  "data": {
    "product_id": 561,
    "available_sizes": [
      "S",
      "M",
      "L",
      "XL",
      "2XL"
    ],
    "size_tables": [
      {
        "type": "measure_yourself",
        "unit": "inches",
        "description": "<p>Measurements are provided by suppliers.<br /><br />US customers should order a size up as the EU sizes for this supplier correspond to a smaller size in the US market.</p>\n<p>Product measurements may vary by up to 2\" (5 cm).&nbsp;</p>",
        "image_url": "https://s3-printful.stage.printful.dev/upload/measure-yourself/6a/6a4fe322f592f2b91d5a735d7ff8d1c0_t?v=1652962720",
        "image_description": "<h6><strong>A Length</strong></h6>\n<p dir=\"ltr\"><span id=\"docs-internal-guid-a3ac3082-7fff-5f98-2623-3eb38d5f43a1\">Place the end of the tape beside the collar at the top of the tee (Highest Point Shoulder). Pull the tape measure t</span><span id=\"docs-internal-guid-a3ac3082-7fff-5f98-2623-3eb38d5f43a1\">o the bottom of the shirt.</span></p>\n<h6>B Chest</h6>\n<p dir=\"ltr\">Measure yourself around the fullest part of your chest. Keep the tape measure horizontal.</p>",
        "measurements": [
          {
            "type_label": "Length",
            "values": [
              {
                "size": "S",
                "value": "25.2"
              },
              {
                "size": "M",
                "value": "26"
              },
              {
                "size": "L",
                "value": "26.7"
              },
              {
                "size": "XL",
                "value": "27.6"
              },
              {
                "size": "2XL",
                "value": "28.3"
              }
            ]
          },
          {
            "type_label": "Chest",
            "values": [
              {
                "size": "S",
                "min_value": "34",
                "max_value": "37"
              },
              {
                "size": "M",
                "min_value": "36",
                "max_value": "39"
              },
              {
                "size": "L",
                "min_value": "39",
                "max_value": "42"
              },
              {
                "size": "XL",
                "min_value": "41",
                "max_value": "44"
              },
              {
                "size": "2XL",
                "min_value": "43",
                "max_value": "46"
              }
            ]
          }
        ]
      },
      {
        "type": "product_measure",
        "unit": "inches",
        "description": "<p dir=\"ltr\">Measurements are provided by our suppliers. Product measurements may vary by up to 2\" (5 cm).</p>\n<p dir=\"ltr\">US customers should order a size up as the EU sizes for this supplier correspond to a smaller size in the US market.</p>\n<p dir=\"ltr\">Pro tip! Measure one of your products at home and compare with the measurements you see in this guide.</p>",
        "image_url": "https://s3-printful.stage.printful.dev/upload/product-measure/85/857e7cc8b802da216e7f1a6114075a72_t?v=1652962720",
        "image_description": "<h6><strong>A Length</strong></h6>\n<p dir=\"ltr\"><span id=\"docs-internal-guid-a3ac3082-7fff-5f98-2623-3eb38d5f43a1\">Place the end of the tape beside the collar at the top of the tee (Highest Point Shoulder). Pull the tape measure t</span><span id=\"docs-internal-guid-a3ac3082-7fff-5f98-2623-3eb38d5f43a1\">o the bottom of the shirt.</span></p>\n<h6>B Width</h6>\n<p dir=\"ltr\">Place the end of the tape at the seam under the sleeve and pull the tape measure across the shirt to the seam under the opposite sleeve.</p>",
        "measurements": [
          {
            "type_label": "Length",
            "values": [
              {
                "size": "S",
                "value": "25.2"
              },
              {
                "size": "M",
                "value": "26"
              },
              {
                "size": "L",
                "value": "26.7"
              },
              {
                "size": "XL",
                "value": "27.6"
              },
              {
                "size": "2XL",
                "value": "28.3"
              }
            ]
          },
          {
            "type_label": "Width",
            "values": [
              {
                "size": "S",
                "value": "16.1"
              },
              {
                "size": "M",
                "value": "17.3"
              },
              {
                "size": "L",
                "value": "18.5"
              },
              {
                "size": "XL",
                "value": "19.7"
              },
              {
                "size": "2XL",
                "value": "20.9"
              }
            ]
          }
        ]
      },
      {
        "type": "international",
        "unit": "none",
        "image_url": "https://s3-printful.stage.printful.dev/upload/product-measure/85/857e7cc8b802da216e7f1a6114075a72_t?v=1652962720",
        "measurements": [
          {
            "type_label": "US size",
            "values": [
              {
                "size": "S",
                "min_value": "6",
                "max_value": "8"
              },
              {
                "size": "M",
                "min_value": "10",
                "max_value": "12"
              },
              {
                "size": "L",
                "min_value": "14",
                "max_value": "16"
              },
              {
                "size": "XL",
                "min_value": "18",
                "max_value": "20"
              },
              {
                "size": "2XL",
                "min_value": "22",
                "max_value": "24"
              }
            ]
          },
          {
            "type_label": "EU size",
            "values": [
              {
                "size": "S",
                "min_value": "36",
                "max_value": "38"
              },
              {
                "size": "M",
                "min_value": "40",
                "max_value": "42"
              },
              {
                "size": "L",
                "min_value": "44",
                "max_value": "46"
              },
              {
                "size": "XL",
                "min_value": "48",
                "max_value": "50"
              },
              {
                "size": "2XL",
                "min_value": "52",
                "max_value": "54"
              }
            ]
          },
          {
            "type_label": "UK size",
            "values": [
              {
                "size": "S",
                "min_value": "10",
                "max_value": "12"
              },
              {
                "size": "M",
                "min_value": "14",
                "max_value": "16"
              },
              {
                "size": "L",
                "min_value": "18",
                "max_value": "20"
              },
              {
                "size": "XL",
                "min_value": "22",
                "max_value": "24"
              },
              {
                "size": "2XL",
                "min_value": "26",
                "max_value": "28"
              }
            ]
          }
        ]
      }
    ],
    "_links": {
      "self": {
        "href": "https://api.printful.test/v2/catalog-products/561/sizes"
      },
      "product": {
        "href": "https://api.printful.test/v2/catalog-products/561"
      }
    }
  },
  "extra": [],
  "debug": []
}

Now, we'll take a closer look at the objects related to all three types of size tables.

Measure yourself size table

This object provides all measurements for the end customers to be able to measure themselves and see what size they should buy.

The corresponding response fragment
...
{
    "type": "measure_yourself",
    "unit": "inches",
    "description": "<p>Measurements are provided by suppliers.<br /><br />US customers should order a size up as the EU sizes for this supplier correspond to a smaller size in the US market.</p>\n<p>Product measurements may vary by up to 2\" (5 cm).&nbsp;</p>",
    "image_url": "https://s3-printful.stage.printful.dev/upload/measure-yourself/6a/6a4fe322f592f2b91d5a735d7ff8d1c0_t?v=1652962720",
    "image_description": "<h6><strong>A Length</strong></h6>\n<p dir=\"ltr\"><span id=\"docs-internal-guid-a3ac3082-7fff-5f98-2623-3eb38d5f43a1\">Place the end of the tape beside the collar at the top of the tee (Highest Point Shoulder). Pull the tape measure t</span><span id=\"docs-internal-guid-a3ac3082-7fff-5f98-2623-3eb38d5f43a1\">o the bottom of the shirt.</span></p>\n<h6>B Chest</h6>\n<p dir=\"ltr\">Measure yourself around the fullest part of your chest. Keep the tape measure horizontal.</p>",
    "measurements": [
        {
            "type_label": "Length",
            "values": [
                {
                    "size": "S",
                    "value": "25.2"
                },
                {
                    "size": "M",
                    "value": "26"
                },
                {
                    "size": "L",
                    "value": "26.7"
                },
                {
                    "size": "XL",
                    "value": "27.6"
                },
                {
                    "size": "2XL",
                    "value": "28.3"
                }
            ]
        },
        {
            "type_label": "Chest",
            "values": [
                {
                    "size": "S",
                    "min_value": "34",
                    "max_value": "37"
                },
                {
                    "size": "M",
                    "min_value": "36",
                    "max_value": "39"
                },
                {
                    "size": "L",
                    "min_value": "39",
                    "max_value": "42"
                },
                {
                    "size": "XL",
                    "min_value": "41",
                    "max_value": "44"
                },
                {
                    "size": "2XL",
                    "min_value": "43",
                    "max_value": "46"
                }
            ]
        }
    ]
},
...

The measurement image with the descriptions for the product as seen in the web version of the size guides:

Image

The size chart from the web version:

Image

Product measurements size table

This object provides all product measurements so the end customer can measure a product they own and see what size they should buy.

The corresponding response fragment
...
{
    "type": "product_measure",
    "unit": "inches",
    "description": "<p dir=\"ltr\">Measurements are provided by our suppliers. Product measurements may vary by up to 2\" (5 cm).</p>\n<p dir=\"ltr\">US customers should order a size up as the EU sizes for this supplier correspond to a smaller size in the US market.</p>\n<p dir=\"ltr\">Pro tip! Measure one of your products at home and compare with the measurements you see in this guide.</p>",
    "image_url": "https://s3-printful.stage.printful.dev/upload/product-measure/85/857e7cc8b802da216e7f1a6114075a72_t?v=1652962720",
    "image_description": "<h6><strong>A Length</strong></h6>\n<p dir=\"ltr\"><span id=\"docs-internal-guid-a3ac3082-7fff-5f98-2623-3eb38d5f43a1\">Place the end of the tape beside the collar at the top of the tee (Highest Point Shoulder). Pull the tape measure t</span><span id=\"docs-internal-guid-a3ac3082-7fff-5f98-2623-3eb38d5f43a1\">o the bottom of the shirt.</span></p>\n<h6>B Width</h6>\n<p dir=\"ltr\">Place the end of the tape at the seam under the sleeve and pull the tape measure across the shirt to the seam under the opposite sleeve.</p>",
    "measurements": [
        {
            "type_label": "Length",
            "values": [
                {
                    "size": "S",
                    "value": "25.2"
                },
                {
                    "size": "M",
                    "value": "26"
                },
                {
                    "size": "L",
                    "value": "26.7"
                },
                {
                    "size": "XL",
                    "value": "27.6"
                },
                {
                    "size": "2XL",
                    "value": "28.3"
                }
            ]
        },
        {
            "type_label": "Width",
            "values": [
                {
                    "size": "S",
                    "value": "16.1"
                },
                {
                    "size": "M",
                    "value": "17.3"
                },
                {
                    "size": "L",
                    "value": "18.5"
                },
                {
                    "size": "XL",
                    "value": "19.7"
                },
                {
                    "size": "2XL",
                    "value": "20.9"
                }
            ]
        }
    ]
},
...

The measurement image with the descriptions for the product as seen in the web version of the size guides:

Image

The size chart from the web version:

Image

International size conversion

This object provides information what international (US, EU, UK) sizes correspond to the product sizes.

The corresponding response fragment
...
{
    "type": "international",
    "unit": "none",
    "measurements": [
        {
            "type_label": "US size",
            "values": [
                {
                    "size": "S",
                    "min_value": "6",
                    "max_value": "8"
                },
                {
                    "size": "M",
                    "min_value": "10",
                    "max_value": "12"
                },
                {
                    "size": "L",
                    "min_value": "14",
                    "max_value": "16"
                },
                {
                    "size": "XL",
                    "min_value": "18",
                    "max_value": "20"
                },
                {
                    "size": "2XL",
                    "min_value": "22",
                    "max_value": "24"
                }
            ]
        },
        {
            "type_label": "EU size",
            "values": [
                {
                    "size": "S",
                    "min_value": "36",
                    "max_value": "38"
                },
                {
                    "size": "M",
                    "min_value": "40",
                    "max_value": "42"
                },
                {
                    "size": "L",
                    "min_value": "44",
                    "max_value": "46"
                },
                {
                    "size": "XL",
                    "min_value": "48",
                    "max_value": "50"
                },
                {
                    "size": "2XL",
                    "min_value": "52",
                    "max_value": "54"
                }
            ]
        },
        {
            "type_label": "UK size",
            "values": [
                {
                    "size": "S",
                    "min_value": "10",
                    "max_value": "12"
                },
                {
                    "size": "M",
                    "min_value": "14",
                    "max_value": "16"
                },
                {
                    "size": "L",
                    "min_value": "18",
                    "max_value": "20"
                },
                {
                    "size": "XL",
                    "min_value": "22",
                    "max_value": "24"
                },
                {
                    "size": "2XL",
                    "min_value": "26",
                    "max_value": "28"
                }
            ]
        }
    ]
}
...

The international size conversion table from the web version:

Image

File Library API examples

Add a new file

Add file to the print file library, filename will be detected from URL. After creation file is not processed instantly.

Request body:

{
    "url": "http://www.example.com/files/tshirts/example.png"
}

Response data:

{
    "data": {
        "id": 11816,
        "url": "http://www.example.com/files/tshirts/example.png",
        "hash": null,
        "filename": null,
        "mime_type": null,
        "size": 0,
        "width": null,
        "height": null,
        "dpi": null,
        "status": "waiting",
        "created": "2024-06-10T15:31:49Z",
        "thumbnail_url": null,
        "preview_url": null,
        "visible": true,
        "is_temporary": false,
        "_links": {
            "self": {
                "href": "https://api.printful.com/v2/files/11816"
            }
        }
    }
}

Add file to the mockup library, and specify file name manually

Request body:

{
    "type": "preview",
    "url": "http://www.example.com/files/tshirts/example.png",
    "filename": "shirt1.png"
}

Add file to the library, but not show up in the web interface.

Request body:

{
    "url": "http://www.example.com/files/tshirts/example.png",
    "visible": false
}

Shipping Rates API examples

Shipment information

For each entry in the response array, in addition to the basic information about the shipping rate (name, rate, estimated delivery time), an expected shipment split will be provided. Each shipment object will contain the following data:

  • departure country (2-letter code) – currently, this may be null for some branches. We plan to fix this in the foreseeable future;
  • shipment items included in the shipment (Catalog Variant ID and item quantity);
  • whether customs fees may be required for the shipment (customs_fees_possible).

It's possible the fees won't apply even if the value of the customs_fees_possible field is true, depending on the characteristics of the products and agreements between the countries. The value of false means the customs fees won't be required for the shipment (e.g. shipment within the EU or the same country).

Example: Same-country shipment

In this example two shipping options are available. All items can be fulfilled in the US and they are split into two shipments because of large quantities. No customs fees will be charged.

Request body
{
    "recipient": {
        "address1": "19749 Dearborn St",
        "city": "Chatsworth",
        "state_code": "CA",
        "country_code": "US",
        "zip": "91311"
    },
    "order_items": [
        {
            "source": "catalog",
            "quantity": 20,
            "catalog_variant_id": 408
        },
        {
            "source": "catalog",
            "quantity": 20,
            "catalog_variant_id": 4011
        },
        {
            "source": "catalog",
            "quantity": 30,
            "catalog_variant_id": 4016
        },
        {
            "source": "catalog",
            "quantity": 40,
            "catalog_variant_id": 4020
        }
    ],
    "currency": "USD"
}
Response data
{
    "data": [
        {
            "shipping": "STANDARD",
            "shipping_method_name": "Flat Rate (Estimated delivery: Jan 20⁠–27) ",
            "rate": "60.74",
            "currency": "USD",
            "min_delivery_days": 5,
            "max_delivery_days": 8,
            "min_delivery_date": "2025-01-20",
            "max_delivery_date": "2025-01-27",
            "shipments": [
                {
                    "departure_country": "US",
                    "shipment_items": [
                        {
                            "catalog_variant_id": 408,
                            "quantity": 20
                        },
                        {
                            "catalog_variant_id": 4011,
                            "quantity": 20
                        },
                        {
                            "catalog_variant_id": 4016,
                            "quantity": 20
                        }
                    ],
                    "customs_fees_possible": false
                },
                {
                    "departure_country": "US",
                    "shipment_items": [
                        {
                            "catalog_variant_id": 4016,
                            "quantity": 10
                        },
                        {
                            "catalog_variant_id": 4020,
                            "quantity": 40
                        }
                    ],
                    "customs_fees_possible": false
                }
            ]
        },
        {
            "shipping": "STANDARD_CARBON_OFFSET",
            "shipping_method_name": "Standard rate with CO2 offsetting (Estimated delivery: Jan 20⁠–27) ",
            "rate": "70.64",
            "currency": "USD",
            "min_delivery_days": 5,
            "max_delivery_days": 8,
            "min_delivery_date": "2025-01-20",
            "max_delivery_date": "2025-01-27",
            "shipments": [
                {
                    "departure_country": "US",
                    "shipment_items": [
                        {
                            "catalog_variant_id": 408,
                            "quantity": 20
                        },
                        {
                            "catalog_variant_id": 4011,
                            "quantity": 20
                        },
                        {
                            "catalog_variant_id": 4016,
                            "quantity": 20
                        }
                    ],
                    "customs_fees_possible": false
                },
                {
                    "departure_country": "US",
                    "shipment_items": [
                        {
                            "catalog_variant_id": 4016,
                            "quantity": 10
                        },
                        {
                            "catalog_variant_id": 4020,
                            "quantity": 40
                        }
                    ],
                    "customs_fees_possible": false
                }
            ]
        }
    ],
    "extra": []
}

Example: shipments from different countries

In this example only one shipping option is available. One item can't be shipped from Europe, so it will be shipped from the US instead, probably incurring customs fees.

Request body
{
    "recipient": {
        "address1": "Warszawska 1",
        "city": "Gdańsk",
        "country_code": "PL"
    },
    "order_items": [
        {
            "source": "catalog",
            "quantity": 1,
            "catalog_variant_id": 408
        },
        {
            "source": "catalog",
            "quantity": 1,
            "catalog_variant_id": 4011
        }
    ]
}
Response data
{
    "data": [
        {
            "shipping": "STANDARD",
            "shipping_method_name": "Flat Rate (Estimated delivery: Jan 21⁠–28) ",
            "rate": "5.54",
            "currency": "EUR",
            "min_delivery_days": 8,
            "max_delivery_days": 14,
            "min_delivery_date": "2025-01-21",
            "max_delivery_date": "2025-01-28",
            "shipments": [
                {
                    "departure_country": "US",
                    "shipment_items": [
                        {
                            "catalog_variant_id": 408,
                            "quantity": 1
                        }
                    ],
                    "customs_fees_possible": true
                },
                {
                    "departure_country": "LV",
                    "shipment_items": [
                        {
                            "catalog_variant_id": 4011,
                            "quantity": 1
                        }
                    ],
                    "customs_fees_possible": false
                }
            ]
        }
    ],
    "extra": []
}

Webhook API examples

Configuring webhooks

Enabling webhook support

We will use an endpoint allowing us to enable webhook support for a store specifying multiple events in one request.

We want to enable support for order_put_hold, shipment_sent, shipment_returned, and catalog_stock_updated events.

We want to receive the event at https://example.org/webhook/store for most events but for shipment_returned we want to use https://example.org/webhook/catalog.

You may replace the URLs with your own. If you don't have a server software that will accept the events, you may use a site like https://webhook.site/.

We don't want the configuration to expire.

We want to be notified of stock updates for the following product IDs: 1, 71.

Endpoint: POST https://api.printful.com/v2/webhooks

The request needs to be authorized with a store-level token or an account-level token with the store ID specified in X-PF-Store-ID header.

Request body
{
    "default_url": "https://example.org/webhook/store",
    "events": [
        {
            "type": "order_put_hold"
        },
        {
            "type": "shipment_sent"
        },
        {
            "type": "shipment_returned",
            "url": "https://example.org/webhook/catalog"
        },
        {
            "type": "catalog_stock_updated",
            "params": [
                {
                    "name": "products",
                    "value": [
                        {
                            "id": 1
                        },
                        {
                            "id": 71
                        }
                    ]
                }
            ]
        }
    ]
}
Response data
{
    "code": 200,
    "result": {
        "default_url": "https://example.org/webhook/store",
        "expires_at": null,
        "events": [
            {
                "type": "order_put_hold",
                "url": null,
                "params": []
            },
            {
                "type": "shipment_sent",
                "url": null,
                "params": []
            },
            {
                "type": "shipment_returned",
                "url": "https://example.org/webhook/catalog",
                "params": []
            },
            {
                "type": "catalog_stock_updated",
                "url": null,
                "params": [
                    {
                        "name": "products",
                        "value": [
                            {
                                "id": 1
                            },
                            {
                                "id": 71
                            }
                        ]
                    }
                ]
            }
        ],
        "public_key": "somePublicKey",
        "secret_key": "0123456789abcdef..."
    },
    "extra": []
}

The public key will be used to distinguish between events coming from different configurations.

For example, if you use the same URL for different stores or create multiple configurations for the same store with different tokens for the same URL, you may use the public key to know which configuration was used.

The secret key will be used to verify the signature of the received event.

Updating or adding event configuration

If you have the general settings created for the store, you may modify or update the settings for specific events.

We will now show how to add support for another event: order_created.

Endpoint: POST https://api.printful.com/v2/webhooks/{eventType}

If you don't need to specify additional fields like URL, you may send the request without body. We will send such a request in this example.

Request URL: https://api.printful.com/v2/webhooks/order_created

Response data
{
    "code": 200,
    "result": {
        "type": "order_created",
        "url": null,
        "params": []
    },
    "extra": []
}

The endpoint may be used to replace existing event settings. It may be used for an already configured event or a new one.

Request URL: https://api.printful.com/v2/webhooks/shipment_returned

If we omit the request body, we will replace the existing configuration with a custom URL with a default one, using the store's default_url.

However, we want to update the URL with another one.

Request body
{
    "url": "https://example.org/webhook/another"
}
Response data
{
    "code": 200,
    "result": {
        "type": "shipment_returned",
        "url": "https://example.org/webhook/another",
        "params": []
    },
    "extra": []
}

Note it's not possible to omit the request body for an event requiring a parameter.

Sending a request without body to https://api.printful.com/v2/webhooks/catalog_stock_updated will result in an error.

Event example

This is an example of an order_created event sent to the specified URL:

Event content
{
  "type": "order_created",
  "occurred_at": "2023-04-04T12:36:42Z",
  "retries": 0,
  "store_id": 123456,
  "data": {
    "order": {
      "id": 11111,
      "external_id": null,
      "status": "pending",
      "created": 1680611801,
      "updated": 1680611802,
      "dashboard_url": "https://www.printful.test/dashboard?order_id=90630659",
    }
  }
}

In headers, you will also receive:

  • The base64-encoded public key associated with the configuration used to trigger the event in x-pf-webhook-public-key header
  • The hexadecimal representation of the signature in x-pf-webhook-signature header.

You may use the secret key associated with the settings to calculate the HMAC-SHA256 hash for the event data and compare it to the value from header. You may create a script or use an online or offline tool to do this.

Please note that in the secret_key field we return the hexadecimal representation of the secret key. It means that you need to decode it before passing it to the tool or method that calculates the signature, unless it supports keys in hexadecimal format.

PATCH Partial Updates

See RFC 7386.

PATCH updates allows you to change only the fields that you've specified in the request.

If you'd like to update the value that is an array please keep in mind that in case of arrays the entire array is replaced with the value provided in the request. For example:

Current array value:

{
  "items": [
    {
      "catalog_variant_id": 4011,
      "placements": [
        {
          "placement": "front",
          "technique": "dtg",
          "layers": [
            {
              "type": "file",
              "url": "https://www.printful.com/static/images/layout/printful-logo.png"
            }
          ]
        }
      ]
    },
    {
      "catalog_variant_id": 4012,
      "placements": [
        {
          "placement": "front",
          "technique": "dtg",
          "layers": [
            {
              "type": "file",
              "url": "https://www.printful.com/static/images/layout/printful-logo.png"
            }
          ]
        },
        {
          "placement": "back",
          "technique": "dtg",
          "layers": [
            {
              "type": "file",
              "url": "https://www.printful.com/static/images/layout/printful-logo.png"
            }
          ]
        }
      ]
    }
  ]
}

PATCH request:

{
  "items": [
    {
      "catalog_variant_id": 4013,
      "placements": [
        {
          "placement": "left_sleeve",
          "technique": "dtg",
          "layers": [
            {
              "type": "file",
              "url": "https://www.printful.com/static/images/layout/printful-logo.png"
            }
          ]
        }
      ]
    }
  ]
}

Results in:

{
  "items": [
    {
      "catalog_variant_id": 4013,
      "placements": [
        {
          "placement": "left_sleeve",
          "technique": "dtg",
          "layers": [
            {
              "type": "file",
              "url": "https://www.printful.com/static/images/layout/printful-logo.png"
            }
          ]
        }
      ]
    }
  ]
}

Notice that all of the previous items were discarded and were replaced with items provided in the request. It's also not possible to override properties in nested arrays. So whenever you are changing the array value you need to provide full object.

Example of order update

Order that is being updated
{
    "data": {
        "id": 94188292,
        "external_id": null,
        "store_id": 11229252,
        "shipping": "STANDARD",
        "status": "draft",
        "created_at": "2023-10-18T12:35:07Z",
        "updated_at": "2023-10-18T12:35:07Z",
        "recipient": {
            "name": "John Smith",
            "company": "John Smith Inc",
            "address1": "19749 Dearborn St",
            "address2": "string",
            "city": "Chatsworth",
            "state_code": "CA",
            "state_name": "California",
            "country_code": "US",
            "country_name": "United States",
            "zip": "91311",
            "phone": "string",
            "email": "[email protected]",
            "tax_number": "123.456.789-10"
        },
        "costs": {
            "calculation_status": "calculating",
            "currency": null,
            "subtotal": null,
            "discount": null,
            "shipping": null,
            "digitization": null,
            "additional_fee": null,
            "fulfillment_fee": null,
            "retail_delivery_fee": null,
            "tax": null,
            "vat": null,
            "total": null
        },
        "retail_costs": {
            "calculation_status": "calculating",
            "currency": "USD",
            "subtotal": null,
            "discount": "0.00",
            "shipping": "0.00",
            "tax": "0.00",
            "vat": "0.00",
            "total": null
        },
        "order_items": [
            {
                "id": 66655730,
                "external_id": "some_external_id",
                "type": "order_item",
                "source": "catalog",
                "catalog_variant_id": 4012,
                "quantity": 1,
                "name": "my_custom_name",
                "price": "10.50",
                "retail_price": null,
                "currency": "EUR",
                "retail_currency": "USD",
                "_links": {
                    "self": {
                        "href": "https://api.printful.test/v2/orders/94188292/order-items/66655730"
                    }
                }
            }
        ],
        "customization": null,
        "_links": {
            "self": {
                "href": "https://api.printful.test/v2/orders/94188292"
            },
            "order_confirmation": {
                "href": "https://api.printful.test/v2/orders/94188292/confirmation"
            },
            "order_items": {
                "href": "https://api.printful.test/v2/orders/94188292/order-items"
            },
            "shipments": {
                "href": "https://api.printful.test/v2/orders/94188292/shipments"
            }
        }
    },
    "extra": [],
}

Changing specified fields in recipient object

Endpoint PATCH https://api.printful.com/v2/orders/{order_id}

Request body
{
  "recipient": {
    "address1": "new address",
    "name": "new name"
  }
}

Endpoint GET https://api.printful.com/v2/orders/{order_id}

Response body
{
    "data": {
        "id": 94188292,
        "external_id": null,
        "store_id": 11229252,
        "shipping": "STANDARD",
        "status": "draft",
        "created_at": "2023-10-18T12:35:07Z",
        "updated_at": "2023-10-18T12:35:07Z",
        "recipient": {
            "name": "new name", <--------Changed field
            "company": "John Smith Inc",
            "address1": "new address", <--------Changed field
            "address2": "string",
            "city": "Chatsworth",
            "state_code": "CA",
            "state_name": "California",
            "country_code": "US",
            "country_name": "United States",
            "zip": "91311",
            "phone": "string",
            "email": "[email protected]",
            "tax_number": "123.456.789-10"
        },
        "costs": {
            "calculation_status": "calculating",
            "currency": null,
            "subtotal": null,
            "discount": null,
            "shipping": null,
            "digitization": null,
            "additional_fee": null,
            "fulfillment_fee": null,
            "retail_delivery_fee": null,
            "tax": null,
            "vat": null,
            "total": null
        },
        "retail_costs": {
            "calculation_status": "calculating",
            "currency": "USD",
            "subtotal": null,
            "discount": "0.00",
            "shipping": "0.00",
            "tax": "0.00",
            "vat": "0.00",
            "total": null
        },
        "order_items": [
            {
                "id": 66655730,
                "external_id": "some_external_id",
                "type": "order_item",
                "source": "catalog",
                "catalog_variant_id": 4012,
                "quantity": 1,
                "name": "my_custom_name",
                "price": "10.50",
                "retail_price": null,
                "currency": "EUR",
                "retail_currency": "USD",
                "_links": {
                    "self": {
                        "href": "https://api.printful.test/v2/orders/94188292/order-items/66655730"
                    }
                }
            }
        ],
        "customization": null,
        "_links": {
            "self": {
                "href": "https://api.printful.test/v2/orders/94188292"
            },
            "order_confirmation": {
                "href": "https://api.printful.test/v2/orders/94188292/confirmation"
            },
            "order_items": {
                "href": "https://api.printful.test/v2/orders/94188292/order-items"
            },
            "shipments": {
                "href": "https://api.printful.test/v2/orders/94188292/shipments"
            }
        }
    },
    "extra": [],
}

Changing external_id property

Endpoint PATCH https://api.printful.com/v2/orders/{order_id}

Request body
{
  "external_id": "1234_abc"
}

Endpoint GET https://api.printful.com/v2/orders/{order_id}

Response body
{
    "data": {
        "id": 94188292,
        "external_id": "1234_abc", <--------Changed field
        "store_id": 11229252,
        "shipping": "STANDARD",
        "status": "draft",
        "created_at": "2023-10-18T12:35:07Z",
        "updated_at": "2023-10-18T12:35:07Z",
        "recipient": {
            "name": "John Smith",
            "company": "John Smith Inc",
            "address1": "19749 Dearborn St",
            "address2": "string",
            "city": "Chatsworth",
            "state_code": "CA",
            "state_name": "California",
            "country_code": "US",
            "country_name": "United States",
            "zip": "91311",
            "phone": "string",
            "email": "[email protected]",
            "tax_number": "123.456.789-10"
        },
        "costs": {
            "calculation_status": "calculating",
            "currency": null,
            "subtotal": null,
            "discount": null,
            "shipping": null,
            "digitization": null,
            "additional_fee": null,
            "fulfillment_fee": null,
            "retail_delivery_fee": null,
            "tax": null,
            "vat": null,
            "total": null
        },
        "retail_costs": {
            "calculation_status": "calculating",
            "currency": "USD",
            "subtotal": null,
            "discount": "0.00",
            "shipping": "0.00",
            "tax": "0.00",
            "vat": "0.00",
            "total": null
        },
        "order_items": [
            {
                "id": 66655730,
                "external_id": "some_external_id",
                "type": "order_item",
                "source": "catalog",
                "catalog_variant_id": 4012,
                "quantity": 1,
                "name": "my_custom_name",
                "price": "10.50",
                "retail_price": null,
                "currency": "EUR",
                "retail_currency": "USD",
                "_links": {
                    "self": {
                        "href": "https://api.printful.test/v2/orders/94188292/order-items/66655730"
                    }
                }
            }
        ],
        "customization": null,
        "_links": {
            "self": {
                "href": "https://api.printful.test/v2/orders/94188292"
            },
            "order_confirmation": {
                "href": "https://api.printful.test/v2/orders/94188292/confirmation"
            },
            "order_items": {
                "href": "https://api.printful.test/v2/orders/94188292/order-items"
            },
            "shipments": {
                "href": "https://api.printful.test/v2/orders/94188292/shipments"
            }
        }
    },
    "extra": [],
}

Replacing ordered item with another one

Endpoint PATCH https://api.printful.com/v2/orders/{order_id}

Request body
{
  "items": [
        {
            "source": "catalog",
            "catalog_variant_id": 4011,
            "quantity": 1,
            "placements": [
                {
                    "placement": "front",
                    "technique": "dtg",
                    "layers": [
                        {
                            "type": "file",
                            "url": "https://www.printful.com/static/images/layout/printful-logo.png",
                        }
                    ]
                }
            ]
        }
    ]
}

Endpoint GET https://api.printful.com/v2/orders/{order_id}

Response body
{
    "data": {
        "id": 94188292,
        "external_id": null,
        "store_id": 11229252,
        "shipping": "STANDARD",
        "status": "draft",
        "created_at": "2023-10-18T12:35:07Z",
        "updated_at": "2023-10-18T12:35:07Z",
        "recipient": {
            "name": "John Smith",
            "company": "John Smith Inc",
            "address1": "19749 Dearborn St",
            "address2": "string",
            "city": "Chatsworth",
            "state_code": "CA",
            "state_name": "California",
            "country_code": "US",
            "country_name": "United States",
            "zip": "91311",
            "phone": "string",
            "email": "[email protected]",
            "tax_number": "123.456.789-10"
        },
        "costs": {
            "calculation_status": "calculating",
            "currency": null,
            "subtotal": null,
            "discount": null,
            "shipping": null,
            "digitization": null,
            "additional_fee": null,
            "fulfillment_fee": null,
            "retail_delivery_fee": null,
            "tax": null,
            "vat": null,
            "total": null
        },
        "retail_costs": {
            "calculation_status": "calculating",
            "currency": "USD",
            "subtotal": null,
            "discount": "0.00",
            "shipping": "0.00",
            "tax": "0.00",
            "vat": "0.00",
            "total": null
        },
        "order_items": [ <--------Changed field
            {
                "id": 66655731,
                "external_id": null,
                "type": "order_item",
                "source": "catalog",
                "catalog_variant_id": 4011,
                "quantity": 1,
                "name": null,
                "price": "10.50",
                "retail_price": null,
                "currency": "EUR",
                "retail_currency": "USD",
                "_links": {
                    "self": {
                        "href": "https://api.printful.test/v2/orders/94188292/order-items/66655730"
                    }
                }
            }
        ],
        "customization": null,
        "_links": {
            "self": {
                "href": "https://api.printful.test/v2/orders/94188292"
            },
            "order_confirmation": {
                "href": "https://api.printful.test/v2/orders/94188292/confirmation"
            },
            "order_items": {
                "href": "https://api.printful.test/v2/orders/94188292/order-items"
            },
            "shipments": {
                "href": "https://api.printful.test/v2/orders/94188292/shipments"
            }
        }
    },
    "extra": [],
}

Utilising options

Options are the special properties which are used to customise the products. Depending on the product and the technique different options might be available. You can check the available options for a product in Retrieve a single catalog product. Currently, there are 3 types of options each referencing a different ascpect of the design:

  • product_options - options which affect the entire product e.g. if the product should contain inside pocket or not.
  • placement_options - options which are affecting the specific placement
  • layer_options - options which are affecting the specific layer e.g. thread colors

Custom border color option

Stickers can have a different border color which can be set by using the thread_colors_outline option. This option is available in product_options for stickers. To showcase the usage we will use the order flow which will create order with a sticker that will have a red border color:

Endpoint POST https://api.printful.com/v2/orders

Request body
{
    "recipient": {
        "name": "John Smith",
        "company": "John Smith Inc",
        "address1": "19749 Dearborn St",
        "address2": "string",
        "city": "Chatsworth",
        "state_code": "CA",
        "state_name": "California",
        "country_code": "US",
        "country_name": "United States",
        "zip": "91311"
    },
    "items": [
        {
            "quantity": 1,
            "variant_id": 10163,
            "source": "catalog",
            "placements": [
                {
                    "placement": "default",
                    "technique": "digital",
                    "layers": [
                        {
                            "type": "file",
                            "url": "https://www.printful.com/static/images/layout/printful-logo.png",
                            "position": {
                                "width": 3,
                                "height": 3,
                                "top": 0,
                                "left": 0
                            }
                        }
                    ]
                }
            ],
            "product_options": [
                {
                    "name": "custom_border_color",
                    "value": "#FFFF00"
                }
            ]
        }
    ]
}

Creating Orders for Knitwear Products

Knitwear products can be configured with some unique options that affect the color of the final knitted product.

These options are trim_color, color_reduction_mode, base_color, they only apply to knitwear and function differently to other similar options.

Note that yarn_colors can be applied on each layer of a product.

Endpoint POST https://api.printful.com/v2/orders

Request body
{
  "recipient": {
    "name": "John Smith",
    "company": "John Smith Inc",
    "address1": "19749 Dearborn St",
    "city": "Chatsworth",
    "state_code": "CA",
    "country_code": "US",
    "country_name": "United States",
    "zip": "91311"
  },
  "order_items": [
    {
      "source": "catalog",
      "quantity": 1,
      "catalog_variant_id": 19634,
      "placements": [
        {
          "placement": "sleeve_right",
          "technique": "knitting",
          "layers": [
            {
              "type": "file",
              "url": "https://picsum.photos/200",
              "layer_options": [
                {
                  "name": "yarn_colors",
                  "value": [
                    "#090909",
                    "#48542e"
                  ]
                }
              ]
            }
          ]
        }
      ],
      "product_options": [
        {
          "name": "trim_color",
          "value": "#dcd3cc"
        },
        {
          "name": "color_reduction_mode",
          "value": "pixelated"
        },
        {
          "name": "base_color",
          "value": "#dda032"
        }
      ]
    }
  ]
}