---
title: "Quote, buy, or remove Agency extra accounts"
method: POST
path: "/api/v1/subscription/extra-accounts"
tags: ["Subscription"]
---

# Quote, buy, or remove Agency extra accounts

`POST /api/v1/subscription/extra-accounts`

## Request

- Base URL: `https://www.poster.ly`
- URL: `https://www.poster.ly/api/v1/subscription/extra-accounts`
- Auth: HTTP bearer

Set the desired TOTAL of paid extra accounts (0 removes them all). Same rules as the dashboard: every increase must add at least 20, there is no maximum, and a decrease never goes below the connected accounts in any workspace the owner owns. Always quote first: send `dry_run: true` to get the exact prorated charge for today and the new recurring cost without charging anything. Then send the same body without `dry_run` to apply it. Applying an increase charges the saved card right away. With a working card the slots are added immediately (`status: applied`). If the card needs 3D Secure or is declined, NOTHING is applied: the response has `status: payment_required` and a Stripe-hosted `hosted_invoice_url` for the owner to complete, and the slots are added automatically when that invoice is paid. Until then further changes are refused with 409 `payment_pending`. `request_id` (8 to 64 letters, digits, `_` or `-`) makes a retry safe: the same id never buys twice, so use a fresh one for each attempt. `expected_current_extra_accounts` and `expected_interval` (optional) pin the quote you showed: if either changed since, nothing is charged and the answer is 409 `quote_stale`. Workspace owner only. Requires the `billing:write` scope. Bypasses the API add-on paywall.

## Request body

- ExtraAccountsChangeRequest
  - `extra_accounts` integer, required: Desired TOTAL of paid extra accounts (not the number to add). 0 removes all. An increase must add at least 20.
  - `dry_run` boolean: true returns the exact quote and charges nothing.
  - `request_id` string: Makes a retry safe: the same id never buys twice. Use a fresh request_id for each attempt; the same id with a different request returns 409 request_id_reused.
  - `expected_current_extra_accounts` integer: Optional. The paid extra accounts total the quote was based on. If the live total differs, nothing is charged and the answer is 409 quote_stale. The MCP confirm always sends it.
  - `expected_interval` 'month' | 'year': Optional. The billing interval the quote was based on. If it changed, nothing is charged and the answer is 409 quote_stale.
  - `workspace_id` string: Optional workspace to act in.

## Response `200`

The quote (dry_run), the applied change, or a payment link when the card needs confirmation.

- union
  - ExtraAccountsQuoteResponse
    - `dry_run` true, required
    - `quote` object, required
      - `kind` 'none' | 'increase' | 'decrease' | 'remove', required
      - `current_extra_accounts` integer
      - `new_extra_accounts` integer, required
      - `change` integer
      - `included_accounts` integer
      - `account_limit_after` integer
      - `accounts_in_use` integer
      - `interval` 'month' | 'year'
      - `trialing` boolean
      - `price_per_account_cents` integer
      - `current_recurring_cents` integer
      - `new_recurring_cents` integer, required
      - `new_recurring` string
      - `charge_today_cents` integer, required: What the saved card is charged right now (prorated). 0 on a trial, a decrease or no change.
      - `charge_today` string
      - `currency` string
  - ExtraAccountsAppliedResponse
    - `applied` true, required
    - `status` 'applied' | 'unchanged', required
    - `kind` 'none' | 'increase' | 'decrease' | 'remove'
    - `previous_extra_accounts` integer
    - `extra_accounts` integer, required
    - `included_accounts` integer
    - `account_limit` integer, required
    - `accounts_in_use` integer
    - `interval` 'month' | 'year'
    - `price_per_account_cents` integer
    - `recurring_cents` integer
  - ExtraAccountsPaymentRequiredResponse
    - `applied` false, required
    - `status` 'payment_required', required
    - `payment_required` true, required
    - `message` string
    - `hosted_invoice_url` string, nullable, required: Send the owner here to complete the payment. The accounts apply automatically once it is paid.
    - `payment_pending` ExtraAccountsPaymentPending
      - `hosted_invoice_url` string, nullable, required: Stripe-hosted payment page. The owner completes 3D Secure or retries the card there.
      - `requested_extra_accounts` integer, required: The total that applies once the invoice is paid.
      - `amount_due_cents` integer, nullable
      - `expires_at` string, date-time, nullable: Stripe discards the pending change after this time.
    - `kind` 'none' | 'increase' | 'decrease' | 'remove'
    - `previous_extra_accounts` integer
    - `requested_extra_accounts` integer
    - `included_accounts` integer
    - `account_limit_after_payment` integer
    - `interval` 'month' | 'year'
    - `price_per_account_cents` integer
    - `recurring_cents` integer

## Other responses

- `400`: Validation error
- `401`: Invalid or missing API key
- `402`: The card was declined at charge time (`payment_failed`) or the bank needs authentication that cannot be completed through a payment link (`payment_requires_authentication`). Nothing was added.
- `403`: Request is authenticated but not allowed
- `404`: Resource not found
- `409`: A previous purchase is still waiting on payment (`payment_pending`, with its payment link), the quote is out of date (`quote_stale`: get a new quote), the request_id was already used for a different request (`request_id_reused`), or the extra accounts changed concurrently (`concurrent_change`).
- `429`: Too many requests
- `502`: The change could not be priced right now (`quote_unavailable`). Try again.
- `503`: Billing is not configured, or connected-account usage could not be checked for a decrease. Nothing changed.

---

[API](https://skmtc.dev/poster/apis/posterly-api.md) · [All operations](https://skmtc.dev/poster/apis/posterly-api/llms.txt) · [OpenAPI document](https://skmtc.dev/poster/apis/posterly-api/revisions/60be02a61f95?raw)
