9 Commits

Author SHA1 Message Date
1725ec68de update subscriptions
Signed-off-by: Maurice Preuß (envoyr) <hello@envoyr.com>
2025-05-01 18:16:51 +02:00
dcda4b990e update user provider
Signed-off-by: Maurice Preuß (envoyr) <hello@envoyr.com>
2025-04-30 12:00:34 +02:00
937fde603b update docs
Signed-off-by: Maurice Preuß (envoyr) <hello@envoyr.com>
2025-04-30 10:03:27 +02:00
80b1f003b2 update docs
Signed-off-by: Maurice Preuß (envoyr) <hello@envoyr.com>
2025-04-30 10:02:53 +02:00
aff901de4e update docs
Signed-off-by: Maurice Preuß (envoyr) <hello@envoyr.com>
2025-04-30 10:02:23 +02:00
92eadcca08 update docs
Signed-off-by: Maurice Preuß (envoyr) <hello@envoyr.com>
2025-04-30 10:00:27 +02:00
8b874f540c update docs
Signed-off-by: Maurice Preuß (envoyr) <hello@envoyr.com>
2025-04-30 09:08:29 +02:00
3bcebd9d45 update subscription, add alias
Signed-off-by: Maurice Preuß (envoyr) <hello@envoyr.com>
2025-04-30 09:02:24 +02:00
71663bffd8 small fixes
Signed-off-by: Maurice Preuß (envoyr) <hello@envoyr.com>
2025-04-30 06:43:07 +02:00
16 changed files with 320 additions and 185 deletions

View File

@@ -109,17 +109,18 @@ public function boot(): void
### Implementing Auth ### Implementing Auth
This method should typically be called in the `boot` method of your `AuthServiceProvider` class: This method should typically be called in the `boot` method of your `AppServiceProvider` class:
```php ```php
use Anikeen\Id\AnikeenId; use Anikeen\Id\AnikeenId;
use Anikeen\Id\Providers\AnikeenIdSsoUserProvider; use Anikeen\Id\Providers\AnikeenIdUserProvider;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
public function boot(): void public function boot(): void
{ {
Auth::provider('sso-users', function ($app, array $config) { Auth::provider('anikeen', function ($app, array $config) {
return new AnikeenIdSsoUserProvider( return new AnikeenIdUserProvider(
$app->make(AnikeenId::class), $app->make(AnikeenId::class),
$app->make(Request::class), $app->make(Request::class),
$config['model'], $config['model'],
@@ -140,7 +141,7 @@ reference the guard in the `guards` configuration of your `auth.php` configurati
'api' => [ 'api' => [
'driver' => 'anikeen', 'driver' => 'anikeen',
'provider' => 'sso-users', 'provider' => 'anikeen',
], ],
], ],
``` ```
@@ -154,8 +155,8 @@ reference the provider in the `providers` configuration of your `auth.php` confi
'model' => App\Models\User::class, 'model' => App\Models\User::class,
], ],
'sso-users' => [ 'anikeen' => [
'driver' => 'sso-users', 'driver' => 'anikeen',
'model' => App\Models\User::class, 'model' => App\Models\User::class,
'fields' => ['first_name', 'last_name', 'email'], 'fields' => ['first_name', 'last_name', 'email'],
], ],
@@ -294,9 +295,7 @@ public function createOrderPreview(array $attributes = []): Result
### ManagesSshKeys ### ManagesSshKeys
```php ```php
public function sshKeysByUserId(string $sskKeyId): Result public function sshKeysByUserId(string $sskKeyId): SshKeys
public function createSshKey(string $publicKey, ?string $name = null): Result
public function deleteSshKey(int $sshKeyId): Result
``` ```
### ManagesUsers ### ManagesUsers
@@ -305,6 +304,8 @@ public function deleteSshKey(int $sshKeyId): Result
public function getAuthedUser(): Result public function getAuthedUser(): Result
public function createUser(array $attributes): Result public function createUser(array $attributes): Result
public function isEmailExisting(string $email): Result public function isEmailExisting(string $email): Result
public function setParent(?mixed $parent): self
public function getParent()
``` ```
@@ -313,11 +314,8 @@ public function isEmailExisting(string $email): Result
### ManagesAddresses ### ManagesAddresses
```php ```php
public function addresses(): Result public function addresses(): Addresses
public function createAddress(array $attributes = []): Result public function hasDefaultBillingAddress(): bool
public function address(string $addressId): Result
public function updateAddress(string $addressId, array $attributes = []): Result
public function deleteAddress(string $addressId): Result
``` ```
### ManagesBalance ### ManagesBalance
@@ -325,55 +323,48 @@ public function deleteAddress(string $addressId): Result
```php ```php
public function balance(): float public function balance(): float
public function charges(): float public function charges(): float
public function charge(float $amount, string $paymentMethodId, array $options = []): Result public function charge(float $amount, string $paymentMethodId, array $options = []): Transaction
```
### ManagesCountries
```php
public function countries(): Countries
``` ```
### ManagesInvoices ### ManagesInvoices
```php ```php
public function invoices(): Result public function invoices(array $parameters = []): Invoices
public function invoice(string $invoiceId): Result
public function getInvoiceTemporaryUrl(string $invoiceId): string
``` ```
### ManagesOrders ### ManagesOrders
```php ```php
public function orders(): Result public function orders(array $parameters = []): Orders
public function createOrder(array $attributes = []): Result
public function order(string $orderId): Result
public function updateOrder(string $orderId, array $attributes = []): Result
public function checkoutOrder(string $orderId): Result
public function revokeOrder(string $orderId): Result
public function deleteOrder(string $orderId): Result
public function orderItems(string $orderId): Result
public function createOrderItem(string $orderId, array $attributes = []): Result
public function orderItem(string $orderId, string $orderItemId): Result
public function updateOrderItem(string $orderId, string $orderItemId, array $attributes = []): Result
public function deleteOrderItem(string $orderId, string $orderItemId): Result
``` ```
### ManagesPaymentMethods ### ManagesPaymentMethods
```php ```php
public function hasPaymentMethod(): bool public function paymentMethods(): PaymentMethods
public function paymentMethods(): Result public function hasPaymentMethod(): ?PaymentMethod
public function defaultPaymentMethod(): ?PaymentMethod
public function hasDefaultPaymentMethod(): bool public function hasDefaultPaymentMethod(): bool
public function defaultPaymentMethod(): Result public function billingPortalUrl(?string $returnUrl = null, array $options = []): string
public function billingPortalUrl(string $returnUrl, array $options): string
public function createSetupIntent(array $options = []): Result public function createSetupIntent(array $options = []): Result
``` ```
### ManagesProfile
```php
public function profilePortalUrl(?string $returnUrl = null, array $options = []): string
```
### ManagesSubscriptions ### ManagesSubscriptions
```php ```php
public function subscriptions(): Result public function subscriptions(): Subscriptions
public function subscription(string $subscriptionId): Result
public function createSubscription(array $attributes): Result
public function checkoutSubscription(string $subscriptionId): Result
public function revokeSubscription(string $subscriptionId): Result
public function resumeSubscription(string $subscriptionId): Result
public function deleteSubscription(string $subscriptionId): Result
``` ```
### ManagesTaxation ### ManagesTaxation
@@ -385,9 +376,7 @@ public function vat(): float
### ManagesTransactions ### ManagesTransactions
```php ```php
public function transactions(): Result public function transactions(): Transactions
public function createTransaction(array $attributes = []): Result
public function transaction(string $transactionId): Result
``` ```

View File

@@ -109,17 +109,18 @@ public function boot(): void
### Implementing Auth ### Implementing Auth
This method should typically be called in the `boot` method of your `AuthServiceProvider` class: This method should typically be called in the `boot` method of your `AppServiceProvider` class:
```php ```php
use Anikeen\Id\AnikeenId; use Anikeen\Id\AnikeenId;
use Anikeen\Id\Providers\AnikeenIdSsoUserProvider; use Anikeen\Id\Providers\AnikeenIdUserProvider;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
public function boot(): void public function boot(): void
{ {
Auth::provider('sso-users', function ($app, array $config) { Auth::provider('anikeen', function ($app, array $config) {
return new AnikeenIdSsoUserProvider( return new AnikeenIdUserProvider(
$app->make(AnikeenId::class), $app->make(AnikeenId::class),
$app->make(Request::class), $app->make(Request::class),
$config['model'], $config['model'],
@@ -140,7 +141,7 @@ reference the guard in the `guards` configuration of your `auth.php` configurati
'api' => [ 'api' => [
'driver' => 'anikeen', 'driver' => 'anikeen',
'provider' => 'sso-users', 'provider' => 'anikeen',
], ],
], ],
``` ```
@@ -154,8 +155,8 @@ reference the provider in the `providers` configuration of your `auth.php` confi
'model' => App\Models\User::class, 'model' => App\Models\User::class,
], ],
'sso-users' => [ 'anikeen' => [
'driver' => 'sso-users', 'driver' => 'anikeen',
'model' => App\Models\User::class, 'model' => App\Models\User::class,
'fields' => ['first_name', 'last_name', 'email'], 'fields' => ['first_name', 'last_name', 'email'],
], ],

View File

@@ -13,7 +13,7 @@
} }
], ],
"require": { "require": {
"php": "^8.0", "php": "^8.1",
"ext-json": "*", "ext-json": "*",
"illuminate/support": "^11.0|^12.0", "illuminate/support": "^11.0|^12.0",
"illuminate/console": "^11.0|^12.0", "illuminate/console": "^11.0|^12.0",

View File

@@ -6,12 +6,34 @@ use stdClass;
trait MagicProperties trait MagicProperties
{ {
protected function setMagicProperties(stdClass $data): void protected function setMagicProperties(stdClass|array $data): void
{ {
foreach ($data as $key => $value) { foreach ((object)$data as $key => $value) {
if (!property_exists($this, $key)) { if (!property_exists($this, $key)) {
$this->{$key} = $value; $this->{$key} = $value;
} }
} }
} }
/**
* Magic getter: return null for undefined properties
*
* @param string $name
* @return mixed|null
*/
public function __get(string $name)
{
return null;
}
/**
* Magic isset: return false for undefined properties
*
* @param string $name
* @return bool
*/
public function __isset(string $name): bool
{
return false;
}
} }

View File

@@ -22,4 +22,16 @@ trait ManagesAddresses
return (new Addresses($this->request('GET', 'v1/addresses'))) return (new Addresses($this->request('GET', 'v1/addresses')))
->setBillable($this); ->setBillable($this);
} }
/**
* Check if the current user has a default billing address.
*
* @see \Anikeen\Id\Resources\Addresses::hasDefaultBillingAddress()
* @throws RequestRequiresClientIdException
* @throws GuzzleException
*/
public function hasDefaultBillingAddress(): bool
{
return $this->addresses()->hasDefaultBillingAddress();
}
} }

View File

@@ -17,9 +17,9 @@ trait ManagesInvoices
* @throws RequestRequiresClientIdException * @throws RequestRequiresClientIdException
* @throws GuzzleException * @throws GuzzleException
*/ */
public function invoices(): Invoices public function invoices(array $parameters = []): Invoices
{ {
return (new Invoices($this->request('GET', 'v1/invoices'))) return (new Invoices($this->request('GET', 'v1/invoices', [], $parameters)))
->setBillable($this); ->setBillable($this);
} }
} }

View File

@@ -18,9 +18,9 @@ trait ManagesOrders
* @throws RequestRequiresClientIdException * @throws RequestRequiresClientIdException
* @throws GuzzleException * @throws GuzzleException
*/ */
public function orders(): Orders public function orders(array $parameters = []): Orders
{ {
return (new Orders($this->request('GET', 'v1/orders'))) return (new Orders($this->request('GET', 'v1/orders', [], $parameters)))
->setBillable($this); ->setBillable($this);
} }
} }

View File

@@ -4,6 +4,7 @@ namespace Anikeen\Id\Concerns;
use Anikeen\Id\ApiOperations\Request; use Anikeen\Id\ApiOperations\Request;
use Anikeen\Id\Exceptions\RequestRequiresClientIdException; use Anikeen\Id\Exceptions\RequestRequiresClientIdException;
use Anikeen\Id\Resources\PaymentMethod;
use Anikeen\Id\Resources\PaymentMethods; use Anikeen\Id\Resources\PaymentMethods;
use Anikeen\Id\Result; use Anikeen\Id\Result;
use GuzzleHttp\Exception\GuzzleException; use GuzzleHttp\Exception\GuzzleException;
@@ -24,6 +25,42 @@ trait ManagesPaymentMethods
->setBillable($this); ->setBillable($this);
} }
/**
* Check if current user has at least one payment method.
*
* @see \Anikeen\Id\Resources\PaymentMethods::hasPaymentMethod()
* @throws RequestRequiresClientIdException
* @throws GuzzleException
*/
public function hasPaymentMethod(): ?PaymentMethod
{
return $this->paymentMethods()->hasPaymentMethod();
}
/**
* Get default payment method from the current user.
*
* @see \Anikeen\Id\Resources\PaymentMethods::defaultPaymentMethod()
* @throws RequestRequiresClientIdException
* @throws GuzzleException
*/
public function defaultPaymentMethod(): ?PaymentMethod
{
return $this->paymentMethods()->defaultPaymentMethod();
}
/**
* Check if the current user has a default payment method.
*
* @see \Anikeen\Id\Resources\PaymentMethods::hasDefaultPaymentMethod()
* @throws RequestRequiresClientIdException
* @throws GuzzleException
*/
public function hasDefaultPaymentMethod(): bool
{
return $this->paymentMethods()->hasDefaultPaymentMethod();
}
/** /**
* Get billing portal URL for the current user. * Get billing portal URL for the current user.
* *

View File

@@ -1,113 +0,0 @@
<?php
namespace Anikeen\Id\Providers;
use Anikeen\Id\AnikeenId;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Contracts\Auth\UserProvider;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
class AnikeenIdSsoUserProvider implements UserProvider
{
private ?string $accessTokenField = null;
public function __construct(
private AnikeenId $anikeenId,
private Request $request,
private string $model,
private array $fields
)
{
$this->accessTokenField = AnikeenId::getAccessTokenField();
}
public function retrieveById(mixed $identifier): ?Authenticatable
{
$model = $this->createModel();
$token = $this->request->bearerToken();
$user = $this->newModelQuery($model)
->where($model->getAuthIdentifierName(), $identifier)
->first();
// Return user when found
if ($user) {
// Update access token when updated
if ($this->accessTokenField) {
$user[$this->accessTokenField] = $token;
if ($user->isDirty()) {
$user->save();
}
}
return $user;
}
// Create new user
$this->anikeenId->setToken($token);
$result = $this->anikeenId->getAuthedUser();
if (!$result->success()) {
return null;
}
$attributes = Arr::only((array)$result->data(), $this->fields);
$attributes[$model->getAuthIdentifierName()] = $result->data->id;
if ($this->accessTokenField) {
$attributes[$this->accessTokenField] = $token;
}
return $this->newModelQuery($model)->create($attributes);
}
/**
* Create a new instance of the model.
*/
public function createModel(): Model
{
$class = '\\' . ltrim($this->model, '\\');
return new $class;
}
/**
* Get a new query builder for the model instance.
*/
protected function newModelQuery(?Model $model = null): Builder
{
return is_null($model)
? $this->createModel()->newQuery()
: $model->newQuery();
}
public function retrieveByToken($identifier, $token)
{
return null;
}
public function updateRememberToken(Authenticatable $user, $token)
{
// void
}
public function retrieveByCredentials(array $credentials)
{
return null;
}
public function validateCredentials(Authenticatable $user, array $credentials): bool
{
return false;
}
public function rehashPasswordIfRequired(Authenticatable $user, #[\SensitiveParameter] array $credentials, bool $force = false)
{
// TODO: Implement rehashPasswordIfRequired() method.
}
}

View File

@@ -0,0 +1,124 @@
<?php
namespace Anikeen\Id\Providers;
use Anikeen\Id\AnikeenId;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Contracts\Auth\UserProvider;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
class AnikeenIdUserProvider implements UserProvider
{
private ?string $accessTokenField;
public function __construct(
private AnikeenId $anikeenId,
private Request $request,
private string $model,
private array $fields = []
) {
$this->accessTokenField = AnikeenId::getAccessTokenField();
}
/**
* {@inheritDoc}
*/
public function retrieveByToken($identifier, $token): ?Authenticatable
{
// Token from request (if not already pass from $token):
$token = $token ?: $this->request->bearerToken();
if (! $token) {
return null;
}
// Set token in SSO client and request user info
$this->anikeenId->setToken($token);
$result = $this->anikeenId->getAuthedUser();
if (! $result->success()) {
return null;
}
// Only the desired fields
$data = Arr::only((array)$result->data(), $this->fields);
// Primary key (e.g. $user->id)
$pk = $this->createModel()->getAuthIdentifierName();
$data[$pk] = $result->data->id;
// Fill in access token field, if available
if ($this->accessTokenField) {
$data[$this->accessTokenField] = $token;
}
// Local eloquent model: either find or create a new one
/** @var Model $modelInstance */
$modelInstance = $this->newModelQuery()
->firstOrNew([$pk => $data[$pk]]);
$modelInstance->fill($data);
$modelInstance->save();
return $modelInstance;
}
/**
* {@inheritDoc}
*/
public function updateRememberToken(Authenticatable $user, $token): void
{
// no-op
}
/**
* {@inheritDoc}
*/
public function retrieveByCredentials(array $credentials): ?Authenticatable
{
return null;
}
/**
* {@inheritDoc}
*/
public function validateCredentials(Authenticatable $user, array $credentials): bool
{
return true;
}
/**
* {@inheritDoc}
*/
public function retrieveById($identifier): ?Authenticatable
{
return $this->newModelQuery()
->where($this->createModel()->getAuthIdentifierName(), $identifier)
->first();
}
/**
* {@inheritDoc}
*/
public function rehashPasswordIfRequired(Authenticatable $user, #[\SensitiveParameter] array $credentials, bool $force = false): void
{
// no-op
}
/**
* @return Model
*/
protected function createModel(): Model
{
$class = '\\' . ltrim($this->model, '\\');
return new $class;
}
/**
* @return Builder
*/
protected function newModelQuery(): Builder
{
return $this->createModel()->newQuery();
}
}

View File

@@ -2,11 +2,14 @@
namespace Anikeen\Id\Resources; namespace Anikeen\Id\Resources;
use Anikeen\Id\Concerns\MagicProperties;
use Anikeen\Id\Result; use Anikeen\Id\Result;
use JsonSerializable; use JsonSerializable;
abstract class BaseCollection implements JsonSerializable abstract class BaseCollection implements JsonSerializable
{ {
use MagicProperties;
public function __construct(protected Result $result) public function __construct(protected Result $result)
{ {
// //

View File

@@ -102,13 +102,12 @@ class Order extends BaseResource
/** /**
* Get order items from given order. * Get order items from given order.
* *
* @param string $orderId The order ID.
* @throws RequestRequiresClientIdException * @throws RequestRequiresClientIdException
* @throws GuzzleException * @throws GuzzleException
*/ */
public function orderItems(string $orderId): OrderItems public function orderItems(array $parameters = []): OrderItems
{ {
return (new OrderItems($this->billable->request('GET', sprintf('v1/orders/%s/items', $this->id)))) return (new OrderItems($this->billable->request('GET', sprintf('v1/orders/%s/items', $this->id), [], $parameters)))
->setBillable($this->billable) ->setBillable($this->billable)
->setParent($this); ->setParent($this);
} }

View File

@@ -4,6 +4,9 @@ namespace Anikeen\Id\Resources;
use Anikeen\Id\Concerns\HasBillable; use Anikeen\Id\Concerns\HasBillable;
/**
* @property string $id
*/
class PaymentMethod extends BaseResource class PaymentMethod extends BaseResource
{ {
use HasBillable; use HasBillable;

View File

@@ -11,6 +11,8 @@ class PaymentMethods extends BaseCollection
{ {
use HasBillable; use HasBillable;
private ?PaymentMethod $cachedDefaultPaymentMethod = null;
/** /**
* Check if current user has at least one payment method. * Check if current user has at least one payment method.
* *
@@ -30,8 +32,24 @@ class PaymentMethods extends BaseCollection
*/ */
public function defaultPaymentMethod(): PaymentMethod public function defaultPaymentMethod(): PaymentMethod
{ {
return (new PaymentMethod($this->billable->request('GET', 'v1/payment-methods/default'))) if ($this->cachedDefaultPaymentMethod === null) {
->setBillable($this->billable); $this->cachedDefaultPaymentMethod = (new PaymentMethod(
$this->billable->request('GET', 'v1/payment-methods/default')
))->setBillable($this->billable);
}
return $this->cachedDefaultPaymentMethod;
}
/**
* Check if the current user has a default payment method.
*
* @throws RequestRequiresClientIdException
* @throws GuzzleException
*/
public function hasDefaultPaymentMethod(): bool
{
return $this->defaultPaymentMethod()?->id !== null;
} }
/** /**

View File

@@ -8,11 +8,52 @@ use GuzzleHttp\Exception\GuzzleException;
/** /**
* @property string $id * @property string $id
* @property string $name
* @property string $description
* @property string $unit
* @property float $price
* @property float $vat_rate
* @property array $payload
* @property string $ends_at
* @property string $webhook_url
* @property string $webhook_secret
*/ */
class Subscription extends BaseResource class Subscription extends BaseResource
{ {
use HasBillable; use HasBillable;
/**
* Update a given subscription from the current user.
*
* @param array{
* name: string,
* description: null|string,
* unit: string,
* price: float,
* vat_rate: float,
* payload: null|array,
* ends_at: null|string,
* webhook_url: null|string,
* webhook_secret: null|string
* } $attributes The subscription data:
* - name: The name (required when set)
* - description: The description (optional)
* - unit: The unit (required when set, e.g. "hour", "day", "week", "month", "year")
* - price: The price per unit (required when set)
* - vat_rate: The VAT rate (required when set)
* - payload: The payload (optional)
* - ends_at: The end date (optional)
* - webhook_url: The webhook URL (optional)
* - webhook_secret: The webhook secret (optional)
* @throws RequestRequiresClientIdException
* @throws GuzzleException
*/
public function update(array $attributes): self
{
return (new self($this->billable->request('PUT', sprintf('v1/subscriptions/%s', $this->id), $attributes)))
->setBillable($this->billable);
}
/** /**
* Force given subscription to check out (trusted apps only). * Force given subscription to check out (trusted apps only).
* *

View File

@@ -4,7 +4,6 @@ namespace Anikeen\Id\Resources;
use Anikeen\Id\Concerns\HasBillable; use Anikeen\Id\Concerns\HasBillable;
use Anikeen\Id\Exceptions\RequestRequiresClientIdException; use Anikeen\Id\Exceptions\RequestRequiresClientIdException;
use Anikeen\Id\Result;
use GuzzleHttp\Exception\GuzzleException; use GuzzleHttp\Exception\GuzzleException;
class Subscriptions extends BaseCollection class Subscriptions extends BaseCollection
@@ -15,25 +14,25 @@ class Subscriptions extends BaseCollection
* Create a new subscription for the current user. * Create a new subscription for the current user.
* *
* @param array{ * @param array{
* name: null, * name: string,
* description: string, * description: null|string,
* unit: string, * unit: string,
* price: float, * price: float,
* vat: null|float, * vat_rate: float,
* payload: null|array, * payload: null|array,
* ends_at: null|string, * ends_at: null|string,
* webhook_url: null|string, * webhook_url: null|string,
* webhook_secret: null|string * webhook_secret: null|string
* } $attributes The subscription data: * } $attributes The subscription data:
* - name: The name * - name: The name
* - description: The description * - description: The description (optional)
* - unit: The unit (e.g. "hour", "day", "week", "month", "year") * - unit: The unit (e.g. "hour", "day", "week", "month", "year")
* - price: The price per unit * - price: The price per unit
* - vat: The VAT (optional) * - vat_rate: The VAT rate (required when set)
* - payload: The payload (optional) * - payload: The payload (optional)
* - ends_at: The end date (optional) * - ends_at: The end date (optional)
* - webhook_url: The webhook URL (optional) * - webhook_url: The webhook URL (optional)
* - webhook_secret: The webhook secret (optional) * - webhook_secret: The webhook secret (optional)
* @throws RequestRequiresClientIdException * @throws RequestRequiresClientIdException
* @throws GuzzleException * @throws GuzzleException
*/ */