Projects

Group resources, scope credentials, and attribute spend inside one workspace

A workspace is who you are: it holds your identity, your members, your plan, and one invoice. A project is where work happens inside it. A project groups the resources you create in it and the spend you incur from it, so a workspace can run several environments or several end customers without splitting into several accounts.

Every workspace has an implicit Default project. It is not a row you create or delete: any resource with no project lives there, which is where everything sits until you make your first project.

A project is a filter and a grouping, not a security boundary. It scopes what a credential may reach, what a scoped member sees, and where spend lands. If you need one team to be unable to see another team’s data at all, use a separate workspace.

Creating a project

$curl -X POST "https://api.speechify.ai/v1/projects" \
> -H "Authorization: Bearer $SPEECHIFY_API_KEY" \
> -H "Content-Type: application/json" \
> -d '{"name": "Production"}'

Names are unique per workspace, case-insensitively. A workspace holds at most 100 live projects; at the cap the create is refused with 409 project_limit_reached.

What a project groups

KindBelongs to a project
Agents, knowledge bases, tools, audio assetsYes, and the project can be changed later
Phone numbers and SIP trunksYes
API keys and service accountsYes, as a pin fixed when the credential is created
Vault credentials and webhook endpointsEither one project, or workspace-wide
Conversations, callers, batch calls, test runs, memoriesYes, frozen at creation and never re-attributed
Usage and spendYes, attributed through the calling credential’s pin
The voice and model catalogNo, it is workspace-wide

A derived record keeps the project it was created in even if its agent later moves, because your usage grouping and your invoice already report it that way.

Every list endpoint that takes a project accepts a project_id query parameter. Omit it to get everything you can reach, pass a proj_... id for one project, or pass the literal default for resources that sit in the implicit Default project.

$curl "https://api.speechify.ai/v1/agents?project_id=proj_01jqr8x9zg5k2m3n4p5q6r7s8t" \
> -H "Authorization: Bearer $SPEECHIFY_API_KEY"

Pinning a credential

An API key or a service account can be pinned to one project when you create it. A pinned credential reads and writes only inside that project, its requests are attributed to that project, and it is subject to that project’s limits.

The pin is fixed at creation and cannot be edited afterwards, so re-scoping means minting a new credential and retiring the old one. A credential with no pin is workspace-wide.

What a grant does

By default every workspace member sees the whole workspace. Granting a member a project narrows them to the projects they hold: from their first grant onward, they see and work in those projects only, in the console and through the API.

  • A member with no grants anywhere is workspace-wide. That is the default state, not a gap.
  • Removing a member’s last grant returns them to workspace-wide access. To narrow someone, grant them the projects they should keep rather than revoking everything.
  • Owners and billing admins cannot be scoped: both already hold workspace-wide access that a project grant would contradict without narrowing anything.
  • A pending invite can carry projects, so an invitee is scoped from the moment they accept.
$curl -X POST "https://api.speechify.ai/v1/projects/proj_01jqr8x9zg5k2m3n4p5q6r7s8t/members" \
> -H "Authorization: Bearer $SPEECHIFY_API_KEY" \
> -H "Content-Type: application/json" \
> -d '{"user_id": "user_kb3fim3yjnyto3kxli4g4ysdmyzgiuttjrudswlkgbawk"}'

Limits and capacity

A project can carry its own ceilings, each sitting under the workspace’s own plan limits so one project cannot consume the whole allowance:

SettingEffect when reached
Monthly spend limitNew billable work attributed to the project is refused with 402 project_spend_limit_exceeded, resetting at the calendar-month boundary (UTC)
Max concurrent callsA call over the ceiling is refused with 429 concurrency_limit_reached, while sibling projects keep their headroom
Max requests per minuteA request from a credential pinned to the project is refused with 429 rate_limited, while other projects and unpinned credentials are untouched

A project limit bounds work; it does not split the bill. The invoice stays workspace-level, and per-project cost shows up as a grouping on the workspace usage breakdown.

Archiving a project

Archiving suspends a project without removing anything. From then on nothing new starts or bills inside it: conversation and widget sessions, inbound and outbound calls, batch calls, test runs, knowledge-base imports, and any synthesis or gateway request on a credential pinned to the project are all refused with 409 project_archived. Work already in flight is left to finish.

Everything in the project stays readable and its configuration stays editable. Archiving is idempotent and reversible: unarchive the project and work resumes.

Deleting a project

Deleting runs in one of two modes.

Detach is the default. Only the grouping is removed, and every resource in the project moves to the Default project. It is refused with 409 project_has_scoped_credentials while an API key, service account, vault credential, webhook endpoint, member grant, or pending invite is scoped to the project, because detaching any of those would silently widen it.

Purge removes the project together with its contents in one transaction. It is available only on an archived project, so an irreversible teardown always has a state you can sit in and reverse first; a live project is refused with 409 project_not_archived.

$# Detach (the default): the grouping row goes, every resource moves to Default.
$curl -X DELETE "https://api.speechify.ai/v1/projects/proj_01jqr8x9zg5k2m3n4p5q6r7s8t" \
> -H "Authorization: Bearer $SPEECHIFY_API_KEY"
$
$# Purge: archived projects only, and `confirm` must equal the project's exact name.
>curl -X DELETE "https://api.speechify.ai/v1/projects/proj_01jqr8x9zg5k2m3n4p5q6r7s8t" \
> -H "Authorization: Bearer $SPEECHIFY_API_KEY" \
> -H "Content-Type: application/json" \
> -d '{"mode": "purge", "confirm": "Production"}'
Purge removesPurge keeps
Agents with their tests, knowledge bases with their documents, tools, audio assetsConversations, with their frozen attribution
Webhook endpoints and vault credentials scoped to the projectCallers, batch calls, suite runs, and memories, which move to the Default project
API keys and service accounts pinned to the project, which are revoked
Member grants and pending-invite scopes on the project, which are cleared

A purge is refused while a phone number is still attached, while a member’s only grant is this project, or while a live invite carries only this project, since clearing either would widen that person to the whole workspace.

Both modes have a preview that reports what the delete would do without doing it: whether a purge is available right now, every row holding the project open and which mode each refuses, what a purge would remove, and the operational records it would keep.

A purge has no undo. Preview it first, and read the list of records it keeps: a project teardown that reads as total and is not would be worse than none.

Promoting a project

Promoting copies one project’s configuration into another project in the same workspace: build in staging, promote to production, tear staging down.

Copied: agents with every setting, tool definitions, knowledge bases with their folders, audio assets, and the webhook endpoints scoped to the source. Never copied: vault credentials, API keys and service accounts, phone numbers and SIP trunks, conversations, callers, memories, call and test history, member grants, spend limits, and every secret. A copied item whose credential reference was cleared, whose secret was minted fresh, or whose name collided in the target is listed for you rather than silently half-configured.

What projects scope in SpeechifyAI Build

Build and Agents share one workspace, and projects apply to them differently. The short answer: projects scope what you build with Agents, and they scope what everything costs. They do not scope the Build catalog, and Build creates almost nothing to scope.

In BuildDoes a project apply
Spend and usage attributionYes, through the calling key’s pin
A project’s monthly spend limitYes, it can refuse a Build request outright with 402 project_spend_limit_exceeded
A project’s requests-per-minute ceilingYes, for credentials pinned to that project
The voice catalog, including your cloned voicesNo, it is workspace-wide
The model catalogNo, it is workspace-wide
Text to speech, Dialogue, and the Waymark gatewayNo resource is created, so there is nothing to group

Two consequences are worth stating plainly, because they are the ones most often misread:

  • A project’s budget can stop a Build request even though Build creates nothing inside the project. Per-project Build cost is a statement about your API traffic, not about your console use.
  • The pin belongs to an API key, so a console session never carries one. Everything a person does in the Build UI, including cloning a voice, is workspace-level spend with no project, whichever project the console is showing.

A voice clone created by a project-pinned credential does record that project alongside the workspace. The voice catalog itself stays workspace-wide, so every member of the workspace can list and use that clone.

Managing projects

Projects are managed in the console under Settings → Workspace → Projects: create and rename them, set their limits, grant members access, archive and unarchive, preview and run a delete, and promote one project into another. The scope picker in the top bar chooses the workspace and the project the console is showing.