Skip to content
Merged
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
14 changes: 8 additions & 6 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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.

Expand Down Expand Up @@ -507,7 +509,7 @@ readonly class WalletsWrapper
}
```

Usage: `$blindpay->wallets->blockchain->list($receiverId)`
Usage: `$blindpay->wallets->blockchain->list($customerId)`

## 8. Testing

Expand Down Expand Up @@ -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)`.
2 changes: 1 addition & 1 deletion src/BlindPay.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
8 changes: 4 additions & 4 deletions src/Resources/Customers/Customers.php
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -127,15 +126,15 @@ 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
{
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'],
Expand All @@ -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
);
}

Expand Down
5 changes: 5 additions & 0 deletions src/Resources/Payins/Payins.php
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -307,6 +308,10 @@ public function toArray(): array
$params['receiver_id'] = $this->receiverId;
}

if ($this->customerId !== null) {
$params['customer_id'] = $this->customerId;
}

return $params;
}
}
Expand Down
5 changes: 5 additions & 0 deletions src/Resources/Payouts/Payouts.php
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -209,6 +210,10 @@ public function toArray(): array
$params['receiver_id'] = $this->receiverId;
}

if ($this->customerId !== null) {
$params['customer_id'] = $this->customerId;
}

return $params;
}
}
Expand Down
18 changes: 18 additions & 0 deletions src/Resources/Webhooks/Webhooks.php
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
33 changes: 0 additions & 33 deletions src/Types/WebhookEvent.php

This file was deleted.

21 changes: 21 additions & 0 deletions tests/Resources/Webhooks/WebhooksTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,27 @@ public function it_creates_a_webhook_endpoint(): void
$this->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
{
Expand Down
Loading