# Open the Ownrecord billing portal

> The platform_billing.portal_sessions.create operation: POST /api/v1/platform_billing/portal_sessions in the REST API and the platform_billing_portal_sessions_create tool in the MCP server.

Makes a one-time sign-in link (15 minutes) to Ownrecord's billing portal for the organization: payment methods,
billing details (the organization is a customer of Ownrecord's entity: legal name, address, VAT ID), invoices
from Ownrecord as PDF, and the upcoming invoice. It is the same customer portal subscribers give their own
customers. Only an org_owner or billing_admin can open it; opening it is recorded in the audit log.

## At a glance

- **REST:** `POST /api/v1/platform_billing/portal_sessions`
- **MCP tool:** `platform_billing_portal_sessions_create`
- **Operation ID:** `platform_billing.portal_sessions.create`
- **Scope:** Organization
- **Permission:** `platform_plan:admin`
- **Risk tier:** `security`
- **Dry run:** Not supported
- **Idempotency:** `Idempotency-Key` required
- **Modes:** Test and live
- **Authentication:** API key with the `platform_plan:admin` scope
- **Since:** M12

## Request

### Body

This operation takes no body.

## Response

`201 Created` with a JSON object:

| Field       | Type                        | Description |
| ----------- | --------------------------- | ----------- |
| `object`    | `"platform_portal_session"` |             |
| `orgId`     | string                      |             |
| `url`       | string                      |             |
| `expiresAt` | date-time                   |             |

## Examples

### A sign-in link to the billing portal

```http
POST /api/v1/platform_billing/portal_sessions
Authorization: Bearer or_test_…
Idempotency-Key: 3f1c9a52-7d0e-4b8f-9a61-0c2d5e8b7f14
```

Response (`201`):

```json
{
  "object": "platform_portal_session",
  "orgId": "org_01jbz3m4k5n6p7q8r9s0t1v2w3",
  "url": "https://ownrecord.io/portal/ownrecord/login/verify?session=psess_…&token=…",
  "expiresAt": "2026-10-26T12:15:00.000Z"
}
```

## Errors

| Code                                                                                                         | HTTP status | When                                                                              | What to do                                                                                                                                       |
| ------------------------------------------------------------------------------------------------------------ | ----------- | --------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| [`platform_billing_unavailable`](https://ownrecord.io/docs/reference/errors.md#platform_billing_unavailable) | 409         | Ownrecord's plans aren't set up on this installation yet.                         | A platform admin runs `pnpm platform:bootstrap`, which creates the plans, prices and features of data/platform/plans.yaml. Try again afterwards. |
| [`platform_customer_missing`](https://ownrecord.io/docs/reference/errors.md#platform_customer_missing)       | 409         | The organization has no billing account (the platform organization isn't billed). | Wait a few seconds and reload the billing page. If it persists, contact support.                                                                 |
| [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied)                       | 403         | Only an org_owner or billing_admin opens the billing portal.                      | Ask an organization owner or admin for a role or scope that allows this action.                                                                  |

It can also return these [common errors](https://ownrecord.io/docs/reference.md#common-errors): [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed), [`api_version_unsupported`](https://ownrecord.io/docs/reference/errors.md#api_version_unsupported), [`invalid_json`](https://ownrecord.io/docs/reference/errors.md#invalid_json), [`unsupported_media_type`](https://ownrecord.io/docs/reference/errors.md#unsupported_media_type), [`authentication_required`](https://ownrecord.io/docs/reference/errors.md#authentication_required), [`api_key_invalid`](https://ownrecord.io/docs/reference/errors.md#api_key_invalid), [`resource_not_found`](https://ownrecord.io/docs/reference/errors.md#resource_not_found), [`idempotency_key_required`](https://ownrecord.io/docs/reference/errors.md#idempotency_key_required), [`idempotency_key_reused`](https://ownrecord.io/docs/reference/errors.md#idempotency_key_reused), [`idempotency_in_progress`](https://ownrecord.io/docs/reference/errors.md#idempotency_in_progress), [`dry_run_not_supported`](https://ownrecord.io/docs/reference/errors.md#dry_run_not_supported), [`approval_required`](https://ownrecord.io/docs/reference/errors.md#approval_required), [`approval_rejected`](https://ownrecord.io/docs/reference/errors.md#approval_rejected), [`approval_expired`](https://ownrecord.io/docs/reference/errors.md#approval_expired), [`stale_approval`](https://ownrecord.io/docs/reference/errors.md#stale_approval), [`approval_policy_denied`](https://ownrecord.io/docs/reference/errors.md#approval_policy_denied), [`rate_limited`](https://ownrecord.io/docs/reference/errors.md#rate_limited), [`internal_error`](https://ownrecord.io/docs/reference/errors.md#internal_error).
