FileMakerのcURLを利用しECモールへ在庫反映
はじめに
各ECモールには在庫更新に関するAPIが用意されていますが、そのリファレンスは慣れていないと手強いと感じるものもあります(記載不備なリファレンスも割とあります)。
サンプルコードも交えて、丁寧にリファレンスが書かれているECモールもありますが、いかんせんソースがPHPなのと、またFileMakerでの具体的な運用サンプルがネット上でヒットしないが為に、結果的に諦めてしまった方もいるかもしれません。
そこで、
実際に私が携わっているモールでの具体的なcURLオプションの指定例と、また、転送するリクエストボディの記述をしていきながら、注意点やハマりやすい点を中心に伝えていけたらと思います。
※2022/03/23 加筆
Qoo10は、OpenAPIサービス
から QAPI
へ変更となり仕様が大きく変わりました。
※2023/04/11 加筆
Amazon の MWS API は、2024年3月31日以降は完全に利用できなくなりますので、SP-APIへの移行が必要です。SP-APIでの在庫更新は、コチラを参考にして下さい。
注意点
- リクエストボディは、見やすさを考えて整形しています。実際には余計な改行などを含んだ状態だとエラーになるケースがあります。
- リクエストボディは、販売商品によって項目や値が変わる場合があります(SKUのバリエーションが有る無し、の違いなど)
- 各ECモールには、それぞれリクエスト制限があります(1リクエスト/1秒まで、など)
ZenPlus
リファレンスもしっかりしていて、非常に分かり易いですね。
HTTPメソッドがPUT
な点に注意です。
"-X \"PUT\" "
&
"-H \"Content-Type: application/json; charset=UTF-8\" "
&
"-H \"zenplus-api-key: " & $auth & "\" "
&
"-d @$data"
-X
というオプションで指定をしない場合、デフォルトではPOST
で処理されますので、-X
のオプションでPUT
をしっかり指定する必要があります。
また、リクエストボディの変数$data
を"-d @$data"
と指定していますが、これは内包という変数の独特な参照方法です。以後、全てこの方法で指定していきます。
$auth
には、ストア設定で確認できるAPIキー
を設定します。
[
{
"item_id": "A000010101",
"item_quantity": 15
},
{
"item_id": "B000010101",
"item_quantity": 3
}
]
リクエストボディがJSONなので組みやすくていいですね、また複数のSKUを同時に更新できるので、Loop
が要らないのもいい。
注意点としては[ ]
(大括弧)で囲む点です。ですので、
JSONSetElement ( "" ;
[ "[]" ;
JSONSetElement ( "" ;
[ "item_id" ; "A000010101" ; 1 ];
[ "item_quantity" ; 3 ; 2 ]
)
; 3 ]
)
と、入れ子にしてJSONを組み上げるかまたは、
JSONSetElement( "[]";
[ "[0].item_id" ; "A000010101"; 1 ];
[ "[0].item_quantity" ; 3 ; 2 ]
)
として組み上げるか、または単純に、
JSONSetElement ( "" ;
[ "item_id" ; "A000010101" ; 1 ];
[ "item_quantity" ; 3 ; 2 ]
)
として、最後にこの計算結果に[
と]
で挟んで結合させるかです。
どれも同じ結果が得られます。
shopserve
HTTPメソッドがPUT
な点に注意です。
"-X \"PUT\" "
&
"-H \"Authorization: " & $auth & "\" "
&
"-H \"Content-Type: application/json; charset=UTF-8\" "
&
"-d @$data"
"Basic " & Base64EncodeRFC ( 4648 ; "##ショップID##" & ":" & "##マネジャー認証キー##" )
##ショップID##
は管理画面にログインする際のID、##マネジャー認証キー##
はモール上で店舗自ら発行できます。
{
"alert_threshold" : 0,
"quantity" : 6,
"unlimited" : "No",
"variation_name1" : "F",
"variation_name2" : "レッド"
}
shopserveはリクエストURL
に商品番号の指定が必要な為、残念ながら異種商品のSKUを同時にPUT
する方法はありません。Loop
で回しましょう。
その他の注意点としては、PUT
が成功してもレスポンスボディ(メッセージ)は空です。エラーメッセージが返却されるのはエラーが発生した場合のみです。
それでも不安な場合は以下のように指定します。
"-X \"PUT\" "
&
"-D $resHeader "
&
"-H \"Authorization: " & $auth & "\" "
&
"-H \"Content-Type: application/json; charset=UTF-8\" "
&
"-d @$data"
3行目に-D $resHeader
を追加していますが、これで変数$resHeader
にレスポンスのヘッダ情報が格納され、その情報が取得できます。
HTTP/1.1 200 OK
Date: Mon, 22 Nov 2020 05:33:56 GMT
Server: Apache/2.2.24 (Unix) mod_ssl/2.2.24 OpenSSL/1.0.0-fips
Content-Length: 0
Content-Type: application/json; charset=UTF-8
Content-Language: ja
1行目、HTTP/1.1 200 OK
の中の200
はHTTPコードと呼ばれるもので、200
は成功を意味します。
YAHOO
YAHOOはリファレンスが丁寧で、POSTサンプル(ただしPHP)もありますね。
"-H \"Authorization: " & $auth & "\" "
&
"-H \"Content-Type: application/x-www-form-urlencoded\" "
&
"-d @$data"
"Bearer " & "##アクセストークン##"
YAHOOの場合、##アクセストークン##
の取得がやや面倒かもしれませんね(コールバックURL等が必要ですので、今回は取得手順は省きます)。
seller_id=##セラーID##&item_code=A00001:A000012233&quantity=6
##セラーID##
はストアアカウントのことです。
A00001
は商品コードの例ですが、個別商品コードもある場合は:
に続けてA000012233
といったように個別商品コードを記述します。
複数のSKUを同時に更新したい場合は、次のようにitem_code=
とquantity=
の中身を,
で繋げていきます。
seller_id=##セラーID##&item_code=A00001:A000012233,B00001:B000012233&quantity=6,99
au PAY(旧Wowma)
au PAYはモール側に接続元IPアドレスの登録が必要です。動的IPアドレスでも大丈夫ですが、接続元IPアドレスが変わった場合はモールに登録し直さないといけません。
"-H \"Authorization: " & $auth & "\" "
&
"-H \"Content-Type: application/xml; charset=utf-8\" "
&
"-d @$data"
Content-Type
の指定は必須で、無い場合はエラーが返ってきますので注意です。
"Bearer " & "##APIキー##"
##APIキー##
はモール上で店舗自ら発行できます。
<request>
<shopId>##ショップID##</shopId>
<stockUpdateItem>
<itemCode>A00001</itemCode>
<stockSegment>2</stockSegment>
<choicesStocks>
<choicesStockHorizontalCode>22</choicesStockHorizontalCode>
<choicesStockVerticalCode>33</choicesStockVerticalCode>
<choicesStockCount>6</choicesStockCount>
<choicesStockShippingDayId>1</choicesStockShippingDayId>
</choicesStocks>
</stockUpdateItem>
</request>
2行目の##ショップID##
は会員番号のことです。
複数のSKUを同時に更新したい場合は、<stockUpdateItem>...</stockUpdateItem>
を繰り返し、次のようにします。
<request>
<shopId>##ショップID##</shopId>
<stockUpdateItem>
<itemCode>A00001</itemCode>
<stockSegment>2</stockSegment>
<choicesStocks>
<choicesStockHorizontalCode>22</choicesStockHorizontalCode>
<choicesStockVerticalCode>33</choicesStockVerticalCode>
<choicesStockCount>6</choicesStockCount>
<choicesStockShippingDayId>1</choicesStockShippingDayId>
</choicesStocks>
</stockUpdateItem>
<stockUpdateItem>
<itemCode>B00001</itemCode>
<stockSegment>2</stockSegment>
<choicesStocks>
<choicesStockHorizontalCode>22</choicesStockHorizontalCode>
<choicesStockVerticalCode>33</choicesStockVerticalCode>
<choicesStockCount>99</choicesStockCount>
<choicesStockShippingDayId>1</choicesStockShippingDayId>
</choicesStocks>
</stockUpdateItem>
</request>
SUPERDELIVERY
"-H \"Content-Type: application/json; charset=UTF-8\" "
&
"-d @$data"
{
"body" :
{
"productSets" :
{
"productSet" :
[
{
"dealerProductCode" : "A000012233",
"stock" : 6
}
]
}
},
"header" :
{
"apiAuthCode" : "##認証コード##"
}
}
認証をヘッダーに含めず、リクエストボディのapiAuthCode
の箇所に記述します。##認証コード##
は、モールへ申請すれば取得できます。
複数のSKUを同時に更新したい場合は、productSet
の配列内を繰り返し次のようにします。
{
"body" :
{
"productSets" :
{
"productSet" :
[
{
"dealerProductCode" : "A000012233",
"stock" : 6
},
{
"dealerProductCode" : "B000012233",
"stock" : 99
}
]
}
},
"header" :
{
"apiAuthCode" : "##認証コード##"
}
}
Rakuten
"-H \"Content-Type:text/xml; charset=utf-8\" "
&
"-d @$data"
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="java:jp.co.rakuten.rms.mall.inventoryapi.v1.model.entity" xmlns:ns2="https://inventoryapi.rms.rakuten.co.jp/rms/mall/inventoryapi">
<SOAP-ENV:Body>
<ns2:updateInventoryExternal>
<ns2:externalUserAuthModel>
<ns1:authKey>$auth</ns1:authKey>
<ns1:userName>##ユーザー名##</ns1:userName>
<ns1:shopUrl>##店舗URL##</ns1:shopUrl>
</ns2:externalUserAuthModel>
<ns2:updateRequestExternalModel>
<ns1:updateRequestExternalItem>
<ns1:UpdateRequestExternalItem>
<ns1:HChoiceName>F</ns1:HChoiceName>
<ns1:VChoiceName>レッド</ns1:VChoiceName>
<ns1:inventory>6</ns1:inventory>
<ns1:normalDeliveryId>0</ns1:normalDeliveryId>
<ns1:inventoryType>3</ns1:inventoryType>
<ns1:inventoryUpdateMode>1</ns1:inventoryUpdateMode>
<ns1:itemUrl>A00001</ns1:itemUrl>
</ns1:UpdateRequestExternalItem>
</ns1:updateRequestExternalItem>
</ns2:updateRequestExternalModel>
</ns2:updateInventoryExternal>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
リクエストボディに各種情報を含めます。
7行目の##ユーザー名##
、8行目の##店舗URL##
はモール上で確認できます。
"ESA " & Base64EncodeRFC ( 4648 ; "##serviceSecret##" & ":" & "##licenseKey##" )
##serviceSecret##
、##licenseKey##
は、共にモール上で確認・店舗自ら発行できます。
複数のSKUを同時に更新したい場合は、
<ns1:UpdateRequestExternalItem>...</ns1:UpdateRequestExternalItem>
ここを繰り返し、次のようにします。
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="java:jp.co.rakuten.rms.mall.inventoryapi.v1.model.entity" xmlns:ns2="https://inventoryapi.rms.rakuten.co.jp/rms/mall/inventoryapi">
<SOAP-ENV:Body>
<ns2:updateInventoryExternal>
<ns2:externalUserAuthModel>
<ns1:authKey>$auth</ns1:authKey>
<ns1:userName>##ユーザー名##</ns1:userName>
<ns1:shopUrl>##店舗URL##</ns1:shopUrl>
</ns2:externalUserAuthModel>
<ns2:updateRequestExternalModel>
<ns1:updateRequestExternalItem>
<ns1:UpdateRequestExternalItem>
<ns1:HChoiceName>F</ns1:HChoiceName>
<ns1:VChoiceName>レッド</ns1:VChoiceName>
<ns1:inventory>6</ns1:inventory>
<ns1:normalDeliveryId>0</ns1:normalDeliveryId>
<ns1:inventoryType>3</ns1:inventoryType>
<ns1:inventoryUpdateMode>1</ns1:inventoryUpdateMode>
<ns1:itemUrl>A00001</ns1:itemUrl>
</ns1:UpdateRequestExternalItem>
<ns1:UpdateRequestExternalItem>
<ns1:HChoiceName>S</ns1:HChoiceName>
<ns1:VChoiceName>ブラック</ns1:VChoiceName>
<ns1:inventory>99</ns1:inventory>
<ns1:normalDeliveryId>0</ns1:normalDeliveryId>
<ns1:inventoryType>3</ns1:inventoryType>
<ns1:inventoryUpdateMode>1</ns1:inventoryUpdateMode>
<ns1:itemUrl>B00001</ns1:itemUrl>
</ns1:UpdateRequestExternalItem>
</ns1:updateRequestExternalItem>
</ns2:updateRequestExternalModel>
</ns2:updateInventoryExternal>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Qoo10
※2022/03/23 新仕様で加筆
OpenAPIサービスからQAPIに仕様が変わりました。それに伴い、各メソッドのエンドポイントが変更されています。販売者認証キーも新たなエンドポイントで取得し直す必要があります。
販売者認証キー取得(GETの場合)
http://Api.qoo10.jp/GMKT.INC.Front.QAPIService/ebayjapan.qapi?v=1.0&returnType=json&method=CertificationAPI.CreateCertificationKey&key=##APIKey##&user_id=##販売者アカウントID##&pwd=##販売者アカウントパスワード##
##APIKey##
は、これはモールにお願いして教えて貰って下さい。
##販売者アカウントID##
、##販売者アカウントパスワード##
は、管理画面へのログインIDとパスワードです。
さて、
SKUバリエーション(オプションバリエーション)別に在庫がある場合の、在庫数量のみを更新する方法ですが、エンドポイントを記載しておきます。
https://api.qoo10.jp/GMKT.INC.Front.QAPIService/ebayjapan.qapi/ItemsOptions.UpdateInventoryQtyUnit
QAPIになって、リクエストボディがなんと、JSONでの記述が可能になりました。ですので、その場合の cURL option
を記載します(xmlでもいけるようですが試していません)。$auth
の変数には前述で取得した販売者認証キーを設定しておきます。
"-H \"Content-Type: application/json; charset=UTF-8\" "
&
"-H \"GiosisCertificationKey: " & $auth & "\" "
&
"-d @$data"
{
"ItemCode" : "",
"OptionCode" : "A000010101",
"OptionName" : "",
"OptionValue" : "",
"Qty" : 330,
"SellerCode" : "A00001"
}
OptionCode
とは販売者オプションコード、SellerCode
とは販売者商品コードのことになります。その他のJSONキーは空欄値で構いませんが、キー自体は必要ですので注意して下さい。
※以下は旧OpenAPIサービス時の内容です(一応、現在も利用できるようです)
ここから旧仕様での記載--------------------
SOAP方式でも受け付けてくれますが、REST方式を記述します。
"-H \"Content-Type: application/x-www-form-urlencoded\" "
&
"-d @$data"
key=##販売者認証キー##&ItemCode=&SellerCode=A00001&OptionName=サイズ||*カラー&OptionValue=F||*レッド&Optioncode=&Qty=6
例では縦(サイズ)、横(カラー)2軸がある商品の場合を記述していますが、こういった場合、項目名も項目値もそれぞれ ||*
で結合します。ただ残念ながら、複数のSKUを同時に更新する方法はないようです。更新は1SKUずつのみですので、複数のSKU更新時はLoop
必須です。
ItemCode=
とOptioncode=
は、例えその値が無くても記述しておく必要があります。省くとエラーが返ってきます。
##販売者認証キー##
は、別途、店舗側で取得しておく必要がありますが、YAHOOより簡単です。GET/POST
またはSOAP
で取得できますが、GET
が楽でしょう。
http://Api.qoo10.jp/GMKT.INC.Front.OpenApiService/Certification.api/CreateCertificationKey?key=##APIKey##&user_id=##販売者アカウントID##&pwd=##販売者アカウントパスワード##
##APIKey##
は、これはモールにお願いして教えて貰って下さい。
##販売者アカウントID##
、##販売者アカウントパスワード##
は、管理画面へのログインIDとパスワードです。
ここまで旧仕様での記載--------------------
Amazon
AmazonはリクエストURL
の作成が非常に面倒なので、それは最後に説明します。
"-H \"Content-Type:text/xml; charset=utf-8\" "
&
"-H \"Content-MD5:" & $ContentMD5Value & "\" "
&
"-d @$data"
Content-MD5
の値、$ContentMD5Value
の求め方ですが、
Base64EncodeRFC ( 4648 ; CryptDigest ( $data ; "MD5" ) )
このように$data
のハッシュ化からのBase64EncodeRFC
を行います。ただし、$data
は改行なしのデータにする必要があります。改行¶
があると、POST
しても Content-MD5エラーが返却されますので注意です(Char(10)
の改行でもエラーになります)。
<?xml version="1.0" encoding="utf-8"?>
<AmazonEnvelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="amzn-envelope.xsd">
<Header>
<DocumentVersion>1.01</DocumentVersion>
<MerchantIdentifier>##セラーId##</MerchantIdentifier>
</Header>
<MessageType>Inventory</MessageType>
<Message>
<MessageID>1</MessageID>
<OperationType>Update</OperationType>
<Inventory>
<SKU>A000012233</SKU>
<Quantity>6</Quantity>
<FulfillmentLatency>1</FulfillmentLatency>
</Inventory>
</Message>
</AmazonEnvelope>
5行目の##セラーID##
は出品者IDとも言います。
複数のSKUを同時に更新したい場合は、<Message>...</Message>
を繰り返すのですが、その際その中の<MessageID>...</MessageID>
で囲まれたIDをカウントアップさせましょう。
<?xml version="1.0" encoding="utf-8"?>
<AmazonEnvelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="amzn-envelope.xsd">
<Header>
<DocumentVersion>1.01</DocumentVersion>
<MerchantIdentifier>##セラーId##</MerchantIdentifier>
</Header>
<MessageType>Inventory</MessageType>
<Message>
<MessageID>1</MessageID>
<OperationType>Update</OperationType>
<Inventory>
<SKU>A000012233</SKU>
<Quantity>6</Quantity>
<FulfillmentLatency>1</FulfillmentLatency>
</Inventory>
</Message>
<Message>
<MessageID>2</MessageID>
<OperationType>Update</OperationType>
<Inventory>
<SKU>B000012233</SKU>
<Quantity>99</Quantity>
<FulfillmentLatency>1</FulfillmentLatency>
</Inventory>
</Message>
</AmazonEnvelope>
さて、問題のリクエストURL
は、次のような構成になります。
"https://mws.amazonservices.jp?" & $params & "&Signature=" & $sig
$params
と$sig
の変数の設定ですが、これが大変です。
まず、$params
はパラメータ結合順も含め、基本形は次のようになります。基本形と言うのには理由があります(後述)。
"AWSAccessKeyId=" & "##AWSアクセスキーID##" &
"&Action=" & "SubmitFeed" &
"&FeedType=" & "_POST_INVENTORY_AVAILABILITY_DATA_" &
"&MarketplaceIdList.Id.1=" & "A1VC38T7YXB528" &
"&Merchant=" & "##セラーID##" &
"&PurgeAndReplace=" & "false" &
"&SignatureMethod=" & "HmacSHA256" &
"&SignatureVersion=" & "2" &
"&Timestamp=" & $timeStamp &
"&Version=" & "2009-01-01"
基本形はこれで問題ないのですが、実は各値はURLエンコード(パーセントエンコード)されている必要があります。が、実際の所URLエンコードが必要な値は恐らく$timeStamp
でしょう。
$timeStamp
は、UTC(協定世界時2020-11-23T15:01:46Z
の形式)での記述になりますが、この中の時間の区切り:
の部分にURLエンコードが必要です。
Substitute (
Left ( GetAsTimestamp ( Get ( 現在の時刻 UTC ミリ秒 ) / 1000 ) ; 19 ) ;
[ " " ; "T" ];
[ "/" ; "-" ];
[ ":" ; "%3A" ]
)
& "Z"
これを実行すると、2020-11-23T15%3A01%3A46Z
とURLエンコードされた値が得られます。注意点は、絶対にFileMaker関数のGetAsURLEncoded
でエンコードしてはいけません。
次に $sig
ですが、手順としてまず$params
の頭に3行追加します(これを$proc
とします)。
"POST" & Char(10) & "mws.amazonservices.jp" & Char(10) & "/" & Char(10) & $params
実際の$proc
の中身は次のようになります。
POST
mws.amazonservices.jp
/
AWSAccessKeyId=##AWSアクセスキーID##&Action=SubmitFeed&FeedType=_POST_INVENTORY_AVAILABILITY_DATA_...
このように頭に3行追加しますが、注意点としては改行コードが違いますので¶
で改行結合してはいけません。必ずChar(10)
で改行結合します。
この$proc
を##シークレットキー##
を使ってハッシュベースの認証コードを求め、Base64EncodeRFC
で排出される可能性のある記号、+
/
=
をURLエンコードします。
Substitute (
Base64EncodeRFC ( 4648 ; CryptAuthCode ( $proc ; "SHA256" ; "##シークレットキー##" ) );
[ "+" ; "%2B" ];
[ "/" ; "%2F" ];
[ "=" ; "%3D" ]
)
URLエンコード用のカスタム関数を作っておくのもいいでしょうね。これを実行すると、以下のような値が得られます。
QEAGyZpsitVE2C4GJc09RaCAMLj92OmGdsab%2B2jOadQ%3D
なかなか面倒ですが、$params
$sig
を求めることができましたので、これでリクエストURL
も完成、cURLオプションと共に在庫データ送信できます。
POST
に成功すると、以下のようなSUBMITTED
レスポンスがあります。
<?xml version="1.0"?>
<SubmitFeedResponse xmlns="http://mws.amazonaws.com/doc/2009-01-01/">
<SubmitFeedResult>
<FeedSubmissionInfo>
<FeedSubmissionId>321535019999</FeedSubmissionId>
<FeedType>_POST_INVENTORY_AVAILABILITY_DATA_</FeedType>
<SubmittedDate>2020-11-23T02:34:32+00:00</SubmittedDate>
<FeedProcessingStatus>_SUBMITTED_</FeedProcessingStatus>
</FeedSubmissionInfo>
</SubmitFeedResult>
<ResponseMetadata>
<RequestId>dcaa96be-5199-4f75-b4f4-52fbe99999b6</RequestId>
</ResponseMetadata>
</SubmitFeedResponse>
おわりに
いかがだったでしょうか。
なかなか手強いECモールもありますが、今までPHPなどを介してでしか出来なかったAPIでの反映が、FileMakerネイティブで出来るようになった意味は非常に大きいです。
ちなみに、urlから挿入
スクリプトステップはサーバー側でも実行でますので、サーバー側のスクリプトスケジュールでスケジュール実行が行え、ASPのように定期自動在庫更新が可能です。
それでは
Let's enjoy FileMaker!
Discussion