Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

### Added

- Support for `sub_merchants` on payment creation
- Support for `hosted_page` on payment creation (`return_uri`, `country_code`, `language_code`, `max_wait_for_result`), exposing `getHostedPageUri()` on the created payment
- Support for `settlement_stalled_at`, `reversed_at` and `reversal_reason` on a failed payment, exposing `getSettlementStalledAt()`, `getReversedAt()` and `getReversalReason()` on `PaymentFailedInterface`
- Support for `failed_attempts` on a retrieved payment, exposing `getFailedAttempts()` on all payment statuses
Expand All @@ -17,7 +18,7 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

### Changed

- Bumped `truelayer/signing` dependency to widen support for the underlying `web-token/jwt-library` ([#89](https://github.com/TrueLayer/truelayer-php/pull/89))
- Bumped `truelayer/signing` dependency to widen support for the underlying `web-token/jwt-library` ([#89](https://github.com/TrueLayer/truelayer-php/pull/89))

## [3.2.0] - 2025-05-13

Expand Down
45 changes: 41 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ $paymentData = $client->getPayment($paymentId)->toArray();

### 1. Creating a beneficiary

*Merchant account beneficiary*
_Merchant account beneficiary_

```php
// If the merchant account id is known:
Expand Down Expand Up @@ -192,14 +192,14 @@ $beneficiary = $client->beneficiary()
->verification($remitterVerification);
```

For your *merchant account beneficiary* you can pass a statement reference that should be set on the end user's
For your _merchant account beneficiary_ you can pass a statement reference that should be set on the end user's
statement. Not all banks support setting such a reference, this value will be used wherever possible.

```php
$beneficiary->statementReference('Statement reference.');
```

*External account beneficiary - Sort code & account number*
_External account beneficiary - Sort code & account number_

```php
$beneficiary = $client->beneficiary()->externalAccount()
Expand All @@ -212,7 +212,7 @@ $beneficiary = $client->beneficiary()->externalAccount()
);
```

*External account beneficiary - IBAN*
_External account beneficiary - IBAN_

```php
$beneficiary = $client->beneficiary()->externalAccount()
Expand Down Expand Up @@ -352,6 +352,43 @@ $payment->hostedPaymentsPage(); // Get the Hosted Payments Page helper, see belo
$payment->toArray(); // Convert to array
```

If needed, you can provide details about the sub-merchant the payment relates to,
for example an underlying division or client of your overall business:

```php
$payment = $client->payment()
->user($user)
->amountInMinor(1)
->currency(\TrueLayer\Constants\PaymentCurrencies::GBP)
->paymentMethod($paymentMethod);

// A business division of your own business:
$ultimateCounterparty = $client->ultimateCounterparty()
->businessDivision()
->id('my-division-id')
->name('My Division');

// Or, an underlying business client:
$ultimateCounterparty = $client->ultimateCounterparty()
->businessClient()
->id('my-client-id')
->tradingName('My Client Trading Name')
->commercialName('My Client Commercial Name') // optional
->url('https://my-client.example.com') // optional
->mcc('1234') // optional, merchant category code
->registrationNumber('12345678'); // required if no address is provided

$ultimateCounterparty->address() // required if no registration number is provided
->addressLine1('1 Example Street')
->city('London')
->zip('EC2A 1PX')
->countryCode('GB');

$payment->subMerchants()->ultimateCounterparty($ultimateCounterparty);

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

You can optionally request a hosted page URI directly as part of payment creation, instead of building the
Hosted Payments Page URL yourself afterwards:

Expand Down
4 changes: 4 additions & 0 deletions config/bindings.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@

Interfaces\Payment\PaymentRequestInterface::class => Entities\Payment\PaymentRequest::class,
Interfaces\Payment\PaymentRiskAssessmentInterface::class => Entities\Payment\PaymentRiskAssessment::class,
Interfaces\Payment\SubMerchants\PaymentSubMerchantsInterface::class => Entities\Payment\SubMerchants\PaymentSubMerchants::class,
Interfaces\Payment\SubMerchants\UltimateCounterpartyBuilderInterface::class => Entities\Payment\SubMerchants\UltimateCounterpartyBuilder::class,
Interfaces\Payment\SubMerchants\BusinessDivisionUltimateCounterpartyInterface::class => Entities\Payment\SubMerchants\BusinessDivisionUltimateCounterparty::class,
Interfaces\Payment\SubMerchants\BusinessClientUltimateCounterpartyInterface::class => Entities\Payment\SubMerchants\BusinessClientUltimateCounterparty::class,
Interfaces\Payment\PaymentHostedPageInterface::class => Entities\Payment\PaymentHostedPage::class,
Interfaces\Payment\PaymentCreatedInterface::class => Entities\Payment\PaymentCreated::class,
Interfaces\Payment\PaymentAuthorizationRequiredInterface::class => Entities\Payment\PaymentRetrieved\PaymentAuthorizationRequired::class,
Expand Down
6 changes: 6 additions & 0 deletions config/discriminations.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use TrueLayer\Constants\RefundStatus;
use TrueLayer\Constants\RemitterVerificationTypes;
use TrueLayer\Constants\SchemeSelectionTypes;
use TrueLayer\Constants\UltimateCounterpartyTypes;
use TrueLayer\Constants\WebhookEventTypes;
use TrueLayer\Interfaces;

Expand Down Expand Up @@ -44,6 +45,11 @@
AccountIdentifierTypes::BBAN => Interfaces\AccountIdentifier\BbanInterface::class,
AccountIdentifierTypes::NRB => Interfaces\AccountIdentifier\NrbInterface::class,
],
Interfaces\Payment\SubMerchants\UltimateCounterpartyInterface::class => [
'discriminate_on' => 'type',
UltimateCounterpartyTypes::BUSINESS_DIVISION => Interfaces\Payment\SubMerchants\BusinessDivisionUltimateCounterpartyInterface::class,
UltimateCounterpartyTypes::BUSINESS_CLIENT => Interfaces\Payment\SubMerchants\BusinessClientUltimateCounterpartyInterface::class,
],
Interfaces\Payment\Beneficiary\BeneficiaryInterface::class => [
'discriminate_on' => 'type',
BeneficiaryTypes::EXTERNAL_ACCOUNT => Interfaces\Payment\Beneficiary\ExternalAccountBeneficiaryInterface::class,
Expand Down
11 changes: 11 additions & 0 deletions src/Constants/UltimateCounterpartyTypes.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

namespace TrueLayer\Constants;

class UltimateCounterpartyTypes
{
public const BUSINESS_DIVISION = 'business_division';
public const BUSINESS_CLIENT = 'business_client';
}
22 changes: 22 additions & 0 deletions src/Entities/Payment/PaymentRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use TrueLayer\Interfaces\Payment\PaymentHostedPageInterface;
use TrueLayer\Interfaces\Payment\PaymentRequestInterface;
use TrueLayer\Interfaces\Payment\PaymentRiskAssessmentInterface;
use TrueLayer\Interfaces\Payment\SubMerchants\PaymentSubMerchantsInterface;
use TrueLayer\Interfaces\PaymentMethod\PaymentMethodInterface;
use TrueLayer\Interfaces\RequestOptionsInterface;
use TrueLayer\Interfaces\UserInterface;
Expand Down Expand Up @@ -58,6 +59,11 @@ final class PaymentRequest extends Entity implements PaymentRequestInterface, Ha
*/
protected ?RequestOptionsInterface $requestOptions = null;

/**
* @var PaymentSubMerchantsInterface
*/
protected PaymentSubMerchantsInterface $subMerchants;

/**
* @var PaymentHostedPageInterface
*/
Expand All @@ -70,6 +76,7 @@ final class PaymentRequest extends Entity implements PaymentRequestInterface, Ha
'payment_method' => PaymentMethodInterface::class,
'risk_assessment' => PaymentRiskAssessmentInterface::class,
'user' => UserInterface::class,
'sub_merchants' => PaymentSubMerchantsInterface::class,
'hosted_page' => PaymentHostedPageInterface::class,
];

Expand All @@ -83,6 +90,7 @@ final class PaymentRequest extends Entity implements PaymentRequestInterface, Ha
'payment_method',
'risk_assessment',
'user',
'sub_merchants',
'hosted_page',
];

Expand Down Expand Up @@ -162,6 +170,20 @@ public function user(UserInterface $user): PaymentRequestInterface
return $this;
}

/**
* @param PaymentSubMerchantsInterface|null $subMerchants
*
* @throws InvalidArgumentException
*
* @return PaymentSubMerchantsInterface
*/
public function subMerchants(?PaymentSubMerchantsInterface $subMerchants = null): PaymentSubMerchantsInterface
{
$this->subMerchants = $subMerchants ?: $this->entityFactory->make(PaymentSubMerchantsInterface::class);

return $this->subMerchants;
}

/**
* @param PaymentHostedPageInterface|null $hostedPage
*
Expand Down
Loading
Loading