NAV Navbar
cURL Node.JS Python PHP

Overview

This documentation describes various ways to access Printify services by using the Printify API. Each section has a detailed description as well as code examples to help you easily start creating products and fulfilling orders.

API Usage Guidelines

All integrations must comply with the Printify Terms and Printify API Terms. Please see these pages for more details:

The Printify public endpoints are powered by the same underlying technology that powers the core Printify Platform. As a result, Printify engineering closely monitors usage of the public APIs to ensure a quality experience for users of the Printify platform.

Below, you'll find the limits by which a single integration (as identified by an access token) can consume the Printify APIs. If you have any questions, please email apiteam@printify.com.

Printify has the following limits in place for API requests:

This daily limit resets at midnight based on the time zone setting of the Printify account. Customers exceeding either of those limits will receive error responses with a 429 response code.

Integrations that use Printify's API to create products and generate mockups have additional daily limits. Product creation as a result of Order creation is not limited. If your application will require heavy usage of the Product or Mockup generation functions, please contact apiteam@printify.com with more information and we will contact you shortly.

Requests resulting in an error response may not exceed 5% of your total requests.

We reserve the right to change or deprecate the APIs over time - we will provide developers ample notification in those cases. These notifications will be sent to the email provided in your API settings.

API features

REST API

Printify's REST API allows your application to manage a Printify shop on behalf of a Printify Merchant. Create products, submit orders, and more...

Check out all available methods: API Reference

Webhooks and Events

Webhooks allow you to get an instant notification after an event occurrs in a Printify shop.

Send information to accounting right after an order was placed, send tracking to end customers as soon as it's available, sync product descriptions, etc... - it's totally up to you.

More information: Webhooks

Access the Printify API

You can access the Printify API as an individual merchant or as a platform. Both of them require different types of authentication. Learn about each of them below.

Individual Accounts

Connect to a single Printify Merchant account and the shops that are a part of that account. Create products, submit artwork, create and receive orders and more. Authentication is achieved through a Personal Access Token.

See more details in Authentication.

Platforms

Connect applications that offer services to multiple merchants each with different Printify merchant accounts. Manage orders for multiple Printify Merchants, offer merchants the option to sell on your platform, and more. Authentication is achieved through OAuth 2.0

See more details in Authentication

Use cases

Create orders with user-generated content

Regardless of whether you use your own mockup generator, or you capture user generated content. Through the Printify API you can easily place those images on any products in our catalog, offer them for purchase, and fulfill.

Connect your own E-commerce channel

Don't use Etsy, Shopify, Woocommerce, or any of our other available E-commerce solutions? Connect your own with the Printify API. Enjoy the same benefits of automation that merchants using our existing integrations do.

Support existing integrations with more functionality

Already using one of our integrations such as Shopify or Woocommerce? Build any additional functionality you need and connect via Printify API to continue to get all of your sales and order data in your existing shop.

Start offering merchandise sales to your community

Do you have an application or platform with an engaged community. Connect to the Printify API and easily start monetizing your community by allowing them to sell Print on Demand merchandise through your platform.

Authentication

The Printify platform provides two ways of integrating. You can integrate with a Personal Access Token that you can use to manage a single Printify account, or you can integrate through OAuth 2.0 as a platform that will be managing multiple Printify Merchant accounts.

Unless otherwise mentioned in the documentation for a specific endpoint, all endpoints support both OAuth 2.0 and Personal Access Token.

Create a personal access token

A personal access token allows your application to connect to a single Printify Merchant account and the shops created within that account.

Step 1

Before creating your personal access token, you will first need a Printify account. If you haven't created an account yet, please do so here and complete the onboarding procedure.

Step 2

Now that you have your Printify account, navigate to My Profile, then Connections. In the Connections section you will be able to generate your Personal Access Tokens and set your Token Access Scopes.

Step 3

You will be able to generate multiple tokens. Tokens can be set to have different Access Scopes.

Please note that for security purposes, this token will only be visible immediately after generating only. Please make sure you store it in a secure location.

If you lose your access token, you will need to generate a new one.

Generate token

Step 4

Once generated, you can use that token as credentials for API requests in place of a user name and password.

All requests must also specify a User-Agent header. The value of this header should either be the type of client, such as "NodeJS" or "PHP," or the name of your application.

After you have authenticated to the API, you can send requests to the API using any programming language or program that can send HTTP requests. The base URL for all endpoints is https://api.printify.com/.

Here is an example:

curl -X GET https://api.printify.com/v1/shops.json --header "Authorization: Bearer $PRINTIFY_API_TOKEN"

Step 5

Once you’ve set the API up, go to your store by clicking on My Stores, then Add new store. You should see Shopify, Etsy, WooCommerce, and the new option, API.

Click connect to connect your store to Printify via the API.

OAuth 2.0

Using OAuth 2.0 you will be able to offer your application to the growing community of Printify Merchants.

Prerequisites

  1. Authentication for your integration starts with registering your app. This link takes you to an application form where you will answer some questions about your business, expected integration timeline and your applications functionality. If your application is approved, you will receive instructions via email for how to receive your Client ID and Client Secret, and how to set the required access scopes your application will need.
  2. You'll use the Client ID and Client Secret to initiate the OAuth handshake between Printify and your integration.

Note: Reviewing applications can take up to 1 week.

Register your app

Connecting your app to Printify

There are 4 main steps to connecting your integration to a Merchant's Printify account using OAuth:

  1. Requesting Authorization Codes The Printify merchant will be presented with a screen that allows them to grant access to your integration.
  2. After the Merchant grants access, they'll be returned to your app, with a code appended to the URL. Use that code and your Client Secret to get an access_token and refresh_token.
  3. Use that access_token to authenticate any API calls that you make for that Printify account.
  4. Once that access_token expires, use the refresh_token from Step 2 to generate a new access_token.

Requesting Authorization Codes

Initiating OAuth access is the first step for having merchants grant you access to their Printify account. In order to initiate OAuth access for your App, you'll first need to send a Printify Merchant to an authorization page, where that Merchant will need to grant access to your app. When your app sends a Merchant to that authorization page, you'll use the query parameters detailed below to identify your app, and to also specify the scopes that your apps requires.

Merchants must be signed into Printify to grant access, so any user that is not logged into Printify will be directed to a login screen before being directed back to the authorization page. The authorization screen will show the details for your app, and the permissions being requested (based on the scopes you include in the URL).

After the Merchant grants access, they will be redirected to the redirect_uri that you specified, with a code query parameter appended to the URL. You'll use that code to get an access token from Printify.

Example Authorization Request

$ curl -X GET "https://app.printify.com/oauth/authorize?
 client_id=xxaabbzzxxxaabbzzxaabbzzxxaabbzz
 &response_type=code
 &scope=shops.read
 &redirect_uri=https://www.example.com"

If they grant access, the user would be redirected to this URL:

https://www.example.com/?code=aabbccxxeeaabbccxxeeaabbccxxee

If there are any problems with the authorization, you'll get the error parameters instead of the code:

https://www.example.com/?
  error=error_code
  &error_description=Human%20readable%20description%20of%20the%20error
Required URL Parameters How to use Description
Response type response_type=code Defines that you should receive an OAuth code in the response
Client ID client_id=x The Client ID provided to you after registering your app.
Redirect URI redirect_uri=x The URL that you want the visitor redirected to after granting access to your app. Please Note: For security reasons, this URL must use https in production. When testing using localhost, http can be used. Also, you must use a domain, as IP addresses are not supported.
Scope scope=x%20x A space separated set of scopes that your app will need access to. Scopes listed in this parameter will be treated as required for your app, and the user will see an error if they select an account that does not have access to the scope you've included. Any scopes that you have checked in your app settings will be treated as required scopes, and you'll need to include any selected scopes in this parameter or the authorization page will display an error.

Converting Authorization Codes To Access Tokens

HTTP POST request to convert authorization codes to access token

$ curl -X POST https://api.printify.com/oauth/v1/token \
-H "Content-Type: application/x-www-form-urlencoded;charset=utf-8"

Body

grant_type=authorization_code
&client_id=xxaabbzzxxxaabbzzxaabbzzxxaabbzz
&client_secret=xxAabBZzEeeeDdDEEaaazzzAAAA
&redirect_uri=https://www.example.com/
&code=AAAAzzzaaaEEDdDeeeEzZBbaAxx

If successful, you will receive a JSON response with the tokens:

{
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1.....",
  "refresh_token": "rcy5yZWFkIiwid2ViaG9va3Mud3JpdGUiXX0.AfaxsUygk-h-XFlP5h...",
  "expires_in": 21600
}

If there are any problems with the request, you'll receive a 400 response with an error message.

{
  "error": "error_code",
  "error_description": "A human readable error message"
}

Use the code you get after a user authorizes your app to get an access token and refresh token. The access token will be used to authenticate requests that your app makes. When you will get the Access tokens you will also get expiration time for the token. When token expires you have to use Refresh token to get a new Access token.

Required Body Parameters How to use Description
Grant Type grant_type=authorization_code The grant type of the request, must be authorization_code for the initial request to get the access and refresh tokens.
Client Id client_id=x The Client ID of your app.
Client Secret client_secret=x The Client Secret of your app.
Redirect URI redirect_uri=x The redirect URI that was used when the user authorized your app. This must exactly match the redirect_uri used when initiating the OAuth 2.0 connection.
Code code=x The code parameter returned to your redirect URI when the user authorized your app.

Note: Printify access tokens will fluctuate in size as we change the information that is encoded in the tokens. We recommend allowing for tokens to be up to 3,000 characters to account for any changes we may make.

Refresh Access Token

Use a previously obtained refresh token to generate a new access token. Access tokens expire after 6 hours, so if you need offline access to data in Printify, you'll need to store the refresh token you get when initiating your OAuth integration, and use that to generate a new access token once the initial access token expires.

Same procedure as in converting authorization codes to access tokens Body

grant_type=refresh_token
&client_id=xxaabbzzxxxaabbzzxaabbzzxxaabbzz
&client_secret=xxAabBZzEeeeDdDEEaaazzzAAAA
&redirect_uri=https://www.example.com/
&refresh_token={refresh-token-provided-from-above}
Required Body Parameters How to use Description
Grant Type grant_type=refresh_token The grant type of the request, must be refresh_token when refreshing an access token.
Client Id client_id=x The Client ID of your app.
Client Secret client_secret=x The Client Secret of your app.
Redirect URI redirect_uri=x The redirect URI that was used when the user authorized your app. This must exactly match the redirect_uri used when initiating the OAuth 2.0 connection.
Code code=x The code parameter returned to your redirect URI when the user authorized your app.

Using Access Tokens

OAuth 2.0 access tokens are provided as a bearer token, in the Authorization http header.

The header format is: Authorization: Bearer {token}

Access scopes

Scopes are permissions that identify the scope of access your application requests from the Printify Merchant Account. Below you can see the names of access scopes that exist in Printify and their description.

Access Scope Notes
shops.read Access shops in a Merchant account
catalog.read See Products and Print Providers from the Printify Product Catalog
products.read See products created in a Merchant shop
products.write Create products in a Merchant shop
orders.read See orders created in a Merchant shop
orders.write Create orders in a Merchant shop
webhooks.read Read installed webhooks
webhooks.write Install, update and delete Webhooks
uploads.write Upload, update and delete files from Media Library

API Reference

The Printify API is organized around REST.

Our API has predictable resource-oriented URLs, accepts form-encoded request bodies, returns JSON-encoded responses, and uses standard HTTP response codes, authentication, and verbs.

API basics

Example Sample use
{baseurl}/v1/shops.json https://api.printify.com/v1/shops.json

Shops

All product creation and order submission in a Printify Merchant's account happens through a shop. Merchant's can have multiple shops in one Printify account. Each of these shops can be connected to different sales channels and each has independent products, orders, and analytics.

Retrieve list of shops in a Printify account

curl -X GET https://api.printify.com/v1/shops.json \
  -H "Accept: application/json" \
  -H "Authorization: Bearer {$PRINTIFY_API_TOKEN}"

const fetch = require('node-fetch');

const headers = {
  'Accept':'application/json',
  'Authorization':'Bearer {$PRINTIFY_API_TOKEN}'

};

fetch('https://api.printify.com/v1/shops.json',
{
  method: 'GET',
  headers: headers
})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

import requests
headers = {
  'Accept': 'application/json',
  'Authorization': 'Bearer {$PRINTIFY_API_TOKEN}'
}

r = requests.get('https://api.printify.com/v1/shops.json', params={

}, headers = headers)

print r.json()

<?php

require 'vendor/autoload.php';

$headers = array(
    'Accept' => 'application/json',
    'Authorization' => 'Bearer {$PRINTIFY_API_TOKEN}',

    );

$client = new \GuzzleHttp\Client();

// Define array of request body.
$request_body = array();

try {
    $response = $client->request('GET','https://api.printify.com/v1/shops.json', array(
        'headers' => $headers,
        'json' => $request_body,
       )
    );
    print_r($response->getBody()->getContents());
 }
 catch (\GuzzleHttp\Exception\BadResponseException $e) {
    // handle exception or api errors.
    print_r($e->getMessage());
 }

 // ...

Example responses

200 Ok

[
  {
    "id": 5432,
    "title": "My new store",
    "sales_channel": "My Sales Channel"
  }
]
Method URL Scope
GET /v1/shops.json shops.read

Catalog

Through the Catalog endpoints you can see all of the products, product variants, variant options and print providers available in the Printify catalog.

Summary:

List available Blueprints

curl -X GET https://api.printify.com/v1/catalog/blueprints.json \
  -H "Accept: application/json" \
  -H "Authorization: Bearer {$PRINTIFY_API_TOKEN}"

const fetch = require('node-fetch');

const headers = {
  'Accept':'application/json',
  'Authorization':'Bearer {$PRINTIFY_API_TOKEN}'

};

fetch('https://api.printify.com/v1/catalog/blueprints.json',
{
  method: 'GET',

  headers: headers
})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

import requests
headers = {
  'Accept': 'application/json',
  'Authorization': 'Bearer {$PRINTIFY_API_TOKEN}'
}

r = requests.get('https://api.printify.com/v1/catalog/blueprints.json', params={

}, headers = headers)

print r.json()

<?php

require 'vendor/autoload.php';

$headers = array(
    'Accept' => 'application/json',
    'Authorization' => 'Bearer {$PRINTIFY_API_TOKEN}',

    );

$client = new \GuzzleHttp\Client();

// Define array of request body.
$request_body = array();

try {
    $response = $client->request('GET','https://api.printify.com/v1/catalog/blueprints.json', array(
        'headers' => $headers,
        'json' => $request_body,
       )
    );
    print_r($response->getBody()->getContents());
 }
 catch (\GuzzleHttp\Exception\BadResponseException $e) {
    // handle exception or api errors.
    print_r($e->getMessage());
 }

 // ...

Example responses

200 Ok

[
  {
    "id": 12,
    "title": "Unisex Jersey Short Sleeve Tee",
    "brand": "Bella+Canvas",
    "model": "3001",
    "images": [
      "https://images.example.com/869549a1a0894a4692371b1f9928e14a.png"
    ]
  }
]

Products in the Printify catalog are referred to as blueprints (only after user artwork has been added, are they referred to as products).

Method URL Scope
GET /v1/catalog/blueprints.json catalog.read
curl -X GET https://api.printify.com/v1/catalog/blueprints/{blueprint_id}/print_providers.json \
  -H "Accept: application/json" \
  -H "Authorization: Bearer {$PRINTIFY_API_TOKEN}"

const fetch = require('node-fetch');

const headers = {
  'Accept':'application/json',
  'Authorization':'Bearer {$PRINTIFY_API_TOKEN}'

};

fetch('https://api.printify.com/v1/catalog/blueprints/{blueprint_id}/print_providers.json',
{
  method: 'GET',

  headers: headers
})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

import requests
headers = {
  'Accept': 'application/json',
  'Authorization': 'Bearer {$PRINTIFY_API_TOKEN}'
}

r = requests.get('https://api.printify.com/v1/catalog/blueprints/{blueprint_id}/print_providers.json', params={

}, headers = headers)

print r.json()

<?php

require 'vendor/autoload.php';

$headers = array(
    'Accept' => 'application/json',
    'Authorization' => 'Bearer {$PRINTIFY_API_TOKEN}',

    );

$client = new \GuzzleHttp\Client();

// Define array of request body.
$request_body = array();

try {
    $response = $client->request('GET','https://api.printify.com/v1/catalog/blueprints/{blueprint_id}/print_providers.json', array(
        'headers' => $headers,
        'json' => $request_body,
       )
    );
    print_r($response->getBody()->getContents());
 }
 catch (\GuzzleHttp\Exception\BadResponseException $e) {
    // handle exception or api errors.
    print_r($e->getMessage());
 }

 // ...

Example responses

200 Ok

[
  {
    "id": 5,
    "title": "Print Provider X"
  }
]

Every product in the printify catalog has multiple Print Providers that offer that product. In addition to general differences between Print Providers including location and print technology employed, each Print Provider also offers different colors, sizes, print areas and prices.

Method URL Scope
GET /v1/catalog/blueprints/{blueprint_id}/print_providers.json catalog.read

Variants

curl -X GET https://api.printify.com/v1/catalog/blueprints/{blueprint_id}/print_providers/{print_provider_id}/variants.json \
  -H "Accept: application/json" \
  -H "Authorization: Bearer {$PRINTIFY_API_TOKEN}"

const fetch = require('node-fetch');

const headers = {
  'Accept':'application/json',
  'Authorization':'Bearer {$PRINTIFY_API_TOKEN}'

};

fetch('https://api.printify.com/v1/catalog/blueprints/{blueprint_id}/print_providers/{print_provider_id}/variants.json',
{
  method: 'GET',

  headers: headers
})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

import requests
headers = {
  'Accept': 'application/json',
  'Authorization': 'Bearer {$PRINTIFY_API_TOKEN}'
}

r = requests.get('https://api.printify.com/v1/catalog/blueprints/{blueprint_id}/print_providers/{print_provider_id}/variants.json', params={

}, headers = headers)

print r.json()

<?php

require 'vendor/autoload.php';

$headers = array(
    'Accept' => 'application/json',
    'Authorization' => 'Bearer {$PRINTIFY_API_TOKEN}',

    );

$client = new \GuzzleHttp\Client();

// Define array of request body.
$request_body = array();

try {
    $response = $client->request('GET','https://api.printify.com/v1/catalog/blueprints/{blueprint_id}/print_providers/{print_provider_id}/variants.json', array(
        'headers' => $headers,
        'json' => $request_body,
       )
    );
    print_r($response->getBody()->getContents());
 }
 catch (\GuzzleHttp\Exception\BadResponseException $e) {
    // handle exception or api errors.
    print_r($e->getMessage());
 }

 // ...

Example responses

200 Ok

{
  "id": 5,
  "title": "Print Provider X",
  "variants": [
    {
      "id": 17887,
      "title": "S / White",
      "options": {
        "color": "White",
        "size": "S"
      },
      "placeholders": [
        {
          "position": "back",
          "height": 1000,
          "width": 1200
        }
      ]
    }
  ]
}

Each Print Provider's product has specific size and color combinations known as variants. Variants also contain information on a products available print areas and sizes.

Method URL Scope
GET /v1/catalog/blueprints/{blueprint_id}/print_providers/{print_provider_id}/variants.json catalog.read

Products

The Product resource lets you list, create, update, delete and publish products to a store.

On this page:

What can you do with product

The Printify Public API lets you do the following with the Product resource:

Product properties

id READ-ONLY "id": "5cb87a8cd490a2ccb256cec4" A unique string identifier for the product. Each id is unique across the Printify system.
title REQUIRED "title": "Product's title" The name of the product.
description REQUIRED "description": "Product's description" A description of the product. Supports HTML formatting.
tags OPTIONAL "tags": ["T-shirt", "Men's"] Tags are also published to sales channel.
options READ-ONLY "options": [{ "name": "Colors", "type": "color", "values": [{ "id": 751, "title": "Solid White" }] }] Options are read only values and describes product options. There can be up to 3 options for a product.
variants REQUIRED "variants": [{ "id": 123, "price": 1000, "title": "Solid Dark Gray / S", "sku": "PRY-123", "grams": 120, "in_stock": true, "is_default": false, "options": [751, 2] }] A list of all product variants, each representing a different version of the product. See variant properties for reference.
images READ-ONLY "images": [{ "src": "http://example.com/tee.jpg", "variant_ids": [123, 124], "position": "front" }] Images are read only values. List of images grouped by variants.
created_at READ-ONLY "created_at": "2017-04-18 13:24:28+00:00" The date and time when a product was created.
update_at READ-ONLY "update_at": "2017-04-18 13:24:28+00:00" The date and time when a product was last updated.
visible READ-ONLY "visible": true Used for publishing. Visibility in sales channel. Can be true or false, defaults to true.
blueprint_id REQUIRED READ-ONLY "blueprint_id": 5 Required when creating a product, but is read only after. See catalog for how to get blueprint_id.
print_provider_id REQUIRED READ-ONLY "print_provider_id": 5 Required when creating a product, but is read only after. See catalog for how to get print_provider_id.
user_id READ-ONLY "user_id": 5 User id that a product belongs to.
shop_id READ-ONLY "shop_id": 1 Shop id that a product belongs to.
print_areas REQUIRED "print_areas": [{ "variant_ids": [123, 124], "placeholders": [{ "position": "front", "images": [] }], }] All print area values are required. Each variant has a print area attached to it. Each print area has placeholders which represent printable areas on a product. For example the front of the t-shirt, back of the t-shirt etc. Each placeholder has images and their positions, where they need to be printed in the printable area. See placeholder properties for reference.
external CONDITIONAL "external": [{ "id": "A123abceASd", "handle": "/path/to/product" }] Updated by sales channel with publishing succeeded endpoint. Id and handle are external references in the sales channel. See Publishing succeeded endpoint for more reference.
is_locked READ-ONLY "is_locked": true A product is locked during publishing. Locked products can't be updated until unlocked.

Variant properties

id REQUIRED READ-ONLY "id": 123 A unique int identifier for the product variant from the blueprint. Each id is unique across the Printify system. See catalog for instructions on how to get variant ids.
sku OPTIONAL "sku": "SKU-123" Optional unique string identifier for the product variant. If one is not provided, one will be generated by Printify.
price REQUIRED "price": 1000 Price in cents, integer value.
cost READ-ONLY "cost": 1000 Product variant's fulfillment cost in cents, integer value.
title READ-ONLY "title": "Solid Dark Gray / S" Variant title.
grams READ-ONLY "grams": 120 Weight in grams for a product variant
in_stock OPTIONAL "in_stock": true Used for publishing, out of stock items will be set to out of stock on a sales channel or skipped during publishing, depends on the particular sales channel integration.
in_default OPTIONAL "in_default": true Only one variant can be default. Used when publishing to sales channel. Default variant's image will be the title image of the product.
options OPTIONAL "options": [751, 2] Reference to options by id.

Placeholder properties

position REQUIRED "position": "front" See catalog for reference on how to get positions.
images REQUIRED "images": [] Array of images. See image properties for reference.

Image properties

id REQUIRED "id": 123 See upload images for reference on how to upload images and get all needed properties.
name READ-ONLY "name": "image.jpg" Name of an image.
type READ-ONLY "type": "image/png" Type of an image. Valid image types are image/png, image/jpg, image/jpeg.
height READ-ONLY "height": 100 Integer value for image height in pixels. See upload images for reference on how to upload images and get all needed properties.
width READ-ONLY "width": 100 Integer value for image width in pixels. See upload images for reference on how to upload images and get all needed properties.
x REQUIRED "x": 100 Float value to position an image on the x axis. See image positioning for reference on how to position images.
y REQUIRED "y": 100 Float value to position an image on the y axis. See image positioning for reference on how to position images.
scale REQUIRED "scale": 1 Float value to scale image up or down. See image positioning for reference on how to position images.
angle REQUIRED "angle": 180 Integer value used to rotate image. See image positioning for reference on how to position images.

Publishing properties

images REQUIRED "images": true Used by the sales channel. If set to false, Images will not be published, and existing images will be used instead.
variants REQUIRED "variants": true Used by the sales channel. If set to false, product variations will not be published.
title REQUIRED "title": true Used by sales channel. If set to false, product title will not be updated.
description REQUIRED "description": true Used by sales channel. If set to false, product description will not be updated.
tags REQUIRED "tags": true Used by sales channel. If set to false, product tags will not be updated.

Endpoints

Retrieve a list of products

GET /v1/shops/{shop_id}/products.json
limit OPTIONAL
Results per page
(default: 10, maximum: 10)
page OPTIONAL Paginate through list of results
Retrieve all products
GET /v1/shops/{shop_id}/products.json
View Response
Retrieve specific page from results
GET /v1/shops/{shop_id}/products.json?page=2
View Response
Retrieve limited results
GET /v1/shops/{shop_id}/products.json?limit=1
View Response

Retrieve a product

GET /v1/shops/{shop_id}/products/{product_id}.json
Retrieve a product
GET /v1/shops/{shop_id}/products/{product_id}.json
View Response

Create a new product

POST /v1/shops/{shop_id}/products.json
Create a new product
POST /v1/shops/{shop_id}/products.json
{ "title": "Product", "description": "Description", "blueprint_id": 5, "print_provider_id": 16, "variants": [ { "id": 10652, "price": 1000 } ], "print_areas": [ { "variant_ids": [ 10652 ], "placeholders": [ { "position": "front", "images": [ { "id": "5941187eb8e7e37b3f0e62e5", "name": "image.png", "type": "image/png", "height": 100, "width": 100, "x": 0.5, "y": 0.5, "scale": 1, "angle": 0 } ] } ] } ] } View Response

Update a product

PUT /v1/shops/{shop_id}/products/{product_id}.json
Update a product
PUT /v1/shops/{shop_id}/products/{product_id}.json
{ "title": "Product" } View Response

A product can be updated partially or as a whole document. When updating variants, all variants must be present in the request.

Delete a product

DELETE /v1/shops/{shop_id}/products/{product_id}.json
Delete a product
DELETE /v1/shops/{shop_id}/products/{product_id}.json
View Response

Publish a product

POST /v1/shops/{shop_id}/products/{product_id}/publish.json
Publish a product
POST /v1/shops/{shop_id}/products/{product_id}/publish.json
{ "title": true, "description": true, "images": true, "variants": true, "tags": true } View Response

Notify that publishing has succeeded

POST /v1/shops/{shop_id}/products/{product_id}/publishing_succeeded.json
Notify that publishing has succeeded
POST /v1/shops/{shop_id}/products/{product_id}/publishing_succeeded.json
{ "external": { "id": "5941187eb8e7e37b3f0e62e5", "handle": "https://example.com/path/to/product" } } View Response

Notify that publishing has failed

POST /v1/shops/{shop_id}/products/{product_id}/publishing_failed.json
Notify that publishing has failed
POST /v1/shops/{shop_id}/products/{product_id}/publishing_failed.json
{ "reason": "Request timed out" } View Response

Image positioning

Rule of thumb: if you use artwork with width equal to print area placeholder width, set scale to 1,00 and position it at x=0,5 y=0,5 - your design will be horizontally and vertically aligned and fill all the print area fully.

Common Error cases

400 Image has low quality error example (See HTTP Status Codes below)

{
  "status": "error",
  // Exact error codes and messages are subject to change.
  "code": 8203,
  "message": "Validation failed.",
  "errors": {
    "reason": "Image has low quality",
    "code": 8203
  }
}

You may receive errors when trying to create or update a product. A common error is due failing dpi validation because the image is low quality. If this happens, you will receive a detailed error message similar to the one shown here.

Orders

Printify API lets your application manage orders in a Merchants shop. You can submit orders for existing products in a merchant's shop or you can create new products with every order as in the case with merchandise created with user-generated content.

Summary:

Get order details by ID

curl -X GET https://api.printify.com/v1/shops/{shop_id}/orders/{order_id}.json \
  -H "Accept: application/json" \
  -H "Authorization: Bearer {$PRINTIFY_API_TOKEN}"

const fetch = require('node-fetch');

const headers = {
  'Accept':'application/json',
  'Authorization':'Bearer {$PRINTIFY_API_TOKEN}'

};

fetch('https://api.printify.com/v1/shops/{shop_id}/orders/{order_id}.json',
{
  method: 'GET',

  headers: headers
})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

import requests
headers = {
  'Accept': 'application/json',
  'Authorization': 'Bearer {$PRINTIFY_API_TOKEN}'
}

r = requests.get('https://api.printify.com/v1/shops/{shop_id}/orders/{order_id}.json', params={

}, headers = headers)

print r.json()

<?php

require 'vendor/autoload.php';

$headers = array(
    'Accept' => 'application/json',
    'Authorization' => 'Bearer {$PRINTIFY_API_TOKEN}',
    );

$client = new \GuzzleHttp\Client();

// Define array of request body.
$request_body = array();

try {
    $response = $client->request('GET','https://api.printify.com/v1/shops/{shop_id}/orders/{order_id}.json', array(
        'headers' => $headers,
        'json' => $request_body,
       )
    );
    print_r($response->getBody()->getContents());
 }
 catch (\GuzzleHttp\Exception\BadResponseException $e) {
    // handle exception or api errors.
    print_r($e->getMessage());
 }

 // ...

Example responses

200 Ok

{
  "id": "5a96f649b2439217d070f507",
  "address_to": {
    "first_name": "John",
    "last_name": "Smith",
    "region": "",
    "address1": "ExampleBaan 121",
    "city": "Retie",
    "zip": "2470",
    "email": "example@msn.com",
    "phone": "0574 69 21 90",
    "country": "BE",
    "company": "MSN"
  },
  "line_items": [
    {
      "product_id": "5b05842f3921c9547531758d",
      "quantity": 1,
      "variant_id": 17887,
      "print_provider_id": 5,
      "cost": 1050,
      "shipping_cost": 400,
      "status": "pending",
      "metadata": {
        "title": "18K gold plated Necklace",
        "price": 2200,
        "variant_label": "Golden indigocoin",
        "sku": "168699843",
        "country": "United States"
      },
      "sent_to_production_at": 1539885617,
      "fulfilled_at": 1539885617
    }
  ],
  "metadata": {
    "order_type": "external",
    "shop_order_id": 1370762297,
    "shop_order_label": "1370762297",
    "shop_fulfilled_at": 1539885617
  },
  "total_price": 2200,
  "total_shipping": 400,
  "total_tax": 0,
  "status": "pending",
  "shipping_method": 1,
  "shipments": [
    {
      "carrier": "usps",
      "number": "94001116990045395649372",
      "url": "http:\\/\\/your.tracking-number.support\\/94001116990045395649372",
      "delivered_at": 1539885617
    }
  ],
  "created_at": 1539885617,
  "sent_to_production_at": 1539885617,
  "fulfilled_at": 1539885617
}
Method URL Scope
GET /v1/shops/{shop_id}/orders/{order_id}.json orders.read

Get the order details by Printify order ID. The details will contain (including, but not limited to):

Submit an order

You can submit orders for existing products in a merchant's shop or you can create new products with every order as in the case with merchandise created with user-generated content.

You need to submit different line items if you are creating an order for an existing product in a merchants shop than if you are creating a new product.

Method URL Scope
POST /v1/shops/{shop_id}/orders.json orders.write

Ordering an existing product

curl -X POST https://api.printify.com/v1/shops/{shop_id}/orders.json \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer {$PRINTIFY_API_TOKEN}"

const fetch = require('node-fetch');
const inputBody = 'See {Body parameter} below';
const headers = {
  'Content-Type':'application/json',
  'Accept':'application/json',
  'Authorization':'Bearer {$PRINTIFY_API_TOKEN}'

};

fetch('https://api.printify.com/v1/shops/{shop_id}/orders.json',
{
  method: 'POST',
  body: inputBody,
  headers: headers
})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

import requests
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json',
  'Authorization': 'Bearer {$PRINTIFY_API_TOKEN}'
}

r = requests.post('https://api.printify.com/v1/shops/{shop_id}/orders.json', params={

}, headers = headers)

print r.json()

<?php

require 'vendor/autoload.php';

$headers = array(
    'Content-Type' => 'application/json',
    'Accept' => 'application/json',
    'Authorization' => 'Bearer {$PRINTIFY_API_TOKEN}',

    );

$client = new \GuzzleHttp\Client();

// Define array of request body.
$request_body = array();

try {
    $response = $client->request('POST','https://api.printify.com/v1/shops/{shop_id}/orders.json', array(
        'headers' => $headers,
        'json' => $request_body,
       )
    );
    print_r($response->getBody()->getContents());
 }
 catch (\GuzzleHttp\Exception\BadResponseException $e) {
    // handle exception or api errors.
    print_r($e->getMessage());
 }

 // ...

Body parameter

{
  "external_id": "2750e210-39bb-11e9-a503-452618153e4a",
  "line_items": [
    {
      "product_id": "5bfd0b66a342bcc9b5563216",
      "variant_id": 17887,
      "quantity": 1
    }
  ],
  "shipping_method": 1,
  "send_shipping_notification": false,
  "address_to": {
    "first_name": "John",
    "last_name": "Smith",
    "email": "example@msn.com",
    "phone": "0574 69 21 90",
    "country": "BE",
    "region": "",
    "address1": "ExampleBaan 121",
    "address2": "45",
    "city": "Retie",
    "zip": "2470"
  }
}

Example responses

200 Ok

{
  "id": "5a96f649b2439217d070f507"
}

Pass in the product_id (Printify Product ID) and variant_id (selected variant, e.g. 'White / XXL').

Creating a product with an order

curl -X POST https://api.printify.com/v1/shops/{shop_id}/orders.json \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer {$PRINTIFY_API_TOKEN}"

const fetch = require('node-fetch');
const inputBody = 'See {Body parameter} below';
const headers = {
  'Content-Type':'application/json',
  'Accept':'application/json',
  'Authorization':'Bearer {$PRINTIFY_API_TOKEN}'

};

fetch('https://api.printify.com/v1/shops/{shop_id}/orders.json',
{
  method: 'POST',
  body: inputBody,
  headers: headers
})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

import requests
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json',
  'Authorization': 'Bearer {$PRINTIFY_API_TOKEN}'
}

r = requests.post('https://api.printify.com/v1/shops/{shop_id}/orders.json', params={

}, headers = headers)

print r.json()

<?php

require 'vendor/autoload.php';

$headers = array(
    'Content-Type' => 'application/json',
    'Accept' => 'application/json',
    'Authorization' => 'Bearer {$PRINTIFY_API_TOKEN}',

    );

$client = new \GuzzleHttp\Client();

// Define array of request body.
$request_body = array();

try {
    $response = $client->request('POST','https://api.printify.com/v1/shops/{shop_id}/orders.json', array(
        'headers' => $headers,
        'json' => $request_body,
       )
    );
    print_r($response->getBody()->getContents());
 }
 catch (\GuzzleHttp\Exception\BadResponseException $e) {
    // handle exception or api errors.
    print_r($e->getMessage());
 }

 // ...

Body parameter

{
  "external_id": "2750e210-39bb-11e9-a503-452618153e5a",
  "line_items": [
    {
      "print_provider_id": 5,
      "blueprint_id": 9,
      "variant_id": 17887,
      "print_areas": {
        "front": "https://images.example.com/zuVahsoo9sohchool7Cu2oo6.png"
      },
      "quantity": 1
    }
  ],
  "shipping_method": 1,
  "send_shipping_notification": false,
  "address_to": {
    "first_name": "John",
    "last_name": "Smith",
    "email": "example@msn.com",
    "phone": "0574 69 21 90",
    "country": "BE",
    "region": "",
    "address1": "ExampleBaan 121",
    "address2": "45",
    "city": "Retie",
    "zip": "2470"
  }
}

Example responses

200 Ok

{
  "id": "5a96f649b2439217d070f508"
}

To create a product with the order, pass in the desired blueprint_id, print_provider_id, variant_id and print_areas with a URLs to custom artwork.

Common Error cases

400 Invalid address validation error example (See HTTP Status Codes below)

{
  "status": "error",
  // Exact error codes and messages are subject to change.
  "code": 8103,
  "message": "Validation failed.",
  "errors": {
    "reason": "{\"zip\":[\"The zip field is required.\"]}",
    "code": 8103
  }
}

Uploads

Artwork added to a Printify Product can be saved in the Media library to be reused on additional products.

You can use this API to directly add files to the media library, and later use image IDs when creating or modifying products.

Summary:

Upload artwork to a Printify account's media library

# You can also use wget
curl -X POST https://api.printify.com/v1/uploads/images.json \
  -H 'Content-Type: application/json' \
  -H "Accept: application/json" \
  -H "Authorization: Bearer {$PRINTIFY_API_TOKEN}"

const fetch = require('node-fetch');
const inputBody = 'See {Body parameter} below';
const headers = {
  'Content-Type':'application/json',
  'Accept':'application/json',
  'Authorization':'Bearer {$PRINTIFY_API_TOKEN}'
};

fetch('https://api.printify.com/v1/uploads/images.json',
{
  method: 'POST',
  body: inputBody,
  headers: headers
})
.then(function(res) {
    return res.json();
}).then(function(body) {
    console.log(body);
});

import requests
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json',
  'Authorization': 'Bearer {$PRINTIFY_API_TOKEN}'
}

r = requests.post('https://api.printify.com/v1/uploads/images.json', params={

}, headers = headers)

print r.json()

<?php

require 'vendor/autoload.php';

$headers = array(
    'Content-Type' => 'application/json',
    'Accept' => 'application/json',
    'Authorization' => 'Bearer {$PRINTIFY_API_TOKEN}',

    );

$client = new \GuzzleHttp\Client();

// Define array of request body.
$request_body = array();

try {
    $response = $client->request('POST','https://api.printify.com/v1/uploads/images.json', array(
        'headers' => $headers,
        'json' => $request_body,
       )
    );
    print_r($response->getBody()->getContents());
 }
 catch (\GuzzleHttp\Exception\BadResponseException $e) {
    // handle exception or api errors.
    print_r($e->getMessage());
 }

 // ...

Body parameter (upload image by URL)

{
  "file_name": "1x1-ff00007f.png",
  "url": "http://png-pixel.com/1x1-ff00007f.png"
}

Body parameter (upload image by base64-encoded contents)

{
  "file_name": "image.png",
  "contents": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg=="
}

Example responses

200 Response

{
  "id": "5941187eb8e7e37b3f0e62e5",
  "file_name": "image.jpg",
  "height": 200,
  "width": 400,
  "size": 1021,
  "mime_type": "image/jpeg",
  "preview_url": "https://images.example.com/869549a1a0894a4692371b1f9928e14a.png"
}
Method URL Scope
POST /v1/uploads/images.json uploads.write

Upload files either via image URL or image file base64-encoded contents. The file will be stored in the Merchant account Media Library.

Common Error cases

400 Image download error example (See HTTP Status Codes below)

{
  "status": "error",
  // Exact error codes and messages are subject to change.
  "code": 10300,
  "message": "Operation failed.",
  "errors": {
    "reason": "cURL error 6: Could not resolve host: png1-pixel.com",
    "code": 10300
  }
}

400 Image too large error example (See HTTP Status Codes below)

{
  "status": "error",
  // Exact error codes and messages are subject to change.
  "code": 8201,
  "message": "Validation failed.",
  "errors": {
    "reason": "Failed to upload image. Cause: {\"code\":\"error.file.size.limit.exceeded\"}",
    "code": 8201
  }
}

400 Unsupported file format error example (See HTTP Status Codes below)

{
  "status": "error",
  // Exact error codes and messages are subject to change.
  "code": 8201,
  "message": "Validation failed.",
  "errors": {
    "reason": "Failed to upload image. Cause: {\"code\":\"error.file.wrong.format\"}",
    "code": 8201
  }
}

When uploading images to the library, you may encounter errors. These are commonly due to download errors, incorrect file formats, or your image being too large. If these are the case, you will receive messages similar to these outlined here.

Events

Events are generated by some resources when certain actions are completed, such as the creation of a product, the fulfillment of an order. By requesting events, your app can know when certain actions have occurred in the shop.

On this page:

Product events

Event Description
product:deleted The product was deleted.
product:publish:started The product publishing was started.
product:publish:succeeded The product published successfully.
product:publish:failed The product publishing has failed.

Order events

Event Description
order:created The order was created.
order:updated The order was updated.
order:sent-to-production The order was sent to production.
order:tracking The order has received tracking updates.

Event properties

id "id": "653b6be8-2ff7-4ab5-a7a6-6889a8b3bbf5" A unique string identifier for the event. Each id is unique across the Printify system.
type "type": "order:created" The type of event that occurred. Different resources generate different types of event.
created_at "created_at": "2017-04-18 13:24:28+00:00" The date and time when the event was triggered.
resource "resource": { "id": "653b6be8-2ff7-4ab5-a7a6-6889a8b3bbf5", "type": "product", "data": { "reason": "Request timed out" } } Information about the resource that triggered the event. Check Resource properties for reference.

Resource properties

id "id": "5cb87a8cd490a2ccb256cec4" A unique string identifier for the resource. Each id is unique across the Printify system.
type "type": "product" Resource type, currently valid types are product and order.
data "data": { "reason": "Request timed out" } For more information see Resource data examples.

Resource data examples

Product events

product:deleted No resource data is sent.
product:publish:started "data": { "title": true, "description": true, "images": true, "variants": true, "tags": true } For reference on what each property means, check Publishing properties.
product:publish:succeeded "data": { "external": { "id": "123abceASd", "handle": "/path/to/product" } } For reference on what each property means, check Product properties external property.
product:publish:failed "data": { "reason": "Request timed out" } Contains the reason why publishing failed.

Order events

order:created No resource data is sent with this event.
order:updated No resource data is sent with this event.
order:tracking No resource data is sent with this event.
order:queued No resource data is sent with this event.

Webhooks

You can use webhook subscriptions to receive notifications about particular events in a shop. After you've subscribed to a webhook, you can let your app execute code immediately after specific events occur in shops that have your app connected, instead of having to make API calls periodically to check their status. For example, you can rely on webhooks to trigger an action in your app when a merchant creates a new product in a store. By using webhooks subscriptions you can make fewer API calls overall, which makes sure that your apps are more efficient and update quickly. For more information what actually gets sent by a webhook check Event properties and Resource data examples.

On this page:

What can you do with Webhooks

The Printify Public API lets you do the following with the Webhook resource:

Webhook properties

id READ-ONLY "id": "5cb87a8cd490a2ccb256cec4" A unique string identifier for the webhook. Each id is unique across the Printify system.
topic REQUIRED READ-ONLY "topic": "product:publish:started" Event that triggers the webhook. See Events for reference. Can't be changed.
url REQUIRED "url": "https://example.com/webhook" URI where the webhook subscription should send the POST request when the event occurs.
shop_id READ-ONLY "shop_id": 1 Id of merchant's store.
secret OPTIONAL "secret": "optional-secret-value" Secret that will be used to sign requests for webhook. See Securing your webhooks for more information.

Webhook endpoints

Retrieve a list of webhooks

GET /v1/shops/{shop_id}/webhooks.json
Retrieve a list of webhooks
GET /v1/shops/{shop_id}/webhooks.json
View Response

Retrieve a single webhook

GET /v1/shops/{shop_id}/webhooks/{webhook_id}.json
Retrieve a single webhook
GET /v1/shops/{shop_id}/webhooks/{webhook_id}.json
View Response

Create a new webhook

POST /v1/shops/{shop_id}/webhooks.json
Create a new webhook
GET /v1/shops/{shop_id}/webhooks.json
{ "topic": "order:created", "url": "https://example.com/webhooks/order/created" } View Response

Modify a webhook

PUT /v1/shops/{shop_id}/webhooks/{webhook_id}.json
Modify a webhook
PUT /v1/shops/{shop_id}/webhooks/{webhook_id}.json
{ "url": "https://example.com/callback/order/created" } View Response

Delete a webhook

DELETE /v1/shops/{shop_id}/webhooks/{webhook_id}.json
Delete a webhook
DELETE /v1/shops/{shop_id}/webhooks/{webhook_id}.json
View Response

Securing your Webhooks

Once your server is configured to receive payloads, it'll listen for any payload sent to the endpoint you configured. For security reasons, you probably want to limit requests to those coming from Printify.

There are a few ways to go about this - for example, you could opt to whitelist requests from Printify's IP address - but a far easier method is to set up a secret token and validate the information.

Summary:

Setting your shared secret with Printify

Secret example:

$  openssl rand -hex 20
7afa37fd47d7a52ea644382e04962a83c16aef62

You can generate the secret by running 'openssl rand -hex 20'.

When your secret token is set, Printify will use it to create a hash signature with each payload body. Printify uses an HMAC hexdigest to compute the hash sha256 signature with your provided secret.

Signature example

x-pfy-signature: sha256=4260d30ec4ee2a17181ae5072c846d8dfcb5ceb195e24de055fd9a21d8c6648f

This payload body signature is passed along with each request in the headers as X-Pfy-Signature. The signature format is: sha256={digest}.

Accessing the Secret from your backend

Setting the SECRET_TOKEN environment variable example

$ export SECRET_TOKEN=your_token

Next, set up a SECRET_TOKEN environment variable on your server that stores this token. Never hardcode the secret into your app!

Validating payloads from Printify

Code samples


# See Node.JS, Python or PHP examples.

const sha256hash = request => {
  const crypto = require('crypto');
  const hex_digest = crypto.createHmac('sha256', process.env.SECRET_TOKEN)
                           .update(request.body)
                           .digest('hex');
  return 'sha256=' + hex_digest;
}

const secure_compare = (a, b) => {
    return a.length === b.length \
           && crypto.timingSafeEqual(Buffer.from(a), Buffer.from(b));
}

console.log(secure_compare(request.headers['x-pfy-signature'], sha256hash(request)));

import os
import hmac

def sha256hash(request):
    hash = hmac.new(os.environ['SECRET_TOKEN'].encode('utf-8'),
                    request.data.encode('utf-8'), 
                    'sha256')
    return 'sha256=' + hash.hexdigest()


def secure_compare(a, b):
    return hmac.compare_digest(a, b)


print('%r' % secure_compare(request.headers['x-pfy-signature'],
                            sha256hash(request)))

<?php 

function sha256(Request $request):string {
    $bodyPayload = $request->getContent();
    $hex_digest = hash_hmac('sha256', $bodyPayload, getenv('SECRET_TOKEN'));
    return 'sha-256=' . $hex_digest;    
}

function secure_compare($a, $b) {
    return hash_equals($a, $b));
}

var_dump(secure_compare($request.headers['HTTP_X_PFY_SIGNATURE'], sha256($request)));

Next, compute a request body hash using your SECRET_TOKEN, and ensure that the hash from Printify matches. Printify uses an HMAC hexdigest to compute the hash. Always use "constant time" string comparisons, which renders it safe from certain timing attacks against regular equality operators.

See the examples in the side panel.

HTTP Status Codes

Printify API relies heavily on standard HTTP response codes codes. Please find the brief summary of status codes used below.

Success

Code Name Description
200 OK Request completed successfully.
201 Created The request has been fulfilled and has resulted in one or more new resources being created.
202 Accepted The request has been accepted for processing, but the processing has not been completed.
204 No Content Indicates that the server has successfully fulfilled the request and that there is no content to send in the response payload body.

User error codes

These errors generally indicate a problem on the client side. If you are getting one of these, check your code and the request details.

Code Name Description
400 Bad Request The request encoding is invalid; the request can't be parsed as a valid JSON.
401 Unauthorized Accessing a protected resource without authorization or with invalid credentials.
402 Payment Required The account associated with the API key making requests hits a quota that can be increased by upgrading the Printify API account plan.
403 Forbidden Accessing a protected resource with API credentials that don't have access to that resource.
404 Not Found Route or resource is not found. This error is returned when the request hits an undefined route, or if the resource doesn't exist (e.g. has been deleted).
413 Request Entity Too Large The request exceeded the maximum allowed payload size. You shouldn't encounter this under normal use.
422 Invalid Request The request data is invalid. This includes most of the base-specific validations. You will receive a detailed error message and code pointing to the exact issue.
429 Too Many Requests Too Many Requests response status code indicates you have sent too many requests in a given amount of time ("rate limiting").

Server error codes

These errors generally represent an error on our side. In the event of a 5xx error code, detailed information about the error will be automatically recorded, and Printify's developers will be notified.

Code Name Description
500 Internal Server Error The server encountered an unexpected condition.
502 Bad Gateway Printify's servers are restarting or an unexpected outage is in progress. You should generally not receive this error, and requests are safe to retry.
503 Service Unavailable The server could not process your request in time. The server could be temporarily unavailable, or it could have timed out processing your request. You should retry the request with backoffs.

History