truelayer/client

TrueLayer的支付平台客户端

v2.5.0 2024-08-13 13:30 UTC

README

  1. 为什么使用此包?
  2. 入门
  3. 缓存
  4. 数组之间的转换
  5. 创建付款
    1. 创建受益人
    2. 创建用户
    3. 创建支付方式
    4. 创建付款
    5. 从数组创建付款
    6. 重定向到托管付款页面
  6. 获取付款详情
    1. 获取用户
    2. 获取支付方式和受益人
    3. 检查付款的状态
    4. 处理特定状态的付款字段
      1. 授权所需状态
      2. 授权状态
        1. 提供商选择操作
        2. 重定向操作
        3. 等待操作
      3. 已授权状态
      4. 执行状态
      5. 结算状态
      6. 失败状态
      7. 尝试失败状态
      8. 授权流程配置
      9. 资金来源
  7. 授权付款
  8. 退款
  9. 支付
  10. 商家账户
  11. 账户标识符
  12. 接收webhook通知
  13. 自定义幂等性键
  14. 自定义API调用
  15. 错误处理

为什么使用此包?

此包通过以下方式简化与TrueLayer API的工作:

  1. 处理身份验证(包括令牌过期)和缓存
  2. 签名请求
  3. 管理幂等性键,包括在冲突时重试
  4. 在需要时重试失败的请求
  5. 提供类型提示的方法和类进行工作

入门

安装

此库需要实现PSR-18的HTTP客户端。

composer require truelayer/client

如果没有安装PSR-18客户端,Composer会通知您。您可以简单地要求一个,例如Guzzle

composer require guzzlehttp/guzzle truelayer/client

初始化

您需要前往TrueLayer控制台并创建凭据,然后您可以将其提供给客户端配置器

$client = \TrueLayer\Client::configure()
    ->clientId($clientId)
    ->clientSecret($clientSecret)
    ->keyId($kid)
    ->pemFile($pemFilePath) // Or ->pem($contents) Or ->pemBase64($contents)
    ->create();

默认情况下,客户端库将在sandbox模式下初始化。要切换到生产环境,请调用useProduction()

$client = \TrueLayer\Client::configure()
    ...
    ->useProduction() // optionally, pass a boolean flag to toggle between production/sandbox mode.
    ->create(); 

此库假设您的client_id是以payments作用域发布的。根据您的账户类型,这可能不适用,并且认证服务器将返回一个invalid_scope错误。您可以使用scopes()方法覆盖库使用的范围

$client = \TrueLayer\Client::configure()
    ...
    ->scopes('foo', 'bar')
    ->create(); 

如果需要,您也可以提供自己的HTTP客户端实例

$client = \TrueLayer\Client::configure()
    ...
    ->httpClient($myPSR18Client)
    ->create(); 

缓存

客户端库支持缓存访问TrueLayer系统上所需资源的client_credentials授权令牌。为了启用它,您需要提供一个实现PSR-16公共缓存接口的实例和32字节的加密密钥。

您可以通过运行openssl rand -hex 32生成一个随机的加密密钥。此密钥必须被视为机密,并存储在从TrueLayer控制台获取的客户端机密旁边。

$client = \TrueLayer\Client::configure()
    ...
    ->cache($cacheImplementation, $encryptionKey)
    ->create();

实现PSR-16的缓存库的好例子是illuminate/cache

数组之间的转换

如果您想跳过调用每个设置方法,可以使用数组创建任何资源

$client->beneficiary()->fill($beneficiaryData);
$client->user()->fill($userData);
$client->payment()->fill($paymentData);
// etc...

您还可以将任何资源转换为数组。如果您需要将其输出到json等,这可能很方便

$paymentData = $client->getPayment($paymentId)->toArray(); 

创建付款

1. 创建受益人

商家账户受益人

// If the merchant account id is known:
$beneficiary = $client->beneficiary()->merchantAccount()
    ->merchantAccountId('a2dcee6d-7a00-414d-a1e6-8a2b23169e00');

// Alternatively you can retrieve merchant accounts and use one of them directly:
$merchantAccounts = $client->getMerchantAccounts();

// Select the merchant account you need...
$merchantAccount = $merchantAccounts[0];

$beneficiary = $client->beneficiary()->merchantAccount($merchantAccount);

如果您已配置商户账户进行支付验证,则可以为您商户账户的支付启用自动汇款方验证。

$remitterVerification = $client
    ->remitterVerification()
    ->automated()
    ->remitterName(true)
    ->remitterDateOfBirth(true);

$beneficiary = $client->beneficiary()
    ->merchantAccount()
    ->merchantAccountId('a2dcee6d-7a00-414d-a1e6-8a2b23169e00')
    ->verification($remitterVerification);

外部账户收款人 - 邮编 & 账号

$beneficiary = $client->beneficiary()->externalAccount()
    ->reference('Transaction reference')
    ->accountHolderName('John Doe')
    ->accountIdentifier(
        $client->accountIdentifier()->sortCodeAccountNumber()
            ->sortCode('010203')
            ->accountNumber('12345678')
    );

外部账户收款人 - IBAN

$beneficiary = $client->beneficiary()->externalAccount()
    ->reference('Transaction reference')
    ->accountHolderName('John Doe')
    ->accountIdentifier(
        $client->accountIdentifier()->iban()
            ->iban('GB53CLRB04066200002723')
    );

2. 创建用户

use TrueLayer\Constants\UserPoliticalExposures;

$user = $client->user()
    ->name('Jane Doe')
    ->phone('+44123456789')
    ->email('jane.doe@truelayer.com')
    ->dateOfBirth('2024-01-01');

// You can also set the user's political exposure field if you need to
$user->politicalExposure(UserPoliticalExposures::CURRENT);

您还可以设置用户的地址

$address = $client->user()
    ->address()
    ->addressLine1('The Gilbert')
    ->addressLine2('City of')
    ->city('London')
    ->state('London')
    ->zip('EC2A 1PX')
    ->countryCode('GB');

3. 创建支付方式

您可以通过最少的配置创建银行转账支付方式

$paymentMethod = $client->paymentMethod()->bankTransfer()
    ->beneficiary($beneficiary);

可选地,您可以筛选授权流程中将返回的提供商

use TrueLayer\Constants\Countries;
use TrueLayer\Constants\CustomerSegments;
use TrueLayer\Constants\ReleaseChannels;

// You can filter the providers that will be returned:
$filter = $client->providerFilter()
    ->countries([Countries::GB, Countries::ES])
    ->customerSegments([CustomerSegments::RETAIL, CustomerSegments::CORPORATE])
    ->releaseChannel(ReleaseChannels::PRIVATE_BETA)
    ->excludesProviderIds(['provider-id'])

// You can also filter providers by the schemes they support:
$schemeSelection = $client->schemeSelection()->userSelected(); // Let the user select. You must provide your own UI for this.
$schemeSelection = $client->schemeSelection()->instantOnly(); // Only allow providers that support instant payments
$schemeSelection = $client->schemeSelection()->instantPreferred(); // Prefer providers that allow instant payments, but allow defaulting back to non-instant payments if unavailable.

// For instant only and instant preferred, you can also allow or disallow remitter fees:
$schemeSelection->allowRemitterFee(true); // Unless explicitly set, this will default to false.

// Create the provider selection configuration
$providerSelection = $client->providerSelection()->userSelected()
    ->filter($filter)
    ->schemeSelection($schemeSelection);

// Create the payment method
$paymentMethod = $client->paymentMethod()->bankTransfer()
    ->providerSelection($providerSelection);

或者,您可以选择在授权流程中使用的提供商以及支付方案

// Preselect the payment scheme
$schemeSelection = $client->schemeSelection()
    ->preselected()
    ->schemeId('faster_payments_service');

// Preselect the provider
$providerSelection = $client->providerSelection()
    ->preselected()
    ->providerId('mock-payments-gb-redirect')
    ->schemeSelection($schemeSelection);

// Create the payment method
$paymentMethod = $client->paymentMethod()->bankTransfer()
    ->providerSelection($providerSelection);

您还可以启用支付重试,但请确保您可以预先处理 attempt_failed 支付状态

$paymentMethod = $client->paymentMethod()->bankTransfer()
    ->enablePaymentRetry()
    ->beneficiary($beneficiary);

4. 创建支付

$payment = $client->payment()
    ->user($user)
    ->amountInMinor(1)
    ->currency(\TrueLayer\Constants\Currencies::GBP) // You can use other currencies defined in this class.
    ->paymentMethod($paymentMethod)
    ->create();

然后您将获得以下方法

$payment->getId(); // The payment id
$payment->getResourceToken(); // The resource token 
$payment->getDetails(); // Get the payment details, same as $client->getPayment($paymentId)
$payment->hostedPaymentsPage(); // Get the Hosted Payments Page helper, see below.
$payment->toArray(); // Convert to array

5. 从数组创建支付

如果您喜欢,您可以直接通过调用 fill 方法与数组一起工作

$paymentData = [
    'amount_in_minor' => 1,
    'currency' => Currencies::GBP,
    'payment_method' => [
        'type' => PaymentMethods::BANK_TRANSFER,
        'beneficiary' => [
            'account_identifier' => [
                'account_number' => '12345678',
                'sort_code' => '010203',
                'type' => 'sort_code_account_number',
            ],
            'reference' => 'Transaction reference',
            'account_holder_name' => 'John Doe',
            'type' => 'external_account',
        ],
        'provider_selection' => [
            'type' => PaymentMethods::PROVIDER_TYPE_USER_SELECTION,
            'filter' => [
                'countries' => [
                    Countries::GB,
                ],
                'release_channel' => ReleaseChannels::PRIVATE_BETA,
                'customer_segments' => [
                    CustomerSegments::RETAIL,
                ],
                'provider_ids' => [
                    'mock-payments-gb-redirect',
                ],
                'excludes' => [
                    'provider_ids' => [],
                ],
            ],
        ],
    ],
];

$payment = $client->payment()->fill($paymentData)->create();

6. 跳转到托管支付页面

TrueLayer的托管支付页面提供了一个高转换率的支付授权UI,默认支持所有动作类型。您可以在创建支付后轻松获取跳转的URL

$url = $client->payment()
    ...
    ->create()
    ->hostedPaymentsPage()
    ->returnUri('http://www.mymerchantwebsite.com')
    ->primaryColour('#000000')
    ->secondaryColour('#e53935')
    ->tertiaryColour('#32329f')
    ->toUrl();

获取付款详情

$payment = $client->getPayment($paymentId);
$payment->getId();
$payment->getUserId();
$payment->getAmountInMinor();
$payment->getCreatedAt(); 
$payment->getCurrency();
$payment->getPaymentMethod();
$payment->toArray();

获取支付方式和受益人

use TrueLayer\Interfaces\PaymentMethod\BankTransferPaymentMethodInterface;
use TrueLayer\Interfaces\Beneficiary\ExternalAccountBeneficiaryInterface;
use TrueLayer\Interfaces\Beneficiary\MerchantBeneficiaryInterface;

$method = $client->getPayment($paymentId)->getPaymentMethod();

if ($method instanceof BankTransferPaymentMethodInterface) {
    $providerSelection = $method->getProviderSelection();
    $beneficiary = $method->getBeneficiary();
    $beneficiary->getAccountHolderName();
    
    if ($beneficiary instanceof ExternalAccountBeneficiaryInterface) {
        $beneficiary->getReference();
        $beneficiary->getAccountIdentifier(); // See account identifiers documentation
    }
    
    if ($beneficiary instanceof MerchantBeneficiaryInterface) {
        $beneficiary->getReference();
        $beneficiary->getMerchantAccountId();
    }
}

检查付款的状态

您可以使用以下辅助方法之一检查状态

$payment = $client->getPayment($paymentId);
$payment->isAuthorizationRequired();
$payment->isAuthorizing();
$payment->isAuthorized(); // Will also return false when the payment has progressed to executed, failed or settled states.
$payment->isExecuted(); // Will also return false when the payment has progressed to failed or settled states.
$payment->isSettled(); 
$payment->isFailed(); // Payment has failed
$payment->isAttemptFailed(); // Payment attempt has failed, only available if payment retries are enabled.

或者,您可以将状态作为字符串获取,并将其与PaymentStatus中提供的常量进行比较

$payment = $client->getPayment($paymentId);
$payment->getStatus() === \TrueLayer\Constants\PaymentStatus::AUTHORIZATION_REQUIRED;

处理特定状态的付款字段

授权所需状态

具有此状态的支付处于初始阶段,在此阶段中,除了创建支付外,未采取任何其他操作。

use TrueLayer\Interfaces\Payment\PaymentAuthorizationRequiredInterface;

if ($payment instanceof PaymentAuthorizationRequiredInterface) {
    // Your logic here, you would normally start the authorization process.
}

授权状态

支付已开始其授权流程,但授权尚未完成

处于 Authorizing 状态的支付将暴露2个额外的检索方法

use TrueLayer\Interfaces\Payment\PaymentAuthorizingInterface;

if ($payment instanceof PaymentAuthorizingInterface) {
    $payment->getAuthorizationFlowConfig(); // see authorization flow config
    
    // Will return a \TrueLayer\Interfaces\Payment\AuthorizationFlow\Action\ActionInterface
    $payment->getAuthorizationFlowNextAction(); 
}

提供商选择操作

此操作表示用户需要从提供的列表中选择一个提供商。为了渲染提供商列表,每个提供商都提供了获取名称、标志、ID等的有用方法。

use TrueLayer\Interfaces\Payment\AuthorizationFlow\Action\ProviderSelectionActionInterface;

$nextAction = $payment->getAuthorizationFlowNextAction();

if ($nextAction instanceof ProviderSelectionActionInterface) {
    foreach ($nextAction->getProviders() as $provider) {
        $provider->getId();
        $provider->getDisplayName();
        $provider->getCountryCode();
        $provider->getLogoUri();
        $provider->getIconUri();
        $provider->getBgColor();       
    }
}

重定向操作

此操作表示用户需要被重定向以完成授权过程。

use TrueLayer\Interfaces\Payment\AuthorizationFlow\Action\RedirectActionInterface;

$nextAction = $payment->getAuthorizationFlowNextAction();

if ($nextAction instanceof RedirectActionInterface) {
    $nextAction->getUri(); // The URL the end user must be redirected to
    $nextAction->getProvider(); // The provider object, see available methods above.
}

等待操作

use TrueLayer\Interfaces\Payment\AuthorizationFlow\Action\WaitActionInterface;

$nextAction = $payment->getAuthorizationFlowNextAction();

if ($nextAction instanceof WaitActionInterface) {
    // your logic here   
}

已授权状态

支付已成功完成其授权流程

use TrueLayer\Interfaces\Payment\PaymentAuthorizedInterface;

if ($payment instanceof PaymentAuthorizedInterface) {
    $payment->getAuthorizationFlowConfig(); // see authorization flow config
}

执行状态

支付已被银行接受

use TrueLayer\Interfaces\Payment\PaymentExecutedInterface;

if ($payment instanceof PaymentExecutedInterface) {
    $payment->getExecutedAt(); // The date and time the payment was executed at
    $payment->getAuthorizationFlowConfig(); // See authorization flow config
}

结算状态

如果收款账户是Truelayer中的商户账户,并且Truelayer已观察到资金已结算,支付可以过渡到此状态。

use TrueLayer\Interfaces\Payment\PaymentSettledInterface;

if ($payment instanceof PaymentSettledInterface) {
    $payment->getExecutedAt(); // The date and time the payment was executed at
    $payment->getSettledAt(); // The date and time the payment was settled at
    $payment->getAuthorizationFlowConfig(); // See authorization flow config
    $payment->getSourceOfFunds(); // See source of funds
}

失败状态

支付已失败。失败原因可以在支付资源上的 failure_reason 字段中观察到

use TrueLayer\Interfaces\Payment\PaymentFailedInterface;

if ($payment instanceof PaymentFailedInterface) {
    $payment->getFailedAt(); // The date and time the payment failed at
    $payment->getFailureStage(); // The status the payment was when it failed, one of `authorization_required`, `authorizing` or `authorized`
    $payment->getFailureReason(); // The reason the payment failed. Handle unexpected values gracefully as an unknown failure.
    $payment->getAuthorizationFlowConfig(); // see authorization flow config
}

尝试失败状态

仅在启用支付重试时才可用。

use TrueLayer\Interfaces\Payment\PaymentAttemptFailedInterface;

if ($payment instanceof PaymentAttemptFailedInterface) {
    $payment->getFailedAt(); // The date and time the payment failed at
    $payment->getFailureStage(); // The status the payment was when it failed, one of `authorization_required`, `authorizing` or `authorized`
    $payment->getFailureReason(); // The reason the payment failed. Handle unexpected values gracefully as an unknown failure.
    $payment->getAuthorizationFlowConfig(); // see authorization flow config
}

授权流程配置

此对象提供了有关支付所经历的授权流程的信息。

use TrueLayer\Interfaces\Payment\PaymentExecutedInterface;

if ($payment instanceof PaymentExecutedInterface) {
    $config = $payment->getAuthorizationFlowConfig(); 
    $config->isRedirectSupported() // Is redirect supported or not
    $config->getRedirectReturnUri(); // The URL the user will be redirected back once the flow on the third-party's website is completed
    $config->isProviderSelectionSupported(); // Is provider selection supported or not
}

资金来源

use TrueLayer\Interfaces\Payment\PaymentExecutedInterface;
use TrueLayer\Interfaces\Payment\PaymentSettledInterface;
use TrueLayer\Interfaces\SchemeIdentifier\ScanDetailsInterface;
use TrueLayer\Interfaces\SchemeIdentifier\IbanDetailsInterface;
use TrueLayer\Interfaces\SchemeIdentifier\BbanDetailsInterface;
use TrueLayer\Interfaces\SchemeIdentifier\NrbDetailsInterface;

if ($payment instanceof PaymentExecutedInterface || $payment instanceof PaymentSettledInterface) {
    $paymentSource = $payment->getPaymentSource();
    $paymentSource->getAccountHolderName(); // The unique ID for the external account
    $paymentSource->getId(); 
    $paymentSource->toArray();
        
    foreach ($paymentSource->getAccountIdentifiers() as $accountIdentifier) {
       // See 'Account identifiers' for available methods.
    }
}

授权付款

使用托管支付页面

我们鼓励您使用我们的HPP,它收集从您的用户处所需的所有支付信息,并引导他们完成支付授权旅程。为此,只需在创建支付后重定向到HPP即可。有关如何开始,请参阅跳转到HPP

手动启动授权流程

在某些情况下,您可能希望手动启动授权流程(例如,如果您想渲染自己的提供商选择屏幕)。

此库对授权流程的支持不完整。要完成授权流程,您最终需要将用户重定向到HPP或使用直接API调用实现缺失的功能(请参阅自定义API调用)。

use TrueLayer\Constants\FormInputTypes;

$payment = $client->payment()->create();

// If you are planning to start the authorization flow manually then hand over to the HPP:
$payment->authorizationFlow()
    ->returnUri($myReturnUri)
    ->useHPPCapabilities()
    ->start();

// If you are planning to build a fully custom UI, you need to manually specify which features your UI is able to support:
$payment->authorizationFlow()
    ->returnUri($myReturnUri)
    ->enableProviderSelection() // Can the UI render a provider selection screen?
    ->enableSchemeSelection() // Can the UI render a scheme selection screen?
    ->enableUserAccountSelection() // Can the UI render a user account selection screen?
    ->formInputTypes([FormInputTypes::TEXT, FormInputTypes::TEXT_WITH_IMAGE, FormInputTypes::SELECT]) // Can the UI render form inputs for the end user to interact with? Which input types can it handle?
    ->start();

一旦授权流程开始,请参考授权支付了解如何处理返回的操作。

提交服务提供商

如果您的支付需要选择一个服务提供商作为其下一步操作,您可以使用submitProvider方法来渲染提供商列表,然后提交用户选择。

$client->submitPaymentProvider($payment, $provider);

退款

仅支持已结算的商户账户支付退款。

在客户端创建和检索退款

use TrueLayer\Interfaces\Payment\RefundRetrievedInterface;
use TrueLayer\Interfaces\Payment\RefundExecutedInterface;
use TrueLayer\Interfaces\Payment\RefundFailedInterface;

// Create and get the refund id
$refundId = $client->refund()
    ->payment($paymentId) // Payment ID, PaymentRetrievedInterface or PaymentCreatedInterface
    ->amountInMinor(1)
    ->reference('My reference')
    ->create()
    ->getId();
    
// Get a refund's details
$refund = $client->getRefund($paymentId, $refundId);

// Common refund methods
$refund->getId();
$refund->getAmountInMinor();
$refund->getCurrency();
$refund->getReference();
$refund->getStatus();
$refund->getCreatedAt();
$refund->isPending();
$refund->isAuthorized();
$refund->isExecuted();
$refund->isFailed();

// Executed refunds
if ($refund instanceof RefundExecutedInterface) {
    $refund->getExecutedAt();
}

// Failed refunds
if ($refund instanceof RefundFailedInterface) {
    $refund->getFailureReason();
    $refund->getFailedAt();
}

// Get all refunds for a payment
$refunds = $client->getRefunds($paymentId); // RefundRetrievedInterface[]

从已结算的支付创建和检索退款

或者,如果您已经有了支付实例,可以使用以下便捷方法

use TrueLayer\Interfaces\Payment\PaymentSettledInterface;

if ($payment instanceof PaymentSettledInterface) {
    // Create a refund
    $refundId = $payment->refund()
        ->amountInMinor(1)
        ->reference('My reference')
        ->create()
        ->getId();
        
    // Get a refund's details
    $payment->getRefund($refundId)
    
    // Get all refunds
    $payment->getRefunds();
}

支付

创建向外部受益人付款

$accountIdentifier = $client->accountIdentifier()
    ->iban()
    ->iban('GB29NWBK60161331926819');

$beneficiary = $client->payoutBeneficiary()->externalAccount()
    ->accountHolderName('John Doe')
    ->reference('My reference')
    ->accountIdentifier($accountIdentifier);

$payout = $client->payout()
    ->amountInMinor(1)
    ->beneficiary($beneficiary)
    ->currency(\TrueLayer\Constants\Currencies::GBP)
    ->merchantAccountId($merchantAccount->getId())
    ->create();

$payout->getId();

创建向支付来源(退款)付款

$beneficiary = $client->payoutBeneficiary()->paymentSource()
    ->paymentSourceId($paymentSourceId)
    ->reference('My reference')
    ->userId($user->getId());

$payout = $client->payout()
    ->amountInMinor(1)
    ->beneficiary($beneficiary)
    ->currency(\TrueLayer\Constants\Currencies::GBP)
    ->merchantAccountId($merchantAccount->getId())
    ->create();

$payout->getId();

创建向预选的商户账户付款

$beneficiary = $client->payoutBeneficiary()
    ->businessAccount()
    ->reference('My reference');

$payout = $client->payout()
    ->amountInMinor(1)
    ->beneficiary($beneficiary)
    ->currency(\TrueLayer\Constants\Currencies::GBP)
    ->merchantAccountId($merchantAccount->getId())
    ->create();

$payout->getId();

检索付款

use TrueLayer\Interfaces\Payout\PayoutRetrievedInterface;
use TrueLayer\Interfaces\Payout\PayoutPendingInterface;
use TrueLayer\Interfaces\Payout\PayoutAuthorizedInterface;
use TrueLayer\Interfaces\Payout\PayoutExecutedInterface;
use TrueLayer\Interfaces\Payout\PayoutFailedInterface;
use TrueLayer\Constants\PayoutStatus;

$payout = $client->getPayout($payoutId);

// All payout statuses implement this common interface
if ($payout instanceof PayoutRetrievedInterface) {
    $payout->getId();
    $payout->getCurrency();
    $payout->getAmountInMinor();
    $payout->getMerchantAccountId();
    $payout->getStatus(); 
    $payout->getBeneficiary();
    $payout->getCreatedAt();
}

// Pending payouts
if ($payout instanceof PayoutPendingInterface) {
    $payout->getStatus(); //PayoutStatus::PENDING
}

// Authorized payouts
if ($payout instanceof PayoutAuthorizedInterface) {
    $payout->getStatus(); //PayoutStatus::AUTHORIZED
}

// Executed payouts
if ($payout instanceof PayoutExecutedInterface) {
    $payout->getStatus(); //PayoutStatus::EXECUTED
    $payout->getExecutedAt();
}

// Failed payouts
if ($payout instanceof PayoutFailedInterface) {
    $payout->getStatus() // PayoutStatus::FAILED
    $payout->getFailedAt();
    $payout->getFailureReason();
}

商家账户

列出所有商户账户

$merchantAccounts = $client->getMerchantAccounts(); // MerchantAccountInterface[]

通过ID检索账户

$merchantAccount = $client->getMerchantAccount('a2dcee6d-7a00-414d-a1e6-8a2b23169e00');

$merchantAccount->getAccountHolderName();
$merchantAccount->getAvailableBalanceInMinor();
$merchantAccount->getCurrentBalanceInMinor();
$merchantAccount->getCurrency();
$merchantAccount->getId();

foreach ($merchantAccount->getAccountIdentifiers() as $accountIdentifier) {
    // See 'Account identifiers' for available methods.
}

接收webhook通知

您可以通过webhooks注册接收关于您的支付或授权状态的通知。webhook的URI端点可以在控制台中进行配置

⚠️ 所有传入的webhook请求都必须验证其签名,否则您可能会接受欺诈性支付状态事件。

这个库使处理webhook事件变得简单且安全。您不需要手动验证传入请求的签名,因为已经为您完成。您应将以下代码添加到您的webhook端点;或者,可以将webhook服务配置在您的IoC容器中,在您的端点中,您可以简单地调用$webhook->execute()

获取webhook实例

如果您已经可以访问客户端实例,这很简单

$webhook = $client->webhook();

或者,您也可以从头创建实例

$webhook = \TrueLayer\Webhook::configure()
    ->httpClient($httpClient)
    ->cache($cacheImplementation, $encryptionKey)  // optional, but recommeded. See Caching
    ->useProduction($useProduction) // bool
    ->create();

处理事件

您通过为关心的事件类型注册处理程序(闭包或可调用类)来处理事件。您可以有任意多的处理程序,但请注意执行顺序没有保证。

您的处理程序将在请求签名验证后以及传入的webhook类型与您在处理程序中指定的接口相匹配后执行。

跳转到支持的事件类型

闭包处理程序

use TrueLayer\Interfaces\Webhook;

$client->webhook()
    ->handler(function (Webhook\EventInterface $event) {
        // Do something on any event
    })
    ->handler(function (Webhook\PaymentEventInterface $event) {
        // Do something on any payment event
    })
    ->handler(function (Webhook\PaymentExecutedEventInterface $event) {
        // Do something on payment executed event only
    })
    ->execute();

可调用类

use TrueLayer\Interfaces\Webhook;

class LogEvents
{
    public function __invoke(Webhook\EventInterface $event)
    {
        // Log event
    }
}

class UpdateOrderStatus
{
    public function __invoke(Webhook\PaymentExecutedEventInterface $event)
    {
        // Update your order when the payment is executed
    }
}

// You can use ->handler()...
$client->webhook()
    ->handler(LogEvents::class)
    ->handler(UpdateOrderStatus::class)
    ->execute();

// Or you can use ->handlers()...
$client->webhook()
    ->handlers(
        LogEvents::class,
        UpdateOrderStatus::class
    )
    ->execute();

// If you need to, you can also provide instances:
$client->webhook()
    ->handlers(
        new LogEvents(),
        new UpdateOrderStatus()
    )
    ->execute();

支持的处理器类型

该库支持以下事件类型的处理器

  • payment_executed
  • payment_settled
  • payment_failed
  • refund_executed
  • refund_failed
  • payout_executed
  • payout_failed

您还可以通过在处理程序中类型提示TrueLayer\Interfaces\Webhook\EventInterface来处理其他事件类型。然后,您可以通过调用您的变量的getBody()方法来获取负载数据。

所有事件都继承自EventInterface

use TrueLayer\Interfaces\Webhook;

$client->webhook()
    ->handler(function (Webhook\EventInterface $event) {
        // handle any incoming event
        $event->getEventId();
        $event->getEventVersion();
        $event->getSignature();
        $event->getTimestamp();
        $event->getType();
        $event->getBody();
    })
    ->handler(function (Webhook\PaymentEventInterface $event) {
        // handle any payment event
        $event->getPaymentId();
        
        $paymentMethod = $event->getPaymentMethod();
        $paymentMethod->getType();
        
        if ($paymentMethod instanceof Webhook\PaymentMethod\BankTransferPaymentMethodInterface) {
            $paymentMethod->getProviderId();
            $paymentMethod->getSchemeId();
        }      
       
       if ($paymentMethod instanceof Webhook\PaymentMethod\MandatePaymentMethodInterface) {
            $paymentMethod->getMandateId();
       }
    })
    ->handler(function (Webhook\PaymentExecutedEventInterface $event) {
        // handle payment executed
        // Inherits from PaymentEventInterface so provides same methods plus:
        $event->getExecutedAt();
        $event->getSettlementRiskCategory();
    })
    ->handler(function (Webhook\PaymentSettledEventInterface $event) {
        // handle payment settled
        // Inherits from PaymentEventInterface so provides same methods plus:
        $event->getSettledAt();
        $event->getSettlementRiskCategory();
        
        $paymentSource = $event->getPaymentSource();
        $paymentSource->getId();
        $paymentSource->getAccountHolderName();
        $paymentSource->getAccountIdentifiers(); // See Account Identifiers
    })
    ->handler(function (Webhook\PaymentFailedEventInterface $event) {
        // handle payment failed
        // Inherits from PaymentEventInterface so provides same methods plus:
        $event->getFailedAt();
        $event->getFailureReason();
        $event->getFailureStage();
    })
    ->handler(function (Webhook\RefundEventInterface $event) {
        // handle any refund event
        $event->getPaymentId();
        $event->getRefundId();
    })
    ->handler(function (Webhook\RefundExecutedEventInterface $event) {
        // handle refund executed
        // Inherits from RefundEventInterface so provides same methods plus:
        $event->getExecutedAt();
    })
    ->handler(function (Webhook\RefundFailedEventInterface $event) {
        // handle refund failed
        // Inherits from RefundEventInterface so provides same methods plus:
        $event->getFailedAt();
        $event->getFailureReason();
    })
    ->handler(function (Webhook\PayoutEventInterface $event) {
        // handle any payout event
        $event->getPayoutId();
        $beneficiary = $event->getBeneficiary();
        $beneficiary->getType();
        
        if ($beneficiary instanceof Webhook\Beneficiary\BusinessAccountBeneficiaryInterface) {
            $beneficiary->getType();
        }
        
        if ($beneficiary instanceof Webhook\Beneficiary\PaymentSourceBeneficiaryInterface) {
            $beneficiary->getPaymentSourceId();
            $beneficiary->getUserId();
        }
    })
    ->handler(function (Webhook\PayoutExecutedEventInterface $event) {
        // handle payout executed
        // Inherits from PayoutEventInterface so provides same methods plus:
        $event->getExecutedAt();
    })
    ->handler(function (Webhook\PayoutFailedEventInterface $event) {
        // handle payout failed
        // Inherits from PayoutEventInterface so provides same methods plus:
        $event->getFailedAt();
        $event->getFailureReason();
    })
    ->execute();

重写全局变量

默认情况下,webhook服务将使用php全局变量来读取端点路径和请求头和正文。如果需要,可以覆盖此行为(例如,您可能需要在队列作业中调用execute()。)

    $client->webhook()
        ->handlers(...)
        ->path('/my/custom/path')
        ->headers($headers) // flat key-value array
        ->body($body) // the raw request body string
        ->execute();

签名验证失败

如果无法验证webhook签名,将抛出\TrueLayer\Exceptions\WebhookVerificationFailedException。当webhook服务配置错误时,还会抛出其他一些异常,请参阅错误处理

账户标识符

所有账户标识符实现了一个公共接口,因此您可以访问

$accountIdentifier->getType();
$accountIdentifier->toArray();

根据特定类型,您可以获取更多信息

use TrueLayer\Interfaces\AccountIdentifier\ScanDetailsInterface;
use TrueLayer\Interfaces\AccountIdentifier\IbanDetailsInterface;
use TrueLayer\Interfaces\AccountIdentifier\NrbDetailsInterface;
use TrueLayer\Interfaces\AccountIdentifier\BbanDetailsInterface;

if ($accountIdentifier instanceof ScanDetailsInterface) {
    $accountIdentifier->getAccountNumber();
    $accountIdentifier->getSortCode();
}

if ($accountIdentifier instanceof IbanDetailsInterface) {
    $accountIdentifier->getIban();
}

if ($accountIdentifier instanceof NrbDetailsInterface) {
    $accountIdentifier->getNrb();
}

if ($accountIdentifier instanceof BbanDetailsInterface) {
    $accountIdentifier->getBban();
}

自定义幂等性键

默认情况下,客户端将为您生成和管理幂等键。但是,有些情况下您可能想设置自己的幂等键,您可以在创建资源时使用requestOptions设置器来完成此操作。

// Create a RequestOptionsInterface instance and set your custom idempotency key
$requestOptions = $client->requestOptions()->idempotencyKey('my-custom-idempotency-key');

// Creating a payment with a custom idempotency key
$client->payment()
    ->paymentMethod($method)
    ->amountInMinor(10)
    ->currency('GBP')
    ->user($user)
    ->requestOptions($requestOptions) 
    ->create();

// Creating a refund with a custom idempotency key
$client->refund()
    ->payment($paymentId)
    ->amountInMinor(1)
    ->reference('My reference')
    ->requestOptions($requestOptions) 
    ->create();

// Creating a payout with a custom idempotency key
$client->payout()
    ->amountInMinor(1)
    ->currency(Currencies::GBP)
    ->merchantAccountId($accountId)
    ->beneficiary($payoutBeneficiary)
    ->requestOptions($requestOptions) 
    ->create();

自定义API调用

您可以使用客户端库来执行自己的API调用,而无需担心身份验证或请求签名。

$responseData = $client->getApiClient()->request()->uri('/merchant-accounts')->get();

$responseData = $client->getApiClient()->request()
    ->uri('/payments')
    ->payload($myData)
    ->header('My Header', 'value')
    ->post();

错误处理

客户端库会抛出以下异常

PSR 异常

ClientExceptionInterface

根据 PSR-18 规范抛出,如果 HTTP 客户端无法发送请求,或者无法将响应解析为 PSR-7 响应对象。

Psr\Http\Client\ClientExceptionInterface

自定义异常

所有自定义异常都将继承自基本类 TrueLayer\Exceptions\Exception

ApiResponseUnsuccessfulException

如果 API 响应状态不是 2xx,则会抛出。

\TrueLayer\Exceptions\ApiResponseUnsuccessfulException

$e->getErrors(); // Get the errors provided by the API, as an array
$e->getStatusCode(); // The response status code
$e->getType(); // The error type, as a link to the TrueLayer docs
$e->getDetail(); // A description of the error message
$e->getTraceId(); // The TrueLayer error trace id

ApiRequestJsonSerializationException

在调用 API 之前,如果请求数据无法进行 JSON 编码,则会抛出。

\TrueLayer\Exceptions\ApiRequestJsonSerializationException

InvalidArgumentException

当提供的参数无效时抛出,例如无效的受益人类型。

\TrueLayer\Exceptions\InvalidArgumentException

SignerException

如果请求签名器无法初始化或签名失败,则会抛出。

\TrueLayer\Exceptions\SignerException

EncryptException

当客户端库无法加密需要缓存的负载时抛出。

\TrueLayer\Exceptions\EncryptException

DecryptException

如果客户端库无法解密缓存密钥的值,则会抛出。

\TrueLayer\Exceptions\DecryptException

TLPublicKeysNotFound

当 webhook 服务无法检索 TL 的公钥时抛出。

\TrueLayer\Exceptions\TLPublicKeysNotFound

WebhookHandlerException

当 webhook 服务提供了一个无效的处理程序时抛出。

\TrueLayer\Exceptions\WebhookHandlerException

WebhookHandlerInvalidArgumentException

当 webhook 服务无法获取请求体、签名头或提供的处理程序有无效参数时抛出。

\TrueLayer\Exceptions\WebhookHandlerInvalidArgumentException

WebhookVerificationFailedException

当 webhook 签名无法验证时抛出。

\TrueLayer\Exceptions\WebhookVerificationFailedException