> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tuco.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Create Agency Workspace

> Create a new client workspace inside your Tuco agency, subscribe it to a plan, and get its workspace API key back — in one call.

<Note>
  Creates a workspace under your agency, optionally **subscribes it to a plan**,
  and returns a ready-to-use **workspace API key** for it — so an onboarding
  script never has to stop and mint a key or make a second billing call by hand.
</Note>

## Endpoint

* **Method**: `POST`
* **Path**: `/api/agency/subaccounts`
* **Auth**: `Authorization: Bearer tucoagency_xxxxxxxxxxxxx` ([agency key](/api-reference/agency-api-keys))

## Body

| Field | Type | Required | Notes |
| - | - | - | - |
| `name` | string | yes | Display name, max 120 characters |
| `legalName` | string | no | The client's legal/LLC name, max 200 characters |
| `timezone` | string | no | IANA zone (e.g. `America/Denver`). Sets the daily-cap reset window. Invalid zones are rejected with `400` |
| `plan` | string | no | `starter` or `growth`. Subscribes the workspace in the same call — see below. Omit to create it unsubscribed |

## Example request

```bash theme={null}
curl https://app.tuco.ai/api/agency/subaccounts \
  -H "Authorization: Bearer tucoagency_xxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme Roofing",
    "legalName": "Acme Roofing LLC",
    "timezone": "America/Denver",
    "plan": "growth"
  }'
```

## Success response (200)

```json theme={null}
{
  "success": true,
  "subAccount": {
    "clerkOrgId": "org_3KKLH9HaVf4KyI6TiNhQk4T0cfa",
    "name": "Acme Roofing",
    "agencyId": "user_3H08IRicrVUYLDZRyOh4jKRVwrx",
    "isAgencyWorkspace": true
  },
  "workspaceApiKey": "tuco_xCsfhTiXXXXXXXXXXXXXXXXXXXXXXXX",
  "workspaceApiKeyWarning": "Save this workspace key now. You will not be able to see it again.",
  "plan": "growth",
  "subscriptionStatus": "active",
  "billingMode": "invoice",
  "planError": null
}
```

The last four fields appear **only when you passed `plan`**. Omit it and the
response is exactly what it always was.

<Warning>
  `workspaceApiKey` is shown **once**. Store it when you create the workspace — it
  cannot be retrieved later, only replaced from the workspace's Integrations page.
</Warning>

It is a normal workspace key: it works on every documented endpoint for that
workspace, and on no other workspace. It is **not** an agency key and cannot reach
the agency endpoints.

In the rare case key creation fails, the workspace is still created and
`workspaceApiKey` is `null` — make one from the workspace's Integrations page.

## Subscribing in the same call

A plan is not optional in practice. `plan` is what grants a workspace its line
limits, and an agency workspace with no plan is refused outright — a line
transfer into one fails. So every onboarding script made the second call anyway.
`plan` on create collapses the two.

| Plan | |
| - | - |
| `starter` | \$149/mo + one-time setup |
| `growth` | Higher line limits |

<Note>
  There is no `enterprise` plan. `email-only` (Mini) exists but is retired and is
  rejected for new subscriptions. Workspaces already on it keep renewing.
</Note>

It runs the same billing path as
[`POST /api/agency/billing/subscribe`](/api-reference/endpoint/agency-subscribe),
so the behaviour matches exactly:

* **Invoiced agency** — the workspace gets the plan and **no card is charged**.
  `billingMode: "invoice"`, and no Stripe subscription exists for it, which is
  what makes your client structurally unreachable by dunning and payment mail.
  **Line caps do not apply either** — see below.
* **Stripe agency** — your saved card is charged off-session, as it would be on
  the standalone route. `billingMode: "stripe"`.

### An invalid plan is rejected before anything is created

```json theme={null}
{
  "error": "Unknown plan \"enterprise\".",
  "code": "INVALID_PLAN",
  "validPlans": ["starter", "growth"]
}
```

`400`, and **no workspace exists** — the plan is validated before the workspace
is created, so a typo cannot leave an orphan behind.

### A billing failure does not lose the workspace

If the plan cannot be applied *after* the workspace exists — a declined card,
Stripe unreachable — you still get `200`, the workspace, and its key:

```json theme={null}
{
  "success": true,
  "subAccount": { "clerkOrgId": "org_3KKLH9HaVf4KyI6TiNhQk4T0cfa", "…": "…" },
  "workspaceApiKey": "tuco_xCsfhTiXXXXXXXXXXXXXXXXXXXXXXXX",
  "plan": null,
  "subscriptionStatus": "none",
  "planError": "Your card was declined."
}
```

Failing the whole request would hide a workspace that already exists and get you
a duplicate on retry. **Check `planError`**, then retry the billing step alone
with [`POST /api/agency/billing/subscribe`](/api-reference/endpoint/agency-subscribe)
— do not create the workspace again.

### If Tuco invoices your agency, lines are uncapped

Plan line limits exist to meter what a card gets charged for. When Tuco invoices
your agency offline for the whole group, there is nothing for them to meter —
they can only block a line you have already agreed to pay for.

So for an invoiced agency, **every client workspace can order any number of
lines**, whatever plan it carries. It applies to all three paths —
[ordering a line](/api-reference/endpoint/create-line-request),
[creating one directly](/api-reference/lines), and the
[capacity the dashboard reports](/api-reference/endpoint/line-limits), which
returns `unlimitedReason: "invoiced_agency"`.

<Note>
  This is a commercial arrangement, not a setting. Tuco switches it on per agency,
  the same switch that enables [line-health webhooks](/api-reference/endpoint/agency-webhooks).
  On Stripe billing, normal plan caps apply and extra lines are add-on purchases.
</Note>

You still pass a `plan`: it is what sets the workspace's message throughput and
what marks it active. It just stops being a ceiling on lines.

## What the new workspace starts as

* Owned by your agency (`isAgencyWorkspace: true`) — it has no card of its own and
  bills through you.
* `subscriptionStatus: "active"` when you passed a plan, `"none"` otherwise.
  Subscribe it before moving lines in; a transfer into an unsubscribed workspace
  is refused.
* You and your agency co-admins are admins on it, so it appears in the workspace
  switcher immediately.
* It has its own workspace API key, returned above.

## Error responses

| Status | Code | When |
| - | - | - |
| `400` | — | `name` missing, or `timezone` is not a valid IANA zone |
| `400` | `INVALID_PLAN` | Unknown `plan`. The body lists `validPlans` |
| `400` | `RETIRED_PLAN` | `plan: "email-only"` — Mini is retired for new subscriptions |
| `401` | `UNAUTHORIZED` | Missing, unknown, revoked or expired key |
| `403` | `AGENCY_KEY_REQUIRED` | A workspace key (`tuco_…`) was used |
| `403` | `NOT_AN_AGENCY` | The account behind the key is not an agency |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.