diff --git a/CLAUDE.md b/CLAUDE.md index a7c8270..cb422eb 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -22,7 +22,10 @@ blindpay-php/ Payins.php # Resource class + inline types (Payin, ListPayinsInput, etc.) PayinsWrapper.php # Wrapper delegating to Payins + exposing Quotes sub-resource Quotes.php # Sub-resource class + inline types - Receivers/ # Complex resource with sub-resource + Customers/ # Complex resource with sub-resource + Customers.php # Resource class + inline types + CustomersWrapper.php # Wrapper delegating to Customers + exposing BankAccounts + Receivers/ # Deprecated alias of Customers, kept for backward compatibility until v3.0.0 Receivers.php # Resource class + inline types ReceiversWrapper.php # Wrapper delegating to Receivers + exposing BankAccounts Wallets/ # Aggregation wrapper (no base methods, only sub-resources) @@ -67,13 +70,12 @@ blindpay-php/ StablecoinToken.php # enum: USDC, USDT, USDB TransactionDocumentType.php TransactionStatus.php # enum: refunded, processing, completed, failed, on_hold, pending_review - WebhookEvent.php # enum: receiver.new, payout.new, payin.new, etc. tests/ Resources/ # Mirrors src/Resources structure Available/AvailableTest.php Payins/PayinsTest.php Payins/PayinQuotesTest.php - Receivers/ReceiversTest.php + Receivers/ReceiversTest.php # No Customers test file yet; Receivers is exercised until callers migrate Wallets/BlockchainWalletsTest.php Wallets/OfframpWalletsTest.php ... (one test file per resource) @@ -440,7 +442,7 @@ Create a new file in `src/Types/`. Use `readonly class` with `fromArray()` and o Sub-resources are used when a resource has logically grouped child endpoints. There are two wrapper patterns: -### Pattern A: Delegation wrapper (Payins, Receivers) +### Pattern A: Delegation wrapper (Payins, Customers, Receivers) The wrapper delegates the base resource's methods AND exposes sub-resources as public properties. @@ -507,7 +509,7 @@ readonly class WalletsWrapper } ``` -Usage: `$blindpay->wallets->blockchain->list($receiverId)` +Usage: `$blindpay->wallets->blockchain->list($customerId)` ## 8. Testing @@ -682,4 +684,4 @@ When translating an OpenAPI spec change to SDK code: ### Nested endpoints -Nested endpoints like `instances/{id}/receivers/{receiverId}/bank-accounts` are modeled as sub-resources accessed via wrappers: `$blindpay->receivers->bankAccounts->list($receiverId)`. +Nested endpoints like `instances/{id}/customers/{customerId}/bank-accounts` are modeled as sub-resources accessed via wrappers: `$blindpay->customers->bankAccounts->list($customerId)`. diff --git a/src/BlindPay.php b/src/BlindPay.php index 9cf0a24..f5d9f14 100644 --- a/src/BlindPay.php +++ b/src/BlindPay.php @@ -42,7 +42,7 @@ class BlindPay implements ApiClientInterface { private const BASE_URL = 'https://api.blindpay.com/v1/'; - private const VERSION = '2.4.0'; + private const VERSION = '2.5.0'; private Client $httpClient; diff --git a/src/Resources/Customers/Customers.php b/src/Resources/Customers/Customers.php index 98c3ccc..955cd4a 100644 --- a/src/Resources/Customers/Customers.php +++ b/src/Resources/Customers/Customers.php @@ -107,7 +107,6 @@ enum OwnerTaxType: string public function __construct( public string $id, public string $instanceId, - public string $customerId, public OwnerRole $role, public string $firstName, public string $lastName, @@ -127,7 +126,8 @@ public function __construct( public string $proofOfAddressDocFile, public ?int $ownershipPercentage = null, public ?string $title = null, - public ?OwnerTaxType $taxType = null + public ?OwnerTaxType $taxType = null, + public ?string $customerId = null ) {} public static function fromArray(array $data): self @@ -135,7 +135,6 @@ public static function fromArray(array $data): self return new self( id: $data['id'], instanceId: $data['instance_id'], - customerId: $data['customer_id'], role: OwnerRole::from($data['role']), firstName: $data['first_name'], lastName: $data['last_name'], @@ -155,7 +154,8 @@ public static function fromArray(array $data): self proofOfAddressDocFile: $data['proof_of_address_doc_file'], ownershipPercentage: isset($data['ownership_percentage']) ? (int) $data['ownership_percentage'] : null, title: $data['title'] ?? null, - taxType: isset($data['tax_type']) ? OwnerTaxType::from($data['tax_type']) : null + taxType: isset($data['tax_type']) ? OwnerTaxType::from($data['tax_type']) : null, + customerId: $data['customer_id'] ?? $data['receiver_id'] ?? null ); } diff --git a/src/Resources/Payins/Payins.php b/src/Resources/Payins/Payins.php index 122fcf4..a8b5878 100644 --- a/src/Resources/Payins/Payins.php +++ b/src/Resources/Payins/Payins.php @@ -287,6 +287,7 @@ public static function fromArray(array $data): self public function __construct( public ?TransactionStatus $status = null, public ?string $receiverId = null, + public ?string $customerId = null, ?int $limit = null, ?int $offset = null, ?string $startingAfter = null, @@ -307,6 +308,10 @@ public function toArray(): array $params['receiver_id'] = $this->receiverId; } + if ($this->customerId !== null) { + $params['customer_id'] = $this->customerId; + } + return $params; } } diff --git a/src/Resources/Payouts/Payouts.php b/src/Resources/Payouts/Payouts.php index 4722b56..e90cae9 100644 --- a/src/Resources/Payouts/Payouts.php +++ b/src/Resources/Payouts/Payouts.php @@ -193,6 +193,7 @@ public static function fromArray(array $data): self { public function __construct( public ?string $receiverId = null, + public ?string $customerId = null, ?int $limit = null, ?int $offset = null, ?string $startingAfter = null, @@ -209,6 +210,10 @@ public function toArray(): array $params['receiver_id'] = $this->receiverId; } + if ($this->customerId !== null) { + $params['customer_id'] = $this->customerId; + } + return $params; } } diff --git a/src/Resources/Webhooks/Webhooks.php b/src/Resources/Webhooks/Webhooks.php index a514c74..9d9a1a2 100644 --- a/src/Resources/Webhooks/Webhooks.php +++ b/src/Resources/Webhooks/Webhooks.php @@ -10,8 +10,26 @@ enum WebhookEvents: string { + /** + * @deprecated 2.5.0 Use CUSTOMER_NEW instead. Will be removed in v3.0.0. + * See https://www.blindpay.com/changelog/2026-06-04-customers-rename + */ case RECEIVER_NEW = 'receiver.new'; + + /** + * @deprecated 2.5.0 Use CUSTOMER_UPDATE instead. Will be removed in v3.0.0. + * See https://www.blindpay.com/changelog/2026-06-04-customers-rename + */ case RECEIVER_UPDATE = 'receiver.update'; + + /** + * @deprecated 2.5.0 Use CUSTOMER_DELETE instead. Will be removed in v3.0.0. + * See https://www.blindpay.com/changelog/2026-06-04-customers-rename + */ + case RECEIVER_DELETE = 'receiver.delete'; + case CUSTOMER_NEW = 'customer.new'; + case CUSTOMER_UPDATE = 'customer.update'; + case CUSTOMER_DELETE = 'customer.delete'; case BANK_ACCOUNT_NEW = 'bankAccount.new'; case PAYOUT_NEW = 'payout.new'; case PAYOUT_UPDATE = 'payout.update'; diff --git a/src/Types/WebhookEvent.php b/src/Types/WebhookEvent.php deleted file mode 100644 index 2fc91bf..0000000 --- a/src/Types/WebhookEvent.php +++ /dev/null @@ -1,33 +0,0 @@ -assertEquals('we_000000000000', $response->data->id); } + #[Test] + public function it_creates_a_webhook_endpoint_with_customer_events(): void + { + $mockedWebhookEndpoint = [ + 'id' => 'we_000000000000', + ]; + + $this->mockResponse($mockedWebhookEndpoint); + + $input = new CreateWebhookEndpointInput( + url: 'https://example.com/webhook', + events: [WebhookEvents::CUSTOMER_NEW, WebhookEvents::CUSTOMER_UPDATE, WebhookEvents::CUSTOMER_DELETE] + ); + + $response = $this->blindpay->instances->webhookEndpoints->create($input); + + $this->assertTrue($response->isSuccess()); + $this->assertNull($response->error); + $this->assertEquals('we_000000000000', $response->data->id); + } + #[Test] public function it_lists_webhook_endpoints(): void {