ansas/amazon-selling-partner-api

Amazon Selling Partner API 的 PHP 客户端


README

一个用于连接 Amazon 的 Selling Partner API 的 PHP 库。

Total Downloads Latest Stable Version License

如果您觉得这个库很有用,请考虑 成为赞助商,或通过下面的按钮进行一次性捐赠。我非常感激您提供的任何支持!

paypal

特性

  • 支持所有 Selling Partner API 操作(针对卖家和供应商)至 2022 年 11 月 13 日(请参阅此处,获取所有调用的文档链接)
  • 支持使用 IAM 用户和 IAM 角色ARN制作的应用程序(文档
  • 自动为所有需要它们的调用生成受限制数据令牌 -- 无需对 Tokens API 进行额外调用
  • 包括一个用于上传和下载数据表的 Document 辅助类

赞助商

安装

composer require ansas/selling-partner-api

目录

请查看下面的入门指南部分,以快速了解。

本 README 被分为几个部分

入门指南

先决条件

您需要一些东西才能开始

  • Selling Partner API 开发者账户
  • 用于与 Selling Partner API 一起使用的 AWS IAM 用户或角色
  • Selling Partner API 应用程序

如果您想了解更多有关如何设置这些内容的信息,请查看此博客文章。它提供了整个设置过程的详细说明。

设置

Configuration 构造函数接受一个参数:一个关联数组,包含连接到 Selling Partner API 所需的所有配置信息

$config = new SellingPartnerApi\Configuration([
    "lwaClientId" => "<LWA client ID>",
    "lwaClientSecret" => "<LWA client secret>",
    "lwaRefreshToken" => "<LWA refresh token>",
    "awsAccessKeyId" => "<AWS access key ID>",
    "awsSecretAccessKey" => "<AWS secret access key>",
    // If you're not working in the North American marketplace, change
    // this to another endpoint from lib/Endpoint.php
    "endpoint" => SellingPartnerApi\Endpoint::NA,
]);

如果您使用 IAM 角色ARN 而不是用户 ARN 创建了 Selling Partner API 应用程序,请将此角色 ARN 传递到配置数组中

$config = new SellingPartnerApi\Configuration([
    "lwaClientId" => "<LWA client ID>",
    "lwaClientSecret" => "<LWA client secret>",
    "lwaRefreshToken" => "<LWA refresh token>",
    "awsAccessKeyId" => "<AWS access key ID>",
    "awsSecretAccessKey" => "<AWS secret access key>",
    // If you're not working in the North American marketplace, change
    // this to another endpoint from lib/Endpoint.php
    "endpoint" => SellingPartnerApi\Endpoint::NA,
    "roleArn" => "<Role ARN>",
]);

存在用于 Configuration 类的 lwaClientIdlwaClientSecretlwaRefreshTokenawsAccessKeyIdawsSecretAccessKeyendpoint 属性的获取器和设置器方法。这些方法名称与它们交互的属性名称一致:getLwaClientIdsetLwaClientIdgetLwaClientSecret 等。

然后将 $config 传递到任何 SellingPartnerApi\Api\*Api 类的构造函数中。请参阅 示例 部分以获取完整的示例。

配置选项

传递给 Configuration 构造函数的数组接受以下键

  • lwaClientId (字符串):必需。用于执行API请求的SP API应用程序的LWA客户端ID。
  • lwaClientSecret (字符串):必需。用于执行API请求的SP API应用程序的LWA客户端密钥。
  • lwaRefreshToken (字符串):用于执行API请求的SP API应用程序的LWA刷新令牌。必需,除非您仅使用Configuration实例调用无需授权的操作
  • awsAccessKeyId (字符串):必需。具有SP API ExecuteAPI权限的AWS IAM用户访问密钥ID。
  • awsSecretAccessKey (字符串):必需。具有SP API ExecuteAPI权限的AWS IAM用户密钥。
  • endpoint (数组):必需。包含一个url键(端点URL)和一个region键(AWS区域)的数组。在lib/Endpoint.php中有这些数组的预定义常量:(NAEUFENA_SANDBOXEU_SANDBOXFE_SANDBOX)。有关更多详细信息,请参阅此处
  • accessToken (字符串):由刷新令牌生成的访问令牌。
  • accessTokenExpiration (整数):与accessToken过期时间相对应的Unix时间戳。如果提供了accessToken,则必需(反之亦然)。
  • onUpdateCredentials (可调用|闭包):当生成新访问令牌时调用的回调函数。该函数应接受一个类型为SellingPartnerApi\Credentials的单个参数。
  • roleArn (字符串):如果您使用AWS IAM角色ARN而不是用户ARN设置了您的SP API应用程序,请在此处传递该ARN。
  • authenticationClient (GuzzleHttp\ClientInterface):可选的GuzzleHttp\ClientInterface对象,将用于从刷新令牌生成访问令牌
  • tokensApi (SellingPartnerApi\Api\TokensApi):可选的SellingPartnerApi\Api\TokensApi对象,将用于在调用受限制的操作时获取受限制数据令牌(RDT)
  • authorizationSigner (SellingPartnerApi\Contract\AuthorizationSignerContract):可选的SellingPartnerApi\Contract\AuthorizationSignerContract实现。请参阅自定义授权签名者部分
  • requestSigner (SellingPartnerApi\Contract\RequestSignerContract):可选的SellingPartnerApi\Contract\RequestSignerContract实现。请参阅自定义请求签名者部分。

示例

本示例假设您有权访问Seller Insights Selling Partner API角色,但一般格式适用于任何Selling Partner API请求。

<?php
require_once(__DIR__ . '/vendor/autoload.php');

use SellingPartnerApi\Api\SellersV1Api as SellersApi;
use SellingPartnerApi\Configuration;
use SellingPartnerApi\Endpoint;

$config = new Configuration([
    "lwaClientId" => "amzn1.application-oa2-client.....",
    "lwaClientSecret" => "abcd....",
    "lwaRefreshToken" => "Aztr|IwEBI....",
    "awsAccessKeyId" => "AKIA....",
    "awsSecretAccessKey" => "ABCD....",
    // If you're not working in the North American marketplace, change
    // this to another endpoint from lib/Endpoint.php
    "endpoint" => Endpoint::NA
]);

$api = new SellersApi($config);
try {
    $result = $api->getMarketplaceParticipations();
    print_r($result);
} catch (Exception $e) {
    echo 'Exception when calling SellersApi->getMarketplaceParticipations: ', $e->getMessage(), PHP_EOL;
}

?>

调试模式

在您进行API请求时,要获取调试输出,您可以调用$config->setDebug(true)。默认情况下,调试输出通过php://output发送到stdout,但您可以用$config->setDebugFile('<path>')将其重定向到文件。

<?php
require_once(__DIR__ . '/vendor/autoload.php');

use SellingPartnerApi\Configuration;

$config = new Configuration([/* ... */]);
$config->setDebug(true);
// To redirect debug info to a file:
$config->setDebugFile('./debug.log');

支持的 API 段

每个API类名称都包含API的版本。这允许在单个版本的这个包中访问同一API的多个版本。这使得类名称有点难看,但允许同时使用同一API段的新旧版本,这通常很有用。可以通过像这样格式化use语句来修复难看的名称

use SellingPartnerApi\Api\SellersV1Api as SellersApi;
use SellingPartnerApi\Model\SellersV1 as Sellers;

这也意味着如果引入了现有API的新版本,库可以更新以包含该新版本,而不会引入破坏性更改。

卖家 API

供应商 API

受限制的操作

当你调用一个受限操作时,会自动生成一个受限数据令牌(RDT)。如果你调用接受dataElements参数的受限操作,你可以将dataElements值作为参数传递给API调用。查看getOrdersgetOrdergetOrderItems文档,了解如何将这些调用传递dataElements值。)(撰写本文时,这些是唯一接受dataElements值的受限操作。)

上传和下载文档

数据传输和报告API包括涉及上传和下载文档到和从亚马逊的操作。亚马逊加密他们生成的所有文档,并要求所有上传的文档都进行加密。SellingPartnerApi\Document类处理所有加密/解密,前提是提供一个Model\ReportsV20210630\ReportDocumentModel\FeedsV20210630\FeedDocumentModel\FeedsV20210630\CreateFeedDocumentResponse类的实例。这些类的实例在亚马逊返回的响应中,当你调用getReportDocumentgetFeedDocumentcreateFeedDocument端点时分别。

下载报告文档

use SellingPartnerApi\Api\ReportsV20210630Api as ReportsApi;
use SellingPartnerApi\ReportType;

// Assume we've already fetched a report document ID, and that a $config object was defined above
$documentId = 'foo.1234';
$reportType = ReportType::GET_FLAT_FILE_OPEN_LISTINGS_DATA;

$reportsApi = new ReportsApi($config);
$reportDocumentInfo = $reportsApi->getReportDocument($documentId, $reportType['name']);

$docToDownload = new SellingPartnerApi\Document($reportDocumentInfo, $reportType);
$contents = $docToDownload->download();  // The raw report text
/*
 * - Array of associative arrays, (each sub array corresponds to a row of the report) if content type is ContentType::TAB or ContentType::CSV
 * - A nested associative array (from json_decode) if content type is ContentType::JSON
 * - The raw report data if content type is ContentType::PLAIN or ContentType::PDF
 * - PHPOffice Spreadsheet object if content type is ContentType::XLSX
 * - SimpleXML object if the content type is ContentType::XML
 */
$data = $docToDownload->getData();
// ... do something with report data

如果你正在操作大量报告,可以使用downloadStream()来最小化内存消耗。downloadStream()将返回一个Psr\Http\Message\StreamInterface

// line to replace >>>>$contents = $docToDownload->download();  // The raw report text
$streamContents = $docToDownload->downloadStream();  // The raw report stream

上传数据表文档

use SellingPartnerApi\Api\FeedsV20210630Api as FeedsApi;
use SellingPartnerApi\FeedType;
use SellingPartnerApi\Model\FeedsV20210630 as Feeds;

$feedType = FeedType::POST_PRODUCT_PRICING_DATA;
$feedsApi = new FeedsApi($config);

// Create feed document
$createFeedDocSpec = new Feeds\CreateFeedDocumentSpecification(['content_type' => $feedType['contentType']]);
$feedDocumentInfo = $feedsApi->createFeedDocument($createFeedDocSpec);
$feedDocumentId = $feedDocumentInfo->getFeedDocumentId();

// Upload feed contents to document
$feedContents = file_get_contents('<your/feed/file.xml>');
// The Document constructor accepts a custom \GuzzleHttp\Client object as an optional 3rd parameter. If that
// parameter is passed, your custom Guzzle client will be used when uploading the feed document contents to Amazon.
$docToUpload = new SellingPartnerApi\Document($feedDocumentInfo, $feedType);
$docToUpload->upload($feedContents);

$createFeedSpec = new Feeds\CreateFeedSpecification();
$createFeedSpec->setMarketplaceIds(['ATVPDKIKX0DER']);
$createFeedSpec->setInputFeedDocumentId($feedDocumentId);
$createFeedSpec->setFeedType($feedType['name']);

$createFeedResult = $feedsApi->createFeed($createFeedSpec);
$feedId = $createFeedResult->getFeedId();

如果你正在操作大量数据传输文档,可以将Guzzle可以转换成流的东西传递给upload()

下载数据表结果文档

这和下载报告文档的工作方式非常相似。

use SellingPartnerApi\Api\FeedsV20210630Api as FeedsApi;
use SellingPartnerApi\FeedType;

$feedType = FeedType::POST_PRODUCT_PRICING_DATA;
$feedsApi = new FeedsApi($config);

// ...
// Create and upload a feed document, and wait for it to finish processing
// ...

$feedId = '1234567890';  // From the createFeed call
$feed = $api->getFeed($feedId);

$feedResultDocumentId = $feed->resultFeedDocumentId;
$feedResultDocument = $api->getFeedDocument($feedResultDocumentId);

$docToDownload = new SellingPartnerApi\Document($feedResultDocument, $feedType);
$contents = $docToDownload->download();  // The raw report data
$data = $docToDownload->getData();  // Parsed/formatted report data

使用模型类

大多数操作都与一个或多个模型相关联。这些模型是包含用于向API发送特定类型请求所需数据的类,或者包含特定请求类型返回的数据的类。所有模型共享相同的一般接口:您可以在初始化期间指定模型的所有属性,或者在实际之后设置每个属性。以下是一个使用服务API的Buyer模型的示例(文档源代码)。

Buyer模型有四个属性:buyer_idnamephoneis_prime_member。(如果您想知道如何自己确定模型具有哪些属性,请查看上面的docs链接。)要创建一个设置了所有这些属性的Buyer模型实例

$buyer = new SellingPartnerApi\Model\ServiceV1\Buyer([
    "buyer_id" => "ABCDEFGHIJKLMNOPQRSTU0123456",
    "name" => "Jane Doe",
    "phone" => "+12345678901",
    "is_prime_member" => true
]);

或者,您可以创建一个Buyer模型实例,然后填充其字段

$buyer = new SellingPartnerApi\Model\ServiceV1\Buyer();
$buyer->buyerId = "ABCDEFGHIJKLMNOPQRSTU0123456";
$buyer->name = "Jane Doe";
$buyer->phone = "+12345678901";
$buyer->isPrimeMember = true;

每个模型也具有您可能期望的属性访问器

$buyer->buyerId;        // -> "ABCDEFGHIJKLMNOPQRSTU0123456"
$buyer->name;           // -> "Jane Doe"
$buyer->phone;          // -> "+12345678901"
$buyer->isPrimeMember;  // -> true

模型可以作为属性具有其他模型

$serviceJob = new SellingPartnerApi\Model\ServiceV1\Buyer([
    // ...
    "buyer" => $buyer,
    // ...
]);

$serviceJob->buyer;        // -> [Buyer instance]
$serviceJob->buyer->name;  // -> "Jane Doe"

响应头

亚马逊在每个SP API响应中包含一些有用的头信息。如果您需要这些信息,可以通过在响应对象上调用getHeaders()来获取响应头信息的关联数组。例如

<?php
require_once(__DIR__ . '/vendor/autoload.php');

use SellingPartnerApi\Api\SellersV1Api as SellersApi;
use SellingPartnerApi\Configuration;
use SellingPartnerApi\Endpoint;

$config = new Configuration([...]);
$api = new Api\SellersApi($config);
try {
    $result = $api->getMarketplaceParticipations();
    $headers = $result->headers;
    print_r($headers);
} catch (Exception $e) {
    echo 'Exception when calling SellersApi->getMarketplaceParticipations: ', $e->getMessage(), PHP_EOL;
}

自定义授权签名者

在签名API请求时,您可能需要进行自定义操作。您可以通过创建一个实现AuthorizationSignerContract接口的实例并将其传递到Configuration构造函数数组中来创建自定义授权签名者。

// CustomAuthorizationSigner.php
use GuzzleHttp\Psr7\Request;
use SellingPartnerApi\Contract\AuthorizationSignerContract;

class CustomAuthorizationSigner implements AuthorizationSignerContract
{
    public function sign(Request $request, Credentials $credentials): Request
    {
        // Calculate request signature and request date.
        
        $requestDate = '20220426T202300Z';
        $signatureHeaderValue = 'some calculated signature value';
        
        $signedRequest = $request
            ->withHeader('Authorization', $signatureHeaderValue)
            ->withHeader('x-amz-date', $requestDate);
        
        return $signedRequest;
    }

    // ...
}

// Consumer code
<?php
require_once(__DIR__ . '/vendor/autoload.php');

use SellingPartnerApi\Api\SellersV1Api as SellersApi;
use SellingPartnerApi\Configuration;
use SellingPartnerApi\Endpoint;
use CustomAuthorizationSigner;

$config = new Configuration([
    ..., 
    'authorizationSigner' => new CustomAuthorizationSigner(),
]);
$api = new SellersApi($config);
try {
    $result = $api->getMarketplaceParticipations();
    print_r($result);
} catch (Exception $e) {
    echo 'Exception when calling SellersApi->getMarketplaceParticipations: ', $e->getMessage(), PHP_EOL;
}

自定义请求签名者

您还可能需要自定义整个请求签名过程 - 例如,如果您需要在签名请求的过程中调用外部服务。您可以通过创建一个实现RequestSignerContract接口的实例,并将其实例传递到Configuration构造函数数组中来实现。

// RemoteRequestSigner.php
use GuzzleHttp\Psr7\Request;
use SellingPartnerApi\Contract\RequestSignerContract;

class RemoteRequestSigner implements RequestSignerContract
{
    public function signRequest(
        Request $request,
        ?string $scope = null,
        ?string $restrictedPath = null,
        ?string $operation = null
    ): Request {
        // Sign request by sending HTTP call
        // to external/separate service instance.
        
        return $signedRequest;
    }
}

// Consumer code
<?php
require_once(__DIR__ . '/vendor/autoload.php');

use SellingPartnerApi\Api\SellersV1Api as SellersApi;
use SellingPartnerApi\Configuration;
use SellingPartnerApi\Endpoint;
use RemoteRequestSigner;

$config = new Configuration([
    ..., 
    'requestSigner' => new RemoteRequestSigner(),
]);
$api = new SellersApi($config);
try {
    $result = $api->getMarketplaceParticipations();
    print_r($result);
} catch (Exception $e) {
    echo 'Exception when calling SellersApi->getMarketplaceParticipations: ', $e->getMessage(), PHP_EOL;
}