🐱

FileMakerのcURLを利用しECモールへ在庫反映

16 min read

はじめに

各ECモールには在庫更新に関するAPIが用意されていますが、そのリファレンスは慣れていないと手強いと感じるものもあります。

サンプルコード(主にPHP)も交えて、丁寧にリファレンスが書かれているECモールもありますが、いかんせんソースがPHPなのと、またFileMakerでの具体的な運用サンプルはネット上でヒットしないが為に、なかなか上手くいかず、結果的に諦めてしまった方もいるかもしれません。

そこで、
有名どころのモールでの具体的なcURLオプションの指定例と、また、転送する在庫データ(リクエストボディ)の記述をしていきながら、注意点やハマりやすい点を中心に伝えていけたらと思います。


注意点

  • リクエストボディは、見やすさを考えて整形しています。実際には余計な改行などを含んだ状態だとエラーになるケースがあります。
  • リクエストボディは、販売商品によって項目や値が変わる場合があります(SKUのバリエーションが有る無し、の違いなど)
  • 各ECモールには、それぞれリクエスト制限があります(1リクエスト/1秒まで、など)

shopserve

HTTPメソッドがPUTな点に注意です。

cURL option
"-X \"PUT\" "
&
"-H \"Authorization: " & $auth & "\" "
&
"-H \"Content-Type: application/json; charset=UTF-8\" "
&
"-d @$data"

-Xというオプションで指定をしない場合、デフォルトではPOSTで処理されますので、-XのオプションでPUTをしっかり指定する必要があります。

また、リクエストボディの変数$data"-d @$data"と指定していますが、これは内包という変数の独特な参照方法で、$dataに対し必要なクォーテーション処理を行ってくれます。特に$dataがJSON形式など、クォーテーションがマシマシの場合は必須です。

$auth
"Basic " & Base64EncodeRFC ( 4648 ; "##ショップID##" & ":" & "##マネジャー認証キー##" )

##ショップID##は管理画面にログインする際のID、##マネジャー認証キー##はモール上で店舗自ら発行できます。

$data
{
	"alert_threshold" : 0,
	"quantity" : 6,
	"unlimited" : "No",
	"variation_name1" : "F",
	"variation_name2" : "レッド"
}

shopserveはリクエストURLに商品番号の指定が必要な為、残念ながら異種商品のSKUを同時にPUTする方法はありません。Loopで回しましょう。

その他の注意点としては、PUTが成功してもレスポンスボディ(メッセージ)は空です。エラーメッセージが返却されるのはエラーが発生した場合のみです。

それでも不安な場合は以下のように指定します。

cURL option
"-X \"PUT\" "
&
"-D $resHeader "
&
"-H \"Authorization: " & $auth & "\" "
&
"-H \"Content-Type: application/json; charset=UTF-8\" "
&
"-d @$data"

3行目に-D $resHeaderを追加していますが、これで変数$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)もありますね。

cURL option
"-H \"Authorization: " & $auth & "\" "
&
"-H \"Content-Type: application/x-www-form-urlencoded\" "
&
"-d @$data"
$auth
"Bearer " & "##アクセストークン##"

YAHOOの場合、##アクセストークン##の取得がやや面倒かもしれませんね(コールバックURL等が必要ですので、今回は取得手順は省きます)。

$data
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アドレスが変わった場合はモールに登録し直さないといけません。

cURL option
"-H \"Authorization: " & $auth & "\" "
&
"-H \"Content-Type: application/xml; charset=utf-8\" "
&
"-d @$data"

Content-Typeの指定は必須で、無い場合はエラーが返ってきますので注意です。

$auth
"Bearer " & "##APIキー##"

##APIキー##はモール上で店舗自ら発行できます。

$data
<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>を繰り返し、次のようにします。

$data
<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

cURL option
"-H \"Content-Type: application/json; charset=UTF-8\" "
&
"-d @$data"
$data
{
	"body" : 
	{
		"productSets" : 
		{
			"productSet" : 
			[
				{
					"dealerProductCode" : "A000012233",
					"stock" : 6
				}
			]
		}
	},
	"header" : 
	{
		"apiAuthCode" : "##認証コード##"
	}
}

認証をヘッダーに含めず、リクエストボディのapiAuthCodeの箇所に記述します。##認証コード##は、モールへ申請すれば取得できます。

複数のSKUを同時に更新したい場合は、productSetの配列内を繰り返し次のようにします。

$data
{
	"body" : 
	{
		"productSets" : 
		{
			"productSet" : 
			[
				{
					"dealerProductCode" : "A000012233",
					"stock" : 6
				},
				{
					"dealerProductCode" : "B000012233",
					"stock" : 99
				}
			]
		}
	},
	"header" : 
	{
		"apiAuthCode" : "##認証コード##"
	}
}

Rakuten

cURL option
"-H \"Content-Type:text/xml; charset=utf-8\" "
&
"-d @$data"
$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##はモール上で確認できます。

$auth
"ESA " & Base64EncodeRFC ( 4648 ; "##serviceSecret##" & ":" & "##licenseKey##" )

##serviceSecret####licenseKey##は、共にモール上で確認・店舗自ら発行できます。

複数のSKUを同時に更新したい場合は、
<ns1:UpdateRequestExternalItem>...</ns1:UpdateRequestExternalItem>
ここを繰り返し、次のようにします。

$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>
                        <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

SOAP方式でも受け付けてくれますが、REST方式を記述します。

cURL option
"-H \"Content-Type: application/x-www-form-urlencoded\" "
&
"-d @$data"
$data
key=##販売者認証キー##&ItemCode=&SellerCode=A00001&OptionName=サイズ||*カラー&OptionValue=F||*レッド&Optioncode=&Qty=6

例では縦(サイズ)、横(カラー)2軸がある商品の場合を記述していますが、こういった場合、項目名も項目値もそれぞれ ||* で結合します。ただ残念ながら、複数のSKUを同時に更新する方法はないようです。更新は1SKUずつのみですので、複数のSKU更新時はLoop必須です。

ItemCode=Optioncode=は、例えその値が無くても記述しておく必要があります。省くとエラーが返ってきます。

##販売者認証キー##は、別途、店舗側で取得しておく必要がありますが、YAHOOより簡単です。GET/POSTまたはSOAPで取得できますが、GET が楽でしょう。

GET URL
http://Api.qoo10.jp/GMKT.INC.Front.OpenApiService/Certification.api/CreateCertificationKey?key=##APIKey##&user_id=##販売者アカウントID##&pwd=##販売者アカウントパスワード##

##APIKey##は、これはモールにお願いして教えて貰って下さい。
##販売者アカウントID####販売者アカウントパスワード## は、管理画面へのログインIDとパスワードです。


Amazon

AmazonはリクエストURLの作成が非常に面倒なので、それは最後に説明します。

cURL option
"-H \"Content-Type:text/xml; charset=utf-8\" "
&
"-H \"Content-MD5:" & $ContentMD5Value & "\" "
&
"-d @$data"

Content-MD5の値、$ContentMD5Valueの求め方ですが、

$ContentMD5Value
Base64EncodeRFC ( 4648 ; CryptDigest ( $data ; "MD5" ) )

このように$dataのハッシュ化からのBase64EncodeRFCを行います。ただし、$data改行なしのデータにする必要があります。改行があると、POSTしても Content-MD5エラーが返却されますので注意です(Char(10)の改行でもエラーになります)。

$data
<?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をカウントアップさせましょう。

$data
<?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は、次のような構成になります。

request URL
"https://mws.amazonservices.jp?" & $params & "&Signature=" & $sig

$params$sigの変数の設定ですが、これが大変です。

まず、$paramsはパラメータ結合順も含め、基本形は次のようになります。基本形と言うのには理由があります(後述)。

$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エンコードが必要です。

$timeStamp
Substitute ( 
	Left ( GetAsTimestamp ( Get ( 現在の時刻 UTC ミリ秒 ) / 1000 ) ; 19 ) ;
	[ " " ; "T" ];
	[ "/" ; "-" ];
	[ ":" ; "%3A" ]
 )
& "Z"

これを実行すると、2020-11-23T15%3A01%3A46ZとURLエンコードされた値が得られます。注意点は、絶対にFileMaker関数のGetAsURLEncodedでエンコードしてはいけません

次に $sig ですが、手順としてまず$paramsの頭に3行追加します(これを$procとします)。

$proc
"POST" & Char(10) & "mws.amazonservices.jp" & Char(10) & "/" & Char(10) & $params

実際の$procの中身は次のようになります。

$procの実際の中身
POST
mws.amazonservices.jp
/
AWSAccessKeyId=##AWSアクセスキーID##&Action=SubmitFeed&FeedType=_POST_INVENTORY_AVAILABILITY_DATA_...

このように頭に3行追加しますが、注意点としては改行コードが違いますのでで改行結合してはいけません。必ずChar(10)で改行結合します。

この$proc##シークレットキー##を使ってハッシュベースの認証コードを求め、Base64EncodeRFCで排出される可能性のある記号、+ / =をURLエンコードします。

$sig
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

ログインするとコメントできます