---
title: "A Stripe Customer Portal link"
method: POST
path: "/v1/billing/portal"
tags: ["Billing"]
---

# A Stripe Customer Portal link

`POST /v1/billing/portal`

## Request

- Base URL: `https://api.galleyrender.com`
- URL: `https://api.galleyrender.com/v1/billing/portal`
- Auth: HTTP bearer

Returns a single-use, short-lived URL to the Stripe-hosted portal, where a customer can switch plans, update a card, download invoices and cancel at period end. This is the only way any of those happen: the API cannot change or cancel a subscription, by design.

`not_found` until the account has a Stripe customer, which the first checkout creates.

## Request body

- object
  - `return_url` string: Where the portal's back link goes. Must be https on galleyrender.com.

## Response `200`

A portal session.

- PortalSession
  - `object` 'portal_session', required
  - `id` string, required
  - `url` string, required
  - `account` string
  - `subscription` Subscription: What Stripe last said about this account's subscription. Written only by the webhook.
    - `plan` 'free' | 'solo' | 'starter' | 'growth' | 'scale'
    - `plan_name` string
    - `interval` 'month' | 'year' | 'null', nullable
    - `status` string, nullable: Stripe's own status, unchanged: `active`, `trialing`, `past_due`, `unpaid`, `canceled`, `incomplete`, `incomplete_expired`, `paused`. Null on an account that has never subscribed.
    - `included_units` integer: The plan's included quantity each billing period, as sold — the first tier of its Stripe price, counted in meter units (`meter_units`: a PDF page is 2.5, an image 1). Monthly Solo's 500 is 200 PDF pages or 500 images; an annual plan's period is a year, so it includes twelve times the monthly figure. On Free it is the monthly allowance, one per PDF page or image.
    - `retention_days` integer: Days a render is kept, as sold: 7 on Free and the keyless trial, 30 on Solo and Starter, 90 on Growth and Scale.
    - `current_period_end` string, date-time, nullable
    - `cancel_at_period_end` boolean: Cancelled in the portal; drops to Free at `current_period_end`.
    - `has_stripe_customer` boolean
    - `features` object
      - `webhooks` boolean
      - `cloud_delivery` boolean
  - `can` string[]
  - `next_step` string

## Other responses

- `401`: `authentication_error`.
- `404`: `not_found` — this account has never subscribed, so it has no Stripe customer.

---

[API](https://skmtc.dev/galleyrender/apis/galley-render-api.md) · [All operations](https://skmtc.dev/galleyrender/apis/galley-render-api/llms.txt) · [OpenAPI document](https://skmtc.dev/galleyrender/apis/galley-render-api/revisions/a85d68468cd2?raw)
