Skip to main content
import { createClient } from "@mailsai/sdk";

const client = createClient(); // reads MAILS_API_KEY

const result = await client.billing.portal(
  "https://app.acme.com/settings/billing",
);
console.log(result);
{ "url": "https://example.com", "mock": false }

Open billing portal or checkout

Returns a Stripe Billing Portal URL when already subscribed, otherwise a Checkout URL to subscribe.
POST/v1/billing/portalscope · manage
import { createClient } from "@mailsai/sdk";

const client = createClient(); // reads MAILS_API_KEY

const result = await client.billing.portal(
  "https://app.acme.com/settings/billing",
);
console.log(result);
{ "url": "https://example.com", "mock": false }

Body Parameters

return_urlstring

Where the customer lands after leaving the billing portal, or after finishing or cancelling checkout: an absolute URL. Left out, it is the dashboard's /billing page.

price_lookup_keystring

The plan checkout subscribes to: mailsai_pro_monthly (the default), mailsai_scale_monthly, mailsai_pro_yearly or mailsai_scale_yearly. Used only when the workspace has no subscription yet; any other value is a 400 invalid_param_value.

A workspace on an active paid plan with no Stripe subscription on file gets 409 billing_state_inconsistent instead of a Checkout URL, since subscribing again would bill it twice: contact support@mails.ai. Closed to apps connected by sign-in (403 connected_app_not_allowed): use the dashboard, an API key or the mails CLI.

Response

urlstring

The page to open: a Stripe Billing Portal session when the workspace has a subscription, otherwise a Stripe Checkout session for price_lookup_key. Both lead back to return_url. When mock is true, it is return_url itself with mock query parameters.

mockboolean

True when the server runs with Stripe mocked, so no Stripe session was created; false for a real session.

Was this page helpful?