# POST /api/v1/billing/addons

Auth: Bearer

HTML: https://cooperemail.com/docs/reference/set-usage-addons

## Summary

Set extra inbox, custom domain, and email quantities on a Starter or Pro subscription. Body fields inboxes, domains, and email_packs are integers from 0 to 100. At least one is required. Each field replaces the previous quantity. One inbox is $1 per month (lookup key cooper_overage_inbox_monthly). One custom domain is $1 per month (cooper_overage_domain_monthly). One email pack is $1 per month and adds 1,000 emails (cooper_overage_sends_1000_monthly). npm run stripe:setup creates those prices. An increase is invoiced immediately, and the cap rises only after Stripe confirms payment. A decrease is not credited. A quantity below live usage returns HTTP 409 addon_below_usage. Email packs already used stay locked until the Stripe period ends. Grandfathered accounts return HTTP 402 plan_limit_exceeded and are not charged. A past_due, unpaid, or incomplete subscription returns HTTP 402 subscription_not_current. The response limits are the caps after this call, so the next inbox, domain, or send can use the new room once payment succeeds. Free, and an account with no Stripe subscription, returns HTTP 402 plan_limit_exceeded and buys nothing. A sub-account key returns HTTP 403 workspace_billing_forbidden. HTTP 402 addon_payment_failed means the invoice was not paid and the quantity was not saved. HTTP 503 stripe_not_configured when Stripe is unset, stripe_price_missing when a price is absent, and usage_addon_failed when Stripe refuses the change for another reason. The customer portal does not change these quantities. MCP: cooper_set_addons.

## Request

```json
{
  "inboxes": 1
}
```

## Response

HTTP 200. Sample values illustrate the schema.

```json
{
  "object": "usage_addons",
  "inboxes": 1,
  "domains": 0,
  "email_packs": 0,
  "previous": {
    "inboxes": 0,
    "domains": 0,
    "email_packs": 0
  },
  "extra_emails": 0,
  "monthly_cents": 100,
  "lookup_keys": {
    "inboxes": "cooper_overage_inbox_monthly",
    "domains": "cooper_overage_domain_monthly",
    "email_packs": "cooper_overage_sends_1000_monthly"
  },
  "limits": {
    "inboxes": 26,
    "emails_per_month": 25000,
    "custom_domains": 15
  }
}
```

## Errors

- HTTP 409 addon_below_usage
- HTTP 402 plan_limit_exceeded
- HTTP 402 subscription_not_current
- HTTP 403 workspace_billing_forbidden
- HTTP 402 addon_payment_failed
- HTTP 503 stripe_not_configured
- HTTP 403 permission_denied
- HTTP 503 stripe_price_missing
- HTTP 503 usage_addon_failed

The live `message` is the sentence for that code. Branch on `code`.

```json
{
  "error": {
    "type": "conflict",
    "code": "addon_below_usage",
    "docs_url": "https://cooperemail.com/docs#addon_below_usage"
  }
}
```

## Idempotency

This route does not document Idempotency-Key or client_id.
