Create billing portal links for users as a trusted app

AnikeenId::createBillingPortalLinkForUser() and $user->appBillingPortalUrl()
create a short-lived link to a user's billing pages with the app's token
(return_url, group, flow), e.g. for a Manage billing button of an app
that bills a team owner's account.
This commit is contained in:
Maurice Preuß committed 2026-11-04 21:27:26 +01:00
1 parent e45a871ca7
commit 35ca9ddd2b
5 files changed
+134

No files matched your search

+30
View File
@@ -4,6 +4,7 @@ namespace Anikeen\Id\Tests;
use Anikeen\Id\AnikeenId;
use Anikeen\Id\Billable;
use Anikeen\Id\Exceptions\ApiException;
use Illuminate\Database\Eloquent\Model;
/**
@@ -199,6 +200,35 @@ class EndpointsTest extends TestCase
$this->assertSame('POST /api/v1/admin/transactions Bearer app-token', $this->sentCall(1));
}
public function test_billing_portal_links_for_users_use_the_app_token(): void
{
$link = ['object' => 'billing_portal_link', 'url' => 'https://id.test/billing/portal/01JUSER?signature=x', 'user_id' => '01JUSER', 'flow' => 'invoices', 'group' => 'team-1', 'return_url' => 'https://console.test/billing', 'expires_at' => '2026-11-04T10:15:00+00:00'];
$this->respond(201, ['data' => $link]);
$this->respond(201, ['data' => $link]);
$created = app(AnikeenId::class)->createBillingPortalLinkForUser('01JUSER', ['return_url' => 'https://console.test/billing', 'group' => 'team-1', 'flow' => 'invoices']);
$url = $this->owner()->appBillingPortalUrl(['flow' => 'payment_method_update']);
$this->assertSame('billing_portal_link', $created->object);
$this->assertSame($link['url'], $url);
$this->assertSame('POST /api/v1/client/users/01JUSER/billing-portal Bearer app-token', $this->sentCall(0));
$this->assertSame(['return_url' => 'https://console.test/billing', 'group' => 'team-1', 'flow' => 'invoices'], $this->sentJson(0));
$this->assertSame('POST /api/v1/client/users/01JUSER/billing-portal Bearer app-token', $this->sentCall(1));
$this->assertSame(['flow' => 'payment_method_update'], $this->sentJson(1));
}
public function test_a_refused_billing_portal_link_is_an_api_exception(): void
{
$this->respond(422, ['message' => 'The return URL has to point to one of the app\'s redirect URIs.', 'errors' => ['return_url' => ['…']]]);
try {
$this->owner()->appBillingPortalUrl(['return_url' => 'https://elsewhere.test']);
$this->fail('Expected an ApiException.');
} catch (ApiException $e) {
$this->assertSame(422, $e->status);
}
}
public function test_order_preview_maps_the_country_into_the_billing_address(): void
{
$this->respond(200, ['data' => ['gross_total' => 11.9]]);