Printful API紹介

Printfulとは?
Printfulとはプリントオンデマンドサービスです。
プリントオンデマンドサービスとは、注文をしたタイミングで必要な分だけ印刷を行なってくれるサービスです。
絵や写真をTシャツやステッカーなどの小物に印刷してグッズの販売とかに使われています。
他によく聞くプリントオンデマンドサービスはSUZURIとかpixiv FACTORYとかがありますね。
これらのサービスでも似たことができるのですが、Printfulがこれらのサービスと異なる点の一つにAPIの充実さがあると思います。
特に、オーダーのAPIまであるプリントオンデマンドサービスはなかなかないと思っています。
今回は、これだけあればWeb上で一通りできるようにいくつかのPrintfulのAPI(v1)を紹介します。
きちんとしたものは公式のものを参考にしてください。ここでは、最低限のものをまとめて、実際に使った時の注意とかを書いておこうと思います。
公式のドキュメント:
https://developers.printful.com/docs/
商品一覧取得
GET https://api.printful.com/store/productsクエリパラメータ
status:string
Enum: "all" "synced" "unsynced" "ignored" "imported" "discontinued" "out_of_stock"
status=ignoredにすると下書きの商品とか呼ばれないので、開発中とかは便利。
category_id
カテゴリーのidでも絞れるらしい。
レスポンス
{
"code": 200,
"result": [
{
"id": 380315566,
"external_id": "68004d4ff086b3",
"name": "キリンオーバーサイズTシャツ",
"variants": 20,
"synced": 20,
"thumbnail_url": "https://files.cdn.printful.com/files/aaa/bbb_preview.png",
"is_ignored": false
},
{
"id": 373423725,
"external_id": "67946a23cc4852",
"name": "ネコステッカー",
"variants": 1,
"synced": 1,
"thumbnail_url": "https://files.cdn.printful.com/files/ccc/ddd_preview.png",
"is_ignored": false
}
],
"extra": [],
"paging": {
"total": 4,
"limit": 20,
"offset": 0
}
}なんか色々返ってきますが、私の場合はとりあえずIDと名前とサムネとページングだけしか使わなかったです。
商品詳細取得
GET https://api.printful.com/store/products/${id}パスパラメータ
id:string(必須)
これはさっき商品一覧で取ってきた商品のIDを入れます。
ややこしいけど、このidはproduct_idではないです。
ここのパスパラメータに入れたidは自分の持っている商品のidで、product_idはprintfulが持つ商品のテンプレート(ステッカーとかスエットTシャツ)に振ってあるidのようです。
レスポンス
{
"code": 200,
"result": {
"sync_product": {
"id": 382507298,
"external_id": "68288ae6a46676",
"name": "キリンスエットシャツ",
"variants": 4,
"synced": 4,
"thumbnail_url": "https://files.cdn.printful.com/files/111/222_preview.png",
"is_ignored": false
},
"sync_variants": [
{
"id": 4825959602,
"external_id": "68288ae6a46729",
"sync_product_id": 382507298,
"name": "キリンスエットシャツ / S",
"synced": true,
"variant_id": 5426,
"main_category_id": 29,
"warehouse_product_id": null,
"warehouse_product_variant_id": null,
"retail_price": "3840.00",
"sku": "68288AE6A3E58_S",
"currency": "JPY",
"product": {
"variant_id": 5426,
"product_id": 145,
"image":
"https://files.cdn.printful.com/products/333/444.jpg",
"name": "Gildan 18000 Unisex Heavy Blend Crewneck Sweatshirt (White / S)",
},
"files": [[Object], [Object]],
"options": [
[Object],
[Object]
],
"is_ignored": false,
"size": "S",
"color": "White",
"availability_status": "active"
},
{
"id": 4825959603,
"external_id": "68288ae6a46794",
"sync_product_id": 382507298,
"name": "キリンスエットシャツ / M",
"synced": true,
"variant_id": 5427,
"main_category_id": 29,
"warehouse_product_id": null,
"warehouse_product_variant_id": null,
"retail_price": "3840.00",
"sku": "68288AE6A3E58_M",
"currency": "JPY",
"product": {
"variant_id": 5427,
"product_id": 145,
"image":
"https://files.cdn.printful.com/products/555/666.jpg",
"name": "Gildan 18000 Unisex Heavy Blend Crewneck Sweatshirt (White / M)",
},
"files": [[Object], [Object]],
"options": [
[Object],
[Object]
],
"is_ignored": false,
"size": "M",
"color": "White",
"availability_status": "active",
},
{
"id": 4825959604,
"external_id": "68288ae6a467e3",
"sync_product_id": 382507298,
"name": "キリンスエットシャツ / L",
"synced": true,
"variant_id": 5428,
"main_category_id": 29,
"warehouse_product_id": null,
"warehouse_product_variant_id": null,
"retail_price": "3840.00",
"sku": "68288AE6A3E58_L",
"currency": "JPY",
"product": {
"variant_id": 5428,
"product_id": 145,
"image":
"https://files.cdn.printful.com/products/888/999.jpg",
"name": "Gildan 18000 Unisex Heavy Blend Crewneck Sweatshirt (White / L)",
},
"files": [[Object], [Object]],
"options": [
[Object],
[Object]
],
"is_ignored": false,
"size": "L",
"color": "White",
"availability_status": "active"
}
]
},
"extra": []
}
なんかめっちゃ返ってきますが、sync_productは商品一覧で取ってきた値と一緒で、sync_variantsは色とかサイズのバリエーションが入ってます。
このキリンスエットTシャツは、色が白の固定でサイズがS・M・Lがあるので、3つのバリエーションが返ってきてますね。
あとは、あらかじめPrintfulのダッシュボードで設定したおいた商品の値段とかもこれで取ってこれます。
サイズ取得
GET https://api.printful.com/products/${productId}/sizesパスパラメータ
productId: string
商品詳細取得APIで取ってきたproduct_idを入れます。このidがPrintfulの管理している商品のテンプレートのidです。
なので、このAPIはPrintfulの商品(テンプレート)のサイズを取得するAPIになってます。
これがちょっと気をつけたいポイントになってきます。
ステッカーなどの商品は枠に対して自分で選んだある程度自由な画像を置くので、余白が生まれることもあり、出来上がるものはサイズがバラバラになる可能性があリます。
なので、一部の商品はサイズは最大○cm、最小○cmのように幅を持った値が返ってくることになるます。
クエリパラメータ
unit: string
Enum: "cm" "inches"
レスポンス
{
"code": 200,
"result": {
"catalog_product_id": 145,
"available_sizes": [
"S",
"M",
"L",
"XL",
"2XL",
"3XL",
"4XL",
"5XL"
],
"size_tables": [
{
"type": "measure_yourself",
"unit": "cm",
"description": "<p>Measurements are provided by suppliers.</p>\n<p>Product measurements may vary by up to 2\" (5 cm).</p>",
"image_url": "https://files.cdn.printful.com/upload/measure-yourself/e2/e26798dd5c7c8dcdf8c0da3faf68feb5_l?v=1729072723",
"image_description": "<h6>A Length</h6>\n<p dir=\"ltr\">Place the end of a measuring tape beside the collar at the top of the garment (high point shoulder). Pull the tape to the bottom of the item.</p>\n<h6>B Chest</h6>\n<p>Measure yourself around the fullest part of your chest. Keep the measuring tape horizontal.</p>\n<h6>C Sleeve length</h6>\n<p>Place the end of a measuring tape at the center back of the collar, then pull the tape along the top seam of the sleeve. When you get to the shoulder hold the tape in place at the shoulder and continue to pull down the sleeve until you reach the hem of the sleeve.</p>",
"measurements": [
{
"type_label": "A",
"values": [
{
"size": "S",
"value": "68.58"
},
{
"size": "M",
"value": "71.12"
},
{
"size": "L",
"value": "73.66"
},
{
"size": "XL",
"value": "76.20"
},
{
"size": "2XL",
"value": "78.74"
},
{
"size": "3XL",
"value": "81.28"
},
{
"size": "4XL",
"value": "83.82"
},
{
"size": "5XL",
"value": "86.36"
}
]
},
{
"type_label": "B",
"values": [
{
"size": "S",
"min_value": "96.52",
"max_value": "104.14"
},
{
"size": "M",
"min_value": "106.68",
"max_value": "114.30"
},
{
"size": "L",
"min_value": "116.84",
"max_value": "124.46"
},
{
"size": "XL",
"min_value": "127.00",
"max_value": "134.62"
},
{
"size": "2XL",
"min_value": "137.16",
"max_value": "144.78"
},
{
"size": "3XL",
"min_value": "147.32",
"max_value": "154.94"
},
{
"size": "4XL",
"min_value": "157.48",
"max_value": "165.10"
},
{
"size": "5XL",
"min_value": "167.64",
"max_value": "175.26"
}
]
},
{
"type_label": "C",
"values": [
{
"size": "S",
"value": "85.09"
},
{
"size": "M",
"value": "87.63"
},
{
"size": "L",
"value": "90.17"
},
{
"size": "XL",
"value": "92.71"
},
{
"size": "2XL",
"value": "95.25"
},
{
"size": "3XL",
"value": "97.79"
},
{
"size": "4XL",
"value": "100.33"
},
{
"size": "5XL",
"value": "102.87"
}
]
}
]
},
{
"type": "product_measure",
"unit": "cm",
"description": "<p>...省略</p>",
"image_url": "https://files.cdn.printful.com/upload/product-measure/08/08929f2417739fea42de6d36b5da37fe_l?v=1729072723",
"image_description": "<h6>A Length</h6<p>...省略</p>",
"measurements": [
{
"type_label": "Length",
"values": [
{
"size": "S",
"value": "68.58"
},
{
"size": "M",
"value": "71.12"
},
{
"size": "L",
"value": "73.66"
},
{
"size": "XL",
"value": "76.20"
},
{
"size": "2XL",
"value": "78.74"
},
{
"size": "3XL",
"value": "81.28"
},
{
"size": "4XL",
"value": "83.82"
},
{
"size": "5XL",
"value": "86.36"
}
]
},
{
"type_label": "Width",
"values": [
{
"size": "S",
"value": "50.80"
},
{
"size": "M",
"value": "55.88"
},
{
"size": "L",
"value": "60.96"
},
{
"size": "XL",
"value": "66.04"
},
{
"size": "2XL",
"value": "71.12"
},
{
"size": "3XL",
"value": "76.20"
},
{
"size": "4XL",
"value": "81.28"
},
{
"size": "5XL",
"value": "86.36"
}
]
},
{
"type_label": "Sleeve length",
"values": [
{
"size": "S",
"value": "85.09"
},
{
"size": "M",
"value": "87.63"
},
{
"size": "L",
"value": "90.17"
},
{
"size": "XL",
"value": "92.71"
},
{
"size": "2XL",
"value": "95.25"
},
{
"size": "3XL",
"value": "97.79"
},
{
"size": "4XL",
"value": "100.33"
},
{
"size": "5XL",
"value": "102.87"
}
]
}
]
}
]
},
"extra": []
}当然ですが、ラベルや説明が英語になってます。
特にtype_labelを英語から日本語に戻す必要がある場合は少し手間です。
スエットTシャツでもステッカーでも、サイズガイドAPIのレスポンスの横幅を示すtype_labelは"Width"です。
日本語なら、"Width"を訳すとTシャツの時は"身幅"として、ステッカーなら"横幅"としたいですよね。
残念ながらPrintful APIのレスポンスを日本語対応していないので、ここはうまいこと自分で直す必要がありました。
その時はこのサイズガイドはどのタイプの商品なのか(Tシャツなのかステッカーなのか)がわかっていれば、"Width"を"身幅"と訳すか"横幅"と訳すか決めれそうです。
ですが、ここも残念ながら、この商品タイプが先ほどの商品詳細取得APIには入っていないです。
そこで登場するのが次のAPIになります。これで商品タイプがわかります。
商品のひながた情報取得
GET https://api.printful.com/products/${productId}パスパラメータ
productId: string
ここもproduct_idを入れます。
レスポンス
{
"code": 200,
"result": {
"product": {
"id": 145,
"main_category_id": 29,
"type": "T-SHIRT",
"description": "A sturdy and warm sweatshirt bound to keep you warm in the colder months. ...省略。素材の情報とかもここに入ってくる。",
"type_name": "Sweatshirt",
"title": "Unisex Crew Neck Sweatshirt | Gildan 18000",
"brand": "Gildan",
"model": "18000",
"image": "https://files.cdn.printful.com/o/upload/product-catalog-img/abc",
"variant_count": 177,
"currency": "JPY",
"options": [
{
"id": "thread_colors_chest_left",
"title": "Left chest thread colors",
"type": "multi_select",
"values": {},
"additional_price": null,
"additional_price_breakdown": []
}
],
"dimensions": null,
"is_discontinued": false,
"avg_fulfillment_time": null,
"techniques": [
{ "key": "DTG", "display_name": "DTG printing", "is_default": true },
{
"key": "EMBROIDERY",
"display_name": "Embroidery",
"is_default": false
},
{ "key": "DTFILM", "display_name": "DTF printing", "is_default": false }
],
"files": [
{
"id": "embroidery_chest_left",
"type": "embroidery_chest_left",
"title": "Left chest",
"additional_price": "350.00",
"options": []
}
],
"origin_country": "Nicaragua"
},
"variants": []
},
"extra": []
}ちょっとここのレスポンスは長すぎるので、結構省略します。
私の目的としてはここのproduct.typeが欲しかったです。ここに製品の種類が入ってきます。
これで翻訳がうまいことできそうです。
ちなみに、ここに他にどんな値が入ってくるか知りたかったですが、公式のドキュメントを読んでも詳しい記載はなかったです。
いくつか試した時は'T-SHIRT'、'POSTCARD'、'STICKER'といった値は確認できました。
注文
POST https://api.printful.com/ordersクエリパラメータ
confirm:boolean
確定するかのパラメータです。
falseにしたら注文は下書きにできるので、テストの時に便利です。
update_existing
「指定されたexternal_idの注文がすでに存在する場合は、既存の注文を更新します。」らしいです。これは試していないです。
リクエスト(最低限必要なもの)
{
recipient: {
name: 届け主の名前,
// address1に全部入れてOK。address2もあるけど省略していい。
address1: 住所,
city: 市,
state_code: 都道府県を番号にしたやつ,
// 日本に固定
country_code: 'JP',
zip: 郵便番号,
},
items: [
{
// 品詳細取得APIのsync_variantsのオブジェクトid。上のキリンスエットシャツ(Sサイズ)を例にすると、4825959602。
sync_variant_id: 4825959602,
// 個数
quantity: 1,
}
]
}送料の見積もり
POST https://api.printful.com/orders/estimate-costsリクエスト(最低限必要なもの)
{
recipient: {
name: 届け主の名前,
address1: 住所,
city: 市,
state_code: 都道府県を番号にしたやつ,
country_code: 'JP',
zip: 郵便番号,
},
items: [
{
sync_variant_id: 4825959602,
quantity: 1,
}
]
}注文時と大体同じものになります。
レスポンス(公式ドキュメントより)
{
"code": 200,
"result": {
// Printfulでのコスト
"costs": {
"currency": "USD",
"subtotal": 10,
"discount": 0,
"shipping": 5,
"digitization": 0,
"additional_fee": 0,
"fulfillment_fee": 0,
"tax": 0,
"vat": 0,
"total": 15
},
// 小売でのコスト(自分で設定した商品の値段)
"retail_costs": {
"currency": "USD",
// 小計
"subtotal": 10,
"discount": 0,
// 送料
"shipping": 5,
// 税
"tax": 0,
"vat": 0,
// 合計
"total": 15
}
}
}コストはPrintfulの値段と自分で設定した小売の値段が出てくるので、必要に応じて使い分けができます。
納期の見積もり
POST https://api.printful.com/shipping/ratesリクエスト(最低限必要なもの)
{
recipient: {
name: 届け主の名前,
address1: 住所,
city: 市,
state_code: 都道府県を番号にしたやつ,
country_code: 'JP',
zip: 郵便番号,
},
items: [
{
sync_variant_id: 4825959602,
quantity: 1,
}
]
}こちらも注文時と大体同じものになります。
レスポンス(公式ドキュメントより)
{
"code": 200,
"result": [
{
"id": "STANDARD",
"name": "Flat Rate (Estimated delivery: May 19–24) ",
// 送料
"rate": "13.60",
"currency": "EUR",
"minDeliveryDays": 4,
"maxDeliveryDays": 7,
"minDeliveryDate": "2022-10-17",
"maxDeliveryDate": "2022-10-20"
}
]
}納期までの見積もりAPIもあるけど、これが絶対に正しいわけではなさそうです。
そこまで大きくずれるわけではないですが、いくつかのものはこのminDeliveryDateより少し早くきたり、maxDeliveryDateより少し遅くきたりといったことがありました。
加工する国と届け先の国が同じだと早かったり、加工する国と届け先の国が異なっていると遅かったりするのかもしれないです。
日本の工場でプリントできるものは早かったけど、中国から届くものはちょっと遅かったです。
注意
注文API、見積もりAPIのリクエストデータの住所はある程度適当なものでもできてしまいます。
例えば、自分で試した時は郵便番号や住所はある程度適当なものでもOKのレスポンスが返ってきます。
なので、こういった細かいチェックは自分で行う必要がありそうです。
まとめ
Printful APIはプリントオンデマンドサービスとしては珍しく注文までAPIがあってすごいです。
今回紹介したもの以外にもまだまだたくさんのAPIがあります。
ですが、日本語への対応や細かいチェックは自分で行う必要がありそうです。
自分で実装している時に、あんま参考例とかなかったから、これが誰かの救いになれば。
公式のドキュメントあるけど、日本の場合はどうするん??とかこれはどういう値??とかなるので。