# Billing — DayZero API

> Subscription billing, plan management, and usage tracking.

18 endpoints. OpenAPI for just this tag: https://www.ondayzero.com/docs/reference/billing/openapi.json · HTML: https://www.ondayzero.com/docs/reference/billing · All tags: https://www.ondayzero.com/docs/reference/index.md

## Endpoints

- `POST /api/v1/billing/addon` — Toggle Addon
- `POST /api/v1/billing/addon/preview` — Preview Addon Change
- `GET /api/v1/billing/ai-usage` — Get Ai Usage
- `GET /api/v1/billing/ai-usage/details` — Get Ai Usage Details
- `POST /api/v1/billing/ai/pause` — Pause Ai Features
- `POST /api/v1/billing/ai/resume` — Resume Ai Features
- `GET /api/v1/billing/catalog` — Get Billing Catalog
- `POST /api/v1/billing/change-plan` — Change Plan
- `POST /api/v1/billing/checkout` — Create Checkout Session
- `POST /api/v1/billing/firm/change-tier` — Change Firm Tier
- `GET /api/v1/billing/firm/client-usage` — Get Firm Client Usage
- `POST /api/v1/billing/grandfather` — Grandfather the current business (superuser only)
- `GET /api/v1/billing/grandfathered-summary` — Get Grandfathered Summary
- `GET /api/v1/billing/invoices` — Get Invoice History
- `POST /api/v1/billing/migrate-from-grandfathered` — Migrate grandfathered account to a paid plan
- `POST /api/v1/billing/portal` — Create Portal Session
- `GET /api/v1/billing/pricing-config` — Get Pricing Config
- `GET /api/v1/billing/status` — Get Billing Status

---

## POST /api/v1/billing/addon

> Toggle Addon

- **Tag:** billing
- **Operation ID:** `toggle_addon`

### Description

Add or remove an add-on from the business's Stripe subscription.

**Request Body:**
- `addon_slug`: Add-on module slug from AddOnModule enum
- `action`: 'add' (charges prorated amount immediately) or 'remove' (effective at period end, no refund)

**Effect:**
- Adding: Stripe subscription is updated, prorated amount is charged immediately
- Removing: Item removed with no proration, takes effect at period end

**Returns:** Updated active_addons list and effective date. Refused
(400 `BILLING_023`) on a business billed under a partner agreement, whose
add-ons the agreement sets.

### Authentication

Bearer token in `Authorization` header.
Required header: `x-business-id: <business uuid>`.

### Request body

Schema: `AddonToggleRequest`

- `addon_slug` (string · required) — Add-on module slug (e.g. 'ai_pro').
- `action` (string · required) (one of: add, remove) — 'add' or 'remove'.

### Responses

#### 201 — Successful Response

Schema: `SuccessEnvelope_ToggleAddonResponse_`

- `success` (boolean)
- `message` (string)
- `code` (string)
- `data` (ToggleAddonResponse)

#### 401 — Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

#### 403 — Forbidden - Insufficient permissions

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

#### 422 — Validation Error

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

### Code samples

#### cURL

```bash
curl -X POST 'https://api.ondayzero.com/api/v1/billing/addon' \
  -H 'Authorization: Bearer dz_your_token' \
  -H 'x-business-id: YOUR_BUSINESS_ID' \
  -H 'Content-Type: application/json' \
  -d '{
  "addon_slug": "string",
  "action": "add"
}'
```

#### JavaScript

```javascript
const response = await fetch('https://api.ondayzero.com/api/v1/billing/addon', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer dz_your_token',
    'x-business-id': 'YOUR_BUSINESS_ID',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
  "addon_slug": "string",
  "action": "add"
}),
});
const data = await response.json();
```

#### Python

```python
import httpx

headers = {
    "Authorization": "Bearer dz_your_token",
    "x-business-id": "YOUR_BUSINESS_ID",
}

payload = {'addon_slug': 'string', 'action': 'add'}

response = httpx.post("https://api.ondayzero.com/api/v1/billing/addon", headers=headers, json=payload)
data = response.json()
```

### See also

- HTML version: https://www.ondayzero.com/docs/reference/billing/toggle-addon
- OpenAPI slice: https://www.ondayzero.com/docs/reference/billing/toggle-addon/openapi.json
- Other endpoints in **billing**: https://www.ondayzero.com/docs/reference/billing (markdown bundle: https://www.ondayzero.com/docs/reference/billing.md, OpenAPI: https://www.ondayzero.com/docs/reference/billing/openapi.json)
- Endpoint catalog: https://www.ondayzero.com/docs/reference/index.md

---

## POST /api/v1/billing/addon/preview

> Preview Addon Change

- **Tag:** billing
- **Operation ID:** `preview_addon_change`

### Description

Preview the billing impact of adding or removing an add-on.

**Request Body:**
- `addon_slug`: Add-on module slug from AddOnModule enum
- `action`: 'add' or 'remove'

**Returns:** Prorated amount (cents; `null` when Stripe could not
produce a preview), addon price, and effective date for removals.
Refused (400 `BILLING_023`) on a business billed under a partner
agreement.

### Authentication

Bearer token in `Authorization` header.
Required header: `x-business-id: <business uuid>`.

### Request body

Schema: `AddonPreviewRequest`

- `addon_slug` (string · required) — Add-on module slug (e.g. 'ai_pro').
- `action` (string · required) (one of: add, remove) — 'add' or 'remove'.

### Responses

#### 201 — Successful Response

Schema: `SuccessEnvelope_PreviewAddonChangeResponse_`

- `success` (boolean)
- `message` (string)
- `code` (string)
- `data` (PreviewAddonChangeResponse)

#### 401 — Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

#### 403 — Forbidden - Insufficient permissions

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

#### 422 — Validation Error

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

### Code samples

#### cURL

```bash
curl -X POST 'https://api.ondayzero.com/api/v1/billing/addon/preview' \
  -H 'Authorization: Bearer dz_your_token' \
  -H 'x-business-id: YOUR_BUSINESS_ID' \
  -H 'Content-Type: application/json' \
  -d '{
  "addon_slug": "string",
  "action": "add"
}'
```

#### JavaScript

```javascript
const response = await fetch('https://api.ondayzero.com/api/v1/billing/addon/preview', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer dz_your_token',
    'x-business-id': 'YOUR_BUSINESS_ID',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
  "addon_slug": "string",
  "action": "add"
}),
});
const data = await response.json();
```

#### Python

```python
import httpx

headers = {
    "Authorization": "Bearer dz_your_token",
    "x-business-id": "YOUR_BUSINESS_ID",
}

payload = {'addon_slug': 'string', 'action': 'add'}

response = httpx.post("https://api.ondayzero.com/api/v1/billing/addon/preview", headers=headers, json=payload)
data = response.json()
```

### See also

- HTML version: https://www.ondayzero.com/docs/reference/billing/preview-addon-change
- OpenAPI slice: https://www.ondayzero.com/docs/reference/billing/preview-addon-change/openapi.json
- Other endpoints in **billing**: https://www.ondayzero.com/docs/reference/billing (markdown bundle: https://www.ondayzero.com/docs/reference/billing.md, OpenAPI: https://www.ondayzero.com/docs/reference/billing/openapi.json)
- Endpoint catalog: https://www.ondayzero.com/docs/reference/index.md

---

## GET /api/v1/billing/ai-usage

> Get Ai Usage

- **Tag:** billing
- **Operation ID:** `get_ai_usage`

### Description

Return current daily and monthly AI request counts with plan limits.

### Authentication

Bearer token in `Authorization` header.
Required header: `x-business-id: <business uuid>`.

### Responses

#### 200 — Successful Response

Schema: `SuccessEnvelope_GetAiUsageResponse_`

- `success` (boolean)
- `message` (string)
- `code` (string)
- `data` (GetAiUsageResponse)

#### 401 — Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

#### 403 — Forbidden - Insufficient permissions

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

#### 422 — Validation Error

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

### Code samples

#### cURL

```bash
curl -X GET 'https://api.ondayzero.com/api/v1/billing/ai-usage' \
  -H 'Authorization: Bearer dz_your_token' \
  -H 'x-business-id: YOUR_BUSINESS_ID'
```

#### JavaScript

```javascript
const response = await fetch('https://api.ondayzero.com/api/v1/billing/ai-usage', {
  method: 'GET',
  headers: {
    Authorization: 'Bearer dz_your_token',
    'x-business-id': 'YOUR_BUSINESS_ID',
  },
});
const data = await response.json();
```

#### Python

```python
import httpx

headers = {
    "Authorization": "Bearer dz_your_token",
    "x-business-id": "YOUR_BUSINESS_ID",
}

response = httpx.get("https://api.ondayzero.com/api/v1/billing/ai-usage", headers=headers)
data = response.json()
```

### See also

- HTML version: https://www.ondayzero.com/docs/reference/billing/get-ai-usage
- OpenAPI slice: https://www.ondayzero.com/docs/reference/billing/get-ai-usage/openapi.json
- Other endpoints in **billing**: https://www.ondayzero.com/docs/reference/billing (markdown bundle: https://www.ondayzero.com/docs/reference/billing.md, OpenAPI: https://www.ondayzero.com/docs/reference/billing/openapi.json)
- Endpoint catalog: https://www.ondayzero.com/docs/reference/index.md

---

## GET /api/v1/billing/ai-usage/details

> Get Ai Usage Details

- **Tag:** billing
- **Operation ID:** `get_ai_usage_details`

### Description

Return detailed AI usage stats: top users, model breakdown, daily trend.

**Query Parameters:**
- `scope`: Optional. Set to 'firm' to see firm-wide AI usage.

**Returns:** Summary, top_users, by_model, daily arrays.

### Authentication

Bearer token in `Authorization` header.
Required header: `x-business-id: <business uuid>`.

### Parameters

- `scope` (query, string, optional) — Set to 'firm' to aggregate across all firm businesses.

### Responses

#### 200 — Successful Response

Schema: `SuccessEnvelope_GetAiUsageDetailsResponse_`

- `success` (boolean)
- `message` (string)
- `code` (string)
- `data` (GetAiUsageDetailsResponse)

#### 401 — Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

#### 403 — Forbidden - Insufficient permissions

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

#### 422 — Validation Error

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

### Code samples

#### cURL

```bash
curl -X GET 'https://api.ondayzero.com/api/v1/billing/ai-usage/details' \
  -H 'Authorization: Bearer dz_your_token' \
  -H 'x-business-id: YOUR_BUSINESS_ID'
```

#### JavaScript

```javascript
const response = await fetch('https://api.ondayzero.com/api/v1/billing/ai-usage/details', {
  method: 'GET',
  headers: {
    Authorization: 'Bearer dz_your_token',
    'x-business-id': 'YOUR_BUSINESS_ID',
  },
});
const data = await response.json();
```

#### Python

```python
import httpx

headers = {
    "Authorization": "Bearer dz_your_token",
    "x-business-id": "YOUR_BUSINESS_ID",
}

response = httpx.get("https://api.ondayzero.com/api/v1/billing/ai-usage/details", headers=headers)
data = response.json()
```

### See also

- HTML version: https://www.ondayzero.com/docs/reference/billing/get-ai-usage-details
- OpenAPI slice: https://www.ondayzero.com/docs/reference/billing/get-ai-usage-details/openapi.json
- Other endpoints in **billing**: https://www.ondayzero.com/docs/reference/billing (markdown bundle: https://www.ondayzero.com/docs/reference/billing.md, OpenAPI: https://www.ondayzero.com/docs/reference/billing/openapi.json)
- Endpoint catalog: https://www.ondayzero.com/docs/reference/index.md

---

## POST /api/v1/billing/ai/pause

> Pause Ai Features

- **Tag:** billing
- **Operation ID:** `pause_ai_features`

### Description

Pause all AI features for the authenticated business.

Sets ``businesses.ai_paused_at`` so:
- ``check_ai_quota`` returns ``allowed=False, paused=True`` for any
  subsequent AI call (chat, panels, OCR, etc.).
- ``track_business_usage`` short-circuits, stopping the Stripe
  overage fire-and-forget.
- ``AITransactionCleaner`` downshifts to rule-only cleaning during
  Plaid sync (no LLM calls).

Idempotent. Returns the refreshed AI usage payload so the widget /
banner can transition to the paused state without a second
round-trip.

### Authentication

Bearer token in `Authorization` header.
Required header: `x-business-id: <business uuid>`.

### Responses

#### 201 — Successful Response

Schema: `SuccessEnvelope_PauseAiFeaturesResponse_`

- `success` (boolean)
- `message` (string)
- `code` (string)
- `data` (PauseAiFeaturesResponse)

#### 401 — Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

#### 403 — Forbidden - Insufficient permissions

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

#### 422 — Validation Error

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

### Code samples

#### cURL

```bash
curl -X POST 'https://api.ondayzero.com/api/v1/billing/ai/pause' \
  -H 'Authorization: Bearer dz_your_token' \
  -H 'x-business-id: YOUR_BUSINESS_ID'
```

#### JavaScript

```javascript
const response = await fetch('https://api.ondayzero.com/api/v1/billing/ai/pause', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer dz_your_token',
    'x-business-id': 'YOUR_BUSINESS_ID',
  },
});
const data = await response.json();
```

#### Python

```python
import httpx

headers = {
    "Authorization": "Bearer dz_your_token",
    "x-business-id": "YOUR_BUSINESS_ID",
}

response = httpx.post("https://api.ondayzero.com/api/v1/billing/ai/pause", headers=headers)
data = response.json()
```

### See also

- HTML version: https://www.ondayzero.com/docs/reference/billing/pause-ai-features
- OpenAPI slice: https://www.ondayzero.com/docs/reference/billing/pause-ai-features/openapi.json
- Other endpoints in **billing**: https://www.ondayzero.com/docs/reference/billing (markdown bundle: https://www.ondayzero.com/docs/reference/billing.md, OpenAPI: https://www.ondayzero.com/docs/reference/billing/openapi.json)
- Endpoint catalog: https://www.ondayzero.com/docs/reference/index.md

---

## POST /api/v1/billing/ai/resume

> Resume Ai Features

- **Tag:** billing
- **Operation ID:** `resume_ai_features`

### Description

Resume AI features for the authenticated business.

Clears ``ai_paused_at`` and ``ai_paused_by_user_id``. Idempotent —
resuming an already-active business is a no-op. Returns the
refreshed AI usage payload so the widget transitions back to the
Calm / Warning / Overage state without a second round-trip.

### Authentication

Bearer token in `Authorization` header.
Required header: `x-business-id: <business uuid>`.

### Responses

#### 201 — Successful Response

Schema: `SuccessEnvelope_ResumeAiFeaturesResponse_`

- `success` (boolean)
- `message` (string)
- `code` (string)
- `data` (ResumeAiFeaturesResponse)

#### 401 — Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

#### 403 — Forbidden - Insufficient permissions

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

#### 422 — Validation Error

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

### Code samples

#### cURL

```bash
curl -X POST 'https://api.ondayzero.com/api/v1/billing/ai/resume' \
  -H 'Authorization: Bearer dz_your_token' \
  -H 'x-business-id: YOUR_BUSINESS_ID'
```

#### JavaScript

```javascript
const response = await fetch('https://api.ondayzero.com/api/v1/billing/ai/resume', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer dz_your_token',
    'x-business-id': 'YOUR_BUSINESS_ID',
  },
});
const data = await response.json();
```

#### Python

```python
import httpx

headers = {
    "Authorization": "Bearer dz_your_token",
    "x-business-id": "YOUR_BUSINESS_ID",
}

response = httpx.post("https://api.ondayzero.com/api/v1/billing/ai/resume", headers=headers)
data = response.json()
```

### See also

- HTML version: https://www.ondayzero.com/docs/reference/billing/resume-ai-features
- OpenAPI slice: https://www.ondayzero.com/docs/reference/billing/resume-ai-features/openapi.json
- Other endpoints in **billing**: https://www.ondayzero.com/docs/reference/billing (markdown bundle: https://www.ondayzero.com/docs/reference/billing.md, OpenAPI: https://www.ondayzero.com/docs/reference/billing/openapi.json)
- Endpoint catalog: https://www.ondayzero.com/docs/reference/index.md

---

## GET /api/v1/billing/catalog

> Get Billing Catalog

- **Tag:** billing
- **Operation ID:** `get_billing_catalog`

### Description

Return the Stripe price catalog (slug → price details).

Used by the frontend to get price IDs for checkout without hardcoding.
Annual variants are stored as ``<slug>_annual`` entries.

### Authentication

Bearer token in `Authorization` header.
Required header: `x-business-id: <business uuid>`.

### Responses

#### 200 — Successful Response

Schema: `SuccessEnvelope_GetBillingCatalogResponse_`

- `success` (boolean)
- `message` (string)
- `code` (string)
- `data` (GetBillingCatalogResponse)

### Code samples

#### cURL

```bash
curl -X GET 'https://api.ondayzero.com/api/v1/billing/catalog' \
  -H 'Authorization: Bearer dz_your_token' \
  -H 'x-business-id: YOUR_BUSINESS_ID'
```

#### JavaScript

```javascript
const response = await fetch('https://api.ondayzero.com/api/v1/billing/catalog', {
  method: 'GET',
  headers: {
    Authorization: 'Bearer dz_your_token',
    'x-business-id': 'YOUR_BUSINESS_ID',
  },
});
const data = await response.json();
```

#### Python

```python
import httpx

headers = {
    "Authorization": "Bearer dz_your_token",
    "x-business-id": "YOUR_BUSINESS_ID",
}

response = httpx.get("https://api.ondayzero.com/api/v1/billing/catalog", headers=headers)
data = response.json()
```

### See also

- HTML version: https://www.ondayzero.com/docs/reference/billing/get-billing-catalog
- OpenAPI slice: https://www.ondayzero.com/docs/reference/billing/get-billing-catalog/openapi.json
- Other endpoints in **billing**: https://www.ondayzero.com/docs/reference/billing (markdown bundle: https://www.ondayzero.com/docs/reference/billing.md, OpenAPI: https://www.ondayzero.com/docs/reference/billing/openapi.json)
- Endpoint catalog: https://www.ondayzero.com/docs/reference/index.md

---

## POST /api/v1/billing/change-plan

> Change Plan

- **Tag:** billing
- **Operation ID:** `change_plan`

### Description

Switch the base subscription plan to a different price.

**Request Body:**
- `price_id`: Stripe Price ID for the new plan

**Effect:** The base plan line item is swapped and the proration is invoiced immediately.
Refused (400 `BILLING_023`) on a business billed under a partner agreement.

### Authentication

Bearer token in `Authorization` header.
Required header: `x-business-id: <business uuid>`.

### Request body

Schema: `PlanChangeRequest`

- `price_id` (string · required) — Stripe Price ID for the new plan.

### Responses

#### 201 — Successful Response

Schema: `SuccessEnvelope_ChangePlanResponse_`

- `success` (boolean)
- `message` (string)
- `code` (string)
- `data` (ChangePlanResponse)

#### 401 — Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

#### 403 — Forbidden - Insufficient permissions

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

#### 422 — Validation Error

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

### Code samples

#### cURL

```bash
curl -X POST 'https://api.ondayzero.com/api/v1/billing/change-plan' \
  -H 'Authorization: Bearer dz_your_token' \
  -H 'x-business-id: YOUR_BUSINESS_ID' \
  -H 'Content-Type: application/json' \
  -d '{
  "price_id": "string"
}'
```

#### JavaScript

```javascript
const response = await fetch('https://api.ondayzero.com/api/v1/billing/change-plan', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer dz_your_token',
    'x-business-id': 'YOUR_BUSINESS_ID',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
  "price_id": "string"
}),
});
const data = await response.json();
```

#### Python

```python
import httpx

headers = {
    "Authorization": "Bearer dz_your_token",
    "x-business-id": "YOUR_BUSINESS_ID",
}

payload = {'price_id': 'string'}

response = httpx.post("https://api.ondayzero.com/api/v1/billing/change-plan", headers=headers, json=payload)
data = response.json()
```

### See also

- HTML version: https://www.ondayzero.com/docs/reference/billing/change-plan
- OpenAPI slice: https://www.ondayzero.com/docs/reference/billing/change-plan/openapi.json
- Other endpoints in **billing**: https://www.ondayzero.com/docs/reference/billing (markdown bundle: https://www.ondayzero.com/docs/reference/billing.md, OpenAPI: https://www.ondayzero.com/docs/reference/billing/openapi.json)
- Endpoint catalog: https://www.ondayzero.com/docs/reference/index.md

---

## POST /api/v1/billing/checkout

> Create Checkout Session

- **Tag:** billing
- **Operation ID:** `create_checkout_session`

### Description

Create a Stripe Checkout session so the user can subscribe.

Refused (400 `BILLING_023`) on a business billed under a partner
agreement (`partner_program`): its plan is set by the agreement.

### Authentication

Bearer token in `Authorization` header.
Required header: `x-business-id: <business uuid>`.

### Request body

Schema: `CheckoutRequest`

- `price_id` (string · required) — Stripe Price ID for the plan.
- `success_url` (string · required) — URL to redirect after successful payment.
- `cancel_url` (string · required) — URL to redirect if checkout is canceled.

### Responses

#### 201 — Successful Response

Schema: `SuccessEnvelope_CreateCheckoutSessionResponse_`

- `success` (boolean)
- `message` (string)
- `code` (string)
- `data` (CreateCheckoutSessionResponse)

#### 401 — Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

#### 403 — Forbidden - Insufficient permissions

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

#### 422 — Validation Error

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

### Code samples

#### cURL

```bash
curl -X POST 'https://api.ondayzero.com/api/v1/billing/checkout' \
  -H 'Authorization: Bearer dz_your_token' \
  -H 'x-business-id: YOUR_BUSINESS_ID' \
  -H 'Content-Type: application/json' \
  -d '{
  "price_id": "string",
  "success_url": "string",
  "cancel_url": "string"
}'
```

#### JavaScript

```javascript
const response = await fetch('https://api.ondayzero.com/api/v1/billing/checkout', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer dz_your_token',
    'x-business-id': 'YOUR_BUSINESS_ID',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
  "price_id": "string",
  "success_url": "string",
  "cancel_url": "string"
}),
});
const data = await response.json();
```

#### Python

```python
import httpx

headers = {
    "Authorization": "Bearer dz_your_token",
    "x-business-id": "YOUR_BUSINESS_ID",
}

payload = {'price_id': 'string', 'success_url': 'string', 'cancel_url': 'string'}

response = httpx.post("https://api.ondayzero.com/api/v1/billing/checkout", headers=headers, json=payload)
data = response.json()
```

### See also

- HTML version: https://www.ondayzero.com/docs/reference/billing/create-checkout-session
- OpenAPI slice: https://www.ondayzero.com/docs/reference/billing/create-checkout-session/openapi.json
- Other endpoints in **billing**: https://www.ondayzero.com/docs/reference/billing (markdown bundle: https://www.ondayzero.com/docs/reference/billing.md, OpenAPI: https://www.ondayzero.com/docs/reference/billing/openapi.json)
- Endpoint catalog: https://www.ondayzero.com/docs/reference/index.md

---

## POST /api/v1/billing/firm/change-tier

> Change Firm Tier

- **Tag:** billing
- **Operation ID:** `change_firm_tier`

### Description

Upgrade or downgrade the firm's plan tier, in-app.

Swaps the per-client price, adds/removes the platform fee, and re-applies
the current client quantity in one prorated Stripe update. Requires the
caller to be an owner/admin of the firm. Blocks a downgrade that would drop
the firm below its current client count.

### Authentication

Bearer token in `Authorization` header.
Required header: `x-business-id: <business uuid>`.

### Request body

Schema: `FirmTierChangeRequest`

- `firm_plan_tier` (string · required) — Target firm tier: 'firm_starter', 'firm_professional', or 'firm_enterprise'.

### Responses

#### 201 — Successful Response

Schema: `SuccessEnvelope_ChangeFirmTierResponse_`

- `success` (boolean)
- `message` (string)
- `code` (string)
- `data` (ChangeFirmTierResponse)

#### 401 — Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

#### 403 — Forbidden - Insufficient permissions

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

#### 422 — Validation Error

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

### Code samples

#### cURL

```bash
curl -X POST 'https://api.ondayzero.com/api/v1/billing/firm/change-tier' \
  -H 'Authorization: Bearer dz_your_token' \
  -H 'x-business-id: YOUR_BUSINESS_ID' \
  -H 'Content-Type: application/json' \
  -d '{
  "firm_plan_tier": "string"
}'
```

#### JavaScript

```javascript
const response = await fetch('https://api.ondayzero.com/api/v1/billing/firm/change-tier', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer dz_your_token',
    'x-business-id': 'YOUR_BUSINESS_ID',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
  "firm_plan_tier": "string"
}),
});
const data = await response.json();
```

#### Python

```python
import httpx

headers = {
    "Authorization": "Bearer dz_your_token",
    "x-business-id": "YOUR_BUSINESS_ID",
}

payload = {'firm_plan_tier': 'string'}

response = httpx.post("https://api.ondayzero.com/api/v1/billing/firm/change-tier", headers=headers, json=payload)
data = response.json()
```

### See also

- HTML version: https://www.ondayzero.com/docs/reference/billing/change-firm-tier
- OpenAPI slice: https://www.ondayzero.com/docs/reference/billing/change-firm-tier/openapi.json
- Other endpoints in **billing**: https://www.ondayzero.com/docs/reference/billing (markdown bundle: https://www.ondayzero.com/docs/reference/billing.md, OpenAPI: https://www.ondayzero.com/docs/reference/billing/openapi.json)
- Endpoint catalog: https://www.ondayzero.com/docs/reference/index.md

---

## GET /api/v1/billing/firm/client-usage

> Get Firm Client Usage

- **Tag:** billing
- **Operation ID:** `get_firm_client_usage`

### Description

Return the firm's active client count, tier cap, and remaining seats.

For non-advisory businesses (self-directed/managed) this returns
``is_advisory_firm: false`` with no limit so callers can hide the
client/upgrade UI.

### Authentication

Bearer token in `Authorization` header.
Required header: `x-business-id: <business uuid>`.

### Responses

#### 200 — Successful Response

Schema: `SuccessEnvelope_GetFirmClientUsageResponse_`

- `success` (boolean)
- `message` (string)
- `code` (string)
- `data` (GetFirmClientUsageResponse)

#### 401 — Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

#### 403 — Forbidden - Insufficient permissions

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

#### 422 — Validation Error

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

### Code samples

#### cURL

```bash
curl -X GET 'https://api.ondayzero.com/api/v1/billing/firm/client-usage' \
  -H 'Authorization: Bearer dz_your_token' \
  -H 'x-business-id: YOUR_BUSINESS_ID'
```

#### JavaScript

```javascript
const response = await fetch('https://api.ondayzero.com/api/v1/billing/firm/client-usage', {
  method: 'GET',
  headers: {
    Authorization: 'Bearer dz_your_token',
    'x-business-id': 'YOUR_BUSINESS_ID',
  },
});
const data = await response.json();
```

#### Python

```python
import httpx

headers = {
    "Authorization": "Bearer dz_your_token",
    "x-business-id": "YOUR_BUSINESS_ID",
}

response = httpx.get("https://api.ondayzero.com/api/v1/billing/firm/client-usage", headers=headers)
data = response.json()
```

### See also

- HTML version: https://www.ondayzero.com/docs/reference/billing/get-firm-client-usage
- OpenAPI slice: https://www.ondayzero.com/docs/reference/billing/get-firm-client-usage/openapi.json
- Other endpoints in **billing**: https://www.ondayzero.com/docs/reference/billing (markdown bundle: https://www.ondayzero.com/docs/reference/billing.md, OpenAPI: https://www.ondayzero.com/docs/reference/billing/openapi.json)
- Endpoint catalog: https://www.ondayzero.com/docs/reference/index.md

---

## POST /api/v1/billing/grandfather

> Grandfather the current business (superuser only)

- **Tag:** billing
- **Operation ID:** `grandfather_business`

### Description

Mark the current business as grandfathered so it keeps access without billing.

**Effect:**
- Sets ``plan_tier`` to ``grandfathered`` and ``billing_status`` to ``active``
- Clears ``trial_ends_at``
- Grants the default grandfathered add-on set

**Prerequisites:**
- Caller must be a superuser. Regular users never see this in the UI
  and receive 403 if they call the endpoint directly.

### Authentication

Bearer token in `Authorization` header.
Required header: `x-business-id: <business uuid>`.

### Responses

#### 201 — Successful Response

Schema: `SuccessEnvelope_GrandfatherBusinessResponse_`

- `success` (boolean)
- `message` (string)
- `code` (string)
- `data` (GrandfatherBusinessResponse)

#### 401 — Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

#### 403 — Forbidden - Insufficient permissions

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

#### 422 — Validation Error

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

### Code samples

#### cURL

```bash
curl -X POST 'https://api.ondayzero.com/api/v1/billing/grandfather' \
  -H 'Authorization: Bearer dz_your_token' \
  -H 'x-business-id: YOUR_BUSINESS_ID'
```

#### JavaScript

```javascript
const response = await fetch('https://api.ondayzero.com/api/v1/billing/grandfather', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer dz_your_token',
    'x-business-id': 'YOUR_BUSINESS_ID',
  },
});
const data = await response.json();
```

#### Python

```python
import httpx

headers = {
    "Authorization": "Bearer dz_your_token",
    "x-business-id": "YOUR_BUSINESS_ID",
}

response = httpx.post("https://api.ondayzero.com/api/v1/billing/grandfather", headers=headers)
data = response.json()
```

### See also

- HTML version: https://www.ondayzero.com/docs/reference/billing/grandfather-business
- OpenAPI slice: https://www.ondayzero.com/docs/reference/billing/grandfather-business/openapi.json
- Other endpoints in **billing**: https://www.ondayzero.com/docs/reference/billing (markdown bundle: https://www.ondayzero.com/docs/reference/billing.md, OpenAPI: https://www.ondayzero.com/docs/reference/billing/openapi.json)
- Endpoint catalog: https://www.ondayzero.com/docs/reference/index.md

---

## GET /api/v1/billing/grandfathered-summary

> Get Grandfathered Summary

- **Tag:** billing
- **Operation ID:** `get_grandfathered_summary`

### Description

Return a summary of the grandfathered business's current access and available plans.

**Returns:**
- `current_access`: What the grandfathered account includes today
- `available_plans`: Plans the business can migrate to with pricing

### Authentication

Bearer token in `Authorization` header.
Required header: `x-business-id: <business uuid>`.

### Responses

#### 200 — Successful Response

Schema: `SuccessEnvelope_GetGrandfatheredSummaryResponse_`

- `success` (boolean)
- `message` (string)
- `code` (string)
- `data` (GetGrandfatheredSummaryResponse)

#### 401 — Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

#### 403 — Forbidden - Insufficient permissions

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

#### 422 — Validation Error

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

### Code samples

#### cURL

```bash
curl -X GET 'https://api.ondayzero.com/api/v1/billing/grandfathered-summary' \
  -H 'Authorization: Bearer dz_your_token' \
  -H 'x-business-id: YOUR_BUSINESS_ID'
```

#### JavaScript

```javascript
const response = await fetch('https://api.ondayzero.com/api/v1/billing/grandfathered-summary', {
  method: 'GET',
  headers: {
    Authorization: 'Bearer dz_your_token',
    'x-business-id': 'YOUR_BUSINESS_ID',
  },
});
const data = await response.json();
```

#### Python

```python
import httpx

headers = {
    "Authorization": "Bearer dz_your_token",
    "x-business-id": "YOUR_BUSINESS_ID",
}

response = httpx.get("https://api.ondayzero.com/api/v1/billing/grandfathered-summary", headers=headers)
data = response.json()
```

### See also

- HTML version: https://www.ondayzero.com/docs/reference/billing/get-grandfathered-summary
- OpenAPI slice: https://www.ondayzero.com/docs/reference/billing/get-grandfathered-summary/openapi.json
- Other endpoints in **billing**: https://www.ondayzero.com/docs/reference/billing (markdown bundle: https://www.ondayzero.com/docs/reference/billing.md, OpenAPI: https://www.ondayzero.com/docs/reference/billing/openapi.json)
- Endpoint catalog: https://www.ondayzero.com/docs/reference/index.md

---

## GET /api/v1/billing/invoices

> Get Invoice History

- **Tag:** billing
- **Operation ID:** `get_invoice_history`

### Description

Return the business's Stripe subscription invoice history.

Each invoice includes a hosted URL for viewing and a PDF download link.

### Authentication

Bearer token in `Authorization` header.
Required header: `x-business-id: <business uuid>`.

### Parameters

- `limit` (query, integer, optional) — Max invoices to return

### Responses

#### 200 — Successful Response

Schema: `SuccessEnvelope_GetInvoiceHistoryResponse_`

- `success` (boolean)
- `message` (string)
- `code` (string)
- `data` (GetInvoiceHistoryResponse)

#### 401 — Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

#### 403 — Forbidden - Insufficient permissions

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

#### 422 — Validation Error

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

### Code samples

#### cURL

```bash
curl -X GET 'https://api.ondayzero.com/api/v1/billing/invoices' \
  -H 'Authorization: Bearer dz_your_token' \
  -H 'x-business-id: YOUR_BUSINESS_ID'
```

#### JavaScript

```javascript
const response = await fetch('https://api.ondayzero.com/api/v1/billing/invoices', {
  method: 'GET',
  headers: {
    Authorization: 'Bearer dz_your_token',
    'x-business-id': 'YOUR_BUSINESS_ID',
  },
});
const data = await response.json();
```

#### Python

```python
import httpx

headers = {
    "Authorization": "Bearer dz_your_token",
    "x-business-id": "YOUR_BUSINESS_ID",
}

response = httpx.get("https://api.ondayzero.com/api/v1/billing/invoices", headers=headers)
data = response.json()
```

### See also

- HTML version: https://www.ondayzero.com/docs/reference/billing/get-invoice-history
- OpenAPI slice: https://www.ondayzero.com/docs/reference/billing/get-invoice-history/openapi.json
- Other endpoints in **billing**: https://www.ondayzero.com/docs/reference/billing (markdown bundle: https://www.ondayzero.com/docs/reference/billing.md, OpenAPI: https://www.ondayzero.com/docs/reference/billing/openapi.json)
- Endpoint catalog: https://www.ondayzero.com/docs/reference/index.md

---

## POST /api/v1/billing/migrate-from-grandfathered

> Migrate grandfathered account to a paid plan

- **Tag:** billing
- **Operation ID:** `migrate_from_grandfathered`

### Description

Create a Stripe Checkout session to move from a grandfathered plan to a paid plan.

**Request Body:**
- `target_plan`: Plan tier to migrate to (`self_directed` or `managed`)
- `success_url`: Redirect URL after successful payment
- `cancel_url`: Redirect URL if checkout is canceled

**Prerequisites:**
- Business must currently be on the `grandfathered` plan tier

**Effect:**
- Creates a Stripe Checkout session
- On payment completion, `plan_tier` is updated to the target plan

**Returns:** Checkout URL and session ID.

### Authentication

Bearer token in `Authorization` header.
Required header: `x-business-id: <business uuid>`.

### Request body

Schema: `GrandfatheredMigrateRequest`

- `target_plan` (string · required) — Target plan tier: 'self_directed' or 'managed'.
- `success_url` (string · required) — URL to redirect after successful payment.
- `cancel_url` (string · required) — URL to redirect if checkout is canceled.
- `billing_interval` (string) (one of: month, year) — Billing cadence: 'month' or discounted annual 'year'.

### Responses

#### 201 — Successful Response

Schema: `SuccessEnvelope_MigrateFromGrandfatheredResponse_`

- `success` (boolean)
- `message` (string)
- `code` (string)
- `data` (MigrateFromGrandfatheredResponse)

#### 400 — Bad Request - Invalid input

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

#### 401 — Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

#### 403 — Forbidden - Insufficient permissions

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

#### 422 — Validation Error

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

### Code samples

#### cURL

```bash
curl -X POST 'https://api.ondayzero.com/api/v1/billing/migrate-from-grandfathered' \
  -H 'Authorization: Bearer dz_your_token' \
  -H 'x-business-id: YOUR_BUSINESS_ID' \
  -H 'Content-Type: application/json' \
  -d '{
  "target_plan": "string",
  "success_url": "string",
  "cancel_url": "string"
}'
```

#### JavaScript

```javascript
const response = await fetch('https://api.ondayzero.com/api/v1/billing/migrate-from-grandfathered', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer dz_your_token',
    'x-business-id': 'YOUR_BUSINESS_ID',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
  "target_plan": "string",
  "success_url": "string",
  "cancel_url": "string"
}),
});
const data = await response.json();
```

#### Python

```python
import httpx

headers = {
    "Authorization": "Bearer dz_your_token",
    "x-business-id": "YOUR_BUSINESS_ID",
}

payload = {'target_plan': 'string',
 'success_url': 'string',
 'cancel_url': 'string'}

response = httpx.post("https://api.ondayzero.com/api/v1/billing/migrate-from-grandfathered", headers=headers, json=payload)
data = response.json()
```

### See also

- HTML version: https://www.ondayzero.com/docs/reference/billing/migrate-from-grandfathered
- OpenAPI slice: https://www.ondayzero.com/docs/reference/billing/migrate-from-grandfathered/openapi.json
- Other endpoints in **billing**: https://www.ondayzero.com/docs/reference/billing (markdown bundle: https://www.ondayzero.com/docs/reference/billing.md, OpenAPI: https://www.ondayzero.com/docs/reference/billing/openapi.json)
- Endpoint catalog: https://www.ondayzero.com/docs/reference/index.md

---

## POST /api/v1/billing/portal

> Create Portal Session

- **Tag:** billing
- **Operation ID:** `create_portal_session`

### Description

Create a Stripe Billing Portal session for subscription management.

Open to every plan: the portal cannot start a subscription, and on a
business billed under a partner agreement it is how a subscription from
before the agreement is cancelled.

### Authentication

Bearer token in `Authorization` header.
Required header: `x-business-id: <business uuid>`.

### Request body

Schema: `PortalRequest`

- `return_url` (string · required) — URL to redirect after leaving the portal.

### Responses

#### 201 — Successful Response

Schema: `SuccessEnvelope_CreatePortalSessionResponse_`

- `success` (boolean)
- `message` (string)
- `code` (string)
- `data` (CreatePortalSessionResponse)

#### 401 — Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

#### 403 — Forbidden - Insufficient permissions

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

#### 422 — Validation Error

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

### Code samples

#### cURL

```bash
curl -X POST 'https://api.ondayzero.com/api/v1/billing/portal' \
  -H 'Authorization: Bearer dz_your_token' \
  -H 'x-business-id: YOUR_BUSINESS_ID' \
  -H 'Content-Type: application/json' \
  -d '{
  "return_url": "string"
}'
```

#### JavaScript

```javascript
const response = await fetch('https://api.ondayzero.com/api/v1/billing/portal', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer dz_your_token',
    'x-business-id': 'YOUR_BUSINESS_ID',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
  "return_url": "string"
}),
});
const data = await response.json();
```

#### Python

```python
import httpx

headers = {
    "Authorization": "Bearer dz_your_token",
    "x-business-id": "YOUR_BUSINESS_ID",
}

payload = {'return_url': 'string'}

response = httpx.post("https://api.ondayzero.com/api/v1/billing/portal", headers=headers, json=payload)
data = response.json()
```

### See also

- HTML version: https://www.ondayzero.com/docs/reference/billing/create-portal-session
- OpenAPI slice: https://www.ondayzero.com/docs/reference/billing/create-portal-session/openapi.json
- Other endpoints in **billing**: https://www.ondayzero.com/docs/reference/billing (markdown bundle: https://www.ondayzero.com/docs/reference/billing.md, OpenAPI: https://www.ondayzero.com/docs/reference/billing/openapi.json)
- Endpoint catalog: https://www.ondayzero.com/docs/reference/index.md

---

## GET /api/v1/billing/pricing-config

> Get Pricing Config

- **Tag:** billing
- **Operation ID:** `get_pricing_config`

### Description

Return billing pricing configuration derived from the single discount knob.

The frontend uses this to render annual savings and badge labels without
duplicating the discount percentage. Changing the discount on the backend
(``ANNUAL_DISCOUNT_PCT``) automatically updates every UI surface.

**Returns:**
- `annual_discount_pct`: Fractional annual discount (e.g. `0.1667`).
- `annual_discount_label`: Human label for the annual badge.

### Authentication

Bearer token in `Authorization` header.
Required header: `x-business-id: <business uuid>`.

### Responses

#### 200 — Successful Response

Schema: `SuccessEnvelope_GetPricingConfigResponse_`

- `success` (boolean)
- `message` (string)
- `code` (string)
- `data` (GetPricingConfigResponse)

### Code samples

#### cURL

```bash
curl -X GET 'https://api.ondayzero.com/api/v1/billing/pricing-config' \
  -H 'Authorization: Bearer dz_your_token' \
  -H 'x-business-id: YOUR_BUSINESS_ID'
```

#### JavaScript

```javascript
const response = await fetch('https://api.ondayzero.com/api/v1/billing/pricing-config', {
  method: 'GET',
  headers: {
    Authorization: 'Bearer dz_your_token',
    'x-business-id': 'YOUR_BUSINESS_ID',
  },
});
const data = await response.json();
```

#### Python

```python
import httpx

headers = {
    "Authorization": "Bearer dz_your_token",
    "x-business-id": "YOUR_BUSINESS_ID",
}

response = httpx.get("https://api.ondayzero.com/api/v1/billing/pricing-config", headers=headers)
data = response.json()
```

### See also

- HTML version: https://www.ondayzero.com/docs/reference/billing/get-pricing-config
- OpenAPI slice: https://www.ondayzero.com/docs/reference/billing/get-pricing-config/openapi.json
- Other endpoints in **billing**: https://www.ondayzero.com/docs/reference/billing (markdown bundle: https://www.ondayzero.com/docs/reference/billing.md, OpenAPI: https://www.ondayzero.com/docs/reference/billing/openapi.json)
- Endpoint catalog: https://www.ondayzero.com/docs/reference/index.md

---

## GET /api/v1/billing/status

> Get Billing Status

- **Tag:** billing
- **Operation ID:** `get_billing_status`

### Description

Return the current billing state for the authenticated business.

### Authentication

Bearer token in `Authorization` header.
Required header: `x-business-id: <business uuid>`.

### Responses

#### 200 — Successful Response

Schema: `SuccessEnvelope_GetBillingStatusResponse_`

- `success` (boolean)
- `message` (string)
- `code` (string)
- `data` (GetBillingStatusResponse)

#### 401 — Unauthorized - Missing or expired token, an MCP OAuth token used against the REST API, or no access to this business

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

#### 403 — Forbidden - Insufficient permissions

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

#### 422 — Validation Error

Schema: `ErrorResponse`

- `error` (string · required) — Error category: `validation_error`, `unauthorized`, `forbidden`, `not_found`, `conflict`, `rate_limited`, `server_error`, or `service_unavailable`.
- `message` (string · required) — Human-readable explanation, safe to show to end users.
- `code` (string · required) — Stable machine-readable code in `CATEGORY_NNN` form (e.g. `NOT_FOUND_006`, `AUTH_010`, `GEN_002`).
- `request_id` (string) — Correlation id for support requests. Echoes the `x-request-id` request header when one was supplied.
- `errors` (object) — Field-level validation messages keyed by field name. Present on 400/422 validation failures only.

### Code samples

#### cURL

```bash
curl -X GET 'https://api.ondayzero.com/api/v1/billing/status' \
  -H 'Authorization: Bearer dz_your_token' \
  -H 'x-business-id: YOUR_BUSINESS_ID'
```

#### JavaScript

```javascript
const response = await fetch('https://api.ondayzero.com/api/v1/billing/status', {
  method: 'GET',
  headers: {
    Authorization: 'Bearer dz_your_token',
    'x-business-id': 'YOUR_BUSINESS_ID',
  },
});
const data = await response.json();
```

#### Python

```python
import httpx

headers = {
    "Authorization": "Bearer dz_your_token",
    "x-business-id": "YOUR_BUSINESS_ID",
}

response = httpx.get("https://api.ondayzero.com/api/v1/billing/status", headers=headers)
data = response.json()
```

### See also

- HTML version: https://www.ondayzero.com/docs/reference/billing/get-billing-status
- OpenAPI slice: https://www.ondayzero.com/docs/reference/billing/get-billing-status/openapi.json
- Other endpoints in **billing**: https://www.ondayzero.com/docs/reference/billing (markdown bundle: https://www.ondayzero.com/docs/reference/billing.md, OpenAPI: https://www.ondayzero.com/docs/reference/billing/openapi.json)
- Endpoint catalog: https://www.ondayzero.com/docs/reference/index.md
