# Get a brand's customer portal

> The portal.brand.get operation: GET /api/v1/public/{brandSlug}/portal in the REST API and the portal_brand_get tool in the MCP server.

Returns what a brand's customer portal shows before sign-in: the brand's name, logo, color and support links,
the seller (legal name, address and VAT ID), and the mode the portal's sign-in works in (`livemode`: test mode
for a brand that is still test-only, live mode once it is live).

Public: no API key needed. Draft and suspended brands have no portal (`resource_not_found`).

## At a glance

- **REST:** `GET /api/v1/public/{brandSlug}/portal`
- **MCP tool:** `portal_brand_get`
- **Operation ID:** `portal.brand.get`
- **Scope:** Brand
- **Permission:** `portal:read`
- **Risk tier:** `read`
- **Dry run:** Not supported
- **Idempotency:** Not needed (read only)
- **Modes:** Test and live
- **Authentication:** None (a public endpoint, rate-limited per IP address)
- **Since:** M9

## Request

### Path parameters

| Field       | Type   | Description                                    |
| ----------- | ------ | ---------------------------------------------- |
| `brandSlug` | string | The brand's slug, as in `/portal/{brandSlug}`. |

### Query parameters

This operation takes no query parameters.

## Response

`200 OK` with a JSON object:

| Field              | Type             | Description                                                                                   |
| ------------------ | ---------------- | --------------------------------------------------------------------------------------------- |
| `object`           | `"portal_brand"` |                                                                                               |
| `slug`             | string           |                                                                                               |
| `name`             | string           |                                                                                               |
| `livemode`         | boolean          | The mode the portal's sign-in page works in: test for a test-only brand.                      |
| `logoUrl`          | string or null   |                                                                                               |
| `primaryColor`     | string or null   |                                                                                               |
| `supportEmail`     | string or null   |                                                                                               |
| `supportUrl`       | string or null   |                                                                                               |
| `termsUrl`         | string or null   |                                                                                               |
| `privacyUrl`       | string or null   |                                                                                               |
| `seller`           | object           | The seller: “Sold by {legal name}, {address}, {VAT ID}” (spec §40.2).                         |
| `seller.legalName` | string           |                                                                                               |
| `seller.address`   | string           |                                                                                               |
| `seller.taxId`     | string           |                                                                                               |
| `locales`          | array of string  | The brand's languages, its default first (`checkoutSettings.locales`): the portal's fallback. |

## Examples

### Genno's portal (test-only brand)

```http
GET /api/v1/public/genno/portal
```

Response (`200`):

```json
{
  "object": "portal_brand",
  "slug": "genno",
  "name": "Genno",
  "livemode": false,
  "logoUrl": null,
  "primaryColor": "#5b3df5",
  "supportEmail": "help@genno.example",
  "supportUrl": null,
  "termsUrl": "https://genno.example/terms",
  "privacyUrl": "https://genno.example/privacy",
  "seller": {
    "legalName": "Etna Labs AG",
    "address": "Dammstrasse 16, 6300 Zug, Switzerland",
    "taxId": "CHE-181.927.786 MWST"
  },
  "locales": ["en", "hr"]
}
```

## Errors

| Code                                                                                     | HTTP status | When                                                                                  | What to do                                                                                           |
| ---------------------------------------------------------------------------------------- | ----------- | ------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed)   | 400         | `brandSlug` isn't a slug.                                                             | Fix the fields listed in `details.issues` and send the request again.                                |
| [`resource_not_found`](https://ownrecord.io/docs/reference/errors.md#resource_not_found) | 404         | No brand with this slug has a customer portal (draft and suspended brands have none). | Check the ID and that your credentials are scoped to the right organization, entity, brand and mode. |
| [`rate_limited`](https://ownrecord.io/docs/reference/errors.md#rate_limited)             | 429         | Too many requests from this address or client IP; wait `retry_after_ms`.              | Wait for `retry_after_ms` and retry with backoff.                                                    |

It can also return these [common errors](https://ownrecord.io/docs/reference.md#common-errors): [`api_version_unsupported`](https://ownrecord.io/docs/reference/errors.md#api_version_unsupported), [`scope_required`](https://ownrecord.io/docs/reference/errors.md#scope_required), [`dry_run_not_supported`](https://ownrecord.io/docs/reference/errors.md#dry_run_not_supported), [`internal_error`](https://ownrecord.io/docs/reference/errors.md#internal_error).
