Download OpenAPI specification:Download
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.
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."
}
We introduced this format after we started working on V2, so it's not yet supported by all endpoints. These are the operations that are not supporting this format yet:
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.
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.
Product management, with sync products or product templates, is not available in version 2 of the API yet.
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.
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.
For migration assistance, you can:
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:
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:
These use cases are tailored to provide actionable insights for efficiently managing your Printful orders, ensuring a smooth integration experience.
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
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.
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:
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
}
]
}
]
}
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
}
]
}
]
}
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.
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.
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}}"
}
]
}
]
}
]
}
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
},
...
To get the notifications about the order status, the webhook events endpoint can be used to subscribe to various webhook events e.g.:
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.
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"
}
}
}
],
...
}
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.
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",
}
]
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}}"
}
]
}
]
}
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
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.
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.
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.
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.~~
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.
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}}"
}
]
}
]
}
]
}
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.
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
).
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.
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.
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 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.
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.
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.
There are a number of strategies you can use to take advantage of rate limiting.
retry-after
header to check when the next
request can be made, then schedule a request to trigger at that time.X-Ratelimit-Policy
120 ÷ 60 = 0.5, so the queue should send requests out at a
rate of once every 500 milliseconds. X-Ratelimit-Reset
time has been met.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:
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",
...
}
}
}
This endpoint will retrieve all OAuth scopes associated with the used token
required | Array of objects (OAuthScope) |
required | object HATEOAS links |
{- "data": [
- {
- "name": "View all orders",
- "value": "orders/read"
}
],
}
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 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.
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.
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.
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:
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 | - |
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 |
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 |
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
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.
Apart from display purposes they can be also used for filtering the products in the API see Filtering options
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:
category_ids | Array of integers Examples:
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:
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:
If true only new Products will be returned. |
offset | integer >= 0 Default: 0 Examples:
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:
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 | 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:
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. |
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. |
required | Array of objects (Product) |
required | object (Paging) Paging information |
required | object (Product links) HATEOAS links |
{- "data": [
- {
- "id": 362,
- "main_category_id": 24,
- "type": "T-Shirt",
- "name": "Unisex Organic T-Shirt | Econscious EC1000",
- "brand": "Econscious",
- "model": "Unisex Organic T-Shirt",
- "variant_count": 10,
- "is_discontinued": false,
- "description": "string",
- "sizes": [
- "M"
], - "colors": [
- {
- "name": "Athletic Heather",
- "value": "#cbcbcb"
}
], - "techniques": [
- {
- "key": "embroidery",
- "display_name": "Embroidery",
- "is_default": true
}
], - "placements": [
- {
- "placement": "back",
- "technique": "embroidery",
- "layers": [
- {
- "type": "file",
- "layer_options": [
- {
- "name": "3d_puff",
- "techniques": [
- "embroidery"
], - "type": "boolean",
- "values": [
- true,
- false
]
}
]
}
], - "placement_options": [
- {
- "name": "unlimited_color",
- "techniques": [
- "embroidery"
], - "type": "boolean",
- "values": [
- true,
- false
]
}
], - "conflicting_placements": [
- "back",
- "label_inside"
]
}
], - "product_options": [
- {
- "name": "stitch_color",
- "techniques": [
- "cut-sew"
], - "type": "string",
- "values": [
- "White",
- "Black"
]
}
], - "_links": {
}
}
], - "paging": {
- "total": 100,
- "offset": 10,
- "limit": 100
}, - "_links": {
}
}
Returns information about a single specified catalog product. See catalog product
id required | integer Product ID. |
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. |
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. |
required | object (Product) Information about the Catalog Product |
{- "data": {
- "id": 362,
- "main_category_id": 24,
- "type": "T-Shirt",
- "name": "Unisex Organic T-Shirt | Econscious EC1000",
- "brand": "Econscious",
- "model": "Unisex Organic T-Shirt",
- "variant_count": 10,
- "is_discontinued": false,
- "description": "string",
- "sizes": [
- "M"
], - "colors": [
- {
- "name": "Athletic Heather",
- "value": "#cbcbcb"
}
], - "techniques": [
- {
- "key": "embroidery",
- "display_name": "Embroidery",
- "is_default": true
}
], - "placements": [
- {
- "placement": "back",
- "technique": "embroidery",
- "layers": [
- {
- "type": "file",
- "layer_options": [
- {
- "name": "3d_puff",
- "techniques": [
- "embroidery"
], - "type": "boolean",
- "values": [
- true,
- false
]
}
]
}
], - "placement_options": [
- {
- "name": "unlimited_color",
- "techniques": [
- "embroidery"
], - "type": "boolean",
- "values": [
- true,
- false
]
}
], - "conflicting_placements": [
- "back",
- "label_inside"
]
}
], - "product_options": [
- {
- "name": "stitch_color",
- "techniques": [
- "cut-sew"
], - "type": "string",
- "values": [
- "White",
- "Black"
]
}
], - "_links": {
}
}
}
Returns information about single specified catalog variant. See catalog variant
id required | integer Variant ID |
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. |
required | object (Variant) |
required | object HATEOAS links |
{- "data": {
- "id": 100,
- "catalog_product_id": 12,
- "name": "Gildan 64000 Unisex Softstyle T-Shirt with Tear Away (Black / 2XL)",
- "size": "2XL",
- "color": "Black",
- "color_code": "#14191e",
- "color_code2": "string",
- "_links": {
}
}, - "_links": {
}
}
Returns information about all catalog variants associated with the specified catalog product. See catalog variant
id required | integer Product ID. |
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. |
required | Array of objects (Variant) |
required | object (Paging) Paging information |
required | object HATEOAS links |
{- "data": [
- {
- "id": 100,
- "catalog_product_id": 12,
- "name": "Gildan 64000 Unisex Softstyle T-Shirt with Tear Away (Black / 2XL)",
- "size": "2XL",
- "color": "Black",
- "color_code": "#14191e",
- "color_code2": "string",
- "_links": {
}
}
], - "paging": {
- "total": 100,
- "offset": 10,
- "limit": 100
}, - "_links": {
- "self": {
}, - "next": {
}, - "previous": {
}, - "last": {
},
}
}
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
required | Array of objects (Category) |
required | object HATEOAS links |
{- "data": [
- {
- "id": 24,
- "parent_id": 6,
- "title": "T-Shirts",
}
], - "_links": {
}
}
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
id required | integer Category ID |
required | object (Category) Information about the Category |
required | object HATEOAS links |
{- "data": {
- "id": 24,
- "parent_id": 6,
- "title": "T-Shirts",
},
}
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.
id required | integer Product ID. |
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. |
required | Array of objects (Category) |
required | object (Paging) Paging information |
required | object HATEOAS links |
{- "data": [
- {
- "id": 24,
- "parent_id": 6,
- "title": "T-Shirts",
}
], - "paging": {
- "total": 100,
- "offset": 10,
- "limit": 100
}, - "_links": {
- "previous": {
},
}
}
Returns information about the size guide for a specific product.
id required | integer Product ID. |
unit | string Example: unit=inches,cm A comma-separated list of measurement unit in which size tables are to be returned ( |
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. |
required | object (ProductSizeGuide) Size Guide information for the Product |
required | object HATEOAS links |
{- "data": {
- "catalog_product_id": 13,
- "available_sizes": [
- "S",
- "M",
- "L"
], - "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). </p>",
- "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": "24"
}, - {
- "size": "M",
- "value": "26"
}, - {
- "size": "L",
- "value": "28"
}
]
}, - {
- "type_label": "Chest",
- "values": [
- {
- "size": "S",
- "min_value": "14",
- "max_value": "16"
}, - {
- "size": "M",
- "min_value": "18",
- "max_value": "20"
}, - {
- "size": "L",
- "min_value": "22",
- "max_value": "24"
}
]
}
]
}, - {
- "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_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": "24"
}, - {
- "size": "M",
- "value": "26"
}, - {
- "size": "L",
- "value": "28"
}
]
}, - {
- "type_label": "Width",
- "values": [
- {
- "size": "S",
- "min_value": "14",
- "max_value": "16"
}, - {
- "size": "M",
- "min_value": "18",
- "max_value": "20"
}, - {
- "size": "L",
- "min_value": "22",
- "max_value": "24"
}
]
}
]
}, - {
- "type": "measure_yourself",
- "unit": "cm",
- "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). </p>",
- "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": "60.96"
}, - {
- "size": "M",
- "value": "66.04"
}, - {
- "size": "L",
- "value": "71.12"
}
]
}, - {
- "type_label": "Chest",
- "values": [
- {
- "size": "S",
- "min_value": "35.56",
- "max_value": "40.64"
}, - {
- "size": "M",
- "min_value": "45.72",
- "max_value": "50.80"
}, - {
- "size": "L",
- "min_value": "55.88",
- "max_value": "60.96"
}
]
}
]
}, - {
- "type": "product_measure",
- "unit": "cm",
- "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_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": "60.96"
}, - {
- "size": "M",
- "value": "66.04"
}, - {
- "size": "L",
- "value": "71.12"
}
]
}, - {
- "type_label": "Width",
- "values": [
- {
- "size": "S",
- "min_value": "35.56",
- "max_value": "40.64"
}, - {
- "size": "M",
- "min_value": "45.72",
- "max_value": "50.80"
}, - {
- "size": "L",
- "min_value": "55.88",
- "max_value": "60.96"
}
]
}
]
}, - {
- "type": "international",
- "unit": "none",
- "measurements": [
- {
- "type_label": "US size",
- "values": [
- {
- "size": "S",
- "min_value": "8",
- "max_value": "10"
}, - {
- "size": "M",
- "min_value": "12",
- "max_value": "14"
}, - {
- "size": "L",
- "min_value": "16",
- "max_value": "18"
}
]
}, - {
- "type_label": "EU size",
- "values": [
- {
- "size": "S",
- "min_value": "38",
- "max_value": "39"
}, - {
- "size": "M",
- "min_value": "40",
- "max_value": "41"
}, - {
- "size": "L",
- "min_value": "42",
- "max_value": "43"
}
]
}, - {
- "type_label": "UK size",
- "values": [
- {
- "size": "S",
- "min_value": "4",
- "max_value": "6"
}, - {
- "size": "M",
- "min_value": "8",
- "max_value": "10"
}, - {
- "size": "L",
- "min_value": "12",
- "max_value": "14"
}
]
}
]
}
]
}, - "_links": {
}
}
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.
id required | integer Product ID. |
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. |
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. |
required | object (ProductPrice) Product prices information |
required | object (Paging) Paging information |
required | object HATEOAS links |
{- "data": {
- "currency": "EUR",
- "product": {
- "id": 1,
- "placements": [
- {
- "id": "default",
- "title": "Print file",
- "type": "Digital printing",
- "technique_key": "digital",
- "price": "19.75",
- "discounted_price": "18.75",
- "placement_options": [
- {
- "name": "unlimited_color",
- "type": "array",
- "values": [
- true,
- false
], - "description": "Unlimited color",
- "price": {
- "false": "0.00",
- "true": "3.50"
}
}
], - "layers": [
- {
- "type": "file",
- "additional_price": "0.00",
- "layer_options": [
- {
- "name": "3d_puff",
- "type": "array",
- "values": [
- true,
- false
], - "description": "3D puff",
- "price": {
- "false": "0.00",
- "true": "1.50"
}
}
]
}
]
}
]
}, - "variants": [
- {
- "id": 1,
- "techniques": [
- {
- "technique_key": "digital",
- "technique_display_name": "Digital printing",
- "price": "9.50",
- "discounted_price": "8.50"
}
]
}
]
}, - "paging": {
- "total": 100,
- "offset": 10,
- "limit": 100
}, - "_links": {
}
}
Return pricing information from a single variant and the parent product
id required | integer Variant ID |
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. |
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. |
required | object (VariantPrice) Variant prices information |
required | object HATEOAS links |
{- "data": {
- "currency": "EUR",
- "product": {
- "id": 1,
- "placements": [
- {
- "id": "default",
- "title": "Print file",
- "type": "Digital printing",
- "technique_key": "digital",
- "price": "19.75",
- "discounted_price": "18.75",
- "placement_options": [
- {
- "name": "unlimited_color",
- "type": "array",
- "values": [
- true,
- false
], - "description": "Unlimited color",
- "price": {
- "false": "0.00",
- "true": "3.50"
}
}
], - "layers": [
- {
- "type": "file",
- "additional_price": "0.00",
- "layer_options": [
- {
- "name": "3d_puff",
- "type": "array",
- "values": [
- true,
- false
], - "description": "3D puff",
- "price": {
- "false": "0.00",
- "true": "1.50"
}
}
]
}
]
}
]
}, - "variant": {
- "id": 1,
- "techniques": [
- {
- "technique_key": "digital",
- "technique_display_name": "Digital printing",
- "price": "9.50",
- "discounted_price": "8.50"
}
]
}
}, - "_links": {
}
}
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.
id required | integer Product ID. |
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 |
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. |
required | Array of objects (VariantImages) |
required | object (Paging) Paging information |
required | object HATEOAS links |
{- "data": [
- {
- "catalog_variant_id": 4017,
- "color": "Turquoise",
- "primary_hex_color": "#15d0d2",
- "secondary_hex_color": null,
- "images": [
- {
- "placement": "front",
- "background_color": "#0f0f0f",
}
]
}
], - "paging": {
- "total": 100,
- "offset": 10,
- "limit": 100
}, - "_links": {
}
}
Retrieve the list of countries the Catalog Product can be shipped to.
id required | integer Product ID. |
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. |
required | Array of objects (Country) |
{- "data": [
- {
- "code": "AU",
- "name": "Australia"
}
]
}
Returns images for a specified Variant.
id required | integer Variant ID |
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 |
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. |
required | Array of objects (VariantImages) |
required | object HATEOAS links |
{- "data": [
- {
- "catalog_variant_id": 4017,
- "color": "Turquoise",
- "primary_hex_color": "#15d0d2",
- "secondary_hex_color": null,
- "images": [
- {
- "placement": "front",
- "background_color": "#0f0f0f",
}
]
}
], - "_links": {
}
}
Returns information about available mockup styles for specified catalog product.
id required | integer Product ID. |
placements | Array of strings Examples:
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) |
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. |
required | Array of objects (MockupStyles) |
required | object (Paging) Paging information |
required | object HATEOAS links |
{- "data": [
- {
- "placement": "front",
- "display_name": "Front print",
- "technique": "dtg",
- "print_area_width": 5,
- "print_area_height": 5,
- "print_area_type": "simple",
- "dpi": 150,
- "mockup_styles": [
- {
- "id": 1,
- "category_name": "Couple's",
- "view_name": "Front",
- "restricted_to_variants": [
- 4,
- 15032,
- 10750
]
}
]
}
], - "paging": {
- "total": 100,
- "offset": 10,
- "limit": 100
}, - "_links": {
- "self": {
}, - "next": {
}, - "previous": {
}, - "last": {
},
}
}
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.
id required | integer Product ID. |
placements | Array of strings Examples:
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:
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 |
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. |
required | Array of objects (MockupTemplates) |
object (Paging) Paging information | |
required | object HATEOAS links |
{- "data": [
- {
- "catalog_variant_ids": [
- 4011
], - "placement": "front",
- "technique": "dtg",
- "background_url": null,
- "background_color": null,
- "template_width": 560,
- "template_height": 295,
- "print_area_width": 520,
- "print_area_height": 202,
- "print_area_top": 18,
- "print_area_left": 20,
- "template_positioning": "overlay",
- "orientation": "any",
- "template_type": "custom",
- "role": "template"
}
], - "paging": {
- "total": 100,
- "offset": 10,
- "limit": 100
}, - "_links": {
- "self": {
}, - "next": {
}, - "previous": {
}, - "last": {
},
}
}
Provides information about the catalog product stock status. Stock availability is grouped by variants → techniques → selling regions.
id required | integer Product ID. |
techniques | Array of strings (TechniqueEnum) Items Enum: "dtg" "digital" "cut-sew" "uv" "embroidery" "sublimation" "dtfilm" Examples:
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:
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 |
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. |
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 |
{- "data": [
- {
- "catalog_variant_id": 4011,
- "techniques": [
- {
- "technique": "dtg",
- "selling_regions": [
- {
- "name": "worldwide",
- "availability": "in stock",
- "placement_option_availability": [
- {
- "name": "unlimited_color",
- "availability": true
}
]
}
]
}
],
}
], - "paging": {
- "total": 100,
- "offset": 10,
- "limit": 100
}, - "filter_settings": [
- {
- "name": "selling_region_name",
- "value": "worldwide"
}
], - "_links": {
- "previous": {
}, - "last": {
},
}
}
Provides information about the catalog variant stock status. Stock availability is grouped by variants → techniques → selling regions.
id required | integer Variant ID |
techniques | Array of strings (TechniqueEnum) Items Enum: "dtg" "digital" "cut-sew" "uv" "embroidery" "sublimation" "dtfilm" Examples:
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. |
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. |
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 |
{- "data": {
- "catalog_variant_id": 4011,
- "techniques": [
- {
- "technique": "dtg",
- "selling_regions": [
- {
- "name": "worldwide",
- "availability": "in stock",
- "placement_option_availability": [
- {
- "name": "unlimited_color",
- "availability": true
}
]
}
]
}
],
}, - "filter_settings": [
- {
- "name": "selling_region_name",
- "value": "worldwide"
}
], - "_links": {
}
}
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"
}
]
}
]
}
]
}
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 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 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"
}
]
}
]
}
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.
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.
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
.
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
}
}
]
...
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.
Position | Mockup | Payload |
Top left | ![]() |
|
Top middle | ![]() |
|
Top right | ![]() |
|
Middle | ![]() |
|
Bottom left | ![]() |
|
Bottom middle | ![]() |
|
Bottom right | ![]() |
|
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:
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.unlimited_color
which if specified causes the
placement to be fulfilled using Unlimited Color embroidery3d_puff
option if set to true causes that particular layer to use 3D puff embroidery.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.
Field annotations:
packing_slip.logo_url
field.packing_slip.store_name
.packing_slip.phone
field.packing_slip.email
field.gift
field was provided in the order request.packing_slip.custom_order_id
field.packing_slip.message
field.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!"
}
}
}
The Orders endpoints for the V2 Beta are incomplete. Some V1 endpoints will still need to be used to achieve certain functionality.
DELETE https://api.printful.com/orders/{order_id}
https://developers.printful.com/docs/#operation/cancelOrderByIdPUT https://api.printful.com/orders/{order_id}
https://developers.printful.com/docs/#operation/updateOrderByIdOrder 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 from a specific store. The order list will be paginated with twenty items per page by default.
limit | integer [ 1 .. 100 ] Default: 20 The number of results to return per page. |
offset | integer >= 0 Default: 0 Examples:
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 |
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. |
required | Array of objects (OrderSummary) |
required | object (Paging) Paging information |
required | object HATEOAS links |
{- "data": [
- {
- "id": 123,
- "external_id": "4235234213",
- "store_id": 10,
- "shipping": "STANDARD",
- "status": "draft",
- "created_at": "2023-04-05T06:07:08Z",
- "updated_at": "2023-04-05T06:07:08Z",
- "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": "2312322334",
- "tax_number": "123.456.789-10"
}, - "costs": {
- "calculation_status": "done",
- "currency": "USD",
- "subtotal": "14.95",
- "discount": "1.79",
- "shipping": "4.79",
- "digitization": "3.95",
- "additional_fee": "0.00",
- "fulfillment_fee": "0.00",
- "retail_delivery_fee": "0.00",
- "vat": "4.60",
- "tax": "0.00",
- "total": "26.50"
}, - "retail_costs": {
- "calculation_status": "done",
- "currency": "EUR",
- "subtotal": "26.55",
- "discount": "0.00",
- "shipping": "4.79",
- "vat": "0.00",
- "tax": "0.00",
- "total": "31.34"
}, - "order_items": [
- {
- "id": 1234,
- "type": "order_item",
- "source": "catalog",
- "catalog_variant_id": 4011,
- "external_id": "123_abc",
- "quantity": 1,
- "name": "Custom name",
- "price": "8.00",
- "retail_price": "10.00",
- "currency": "EUR",
- "retail_currency": "USD",
- "_links": {
- "self": {
- "href": "/v2/orders/123/items/123"
}
}
}
], - "_links": {
}
}
], - "paging": {
- "total": 100,
- "offset": 10,
- "limit": 100
}, - "_links": {
}
}
This endpoint allows the creation of a new order in which the default status will be draft
.
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. |
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 |
required | object (Order) Order |
{- "external_id": "4235234213",
- "shipping": "STANDARD",
- "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": "2312322334",
- "tax_number": "123.456.789-10"
}, - "order_items": [
- {
- "source": "catalog",
- "catalog_variant_id": 4011,
- "external_id": "123_abc",
- "quantity": 1,
- "retail_price": "10.00",
- "name": "Custom name",
- "placements": [
- {
- "placement": "front",
- "technique": "dtg",
- "print_area_type": "simple",
- "layers": [
- {
- "type": "file",
- "url": "https://www.printful.com/static/images/layout/printful-logo.png",
- "layer_options": [
- {
- "name": "3d_puff",
- "value": true
}
], - "position": {
- "width": 10,
- "height": 10,
- "top": 0,
- "left": 0
}
}
], - "placement_options": [
- {
- "name": "unlimited_color",
- "value": true
}
]
}
], - "product_options": [
- {
- "name": "inside_pocket",
- "value": true
}
]
}
], - "customization": {
- "gift": {
- "subject": "To John",
- "message": "Happy birthday!"
}, - "packing_slip": {
- "phone": "+48000000000",
- "message": "This is a message",
- "store_name": "A store",
- "custom_order_id": "11235813"
}
}, - "retail_costs": {
- "currency": "EUR",
- "discount": "123.40",
- "shipping": "123.40",
- "tax": "123.40"
}
}
{- "data": {
- "id": 123,
- "external_id": "4235234213",
- "store_id": 10,
- "shipping": "STANDARD",
- "status": "draft",
- "created_at": "2023-04-05T06:07:08Z",
- "updated_at": "2023-04-05T06:07:08Z",
- "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": "2312322334",
- "tax_number": "123.456.789-10"
}, - "costs": {
- "calculation_status": "done",
- "currency": "USD",
- "subtotal": "14.95",
- "discount": "1.79",
- "shipping": "4.79",
- "digitization": "3.95",
- "additional_fee": "0.00",
- "fulfillment_fee": "0.00",
- "retail_delivery_fee": "0.00",
- "vat": "4.60",
- "tax": "0.00",
- "total": "26.50"
}, - "retail_costs": {
- "calculation_status": "done",
- "currency": "EUR",
- "subtotal": "26.55",
- "discount": "0.00",
- "shipping": "4.79",
- "vat": "0.00",
- "tax": "0.00",
- "total": "31.34"
}, - "order_items": [
- {
- "id": 1234,
- "type": "order_item",
- "source": "catalog",
- "catalog_variant_id": 4011,
- "external_id": "123_abc",
- "quantity": 1,
- "name": "Custom name",
- "price": "8.00",
- "retail_price": "10.00",
- "currency": "EUR",
- "retail_currency": "USD",
- "_links": {
- "self": {
- "href": "/v2/orders/123/items/123"
}
}
}
], - "customization": {
- "gift": {
- "subject": "To John",
- "message": "Happy birthday!"
}, - "packing_slip": {
- "phone": "+48000000000",
- "message": "This is a message",
- "store_name": "A store",
- "custom_order_id": "11235813"
}
}, - "_links": {
}
}
}
Retrieve a single order from the specified store. The result object will contain links to the same resource, order items, and shipments.
required | integer or string Order ID (integer) or Order External ID (string prepended with "@" symbol) |
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. |
required | object (Order) Order |
{- "data": {
- "id": 123,
- "external_id": "4235234213",
- "store_id": 10,
- "shipping": "STANDARD",
- "status": "draft",
- "created_at": "2023-04-05T06:07:08Z",
- "updated_at": "2023-04-05T06:07:08Z",
- "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": "2312322334",
- "tax_number": "123.456.789-10"
}, - "costs": {
- "calculation_status": "done",
- "currency": "USD",
- "subtotal": "14.95",
- "discount": "1.79",
- "shipping": "4.79",
- "digitization": "3.95",
- "additional_fee": "0.00",
- "fulfillment_fee": "0.00",
- "retail_delivery_fee": "0.00",
- "vat": "4.60",
- "tax": "0.00",
- "total": "26.50"
}, - "retail_costs": {
- "calculation_status": "done",
- "currency": "EUR",
- "subtotal": "26.55",
- "discount": "0.00",
- "shipping": "4.79",
- "vat": "0.00",
- "tax": "0.00",
- "total": "31.34"
}, - "order_items": [
- {
- "id": 1234,
- "type": "order_item",
- "source": "catalog",
- "catalog_variant_id": 4011,
- "external_id": "123_abc",
- "quantity": 1,
- "name": "Custom name",
- "price": "8.00",
- "retail_price": "10.00",
- "currency": "EUR",
- "retail_currency": "USD",
- "_links": {
- "self": {
- "href": "/v2/orders/123/items/123"
}
}
}
], - "customization": {
- "gift": {
- "subject": "To John",
- "message": "Happy birthday!"
}, - "packing_slip": {
- "phone": "+48000000000",
- "message": "This is a message",
- "store_name": "A store",
- "custom_order_id": "11235813"
}
}, - "_links": {
}
}
}
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.
required | integer or string Order ID (integer) or Order External ID (string prepended with "@" symbol) |
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. |
{- "code": 401,
- "result": "Malformed Authorization header.",
- "error": {
- "reason": "BadRequest",
- "message": "Malformed Authorization header."
}
}
Make a partial update of an order.
required | integer or string Order ID (integer) or Order External ID (string prepended with "@" symbol) |
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. |
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 |
required | object (Order) Order |
{- "external_id": "4235234213",
- "shipping": "STANDARD",
- "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": "2312322334",
- "tax_number": "123.456.789-10"
}, - "order_items": [
- {
- "source": "catalog",
- "catalog_variant_id": 4011,
- "external_id": "123_abc",
- "quantity": 1,
- "retail_price": "10.00",
- "name": "Custom name",
- "placements": [
- {
- "placement": "front",
- "technique": "dtg",
- "print_area_type": "simple",
- "layers": [
- {
- "type": "file",
- "url": "https://www.printful.com/static/images/layout/printful-logo.png",
- "layer_options": [
- {
- "name": "3d_puff",
- "value": true
}
], - "position": {
- "width": 10,
- "height": 10,
- "top": 0,
- "left": 0
}
}
], - "placement_options": [
- {
- "name": "unlimited_color",
- "value": true
}
]
}
], - "product_options": [
- {
- "name": "inside_pocket",
- "value": true
}
]
}
], - "customization": {
- "gift": {
- "subject": "To John",
- "message": "Happy birthday!"
}, - "packing_slip": {
- "phone": "+48000000000",
- "message": "This is a message",
- "store_name": "A store",
- "custom_order_id": "11235813"
}
}, - "retail_costs": {
- "currency": "EUR",
- "discount": "123.40",
- "shipping": "123.40",
- "tax": "123.40"
}
}
{- "data": {
- "id": 123,
- "external_id": "4235234213",
- "store_id": 10,
- "shipping": "STANDARD",
- "status": "draft",
- "created_at": "2023-04-05T06:07:08Z",
- "updated_at": "2023-04-05T06:07:08Z",
- "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": "2312322334",
- "tax_number": "123.456.789-10"
}, - "costs": {
- "calculation_status": "done",
- "currency": "USD",
- "subtotal": "14.95",
- "discount": "1.79",
- "shipping": "4.79",
- "digitization": "3.95",
- "additional_fee": "0.00",
- "fulfillment_fee": "0.00",
- "retail_delivery_fee": "0.00",
- "vat": "4.60",
- "tax": "0.00",
- "total": "26.50"
}, - "retail_costs": {
- "calculation_status": "done",
- "currency": "EUR",
- "subtotal": "26.55",
- "discount": "0.00",
- "shipping": "4.79",
- "vat": "0.00",
- "tax": "0.00",
- "total": "31.34"
}, - "order_items": [
- {
- "id": 1234,
- "type": "order_item",
- "source": "catalog",
- "catalog_variant_id": 4011,
- "external_id": "123_abc",
- "quantity": 1,
- "name": "Custom name",
- "price": "8.00",
- "retail_price": "10.00",
- "currency": "EUR",
- "retail_currency": "USD",
- "_links": {
- "self": {
- "href": "/v2/orders/123/items/123"
}
}
}
], - "customization": {
- "gift": {
- "subject": "To John",
- "message": "Happy birthday!"
}, - "packing_slip": {
- "phone": "+48000000000",
- "message": "This is a message",
- "store_name": "A store",
- "custom_order_id": "11235813"
}
}, - "_links": {
}
}
}
This endpoint allows customers to confirm the order and start the fulfillment in the production facility.
required | integer or string Order ID (integer) or Order External ID (string prepended with "@" symbol) |
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. |
required | object (Order) Order |
required | object HATEOAS links |
{- "data": {
- "id": 123,
- "external_id": "4235234213",
- "store_id": 10,
- "shipping": "STANDARD",
- "status": "draft",
- "created_at": "2023-04-05T06:07:08Z",
- "updated_at": "2023-04-05T06:07:08Z",
- "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": "2312322334",
- "tax_number": "123.456.789-10"
}, - "costs": {
- "calculation_status": "done",
- "currency": "USD",
- "subtotal": "14.95",
- "discount": "1.79",
- "shipping": "4.79",
- "digitization": "3.95",
- "additional_fee": "0.00",
- "fulfillment_fee": "0.00",
- "retail_delivery_fee": "0.00",
- "vat": "4.60",
- "tax": "0.00",
- "total": "26.50"
}, - "retail_costs": {
- "calculation_status": "done",
- "currency": "EUR",
- "subtotal": "26.55",
- "discount": "0.00",
- "shipping": "4.79",
- "vat": "0.00",
- "tax": "0.00",
- "total": "31.34"
}, - "order_items": [
- {
- "id": 1234,
- "type": "order_item",
- "source": "catalog",
- "catalog_variant_id": 4011,
- "external_id": "123_abc",
- "quantity": 1,
- "name": "Custom name",
- "price": "8.00",
- "retail_price": "10.00",
- "currency": "EUR",
- "retail_currency": "USD",
- "_links": {
- "self": {
- "href": "/v2/orders/123/items/123"
}
}
}
], - "customization": {
- "gift": {
- "subject": "To John",
- "message": "Happy birthday!"
}, - "packing_slip": {
- "phone": "+48000000000",
- "message": "This is a message",
- "store_name": "A store",
- "custom_order_id": "11235813"
}
}, - "_links": {
}
}, - "_links": {
}
}
This endpoint retrieves the list of items that belong to the order.
required | integer or string Order ID (integer) or Order External ID (string prepended with "@" symbol) |
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:
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 |
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. |
required | Array of any |
required | object HATEOAS links |
{- "data": [
- {
- "source": "catalog",
- "catalog_variant_id": 4011,
- "id": 1234,
- "external_id": "123_abc",
- "quantity": 1,
- "retail_price": "10.00",
- "name": "Custom name",
- "placements": [
- {
- "placement": "front",
- "technique": "dtg",
- "layers": [
- {
- "type": "file",
- "url": "https://www.printful.com/static/images/layout/printful-logo.png",
- "layer_options": [
- {
- "name": "3d_puff",
- "value": true
}
], - "position": {
- "width": 10,
- "height": 10,
- "top": 0,
- "left": 0
}
}
], - "placement_options": [
- {
- "name": "unlimited_color",
- "value": true
}
], - "status": "ok",
- "status_explanation": "Product with ID: 656 cannot have disjointed design elements."
}
], - "product_options": [
- {
- "name": "inside_pocket",
- "value": true
}
], - "_links": {
- "self": {
- "href": "/v2/orders/123/order-items/123"
}
}
}
], - "_links": {
}
}
This endpoint allows the creation of a new item that will be added to an existing order.
required | integer or string Order ID (integer) or Order External ID (string prepended with "@" symbol) |
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. |
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 |
required | Array of any |
required | object HATEOAS links |
{- "source": "catalog",
- "catalog_variant_id": 4011,
- "external_id": "123_abc",
- "quantity": 1,
- "retail_price": "10.00",
- "name": "Custom name",
- "placements": [
- {
- "placement": "front",
- "technique": "dtg",
- "print_area_type": "simple",
- "layers": [
- {
- "type": "file",
- "url": "https://www.printful.com/static/images/layout/printful-logo.png",
- "layer_options": [
- {
- "name": "3d_puff",
- "value": true
}
], - "position": {
- "width": 10,
- "height": 10,
- "top": 0,
- "left": 0
}
}
], - "placement_options": [
- {
- "name": "unlimited_color",
- "value": true
}
]
}
], - "product_options": [
- {
- "name": "inside_pocket",
- "value": true
}
]
}
{- "data": [
- {
- "source": "catalog",
- "catalog_variant_id": 4011,
- "id": 1234,
- "external_id": "123_abc",
- "quantity": 1,
- "retail_price": "10.00",
- "name": "Custom name",
- "placements": [
- {
- "placement": "front",
- "technique": "dtg",
- "layers": [
- {
- "type": "file",
- "url": "https://www.printful.com/static/images/layout/printful-logo.png",
- "layer_options": [
- {
- "name": "3d_puff",
- "value": true
}
], - "position": {
- "width": 10,
- "height": 10,
- "top": 0,
- "left": 0
}
}
], - "placement_options": [
- {
- "name": "unlimited_color",
- "value": true
}
], - "status": "ok",
- "status_explanation": "Product with ID: 656 cannot have disjointed design elements."
}
], - "product_options": [
- {
- "name": "inside_pocket",
- "value": true
}
], - "_links": {
- "self": {
- "href": "/v2/orders/123/order-items/123"
}
}
}
], - "_links": {
}
}
This endpoint will retrieve a single order item specified in the request.
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) |
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. |
required | any |
required | object HATEOAS links |
{- "data": {
- "source": "catalog",
- "catalog_variant_id": 4011,
- "id": 1234,
- "external_id": "123_abc",
- "quantity": 1,
- "retail_price": "10.00",
- "name": "Custom name",
- "placements": [
- {
- "placement": "front",
- "technique": "dtg",
- "layers": [
- {
- "type": "file",
- "url": "https://www.printful.com/static/images/layout/printful-logo.png",
- "layer_options": [
- {
- "name": "3d_puff",
- "value": true
}
], - "position": {
- "width": 10,
- "height": 10,
- "top": 0,
- "left": 0
}
}
], - "placement_options": [
- {
- "name": "unlimited_color",
- "value": true
}
], - "status": "ok",
- "status_explanation": "Product with ID: 656 cannot have disjointed design elements."
}
], - "product_options": [
- {
- "name": "inside_pocket",
- "value": true
}
], - "_links": {
- "self": {
- "href": "/v2/orders/123/order-items/123"
}
}
}, - "_links": {
}
}
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.
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) |
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. |
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 |
required | Array of any |
required | object HATEOAS links |
{- "source": "catalog",
- "catalog_variant_id": 4011,
- "external_id": "123_abc",
- "quantity": 1,
- "retail_price": "10.00",
- "name": "Custom name",
- "placements": [
- {
- "placement": "front",
- "technique": "dtg",
- "print_area_type": "simple",
- "layers": [
- {
- "type": "file",
- "url": "https://www.printful.com/static/images/layout/printful-logo.png",
- "layer_options": [
- {
- "name": "3d_puff",
- "value": true
}
], - "position": {
- "width": 10,
- "height": 10,
- "top": 0,
- "left": 0
}
}
], - "placement_options": [
- {
- "name": "unlimited_color",
- "value": true
}
]
}
], - "product_options": [
- {
- "name": "inside_pocket",
- "value": true
}
]
}
{- "data": [
- {
- "source": "catalog",
- "catalog_variant_id": 4011,
- "id": 1234,
- "external_id": "123_abc",
- "quantity": 1,
- "retail_price": "10.00",
- "name": "Custom name",
- "placements": [
- {
- "placement": "front",
- "technique": "dtg",
- "layers": [
- {
- "type": "file",
- "url": "https://www.printful.com/static/images/layout/printful-logo.png",
- "layer_options": [
- {
- "name": "3d_puff",
- "value": true
}
], - "position": {
- "width": 10,
- "height": 10,
- "top": 0,
- "left": 0
}
}
], - "placement_options": [
- {
- "name": "unlimited_color",
- "value": true
}
], - "status": "ok",
- "status_explanation": "Product with ID: 656 cannot have disjointed design elements."
}
], - "product_options": [
- {
- "name": "inside_pocket",
- "value": true
}
], - "_links": {
- "self": {
- "href": "/v2/orders/123/order-items/123"
}
}
}
], - "_links": {
}
}
Remove a single item from the order.
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) |
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. |
{- "code": 400,
- "result": "Missing required parameters",
- "error": {
- "reason": "BadRequest",
- "message": "Missing required parameters"
}
}
Shipments contain information about how and when your orders items will be delivered and fulfilled.
required | integer or string Order ID (integer) or Order External ID (string prepended with "@" symbol) |
limit | integer [ 1 .. 100 ] Default: 20 The number of results to return per page. |
offset | integer >= 0 Default: 0 Examples:
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 |
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. |
required | Array of objects (Shipment) |
required | object |
required | object (Paging) Paging information |
{- "data": [
- {
- "id": 1,
- "order_id": 2,
- "order_external_id": "my_custom_id_1234",
- "carrier": "USPS",
- "service": "USPS Priority Mail",
- "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"
}, - "is_reshipment": true,
- "tracking_url": "https://myorders.com/tracking/39925631",
- "tracking_events": [
- {
- "triggered_at": "2023-06-15T19:15:05Z",
- "description": "Arrived At Destination"
}
], - "estimated_delivery": {
- "from_date": "2023-06-15",
- "to_date": "2023-06-15",
- "calculated_at": "2023-06-15T16:35:35Z"
}, - "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"
}
}
}
], - "_links": {
- "self": {
- "href": "https://api.printful.com/v2/shipments/1"
}, - "order": {
- "href": "https://api.printful.com/v2/orders/2"
}
}
}
], - "_links": {
- "self": {
- "href": "https://api.printful.com/v2/orders/123/shipments?limit=20&offset=0"
}, - "next": {
- "href": "https://api.printful.com/v2/orders/123/shipments?limit=20&offset=20"
}, - "previous": {
- "href": "https://api.printful.com/v2/orders/123/shipments?limit=20&offset=0"
}, - "first": {
- "href": "https://api.printful.com/v2/orders/123/shipments?limit=20&offset=0"
}, - "last": {
- "href": "https://api.printful.com/v2/orders/123/shipments?limit=20&offset=20"
}
}, - "paging": {
- "total": 100,
- "offset": 10,
- "limit": 100
}
}
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}
.
required | integer or string Order ID (integer) or Order External ID (string prepended with "@" symbol) |
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. |
required | object |
{- "data": {
- "media_type": "application/pdf",
- "content": "0xLjQKJeLjz9MKMyAwIG9iago8PC9UeXBlIC9QYWdlCi9QYXJlbnQgMSAwIFIKL01lZG",
- "_links": {
}
}
}
Retrieve an order cost estimation task from a specific store. Estimation results are only available for one hour after cost estimation task is done.
id required | string Order estimation task ID. |
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. |
required | object (OrderEstimationTaskSummary) Order estimation task summary |
{- "data": {
- "id": "fc959efb-b3a0-4c12-9cc6-f54d3158291d",
- "status": "completed",
- "costs": {
- "calculation_status": "done",
- "currency": "USD",
- "subtotal": "14.95",
- "discount": "1.79",
- "shipping": "4.79",
- "digitization": "3.95",
- "additional_fee": "0.00",
- "fulfillment_fee": "0.00",
- "retail_delivery_fee": "0.00",
- "vat": "4.60",
- "tax": "0.00",
- "total": "26.50"
}, - "retail_costs": {
- "calculation_status": "done",
- "currency": "EUR",
- "subtotal": "26.55",
- "discount": "0.00",
- "shipping": "4.79",
- "vat": "0.00",
- "tax": "0.00",
- "total": "31.34"
}, - "failure_reasons": [ ]
}
}
Use this endpoint to estimate orders with items.
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. |
POST request body
required | object (Address) The recipient data. |
required | Array of any Array of order items |
object (RetailCosts-2) Retail costs |
required | object (OrderEstimationTaskSummary) Order estimation task summary |
{- "recipient": {
- "state_code": "CA",
- "country_code": "US",
- "zip": "91311"
}, - "order_items": [
- {
- "source": "catalog",
- "catalog_variant_id": 4011,
- "external_id": "123_abc",
- "quantity": 1,
- "retail_price": "10.00",
- "name": "Custom name",
- "placements": [
- {
- "placement": "front",
- "technique": "dtg",
- "print_area_type": "simple",
- "layers": [
- {
- "type": "file",
- "url": "https://www.printful.com/static/images/layout/printful-logo.png",
- "layer_options": [
- {
- "name": "3d_puff",
- "value": true
}
], - "position": {
- "width": 10,
- "height": 10,
- "top": 0,
- "left": 0
}
}
], - "placement_options": [
- {
- "name": "unlimited_color",
- "value": true
}
]
}
], - "product_options": [
- {
- "name": "inside_pocket",
- "value": true
}
]
}
], - "retail_costs": {
- "currency": "EUR",
- "discount": "123.40",
- "shipping": "123.40",
- "tax": "123.40"
}
}
{- "data": {
- "id": "fc959efb-b3a0-4c12-9cc6-f54d3158291d",
- "status": "pending",
- "costs": null,
- "retail_costs": null,
- "failure_reasons": [ ]
}
}
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.
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.
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.
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.
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. |
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 |
visible | boolean Default: true Show file in the Printfile Library |
required | object (File) Information about the File |
{- "role": "printfile",
- "url": "https://www.example.com/files/tshirts/example.png",
- "filename": "shirt1.png",
- "visible": true
}
{- "data": {
- "id": 123,
- "url": "https://www.example.com/files/tshirts/example.png",
- "hash": "ea44330b887dfec278dbc4626a759547",
- "filename": "shirt1.png",
- "mime_type": "image/png",
- "size": 45582633,
- "width": 1000,
- "height": 1000,
- "dpi": 300,
- "status": "ok",
- "created": "2023-04-05T06:07:08Z",
- "visible": true,
- "is_temporary": false,
}
}
Get basic information about the file stored in the file library
id required | integer File ID. |
required | object (File) Information about the File |
{- "data": {
- "id": 123,
- "url": "https://www.example.com/files/tshirts/example.png",
- "hash": "ea44330b887dfec278dbc4626a759547",
- "filename": "shirt1.png",
- "mime_type": "image/png",
- "size": 45582633,
- "width": 1000,
- "height": 1000,
- "dpi": 300,
- "status": "ok",
- "created": "2023-04-05T06:07:08Z",
- "visible": true,
- "is_temporary": false,
}
}
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.
Get information about all countries where Printful is available
offset | integer >= 0 Default: 0 Examples:
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. |
required | Array of objects (Country) |
required | object (Paging) Paging information |
required | object HATEOAS links |
{- "data": [
- {
- "code": "AU",
- "name": "Australia",
- "states": [
- {
- "code": "ACT",
- "name": "Australian Capital Territory"
}
]
}
], - "paging": {
- "total": 100,
- "offset": 10,
- "limit": 100
}, - "_links": {
}
}
Rate limiting: The default rate limit is 120 requests per 60 seconds.
A 60 seconds lockout is applied if request count is exceeded.
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.
Returns available shipping options and rates for the given list of products.
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. |
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. |
required | Array of objects |
{- "recipient": {
- "address1": "19749 Dearborn St",
- "address2": "string",
- "city": "Chatsworth",
- "state_code": "CA",
- "country_code": "US",
- "zip": "91311"
}, - "order_items": [
- {
- "source": "catalog",
- "quantity": 1,
- "catalog_variant_id": 4011,
- "placements": [
- {
- "placement": "front",
- "technique": "dtg",
- "print_area_type": "simple",
- "placement_options": [
- {
- "name": "unlimited_color",
- "value": true
}
]
}
], - "product_options": [
- {
- "name": "inside_pocket",
- "value": true
}
]
}
], - "currency": "string"
}
{- "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
}
]
}
]
}
This endpoint returns paginated results containing detailed information about warehouse products, including their variants, stock levels, and dimensions.
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:
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 |
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. |
required | Array of objects |
required | object (Paging) Paging information |
required | object HATEOAS links |
{- "data": [
- {
- "id": 356,
- "name": "Black Heather",
- "status": "draft",
- "currency": "USD",
- "retail_price": 21.54,
- "warehouse_variants": [
- {
- "id": 32453,
- "name": "Black Heather",
- "sku": "some-sku-12",
- "image_url": "url.to/your/image/location.png",
- "retail_price": 32.56,
- "quantity": 23,
- "dimensions": {
- "measurement_system": "imperial",
- "width": 3.21,
- "height": 4.56,
- "length": 6.53,
- "weight": 3
},
}
], - "_links": {
- "warehouse_variants": {
}
}
}
], - "paging": {
- "total": 100,
- "offset": 10,
- "limit": 100
}, - "_links": {
}
}
Get information about a single warehouse product with it's stock location.
warehouse_product_id required | integer Warehouse Product ID. |
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. |
required | object |
{- "data": {
- "id": 356,
- "name": "Black Heather",
- "status": "draft",
- "currency": "USD",
- "retail_price": 21.54,
- "warehouse_variants": [
- {
- "id": 32453,
- "name": "Black Heather",
- "sku": "some-sku-12",
- "image_url": "url.to/your/image/location.png",
- "retail_price": 32.56,
- "quantity": 23,
- "stock_location": [
- {
- "facility": "Charlotte Steele Point, United States",
- "stocked": 10,
- "available": 10
}
], - "dimensions": {
- "measurement_system": "imperial",
- "width": 3.21,
- "height": 4.56,
- "length": 6.53,
- "weight": 3
},
}
], - "_links": {
- "warehouse_variants": {
}
}
}
}
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 |
|
![]() |
|
![]() |
|
![]() |
|
![]() |
|
![]() |
|
![]() |
|
![]() |
|
![]() |
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.
An account is allowed to make a number of mockup generation requests per minute. The limit is:
Additionally, there is a limit of 20,000 files that can be generated daily by each environment.
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
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. |
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) |
required | Array of objects (MockupGeneratorTask) |
required | object HATEOAS links |
{- "format": "jpg",
- "products": [
- {
- "source": "catalog",
- "mockup_style_ids": [
- 123
], - "catalog_product_id": 71,
- "catalog_variant_ids": [ ],
- "orientation": "vertical",
- "placements": [
- {
- "placement": "front",
- "technique": "dtg",
- "print_area_type": "simple",
- "layers": [
- {
- "type": "file",
- "url": "https://www.printful.com/static/images/layout/printful-logo.png",
- "layer_options": [
- {
- "name": "3d_puff",
- "value": true
}
], - "position": {
- "width": 10,
- "height": 10,
- "top": 0,
- "left": 0
}
}
], - "placement_options": [
- {
- "name": "unlimited_color",
- "value": true
}
]
}
], - "product_options": [
- {
- "name": "inside_pocket",
- "value": true
}
]
}
]
}
{- "data": [
- {
- "id": 597350033,
- "status": "completed",
- "catalog_variant_mockups": [
- {
- "catalog_variant_id": 4011,
- "mockups": [
- {
- "placement": "front",
- "display_name": "Front Print",
- "technique": "dtg",
- "style_id": 1,
}
]
}
], - "failure_reasons": [
- {
- "detail": "Parameter `xyz` was incorrect",
- "source": {
- "header": "X-PF-Language"
}, - "valid_values": [
- "Front"
]
}
],
}
],
}
Returns result of Mockup Generator tasks
id required | Array of strings Examples:
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:
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 |
required | Array of objects (MockupGeneratorTask) |
required | object (Paging) Paging information |
required | object HATEOAS links |
{- "data": [
- {
- "id": 597350033,
- "status": "completed",
- "catalog_variant_mockups": [
- {
- "catalog_variant_id": 4011,
- "mockups": [
- {
- "placement": "front",
- "display_name": "Front Print",
- "technique": "dtg",
- "style_id": 1,
}
]
}
], - "failure_reasons": [
- {
- "detail": "Parameter `xyz` was incorrect",
- "source": {
- "header": "X-PF-Language"
}, - "valid_values": [
- "Front"
]
}
],
}
], - "paging": {
- "total": 100,
- "offset": 10,
- "limit": 100
}, - "_links": {
}
}
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.
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.
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.
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.
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 |
{- "type": "shipment_sent",
- "occurred_at": "2023-04-05T06:07:08Z",
- "retries": 2,
- "store_id": 12,
- "data": {
- "shipment": {
- "id": 0,
- "status": "string",
- "store_id": 0,
- "tracking_number": "string",
- "tracking_url": "https://www.fedex.com/fedextrack/?tracknumbers=0000000000",
- "created_at": "2023-04-05T06:07:08Z",
- "ship_date": "2023-03-21",
- "shipped_at": "2023-04-05T06:07:08Z",
- "reshipment": false
}, - "order": {
- "id": 0,
- "external_id": "string",
- "status": "string",
- "store_id": 0,
- "dashboard_url": "string",
- "created_at": "2023-04-05T06:07:08Z",
- "updated_at": "2023-04-05T06:07:08Z"
}
}
}
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
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 |
{- "type": "shipment_returned",
- "occurred_at": "2023-04-05T06:07:08Z",
- "retries": 2,
- "store_id": 12,
- "data": {
- "reason": "string",
- "shipment": {
- "id": 0,
- "status": "string",
- "store_id": 0,
- "tracking_number": "string",
- "tracking_url": "https://www.fedex.com/fedextrack/?tracknumbers=0000000000",
- "created_at": "2023-04-05T06:07:08Z",
- "ship_date": "2023-03-21",
- "shipped_at": "2023-04-05T06:07:08Z",
- "reshipment": false
}, - "order": {
- "id": 0,
- "external_id": "string",
- "status": "string",
- "store_id": 0,
- "dashboard_url": "string",
- "created_at": "2023-04-05T06:07:08Z",
- "updated_at": "2023-04-05T06:07:08Z"
}
}
}
Is called when a shipment goes out of stock (is_out_of_stock = true
) or comes back in stock (is_out_of_stock = false
).
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 |
{- "type": "shipment_out_of_stock",
- "occurred_at": "2023-04-05T06:07:08Z",
- "retries": 2,
- "store_id": 12,
- "data": {
- "is_out_of_stock": true,
- "shipment": {
- "id": 0,
- "status": "string",
- "store_id": 0,
- "tracking_number": "string",
- "tracking_url": "https://www.fedex.com/fedextrack/?tracknumbers=0000000000",
- "created_at": "2023-04-05T06:07:08Z",
- "ship_date": "2023-03-21",
- "shipped_at": "2023-04-05T06:07:08Z",
- "reshipment": false
}, - "order": {
- "id": 0,
- "external_id": "string",
- "status": "string",
- "store_id": 0,
- "dashboard_url": "string",
- "created_at": "2023-04-05T06:07:08Z",
- "updated_at": "2023-04-05T06:07:08Z"
}
}
}
Is called when the order is first created.
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 |
{- "type": "order_created",
- "occurred_at": "2023-04-05T06:07:08Z",
- "retries": 2,
- "store_id": 12,
- "data": {
- "order": {
- "id": 0,
- "external_id": "string",
- "status": "string",
- "store_id": 0,
- "dashboard_url": "string",
- "created_at": "2023-04-05T06:07:08Z",
- "updated_at": "2023-04-05T06:07:08Z"
}
}
}
Is called when an existing order gets updated for any reason - including things that are covered with other webhooks like order_canceled
.
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 |
{- "type": "order_updated",
- "occurred_at": "2023-04-05T06:07:08Z",
- "retries": 2,
- "store_id": 12,
- "data": {
- "order": {
- "id": 0,
- "external_id": "string",
- "status": "string",
- "store_id": 0,
- "dashboard_url": "string",
- "created_at": "2023-04-05T06:07:08Z",
- "updated_at": "2023-04-05T06:07:08Z"
}
}
}
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.
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 |
{- "type": "order_failed",
- "occurred_at": "2023-04-05T06:07:08Z",
- "retries": 2,
- "store_id": 12,
- "data": {
- "reason": "string",
- "order": {
- "id": 0,
- "external_id": "string",
- "status": "string",
- "store_id": 0,
- "dashboard_url": "string",
- "created_at": "2023-04-05T06:07:08Z",
- "updated_at": "2023-04-05T06:07:08Z"
}
}
}
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.
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 |
{- "type": "order_canceled",
- "occurred_at": "2023-04-05T06:07:08Z",
- "retries": 2,
- "store_id": 12,
- "data": {
- "reason": "string",
- "order": {
- "id": 0,
- "external_id": "string",
- "status": "string",
- "store_id": 0,
- "dashboard_url": "string",
- "created_at": "2023-04-05T06:07:08Z",
- "updated_at": "2023-04-05T06:07:08Z"
}
}
}
Is called when stock is updated for some of a product's variants.
Contains information about the availability of product variants that have changed.
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) |
{- "type": "catalog_stock_updated",
- "occurred_at": "2023-04-05T06:07:08Z",
- "retries": 2,
- "store_id": 12,
- "data": [
- {
- "catalog_product_id": 71,
- "catalog_variant_id": 4011,
- "techniques": [
- "string"
], - "availability": "in stock"
}
]
}
Is called when a catalog product price has changed.
This webhook is related to the pricing endpoint.
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 |
{- "type": "catalog_price_changed",
- "occurred_at": "2023-04-05T06:07:08Z",
- "retries": 2,
- "store_id": 12,
- "data": {
- "catalog_product_ids": [
- 71
]
}
}
Is called when order is put on hold.
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) |
{- "type": "order_put_hold",
- "occurred_at": "2023-04-05T06:07:08Z",
- "retries": 2,
- "store_id": 12,
- "data": {
- "reason": "string",
- "order": {
- "id": 0,
- "external_id": "string",
- "status": "string",
- "store_id": 0,
- "dashboard_url": "string",
- "created_at": "2023-04-05T06:07:08Z",
- "updated_at": "2023-04-05T06:07:08Z"
}
}
}
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.
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) |
{- "type": "order_put_hold_approval",
- "occurred_at": "2023-04-05T06:07:08Z",
- "retries": 2,
- "store_id": 12,
- "data": {
- "reason": "string",
- "approval_files": [
- {
- "confirm_hash": "a14e51714be01f98487fcf5131727d31",
- "submitted_design": "https://s3.staging.printful.com/upload/approval-design/ae/ae7b3d3e965c238b3e5c1a4e15696f07_l",
- "recommended_design": "https://s3.staging.printful.com/upload/approval-design/aa/aaf9e1c6b32cb7a2c04d2746108d4124_l",
}
], - "order": {
- "id": 0,
- "external_id": "string",
- "status": "string",
- "store_id": 0,
- "dashboard_url": "string",
- "created_at": "2023-04-05T06:07:08Z",
- "updated_at": "2023-04-05T06:07:08Z"
}
}
}
Is called when order is removed from hold.
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) |
{- "type": "order_remove_hold",
- "occurred_at": "2023-04-05T06:07:08Z",
- "retries": 2,
- "store_id": 12,
- "data": {
- "reason": "string",
- "order": {
- "id": 0,
- "external_id": "string",
- "status": "string",
- "store_id": 0,
- "dashboard_url": "string",
- "created_at": "2023-04-05T06:07:08Z",
- "updated_at": "2023-04-05T06:07:08Z"
}
}
}
Is called when a confirmed order has been refunded.
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 |
{- "type": "order_refunded",
- "occurred_at": "2023-04-05T06:07:08Z",
- "retries": 2,
- "store_id": 12,
- "data": {
- "currency": "string",
- "amount": "string",
- "order": {
- "id": 0,
- "external_id": "string",
- "status": "string",
- "store_id": 0,
- "dashboard_url": "string",
- "created_at": "2023-04-05T06:07:08Z",
- "updated_at": "2023-04-05T06:07:08Z"
}
}
}
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.
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 |
{- "type": "mockup_task_finished",
- "occurred_at": "2023-04-05T06:07:08Z",
- "retries": 2,
- "store_id": 12,
- "data": {
- "id": 597350033,
- "status": "completed",
- "catalog_variant_mockups": [
- {
- "catalog_variant_id": 4011,
- "mockups": [
- {
- "placement": "front",
- "display_name": "Front Print",
- "technique": "dtg",
- "style_id": 1,
}
]
}
], - "failure_reasons": [
- {
- "detail": "Parameter `xyz` was incorrect",
- "source": {
- "header": "X-PF-Language"
}, - "valid_values": [
- "Front"
]
}
],
}
}
Is called when a shipment is put on hold
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) |
{- "type": "shipment_put_hold",
- "occurred_at": "2023-04-05T06:07:08Z",
- "retries": 2,
- "store_id": 12,
- "data": {
- "reason": "string",
- "shipment": {
- "id": 0,
- "status": "string",
- "store_id": 0,
- "tracking_number": "string",
- "tracking_url": "https://www.fedex.com/fedextrack/?tracknumbers=0000000000",
- "created_at": "2023-04-05T06:07:08Z",
- "ship_date": "2023-03-21",
- "shipped_at": "2023-04-05T06:07:08Z",
- "reshipment": false
}, - "order": {
- "id": 0,
- "external_id": "string",
- "status": "string",
- "store_id": 0,
- "dashboard_url": "string",
- "created_at": "2023-04-05T06:07:08Z",
- "updated_at": "2023-04-05T06:07:08Z"
}
}
}
Is called when shipment is put on hold and there are changes that must be approved by the customer before fulfillment.
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) |
{- "type": "shipment_put_hold_approval",
- "occurred_at": "2023-04-05T06:07:08Z",
- "retries": 2,
- "store_id": 12,
- "data": {
- "reason": "string",
- "approval_files": [
- {
- "confirm_hash": "a14e51714be01f98487fcf5131727d31",
- "submitted_design": "https://s3.staging.printful.com/upload/approval-design/ae/ae7b3d3e965c238b3e5c1a4e15696f07_l",
- "recommended_design": "https://s3.staging.printful.com/upload/approval-design/aa/aaf9e1c6b32cb7a2c04d2746108d4124_l",
}
], - "shipment": {
- "id": 0,
- "status": "string",
- "store_id": 0,
- "tracking_number": "string",
- "tracking_url": "https://www.fedex.com/fedextrack/?tracknumbers=0000000000",
- "created_at": "2023-04-05T06:07:08Z",
- "ship_date": "2023-03-21",
- "shipped_at": "2023-04-05T06:07:08Z",
- "reshipment": false
}, - "order": {
- "id": 0,
- "external_id": "string",
- "status": "string",
- "store_id": 0,
- "dashboard_url": "string",
- "created_at": "2023-04-05T06:07:08Z",
- "updated_at": "2023-04-05T06:07:08Z"
}
}
}
Is called when shipment is removed from hold.
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) |
{- "type": "shipment_remove_hold",
- "occurred_at": "2023-04-05T06:07:08Z",
- "retries": 2,
- "store_id": 12,
- "data": {
- "reason": "string",
- "shipment": {
- "id": 0,
- "status": "string",
- "store_id": 0,
- "tracking_number": "string",
- "tracking_url": "https://www.fedex.com/fedextrack/?tracknumbers=0000000000",
- "created_at": "2023-04-05T06:07:08Z",
- "ship_date": "2023-03-21",
- "shipped_at": "2023-04-05T06:07:08Z",
- "reshipment": false
}, - "order": {
- "id": 0,
- "external_id": "string",
- "status": "string",
- "store_id": 0,
- "dashboard_url": "string",
- "created_at": "2023-04-05T06:07:08Z",
- "updated_at": "2023-04-05T06:07:08Z"
}
}
}
Returns a configured webhook URL and a list of webhook event types enabled for the store
show_expired | boolean If this parameter is passed with value |
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. |
code | integer Response status code |
object (WebhookInfo) |
curl --location --request GET 'https://api.printful.com/v2/webhooks' \ --header 'Authorization: Bearer {oauth_token}'
{- "code": 200,
- "result": {
- "default_url": "https://www.example.com/printful/webhook",
- "expires_at": "2023-04-05T06:07:08Z",
- "events": [
- {
- "type": "shipment_sent",
- "url": "https://www.example.com/printful/webhook/shipment_sent"
}, - {
- "type": "catalog_stock_updated",
- "params": [
- {
- "name": "products",
- "value": [
- {
- "id": 1
}, - {
- "id": 71
}
]
}
]
}
], - "public_key": "SbF/9d/uWguI"
}
}
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.
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. |
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 |
required | Array of objects (EventConfiguration) Array of enabled webhook event configurations |
code | integer Response status code |
object (WebhookInfo) |
{- "default_url": "https://www.example.com/printful/webhook",
- "expires_at": "2023-04-05T06:07:08Z",
- "events": [
- {
- "type": "shipment_sent",
- "url": "https://www.example.com/printful/webhook/shipment_sent"
}, - {
- "type": "catalog_stock_updated",
- "params": [
- {
- "name": "products",
- "value": [
- {
- "id": 1
}, - {
- "id": 71
}
]
}
]
}
]
}
{- "code": 200,
- "result": {
- "default_url": "https://www.example.com/printful/webhook",
- "expires_at": "2023-04-05T06:07:08Z",
- "events": [
- {
- "type": "shipment_sent",
- "url": "https://www.example.com/printful/webhook/shipment_sent"
}, - {
- "type": "catalog_stock_updated",
- "params": [
- {
- "name": "products",
- "value": [
- {
- "id": 1
}, - {
- "id": 71
}
]
}
]
}
], - "public_key": "SbF/9d/uWguI",
- "secret_key": "a01376f30766acf7f706cc84beb57b79f9779e4a3e79d5519b3a9069c2156807098aw1d2abb43d356e03a46e71eeb9ab4519b3774d993abde8a3fabcebeb30fe"
}
}
Removes the webhook URL and all event types from the store.
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. |
curl --location --request DELETE 'https://api.printful.com/v2/webhooks' \ --header 'Content-Type: application/json'
{- "code": 401,
- "result": "Malformed Authorization header.",
- "error": {
- "reason": "BadRequest",
- "message": "Malformed Authorization header."
}
}
Returns event configuration for store
eventType required | string Event type |
show_expired | boolean If this parameter is passed with value |
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. |
code | integer Response status code |
object (EventConfiguration) |
curl --location --request GET 'https://api.printful.com/v2/webhooks/shipment_sent' \ --header 'Authorization: Bearer {oauth_token}'
{- "code": 200,
- "result": {
- "type": "catalog_stock_updated",
- "url": "https://www.example.com/printful/webhook",
- "params": [
- {
- "name": "products",
- "value": [
- {
- "id": 1
}, - {
- "id": 71
}
]
}
]
}
}
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.
eventType required | string Event type |
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. |
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 |
code | integer Response status code |
object (EventConfiguration) |
{- "type": "catalog_stock_updated",
- "url": "https://www.example.com/printful/webhook",
- "params": [
- {
- "name": "products",
- "value": [
- {
- "id": 1
}, - {
- "id": 71
}
]
}
]
}
{- "code": 200,
- "result": {
- "type": "catalog_stock_updated",
- "url": "https://www.example.com/printful/webhook",
- "params": [
- {
- "name": "products",
- "value": [
- {
- "id": 1
}, - {
- "id": 71
}
]
}
]
}
}
Disables the event for a store and clears its configuration, leaving other webhooks intact.
eventType required | string Event type |
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. |
curl --location --request DELETE 'https://api.printful.com/v2/webhooks/shipment_sent' \ --header 'Content-Type: application/json'
{- "code": 401,
- "result": "Malformed Authorization header.",
- "error": {
- "reason": "BadRequest",
- "message": "Malformed Authorization header."
}
}
Get information about a single store.
store_id required | integer (InternalId) Example: 1234 Store ID |
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. |
required | object (StoreSchema) Information about the Store |
{- "data": {
- "id": 10,
- "type": "native",
- "name": "My Store"
}
}
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.
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. |
required | Array of objects (StoreSchema) |
required | object |
required | object (Paging) Paging information |
{- "data": [
- {
- "id": 10,
- "type": "native",
- "name": "My Store"
}
], - "_links": {
- "self": {
- "href": "https://api.printful.com/v2/stores?limit=20&offset=0"
}, - "next": {
- "href": "https://api.printful.com/v2/stores?limit=20&offset=20"
}, - "previous": {
- "href": "https://api.printful.com/v2/stores?limit=20&offset=0"
}, - "first": {
- "href": "https://api.printful.com/v2/stores?limit=20&offset=0"
}, - "last": {
- "href": "https://api.printful.com/v2/stores?limit=20&offset=20"
}
}, - "paging": {
- "total": 100,
- "offset": 10,
- "limit": 100
}
}
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.
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.
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]
).
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. |
date_from required | string <date> Example: date_from=2022-08-01 The beginning of the period to get the statistics from (date in |
date_to required | string <date> Example: date_to=2022-08-31 The end of the period to get the statistics from (date in |
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. |
required | object (StoreStatistics) Statistics for a single store |
{- "data": {
- "store_id": 0,
- "currency": "USD",
- "sales_and_costs": [
- {
- "date": "string",
- "sales": "string",
- "fulfillment": "string",
- "profit": "string",
- "sales_discount": "string",
- "fulfillment_discount": "string",
- "sales_shipping": "string",
- "fulfillment_shipping": "string"
}
], - "sales_and_costs_summary": [
- {
- "date": "string",
- "order_count": 0,
- "costs": "string",
- "profit": "string"
}
], - "printful_costs": {
- "value": "string",
- "relative_difference": "string"
}, - "profit": {
- "value": "string",
- "relative_difference": "string"
}, - "total_paid_orders": {
- "value": 0,
- "relative_difference": "string"
}, - "costs_by_amount": [
- {
- "date": "string",
- "product_amount": "string",
- "digitization": "string",
- "branding": "string",
- "vat": "string",
- "sales_tax": "string",
- "shipping": "string",
- "discount": "string",
- "total": "string"
}
], - "costs_by_product": [
- {
- "product_id": 0,
- "product_name": "string",
- "fulfillment": "string",
- "sales": "string",
- "quantity": 0
}
], - "costs_by_variant": [
- {
- "variant_id": 0,
- "variant_name": "string",
- "product_id": 0,
- "fulfillment": "string",
- "sales": "string",
- "quantity": 0
}
], - "average_fulfillment_time": {
- "value": "string",
- "relative_difference": "string"
}
}
}
Retrieve a list of approval sheets confirming suggested changes to files of on hold orders.
order_id | integer Order ID. |
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. |
required | Array of objects (ApprovalSheet) |
required | object (Approval sheet links) HATEOAS links |
{- "data": [
- {
- "confirm_hash": "a14e51714be01f98487fcf5131727d31",
- "status": "waiting_for_action",
- "submitted_design": "https://s3.staging.printful.com/upload/approval-design/ae/ae7b3d3e965c238b3e5c1a4e15696f07_l",
- "recommended_design": "https://s3.staging.printful.com/upload/approval-design/aa/aaf9e1c6b32cb7a2c04d2746108d4124_l",
- "approval_sheet": "https://example.com/approval-sheet.pdf",
- "order_id": 123,
- "order_item_id": 123,
- "_links": {
- "order": {
- "href": "/v2/orders/123"
}, - "order_item": {
- "href": "/v2/orders/123/order-items/123"
}
}
}
], - "_links": {
}
}
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
{
"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). </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.
This object provides all measurements for the end customers to be able to measure themselves and see what size they should buy.
...
{
"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). </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:
The size chart from the web version:
This object provides all product measurements so the end customer can measure a product they own and see what size they should buy.
...
{
"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:
The size chart from the web version:
This object provides information what international (US, EU, UK) sizes correspond to the product sizes.
...
{
"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:
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
}
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:
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).
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.
{
"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"
}
{
"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": []
}
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.
{
"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
}
]
}
{
"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": []
}
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.
{
"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
}
]
}
]
}
]
}
{
"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.
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
{
"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.
{
"url": "https://example.org/webhook/another"
}
{
"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.
This is an example of an order_created
event sent to the specified URL:
{
"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:
x-pf-webhook-public-key
headerx-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.
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.
{
"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": [],
}
Endpoint PATCH https://api.printful.com/v2/orders/{order_id}
{
"recipient": {
"address1": "new address",
"name": "new name"
}
}
Endpoint GET https://api.printful.com/v2/orders/{order_id}
{
"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": [],
}
external_id
propertyEndpoint PATCH https://api.printful.com/v2/orders/{order_id}
{
"external_id": "1234_abc"
}
Endpoint GET https://api.printful.com/v2/orders/{order_id}
{
"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": [],
}
Endpoint PATCH https://api.printful.com/v2/orders/{order_id}
{
"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}
{
"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": [],
}
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 placementlayer_options
- options which are affecting the specific layer e.g. thread colorsStickers 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
{
"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"
}
]
}
]
}
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
{
"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"
}
]
}
]
}