---
title: "Customer portal (server-side get-customer-portal)"
method: POST
path: "/api/v2/billing/portal"
tags: ["v2 Billing"]
---

# Customer portal (server-side get-customer-portal)

`POST /api/v2/billing/portal`

## Request

- Base URL: `https://pdf2md.dev`
- URL: `https://pdf2md.dev/api/v2/billing/portal`
- Auth: one of:
  - API key in cookie `p2m_session`
  - HTTP bearer

EP-023-T8 (implemented). EP-025-T5: now reachable by a web session OR a device-signed linked device (the extension), resolved by AccountAuthMiddleware — so "Manage billing" works from the extension, which cannot send a SameSite=Lax session cookie cross-site. Email/account are taken from the resolved actor. x-api-key only on the server.

## Response `200`

Portal URL

- V2PortalResponse
  - `portal_url` string, uri, required: customer portal

## Other responses

- `401`: Missing/invalid API key or session
- `503`: provider_unavailable — the provider errored, was unreachable, or answered 200 with an EMPTY url. EP-076-T2: the empty-url case used to be forwarded as 200 {portal_url: ""}, a success carrying nothing to open. Both clients happened to survive it by checking the url themselves, which is exactly why it sat here unnoticed — the contract was already lying. | billing_not_configured — this deployment sells nothing.

---

[API](https://skmtc.dev/pdf2md/apis/pdf-to-markdown-api-facade.md) · [All operations](https://skmtc.dev/pdf2md/apis/pdf-to-markdown-api-facade/llms.txt) · [OpenAPI document](https://skmtc.dev/pdf2md/apis/pdf-to-markdown-api-facade/revisions/4636782fb8b6?raw)
