feat: customer portal sessions + subscription cancellationReason + canceled_for_nonpayment webhook - #59
Merged
Conversation
…nonpayment webhook
Adopts three additions from the latest vatlify OpenAPI bundle (re-vendored).
1. Customer portal sessions — POST /v1/customers/{customerId}/portal-sessions.
- customers->createPortalSession($id, [...]) returns a new
Vatly\API\Types\PortalSession (url, expiresAt, returnUrl). Body optional
(returnUrl: absolute HTTPS, max 2048 bytes). Credential-bearing link — not
cached by the SDK.
2. Subscription->cancellationReason — nullable string
(payment_failure | merchant_request | customer_request | null), now in the
schema's required set. Added to the resource + a Vatly\API\Types\CancellationReason
constant class (matches TaxBehavior/UpdateStatus).
3. subscription.canceled_for_nonpayment webhook — payment recovery exhausted.
New WebhookEventName::SUBSCRIPTION_CANCELED_FOR_NONPAYMENT constant and typed
DTO SubscriptionCanceledForNonpayment (follows SubscriptionCanceledImmediately;
also exposes cancellationReason), wired into WebhookEventFactory and
getSupportedEvents()/isSupported().
Re-vendored openapi.yaml from vatlify main. Tests added for all three (endpoint,
webhook factory + DTO, resource hydration, and PortalSession/type units). Docs
updated (Customers, Subscriptions, Webhooks) + CHANGELOG.
273 tests green; phpstan (level 5) and php-cs-fixer clean.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adopts three additions from the latest vatlify OpenAPI bundle (re-vendored into
openapi.yaml). Spec treated as source of truth.1. Customer portal sessions —
POST /v1/customers/{customerId}/portal-sessionscustomers->createPortalSession($id, [...])creates a short-lived, single-usehosted portal link. Returns a new
Vatly\API\Types\PortalSession(url,expiresAt,returnUrl).returnUrlis a nullable absolute HTTPS URL(max 2048 bytes). The link is credential-bearing — the SDK never caches it.
2. Subscription
cancellationReasonSubscriptionresource:payment_failure/merchant_request/customer_request/null(now in the schema's requiredset), hydrated like any scalar.
Vatly\API\Types\CancellationReasonconstant class (matches theTaxBehavior/UpdateStatusconvention).3.
subscription.canceled_for_nonpaymentwebhook eventWebhookEventName::SUBSCRIPTION_CANCELED_FOR_NONPAYMENTconstant.Vatly\API\Webhooks\Events\SubscriptionCanceledForNonpaymentfollowing the existing
SubscriptionCanceledImmediatelypattern — exposescustomerId,subscriptionId,endsAt,testmode, pluscancellationReason(
payment_failure). Wired intoWebhookEventFactoryand reported bygetSupportedEvents()/isSupported().Tests
CustomersEndpointTest: portal session create (withreturnUrl, andbody-less), asserting method/URL/body and the hydrated
PortalSession.SubscriptionEndpointTest:cancellationReasonhydration (value + null).WebhookEventFactoryTest+SubscriptionEventsTest: the new event maps to thetyped DTO, carries the reason, defaults it when absent, and appears in the
supported/isSupported lists; plus the event-name constant.
PortalSessionTest(array + stdClass hydration, null/absent returnUrl).Docs updated (
Customers.md,Subscriptions.md,Webhooks.md) andCHANGELOG.md.Verification
composer test→ 273 tests, 1364 assertions, OK.php -d memory_limit=1G vendor/bin/phpstan analyse src tests→ No errors (level 5).vendor/bin/php-cs-fixer fix --allow-risky=yes --dry-run→ 0 files to fix.Over to you to merge once CI is green.