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
34 changes: 0 additions & 34 deletions .api-sync/known-divergences.json
Original file line number Diff line number Diff line change
@@ -1,29 +1,13 @@
{
"$schema": "Recorded, reasoned, owned divergences that state reconciliation must not silently paper over. Two kinds: `enumValues` is a spec enum member whose value does not match any SDK case value even though the SDK models that enum (usually because an SDK case value has a typo/format bug) -- the fix is to CORRECT the existing case, not to add a near-duplicate new one, so scripts/api-sync.php treats a listed (enum, specValue) pair as satisfied rather than pending drift. `fields` covers two situations, both keyed by {schema, field}: (a) a spec property backed by a constrained enum but modeled as a plain untyped field in the SDK, so there is no case-completeness gap to begin with; (b) a genuine type-representation mismatch between the spec's declared type and the SDK's declared PHP property type on an already-modeled field, recorded here rather than silently accepted or blindly auto-fixed, since correcting it is a deliberate code change a human must make. Distinct from .api-sync/unmodeled.json, which is for properties absent from the SDK outright.",
"enumValues": [
{
"enum": "BankAccountType",
"specValue": "saving",
"sdkCase": "SAVINGS",
"sdkValue": "savings",
"reason": "LIVE DEFECT (not fixed in this PR): the API's wire value is 'saving' (singular); this SDK's case value is 'savings' (plural), so a PHP backed enum currently serializes the wrong string and a real 'saving' account_type response would fail to parse via BankAccountType::from(). To be fixed in its own deliberate PR that corrects the case value directly instead of adding a second near-duplicate case.",
"owner": "eric@blindpay.com"
},
{
"enum": "BankAccountType",
"specValue": null,
"sdkCase": "TED",
"sdkValue": "ted",
"reason": "SDK-only case with no counterpart in the spec's account_type enum (which only has checking/saving). Pre-existing, unrelated to account_type modeling; not touched here.",
"owner": "eric@blindpay.com"
},
{
"enum": "EstimatedAnnualRevenue",
"specValue": "250000000_plus",
"sdkCase": "RANGE_2500000000_PLUS",
"sdkValue": "2500000000_plus",
"reason": "The API's top revenue bucket is '250000000_plus' (250 million); this SDK's case value has an extra digit, '2500000000_plus' (2.5 billion), so a real API response for the top bucket would fail to parse via EstimatedAnnualRevenue::from(). Same shape of bug as BankAccountType.saving/savings -- to be fixed in its own deliberate PR that corrects the case value, not by adding a second near-duplicate case.",
"owner": "eric@blindpay.com"
}
],
"fields": [
Expand All @@ -44,24 +28,6 @@
"field": "expires_at",
"reason": "Same pre-existing mismatch as QuoteOut.expires_at, on the payin-quote equivalent (CreatePayinQuoteResponse). Here the field IS cast, `expiresAt: (int) $data['expires_at']`, so a fractional value would silently truncate rather than throw -- a real risk in disguise if the API ever returns one.",
"owner": "eric@blindpay.com"
},
{
"schema": "PayinOut",
"field": "billing_fee_amount",
"reason": "LIVE DEFECT, VERIFIED BY RUNNING CODE (not fixed in this PR): spec declares billing_fee_amount as `number|null` (a fee in cents), Payin declares `public ?string $billingFeeAmount` with no cast in fromArray. Calling Payin::fromArray() with any present, non-null billing_fee_amount throws `TypeError: BlindPay\\SDK\\Resources\\Payins\\Payin::__construct(): Argument #35 ($billingFeeAmount) must be of type ?string, int given` -- reproduced directly, not theoretical. Every payin response where this fee is populated (end of month) fails to parse. Not fixed here: choosing the correct type (float? string with an explicit cast?) is a deliberate decision, pre-existing and identical between the last two spec snapshots (not new drift).",
"owner": "eric@blindpay.com"
},
{
"schema": "PaginationMetadata",
"field": "next_page",
"reason": "LIVE DEFECT, VERIFIED BY RUNNING CODE (not fixed in this PR): spec declares next_page as a nullable STRING cursor (`type: [\"string\",\"null\"]`, example `\"pi_123\"`, the ID of the first item in the next page), but PaginationMetadata declares `public int $nextPage` with no cast. Calling PaginationMetadata::fromArray() with any present, non-null next_page throws `TypeError: BlindPay\\SDK\\Types\\PaginationMetadata::__construct(): Argument #2 ($nextPage) must be of type int, string given` -- reproduced directly, not theoretical. PaginationMetadata backs the customers/payouts/payins/transfers list responses, so ANY paginated list response that actually has a next page fails to parse through this SDK. Not fixed here: the property type needs to become `?string`, a deliberate code change with its own PR.",
"owner": "eric@blindpay.com"
},
{
"schema": "PaginationMetadata",
"field": "prev_page",
"reason": "Same live defect as PaginationMetadata.next_page, on the previous-page cursor (`public int $prevPage`, spec declares a nullable string). Not independently re-verified by execution but identical shape and identical code path.",
"owner": "eric@blindpay.com"
}
]
}
8 changes: 4 additions & 4 deletions .api-sync/spec-map.json
Original file line number Diff line number Diff line change
Expand Up @@ -170,14 +170,14 @@
{
"spec": ["PayoutOut", "PayoutOnEvmOut"],
"path": "tracking_payment",
"sdk": [ { "file": "src/Types/TrackingPayment.php", "class": "TrackingPayment" } ],
"sdk": [ { "file": "src/Types/PayoutTrackingPayment.php", "class": "PayoutTrackingPayment" } ],
"note": "inline object, not a $ref'd component schema (no `Tracking*` schema exists in components.schemas); the same 20-property shape also recurs verbatim, unchecked here, in PayoutNewWebhookOut/PayoutUpdateWebhookOut/PayoutCompleteWebhookOut/PayoutPartnerFeeWebhookOut, which this SDK never deserializes (see 'webhook payloads' note below)."
},
{
"spec": "PayinOut",
"path": "tracking_payment",
"sdk": [ { "file": "src/Types/TrackingPayment.php", "class": "TrackingPayment" } ],
"note": "same SDK class as the payout-side tracking_payment, but PayinOut's inline tracking_payment is a DIFFERENT, smaller shape (step/provider_name/completed_at/review_source/review_context/approved_risk_sources) than the payout one. TrackingPayment models step/provider_name/completed_at plus 3 payout-only fields (provider_transaction_id/provider_status/estimated_time_of_arrival) that PayinOut's tracking_payment does not have."
"sdk": [ { "file": "src/Types/PayinTrackingPayment.php", "class": "PayinTrackingPayment" } ],
"note": "PayinOut's inline tracking_payment is a DIFFERENT, smaller shape (step/provider_name/completed_at/review_source/review_context/approved_risk_sources) than the payout one; previously shared with the payout-side TrackingPayment class, which threw a TypeError on payin fetch. Split into a payin-specific class (step/provider_name/completed_at) and PayoutTrackingPayment (step/provider_name/provider_transaction_id/provider_status/estimated_time_of_arrival/completed_at)."
},
{ "spec": "CreateVirtualAccountIn", "sdk": [ { "file": "src/Resources/VirtualAccounts/VirtualAccounts.php", "class": "CreateVirtualAccountInput" } ] },
{ "spec": "UpdateVirtualAccountIn", "sdk": [ { "file": "src/Resources/VirtualAccounts/VirtualAccounts.php", "class": "UpdateVirtualAccountInput" } ] },
Expand Down Expand Up @@ -214,7 +214,7 @@
{ "spec": "AvailableNaicsList", "sdk": [ { "file": "src/Resources/Available/Available.php", "class": "NaicsCode" } ] },
{ "spec": "UploadIn", "sdk": [ { "file": "src/Resources/Upload/Upload.php", "class": "UploadInput" } ] },
{ "spec": "UploadOut", "sdk": [ { "file": "src/Resources/Upload/Upload.php", "class": "UploadResponse" } ] },
{ "spec": "PaginationMetadata", "sdk": [ { "file": "src/Types/PaginationMetadata.php", "class": "PaginationMetadata" } ], "note": "referenced from the customers/payouts/payins/transfers list-response envelopes. next_page/prev_page type mismatch is a LIVE DEFECT, see known-divergences.json -- not fixed here." }
{ "spec": "PaginationMetadata", "sdk": [ { "file": "src/Types/PaginationMetadata.php", "class": "PaginationMetadata" } ], "note": "referenced from the customers/payouts/payins/transfers list-response envelopes." }
],
"webhookPayloadsNote": "This SDK never deserializes webhook request bodies into typed classes -- BlindPay::verifyWebhookSignature() only verifies the signature and returns bool; callers get the raw payload. Consequently no `*WebhookOut` schema (BankAccountWebhookOut, BlockchainWalletWebhookOut, CustomerNewWebhookOut, CustomerUpdateWebhookOut, CustomerDeleteWebhookOut, PayinNewWebhookOut, PayinUpdateWebhookOut, PayinCompleteWebhookOut, PayinPartnerFeeWebhookOut, PayoutNewWebhookOut, PayoutUpdateWebhookOut, PayoutCompleteWebhookOut, PayoutPartnerFeeWebhookOut, LimitIncreaseNewWebhookOut, LimitIncreaseUpdateWebhookOut, TosAcceptWebhookOut) is mapped below; this is a structural fact about the SDK, not an oversight, and shows up as non-blocking coverage gaps rather than reconciliation failures.",
"ignore": {
Expand Down
6 changes: 0 additions & 6 deletions .api-sync/unmodeled.json
Original file line number Diff line number Diff line change
Expand Up @@ -510,12 +510,6 @@
"reason": "Not modeled on VirtualAccount; callers already have the customer_id they used to make the request.",
"owner": "eric@blindpay.com"
},
{
"schema": "CreateWalletIn",
"field": "name",
"reason": "LIVE DEFECT, not cosmetic: `name` is REQUIRED on CreateWalletIn (spec `required: [\"network\",\"name\"]`), but CreateCustodialWalletInput's constructor accepts only customerId and network. Every custodial-wallet-creation call through this SDK omits a required field and is rejected by the API -- custodial wallet creation is completely broken through this SDK today. node, go and swift all send `name`; python and php do not. Not fixed here: this needs a required (non-defaulted) constructor parameter, which is a breaking API-shape change to CreateCustodialWalletInput, not a mechanical optional-field add.",
"owner": "eric@blindpay.com"
},
{
"schema": "CreateWalletIn",
"field": "external_id",
Expand Down
2 changes: 1 addition & 1 deletion src/BlindPay.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class BlindPay implements ApiClientInterface
{
private const BASE_URL = 'https://api.blindpay.com/v1/';

private const VERSION = '3.1.0';
private const VERSION = '3.2.0';

private Client $httpClient;

Expand Down
4 changes: 3 additions & 1 deletion src/Resources/CustodialWallets/CustodialWallets.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,15 @@ public static function fromArray(array $data): self
{
public function __construct(
public string $customerId,
public Network $network
public Network $network,
public string $name
) {}

public function toArray(): array
{
return [
'network' => $this->network->value,
'name' => $this->name,
];
}
}
Expand Down
14 changes: 7 additions & 7 deletions src/Resources/Payins/Payins.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
use BlindPay\SDK\Types\ManualExecutionStatus;
use BlindPay\SDK\Types\Network;
use BlindPay\SDK\Types\PaginationParams;
use BlindPay\SDK\Types\PayinTrackingPayment;
use BlindPay\SDK\Types\StablecoinToken;
use BlindPay\SDK\Types\TrackingComplete;
use BlindPay\SDK\Types\TrackingPartnerFee;
use BlindPay\SDK\Types\TrackingPayment;
use BlindPay\SDK\Types\TrackingTransaction;
use BlindPay\SDK\Types\TransactionStatus;
use DateTimeImmutable;
Expand Down Expand Up @@ -217,15 +217,15 @@ public function __construct(
public ?string $memoCode = null,
public ?string $clabe = null,
public ?TrackingTransaction $trackingTransaction = null,
public ?TrackingPayment $trackingPayment = null,
public ?PayinTrackingPayment $trackingPayment = null,
public ?TrackingComplete $trackingComplete = null,
public ?TrackingPartnerFee $trackingPartnerFee = null,
public ?string $imageUrl = null,
public ?string $firstName = null,
public ?string $lastName = null,
public ?string $legalName = null,
public ?bool $isOtc = null,
public ?string $billingFeeAmount = null,
public ?float $billingFeeAmount = null,
public ?string $pseDocumentType = null,
public ?string $pseFullName = null,
public ?string $psePaymentLink = null,
Expand Down Expand Up @@ -263,15 +263,15 @@ public static function fromArray(array $data): self
memoCode: $data['memo_code'] ?? null,
clabe: $data['clabe'] ?? null,
trackingTransaction: isset($data['tracking_transaction']) ? TrackingTransaction::fromArray($data['tracking_transaction']) : null,
trackingPayment: isset($data['tracking_payment']) ? TrackingPayment::fromArray($data['tracking_payment']) : null,
trackingPayment: isset($data['tracking_payment']) ? PayinTrackingPayment::fromArray($data['tracking_payment']) : null,
trackingComplete: isset($data['tracking_complete']) ? TrackingComplete::fromArray($data['tracking_complete']) : null,
trackingPartnerFee: isset($data['tracking_partner_fee']) ? TrackingPartnerFee::fromArray($data['tracking_partner_fee']) : null,
imageUrl: $data['image_url'] ?? null,
firstName: $data['first_name'] ?? null,
lastName: $data['last_name'] ?? null,
legalName: $data['legal_name'] ?? null,
isOtc: $data['is_otc'] ?? null,
billingFeeAmount: $data['billing_fee_amount'] ?? null,
billingFeeAmount: isset($data['billing_fee_amount']) ? (float) $data['billing_fee_amount'] : null,
pseDocumentType: $data['pse_document_type'] ?? null,
pseFullName: $data['pse_full_name'] ?? null,
psePaymentLink: $data['pse_payment_link'] ?? null,
Expand Down Expand Up @@ -373,7 +373,7 @@ public function __construct(
public ?string $memoCode = null,
public ?string $clabe = null,
public ?TrackingComplete $trackingComplete = null,
public ?TrackingPayment $trackingPayment = null,
public ?PayinTrackingPayment $trackingPayment = null,
public ?TrackingTransaction $trackingTransaction = null,
public ?TrackingPartnerFee $trackingPartnerFee = null
) {}
Expand All @@ -390,7 +390,7 @@ public static function fromArray(array $data): self
memoCode: $data['memo_code'] ?? null,
clabe: $data['clabe'] ?? null,
trackingComplete: isset($data['tracking_complete']) ? TrackingComplete::fromArray($data['tracking_complete']) : null,
trackingPayment: isset($data['tracking_payment']) ? TrackingPayment::fromArray($data['tracking_payment']) : null,
trackingPayment: isset($data['tracking_payment']) ? PayinTrackingPayment::fromArray($data['tracking_payment']) : null,
trackingTransaction: isset($data['tracking_transaction']) ? TrackingTransaction::fromArray($data['tracking_transaction']) : null,
trackingPartnerFee: isset($data['tracking_partner_fee']) ? TrackingPartnerFee::fromArray($data['tracking_partner_fee']) : null
);
Expand Down
Loading
Loading