铁路媒体/helpscout-api-php

Help Scout API v2 客户端 - musora media 分支

3.8.0 2023-07-06 21:12 UTC

README

Build Status Maintainability Test Coverage

这是官方的 Help Scout PHP 客户端。此客户端包含用于轻松与 Help Scout 邮箱 API 交互的方法。

目录

安装

建议使用 Composer 安装客户端。

composer require helpscout/api "^3.0"

对于 Laravel 项目,请查看 helpscout/api-laravel

使用

您应该在应用程序中使用 Composer 的自动加载器来自动加载类。以下所有示例都假设您已在代码中包含此内容

require_once 'vendor/autoload.php';

身份验证

使用工厂创建一个客户端。创建后,您可以设置各种凭证以进行请求。

use HelpScout\Api\ApiClientFactory;

$client = ApiClientFactory::createClient();

// Set Client credentials if using that grant type.  Using this approach will lazily fetch an access token on-demand
// when needed.
$client->useClientCredentials($appId, $appSecret);

// Set Access token directly if you have it
$client->setAccessToken('abc123');

// Use a refresh token to get a new access token
$client->useRefreshToken($appId, $appSecret, $refreshToken);

注意

所有凭证类型都会触发一个预检请求来获取访问令牌(HTTP 'POST' 请求)。为了避免这种情况,请在使用客户端的 setAccessToken 方法之前设置访问令牌。

$client = ApiClientFactory::createClient();
$client->setAccessToken('asdfasdf');

如果可用,将始终使用访问令牌,无论是否设置了其他凭证。

自动刷新过期的令牌

当请求由于身份验证错误而失败时,SDK 可以自动尝试获取新的刷新令牌,然后自动重试给定的请求。要启用此功能,您可以在创建 ApiClient 时提供一个回调,该回调可用于根据您的需求在其他进程中使用令牌持久化

$client = ApiClientFactory::createClient([], function (Authenticator $authenticator) {
    // This $authenticator contains the refreshed token
    echo 'New token: '.$authenticator->accessToken().PHP_EOL;
});

回调也可以是任何实现 HelpScout\Api\Http\Auth\HandlesTokenRefreshes 的类实例

use HelpScout\Api\Http\Auth\HandlesTokenRefreshes;
use HelpScout\Api\Http\Authenticator;

$callback = new class implements HandlesTokenRefreshes {
    public function whenTokenRefreshed(Authenticator $authenticator)
    {
        // @todo Persist the token
    }
};
$client = ApiClientFactory::createClient([], $callback);

授权码流程

由于 授权码 只适用于单次使用,您在执行其他 API 调用之前需要用访问令牌和刷新令牌交换代码。您还需要持久化令牌以供以后重用。

$client = ApiClientFactory::createClient();
$client = $client->swapAuthorizationCodeForReusableTokens(
    $appId,
    $appSecret,
    $authorizationCode
);

$credentials = $client->getAuthenticator()->getTokens();

echo $credentials['access_token'].PHP_EOL;
echo $credentials['refresh_token'].PHP_EOL;
echo $credentials['expires_in'].PHP_EOL;

除了提供访问/刷新令牌外,这还将设置当前身份验证以使用这些令牌,因此您可以自由地进行后续请求而无需重新初始化客户端。

// uses the one-time authorization code for auth
$client = $client->swapAuthorizationCodeForReusableTokens(
    $appId,
    $appSecret,
    $authorizationCode
);

// uses access/refresh tokens for auth
$client->users()->list();

示例

本 README 包含许多示例,但您还可以在 ./examples 中找到更多供您实验的示例。

客户

获取客户。获取客户时,其所有实体(电子邮件地址、电话号码、社交档案等)都会在相同的请求中预加载。

$customer = $client->customers()->get($customerId);

获取客户。

$customers = $client->customers()->list();

使用过滤器获取客户。

如 API 文档中所述,客户列表可以按各种字段进行筛选。CustomerFields 类提供了一个简单的接口来设置筛选值。例如

use HelpScout\Api\Customers\CustomerFilters;

$filter = (new CustomerFilters())
    ->byFirstName('Tom')
    ->byLastName('Graham');

$customers = $client->customers()->list($filter);

创建客户。

use HelpScout\Api\Customers\Customer;

$customer = new Customer();
$customer->setFirstName('Bob');
// ...

try {
    $customerId = $client->customers()->create($customer);
} catch (\HelpScout\Api\Exception\ValidationErrorException $e) {
    var_dump($e->getError()->getErrors());
}

更新客户。

// ...
$customer->setFirstName('Bob');

$client->customers()->update($customer);

电子邮件

创建客户电子邮件。

use HelpScout\Api\Customers\Entry\Email;

$email = new Email();
$email->setValue('lucy@helpscout.com');
$email->setType('work');
// ...

$client->customerEntry()->createEmail($customerId, $email);

更新客户电子邮件。

// ...
$email->setType('home');

$client->customerEntry()->updateEmail($customerId, $email);

删除客户电子邮件。

$client->customerEntry()->deleteEmail($customerId, $emailId);

地址

创建客户地址。

use HelpScout\Api\Customers\Entry\Address;

$address = new Address();
$address->setCity('Boston');
// ...

$client->customerEntry()->createAddress($customerId, $address);

更新客户地址。

// ...
$address->setCity('Boston');

$client->customerEntry()->updateAddress($customerId, $address);

删除客户地址。

$client->customerEntry()->deleteAddress($customerId);

电话号码

创建客户电话。

use HelpScout\Api\Customers\Entry\Phone;

$phone = new Phone();
$phone->setValue('123456789');
$phone->setType('work');
// ...

$client->customerEntry()->createPhone($customerId, $phone);

更新客户电话。

// ...
$phone->setType('home');

$client->customerEntry()->updatePhone($customerId, $phone);

删除客户电话。

$client->customerEntry()->deletePhone($customerId, $phoneId);

聊天处理

创建客户聊天。

use HelpScout\Api\Customers\Entry\ChatHandle;

$chat = new ChatHandle();
$chat->setValue('1239134812348');
$chat->setType('icq');
// ...

$client->customerEntry()->createChat($customerId, $chat);

更新客户聊天。

// ...
$chat->setValue('1230148584583');

$client->customerEntry()->updateChat($customerId, $chat);

删除客户聊天。

$client->customerEntry()->deleteChat($customerId, $chatId);

社交资料

创建客户社交资料。

use HelpScout\Api\Customers\Entry\SocialProfile;

$socialProfile = new SocialProfile();
$socialProfile->setValue('helpscout');
$socialProfile->setType('twitter');
// ...

$client->customerEntry()->createSocialProfile($customerId, $socialProfile);

更新客户社交资料。

// ...
$socialProfile->setType('facebook');

$client->customerEntry()->updateSocialProfile($customerId, $socialProfile);

删除客户社交资料。

$client->customerEntry()->deleteSocialProfile($customerId, $socialProfileId);

网站

创建客户网站。

use HelpScout\Api\Customers\Entry\Website;

$website = new Website();
$website->setValue('https://www.helpscout.com');
// ...

$client->customerEntry()->createWebsite($customerId, $website);

更新客户网站。

// ...
$website->setValue('https://www.helpscout.net');

$client->customerEntry()->updateWebsite($customerId, $website);

删除客户网站。

$client->customerEntry()->deleteWebsite($customerId, $websiteId);

属性

获取客户的属性及其值

use HelpScout\Api\Customers\Entry\Website;

$customer = $client->customers()->get(418048101);
// ...

foreach ($customer->getProperties() as $property) {
    echo $property->getName().': '.$property->getValue().PHP_EOL;
}

邮箱

获取邮箱。

$mailbox = $client->mailboxes()->get($mailboxId);

获取预加载子实体的邮箱。

邮箱实体有两个相关子实体

  • 字段
  • 文件夹

在获取邮箱时,可以预先加载这些子实体,以减少多次方法调用的需求。使用MailboxRequest类来描述哪些子实体应该被预先加载。例如

use HelpScout\Api\Mailboxes\MailboxRequest;

$request = (new MailboxRequest)
    ->withFields()
    ->withFolders();

$mailbox = $client->mailboxes()->get($mailboxId, $request);

$fields = $mailbox->getFields();
$folders = $mailbox->getFolders();

获取邮箱。

$mailboxes = $client->mailboxes()->list();

获取预加载子实体的邮箱。

use HelpScout\Api\Mailboxes\MailboxRequest;

$request = (new MailboxRequest)
    ->withFields()
    ->withFolders();

$mailboxes = $client->mailboxes()->list($request);

对话

获取会话。

$conversation = $client->conversations()->get($conversationId);

您可以轻松地懒加载会话的额外信息/关系。例如

use HelpScout\Api\Conversations\ConversationRequest;

$request = (new ConversationRequest)
    ->withMailbox()
    ->withPrimaryCustomer()
    ->withCreatedByCustomer()
    ->withCreatedByUser()
    ->withClosedBy()
    ->withThreads()
    ->withAssignee();

$conversation = $client->conversations()->get($conversationId, $request);

$mailbox = $conversation->getMailbox();
$primaryCustomer = $conversation->getCustomer();

获取会话。

$conversations = $client->conversations()->list();

获取预加载子实体的会话。

use HelpScout\Api\Conversations\ConversationRequest;

$request = (new ConversationRequest)
    ->withMailbox()
    ->withPrimaryCustomer()
    ->withCreatedByCustomer()
    ->withCreatedByUser()
    ->withClosedBy()
    ->withThreads()
    ->withAssignee();

$conversations = $client->conversations()->list(null, $request);

基于一组过滤器缩小会话列表。

use HelpScout\Api\Conversations\ConversationFilters;

$filters = (new ConversationFilters())
    ->inMailbox(1)
    ->inFolder(13)
    ->inStatus('all')
    ->hasTag('testing')
    ->assignedTo(1771)
    ->modifiedSince(new DateTime('2017-05-06T09:04:23+05:00'))
    ->byNumber(42)
    ->sortField('createdAt')
    ->sortOrder('asc')
    ->withQuery('query')
    ->byCustomField(123, 'blue');

$conversations = $client->conversations()->list($filters);

您甚至可以将过滤器与预加载子实体结合在一个请求中

use HelpScout\Api\Conversations\ConversationRequest;
use HelpScout\Api\Conversations\ConversationFilters;

$request = (new ConversationRequest)
    ->withMailbox()
    ->withThreads();

$filters = (new ConversationFilters())
    ->inMailbox(1)
    ->inFolder(13)
    ->byCustomField(123, 'blue');

$conversations = $client->conversations()->list($filters, $request);

更新会话上的自定义字段

$customField = new CustomField();
$customField->setId(10524);
$customField->setValue(new DateTime('today'));
$client->conversations()->updateCustomFields($conversationId, [$customField]);

创建一个新的会话,就像客户向您的邮箱发送电子邮件一样。

// We can specify either the id or email for the Customer
$customer = new Customer();
$customer->addEmail('my-customer@company.com');

$thread = new CustomerThread();
$thread->setCustomer($customer);
$thread->setText('Test');

$conversation = new Conversation();
$conversation->setSubject('Testing the PHP SDK v2: Phone Thread');
$conversation->setStatus('active');
$conversation->setType('email');
$conversation->setMailboxId(80261);
$conversation->setCustomer($customer);
$conversation->setThreads(new Collection([
    $thread,
]));

// You can optionally add tags
$tag = new Tag();
$tag->setName('testing');
$conversation->addTag($tag);

try {
    $conversationId = $client->conversations()->create($conversation);
} catch (ValidationErrorException $e) {
    var_dump($e->getError()->getErrors());
}

以下是一些您可能创建会话的其他示例场景

电话会话,由Help Scout用户发起
$user = $client->users()->get(31231);

$customer = new Customer();
$customer->setId(193338443);

$thread = new PhoneThread();
$thread->setCustomer($customer);
$thread->setCreatedByUser($user);
$thread->setText('Test');

$conversation = new Conversation();
$conversation->setSubject('Testing the PHP SDK v2: Phone Thread');
$conversation->setStatus('active');
$conversation->setType('phone');
$conversation->setMailboxId(80261);
$conversation->setCustomer($noteCustomer);
$conversation->setCreatedByUser($user);
$conversation->setThreads(new Collection([
    $thread,
]));
聊天会话,由客户发起
$noteCustomer = new Customer();
$noteCustomer->setId(163315601);
$thread = new ChatThread();
$thread->setCustomer($noteCustomer);
$thread->setText('Test');
$conversation = new Conversation();
$conversation->setSubject('Testing the PHP SDK v2: Chat Thread');
$conversation->setStatus('active');
$conversation->setType('chat');
$conversation->setAssignTo(271315);
$conversation->setMailboxId(138367);
$conversation->setCustomer($noteCustomer);
$conversation->setThreads(new Collection([
    $thread,
]));

// Also adding a tag to this conversation
$tag = new Tag();
$tag->setName('testing');
$conversation->addTag($tag);

$conversationId = $client->conversations()->create($conversation);

删除会话

$client->conversations()->delete($conversationId);

更新现有会话

$client->conversations()->move($conversationId, 18);
$client->conversations()->updateSubject($conversationId, 'Need more help please');
$client->conversations()->updateCustomer($conversationId, 6854);
$client->conversations()->publishDraft($conversationId);
$client->conversations()->updateStatus($conversationId, 'closed');
$client->conversations()->assign($conversationId, 127);
$client->conversations()->unassign($conversationId);

线程

聊天线程

为会话创建新的聊天线程。

use HelpScout\Api\Customers\Customer;
use HelpScout\Api\Conversations\Threads\ChatThread;

$thread = new ChatThread();
$customer = new Customer();
$customer->setId(163487350);

$thread->setCustomer($customer);
$thread->setText('Thanks for reaching out to us!');

$client->threads()->create($conversationId, $thread);

客户线程

为会话创建新的客户线程。

use HelpScout\Api\Customers\Customer;
use HelpScout\Api\Conversations\Threads\CustomerThread;

$thread = new CustomerThread();
$customer = new Customer();
$customer->setId(163487350);

$thread->setCustomer($customer);
$thread->setText('Please help me figure this out');

$client->threads()->create($conversationId, $thread);

备注线程

为会话创建新的备注线程。

use HelpScout\Api\Conversations\Threads\NoteThread;

$thread->setText('We are still looking into this');

$client->threads()->create($conversationId, $thread);

电话线程

为会话创建新的电话线程。

use HelpScout\Api\Customers\Customer;
use HelpScout\Api\Conversations\Threads\PhoneThread;

$thread = new PhoneThread();
$customer = new Customer();
$customer->setId(163487350);

$thread->setCustomer($customer);
$thread->setText('This customer called and spoke with us directly about the delay on their order');

$client->threads()->create($conversationId, $thread);

回复线程

为会话创建新的回复线程。

use HelpScout\Api\Customers\Customer;
use HelpScout\Api\Conversations\Threads\ReplyThread;

$thread = new ReplyThread();
$customer = new Customer();
$customer->setId(163487350);

$thread->setCustomer($customer);
$thread->setText("Thanks, we'll be with you shortly!");

$client->threads()->create($conversationId, $thread);

获取会话的线程。

$threads = $client->threads()->list($conversationId);

附件

获取附件。

$attachment = $client->attachments()->get($conversationId, $attachmentId);
$attachment->getData(); // attached file's contents

创建附件

use HelpScout\Api\Conversations\Threads\Attachments\AttachmentFactory;
use HelpScout\Api\Support\Filesystem;

$attachmentFactory = new AttachmentFactory(new Filesystem());
$attachment = $attachmentFactory->make('path/to/profile.jpg');

$attachment->getMimeType(); // image/jpeg
$attachment->getFilename(); // profile.jpg
$attachment->getData(); // base64 encoded contents of the file

$client->attachments()->create($conversationId, $threadId, $attachment);

删除附件

$client->attachments()->delete($conversationId, $attachmentId);

聊天

获取聊天

$chat = $client->chats()->get($chatId);

列出聊天事件

$events = $client->chats()->events($chatId);

标签

列出标签

$tags = $client->tags()->list();

团队

列出团队

$teams = $client->teams()->list();

列出团队成员

$users = $client->teams()->members($teamId);

用户

获取用户。

$user = $client->users()->get($userId);

获取用户。

$users = $client->users()->list();

基于一组过滤器缩小用户列表。

use HelpScout\Api\Users\UserFilters;

$filters = (new UserFilters())
    ->inMailbox(1)
    ->byEmail('tester@test.com');

$users = $client->users()->list($filters);

报告

在运行SDK报告时,请参考开发者文档以获取确切的端点、参数和响应格式。虽然此SDK中的大多数端点都只是调用API的透传方法,但也有一些便利之处。

首先,对于startendpreviousStartpreviousEnd参数,您可以传递格式化的日期时间字符串或实现\DateTimeInterface的任何对象作为参数。客户端将自动将这些对象转换为正确格式。

对于接受多个值(mailboxestagstypesfolders)的参数,您可以传递值数组,让客户端转换为正确格式。如果您愿意,也可以传递单个值(或以逗号分隔的值列表)。

要运行报告,请使用ApiClient实例上可用的runReport方法。将您想使用的报告类的类路径作为第一个参数,并将报告参数数组作为第二个参数。请确保参数数组中的键与文档中指定的URL参数相匹配。客户端将把API返回的JSON响应转换为数组。

// Example of running the Company Overall Report
// https://developer.helpscout.com/mailbox-api/endpoints/reports/company/reports-company-overall/

use HelpScout\Api\Reports\Company;

$params = [
    // Date interval fields can be passed as an object implementing the \DateTimeInterface
    // or as a string in the 'Y-m-d\Th:m:s\Z' format. All times should be in UTC.
    'start' => new \DateTime('-7 days'),
    'end' => new \DateTimeImmutable(),
    'previousStart' => '2015-01-01T00:00:00Z',
    'previousEnd' => '2015-01-31T23:59:59Z',

    // Fields accepting multiple values can be passed as an array or a comma-separated string
    'mailboxes' => [123, 321],
    'tags' => '987,789',
    'types' => ['chat', 'email'],
    'folders' => [111, 222]
];

$report = $client->runReport(Company\Overall::class, $params);

Webhooks

获取webhook。

$webhook = $client->webhooks()->get($webhookId);

列出webhook。

$webhooks = $client->webhooks()->list();

创建一个webhook。

新创建的webhook的默认状态是启用

use HelpScout\Api\Webhooks\Webhook;

$data = [
    'url' => 'http://bad-url.com',
    'events' => ['convo.assigned', 'convo.moved'],
    'secret' => 'notARealSecret'
];
$webhook = new Webhook();
$webhook->hydrate($data);
// ...

$client->webhooks()->create($webhook);

更新webhook

此操作将替换整个webhook实体,因此您必须再次提供密钥。更新后,webhook将再次处于启用状态。

$webhook->setUrl('http://bad-url.com/really_really_bad');
$webhook->setSecret('mZ9XbGHodY');
$client->webhooks()->update($webhook);

删除webhook。

$client->webhooks()->delete($webhookId);

处理传入的webhook

您还可以使用SDK轻松处理传入的webhook。签名验证将在创建新对象时发生,因此无需检查其是否有效。如果签名不匹配,则IncomingWebhook对象的构造函数将抛出InvalidSignatureException异常,以告知您存在问题。

// Build it from globals
$incoming = IncomingWebhook::makeFromGlobals($secret);
// or build using a request object that satisfies the PSR-7 RequestInterface
/** @var RequestInterface $request */
$request = new Request(...);
$secret = 'superSekretKey';
$incoming = new IncomingWebhook($request, $secret);

一旦您拥有传入的webhook对象,您可以检查有效负载的类型(客户、会话或测试),以及检索数据(查看示例)。如果是客户或会话,您可以检索相关的模型。否则,您可以获取有效负载作为关联数组或标准类对象。

工作流程

获取所有工作流程的分页列表。

$workflows = $client->workflows()->list();

在会话列表上运行手动工作流程。

$convos = [
    123,
    321
];
$client->workflows()->runWorkflow($id, $convos);

将工作流程状态更改为“活动”或“非活动”

$client->workflows()->updateStatus($id, 'active');

错误处理

客户端直接抛出的任何异常都将实现HelpScout\Api\Exception,而HTTP错误将导致抛出Http\Client\Exception\RequestException

如果未提供OAuth2令牌或令牌无效,则将抛出HelpScout\Api\Exception\AuthenticationException

验证

如果提交给API的请求中存在任何验证错误,您将遇到ValidationErrorException。以下是如何使用该异常的快速示例

try {
    // do something
} catch (\HelpScout\Api\Exception\ValidationErrorException $e) {
    $error = $e->getError();

    var_dump(
        // A reference id for that request.  Including this anytime you contact Help Scout will
        // empower us to dig right to the heart of the issue
        $error->getCorrelationId(),

        // Details about the invalid fields in the request
        $error->getErrors()
    );
    exit;
}

分页

在获取实体集合时,客户端将返回HelpScout\Api\Entity\Collection的实例。如果端点支持分页,则返回HelpScout\Api\Entity\PagedCollection的实例。

/** @var PagedCollection $users */
$users = $client->users()->list();

// Iterate over the first page of results
foreach ($users as $user) {
    echo $users->getFirstName();
}

// The current page number
$users->getPageNumber();

// The total number of pages
$users->getTotalPageCount();

// Load the next page
$nextUsers = $users->getNextPage();

// Load the previous page
$previousUsers = $users->getPreviousPage();

// Load the first page
$firstUsers = $users->getFirstPage();

// Load the last page
$lastUsers = $users->getLastPage();

// Load a specific page
$otherUsers = $users->getPage(12);

// Paged results are accessible as normal arrays, so you can simply iterate over them
foreach ($otherUsers as $user) {
    echo $user->getFirstName();
}

测试

SDK在ApiClient类中提供了一个方便的mock方法。要使用它,请传递您想要模拟的端点名称。您将返回一个\Mockery\MockInterface对象。一旦设置了模拟,对那个端点的后续调用将返回模拟对象。

// From within the tests/ApiClientTest.php file...
public function testMockReturnsProperMock()
{
    $client = ApiClientFactory::createClient();
    $mockedWorkflows = $client->mock('workflows');

    $this->assertInstanceOf(WorkflowsEndpoint::class, $mockedWorkflows);
    $this->assertInstanceOf(MockInterface::class, $mockedWorkflows);

    $this->assertSame(
        $mockedWorkflows,
        $client->workflows()
    );
}

一旦模拟了一个端点,您可能希望在以后清除它。为此,您可以在ApiClient上使用clearMock($endpoint)方法。

获取支持

请为任何SDK相关问题或功能请求提交一个问题。对于可能涉及敏感客户或账户数据的问题,请通过电子邮件与我们联系help@helpscout.com