Skip to navigation

Projects and Subprojects

View as MarkdownOpen in Claude

Your SignalWire Space can hold everything your business builds, including a separate, isolated workspace for each of your customers. You don’t need a new Space per customer, per app, or per environment. One Space with Projects and Subprojects keeps your billing, your team, and your Dashboard in one place, while each customer still gets its own phone numbers, credentials, and logs.

How the levels fit together

A Space is your SignalWire account’s home, reached at its own subdomain such as example.signalwire.com. Inside it, Projects group what you build, and each Project can hold Subprojects, one level deep. Your Space starts with one Project, created alongside the Space itself, and you can add more at any time.

Space: example.signalwire.com Project: Clinic Platform Project: Main Subproject: Acme Dental Subproject: Bayview Clinic Subproject: Northside Pediatrics

A Subproject is a complete Project in its own right, with its own Project ID, API tokens, phone numbers, and Resources. The only thing it can’t do is hold Subprojects of its own.

What each level owns

The Space owns everything that is about your business as a whole. Every Project and Subproject in it shares these:

  • The Space URL, such as example.signalwire.com, that the Dashboard and every API request go through
  • The balance, payment methods, billing profile, and monthly statements
  • The members of your team and their access levels
  • Trial mode, and Space settings such as geographic permissions
  • Voice and messaging rate limits, counted across every Project in the Space

The Space menu, opened from the Space name at the top of the sidebar, shows your balance and Switch Space. Owners and administrators also see Space Settings, Members, and Usage & Billing.

Projects and Subprojects own everything that is about one workload. Each one keeps its own copy, isolated from the others:

Belongs to each Project and SubprojectWhere to find it in the Dashboard
Project ID, API tokens, and webhook signing keyAPI Credentials
Phone numbersPhone Numbers
Verified caller IDsPhone Numbers > Verified
Resources, such as AI Agents, SIP endpoints, and SubscribersMy Resources
10DLC brands and campaignsMessaging Campaigns
Call, message, and other logsLogs
Recordings and Datasphere documentsStorage
SIP URI, in the form example-<name>.sip.signalwire.comConfiguration > SIP Settings
Media URL protection settingsConfiguration > Project > Settings

How APIs and Resources follow the Project

Every API request is authenticated as one Project. Your code sends the Project ID as the username and one of that Project’s API tokens as the password, to your Space URL; the API Credentials page has all three. The Server SDKs take the same three values, over REST and over Relay. Each token also carries permissions, such as calling, messaging, or numbers, that limit which kinds of requests it can make.

A request acts on the Project it authenticated as. Listing phone numbers, Resources, or logs returns that Project’s alone, and a Subproject’s API token reaches only that Subproject, so credentials you give to one customer’s integration can’t touch another customer’s numbers or logs.

Resources connect only within their Project, too. A phone number can only be assigned to Resources in its own Project, so the AI Agent, SWML script, or SIP endpoint that answers a number has to live beside it. When SignalWire calls your webhooks, it signs each request with the Project’s own signing key, and the Project’s Force Https Requests setting, under Configuration > Project > Settings, decides whether webhooks and callbacks must use HTTPS.

The Compatibility API uses the same structure under different names: a Project’s ID is its Account SID, and its Subprojects are listed as Accounts beneath it.

Choose a structure

The hierarchy has no fixed meaning. A Project is whatever you need to keep separate, so pick the structure that matches who you serve.

Your customers’ customers

If you build a product that other businesses use, give that product a root Project, and give each of your customers a Subproject beneath it.

Take a company that sells appointment-reminder software to medical practices. It creates a root Project called Clinic Platform, and each practice that signs up gets its own Subproject: Acme Dental, Bayview Clinic, Northside Pediatrics. That structure gives each practice:

  • Its own phone numbers, Resources, and logs, listed only inside its Subproject
  • Its own 10DLC brand and campaigns, registered under the practice’s own business name through the Campaign Registry
  • Its own API token, which can’t read or change another practice’s Subproject
  • Its own row on your monthly statement, so you can bill each practice for what it used

Usage from every Subproject draws on the Space’s one balance, so you fund one account and still see each customer’s share. See Bill customers by Project.

Your application doesn’t have to wait for someone to click through the Dashboard: it can create each customer’s Subproject the moment they sign up. See Create a Subproject.

Environments

Keep test traffic away from live customers by giving each environment its own root Project, such as Production and Staging. Numbers, Resources, and credentials stay apart, so a test script with a Staging token can’t reach a Production number, and both environments draw on the same balance.

Teams and products

When different teams or product lines share a Space, give each one a root Project and grant each member only the Projects they work on. Every team keeps its own numbers and logs, and your billing and member list stay in one place.

When to create another Space

Create a separate Space only when you need something that the Space itself owns to be separate:

  • A different balance, payment method, or billing profile, such as a business unit that pays its own bills
  • A completely different set of members
  • A different Space URL

A new customer, a new app, or a new environment doesn’t need a new Space; a Project or Subproject covers it. Every Space is set up, verified, and funded on its own, so splitting work across several Spaces multiplies that setup and spreads your usage and team across several Dashboards.

Work with Projects in the Dashboard

The Project name at the top of the Dashboard opens the Project menu, where every Project-level action starts: Project Configuration opens the active Project’s settings, Switch Project changes which Project the Dashboard shows, and Create New Project adds a root Project. A Project’s Project ID, Space URL, API tokens, and signing key are on its API Credentials page, which always shows the active Project.

Creating a root Project takes the owner or administrator access level. Any member who can open a root Project can create Subprojects beneath it.

1

Create a root Project

Open the Project menu, select Create New Project, enter a name, and select Save. The Dashboard switches to the new Project.

2

Add Subprojects

With the root Project selected, open Configuration > Subprojects in the sidebar. The page lists the Project’s Subprojects, and New opens the Create a New Subproject form. Enter the Subproject’s name and select Save.

Configuration > Subprojects appears only while a root Project is selected, since a Subproject can’t hold Subprojects of its own.

After you save, the Dashboard switches to the new Subproject. To add another, select the root Project again first.

3

Switch between Projects

Open the Project menu and select Switch Project. Subprojects are listed under their root Project, and the header shows both names while a Subproject is selected, for example Clinic Platform / Northside Pediatrics. The list shows up to 10 Subprojects under each root Project; to see every one, select the root Project and open Configuration > Subprojects.

The Select a Project page listing Clinic Platform with Acme Dental, Bayview Clinic, and Northside Pediatrics indented beneath it as Subprojects, followed by a second root Project named Main. The header reads Clinic Platform / Northside Pediatrics.

Switch Project lists each Subproject beneath its root Project
4

Give your team access

Open the Space menu, select Members, then Invite. Choose an Access Level of User or Administrator, and under Project Access turn on each root Project the person should reach.

Access to a root Project includes all of its Subprojects, so Project Access lists root Projects only. A member sees only the Projects they’ve been granted, along with their Subprojects.

To change an existing member’s access over the API, use Enable a member for a project and List a member’s projects with a Personal access token.

To confirm the setup, open Switch Project: each Subproject should appear indented under its root Project. If Configuration > Subprojects is missing from the sidebar, a Subproject is selected; switch to its root Project and look again.

To rename or delete a Project, select it and open Project Configuration from the Project menu. A Project can be deleted with Delete Project only after its phone numbers and Subprojects are removed, and a Space’s only Project can’t be deleted. Deleting a Project invalidates its API tokens and settings immediately and can’t be undone.

Create and delete Subprojects through the API

An application can open and retire Subprojects on its own, one per customer, per tenant, or per environment, by calling the Projects API with a Project’s API token. Root Projects are created in the Dashboard, or through the same API with a Personal access token. That token carries your owner or administrator role in the Space rather than a Project’s scopes, so it can create and delete root Projects too.

Create a Subproject

When your application onboards a new customer, it can create the customer’s Subproject and its first API token in two calls, authenticated with the root Project’s credentials. The Server SDKs wrap both calls:

ValueReplace with
<YOUR_SPACE>Your Space name, such as example for example.signalwire.com
<YOUR_PROJECT_ID>The root Project’s Project ID, from API Credentials
<YOUR_API_TOKEN>An API token for the root Project with the Management permission
<YOUR_SUBPROJECT_ID>The id returned when you create the Subproject (cURL only)
# Install: python -m pip install signalwire-sdk
# Save as onboard_customer.py and run: python onboard_customer.py
from signalwire.rest import RestClient
client = RestClient(
project="<YOUR_PROJECT_ID>",
token="<YOUR_API_TOKEN>",
host="<YOUR_SPACE>.signalwire.com",
)
subproject = client.projects.create(name="Acme Dental")
token = client.project.tokens.create(
name="Acme Dental integration",
permissions=["calling", "messaging", "numbers"],
subproject_id=subproject["id"],
)
print("Subproject ID:", subproject["id"])
print("API token:", token["token"])

The calls are Create a project and Create API token. Store the new Subproject’s ID and token in your own records for that customer: your integration authenticates as the customer’s Subproject with that ID as the username and that token as the password. The create request can also set the Subproject’s security settings, such as media URL protection, from the start.

A Subproject can’t create another Subproject, so a create request authenticated as a Subproject fails with 422 nested_subprojects_not_allowed.

SignalWire signs every request it makes to your webhooks with the Project’s signing_key, so your server can verify that a request really came from SignalWire. The API returns that key only in the create response and when you rotate it, so capture it there. Afterward you can read it from the new Project’s API Credentials page in the Dashboard, or replace it with Rotate a project’s signing key, which returns the new key.

Response
{
"id": "8f14e45f-ceea-467d-9c2b-7a1d3a9b2c34",
"name": "Acme Staging",
"parent_project_id": "b3877739-5c7e-4d4f-9d1a-2f0c8c2f1a11",
"subproject": true,
"region_preference": "us-west",
"protect_recordings": false,
"protect_message_media": false,
"protect_fax_media": false,
"force_https_requests": true,
"created_at": "2024-05-06T12:20:00Z",
"updated_at": "2024-05-06T12:20:00Z",
"signing_key": "swpsk_0123456789ab0123456789ab0123456789ab"
}

Delete a Subproject

With a Project’s API token, only Subprojects can be deleted; targeting the root Project returns 422 only_subprojects_can_be_deleted. A Personal access token can delete a root Project as well, once its Subprojects are gone (422 subprojects_must_be_removed), and the last Project in a Space can’t be deleted (422 last_project_cannot_be_deleted).

Release phone numbers first

A Project must have no phone numbers before it can be deleted, or the request returns 422 phone_numbers_must_be_removed. Deleting a Subproject also migrates its registry brands and campaigns up to the parent Project.

DELETE
/api/projects/:id
curl -X DELETE https://{your_space_name}.signalwire.com/api/projects/id \
-u "<project_id>:<api_token>"

Manage Projects through the API

Every Projects API request reaches only the authenticated Project and the Subprojects beneath it. List projects returns the authenticated Project alongside its Subprojects, and each entry reports whether it is a Subproject and which Project it belongs to. A Project ID outside that tree returns 404 Not Found. With a Personal access token the tree is wider: every root Project you are enabled for, plus their Subprojects.

Update a project changes the name and security settings of any Project in that tree, root Project included. Rotate a project’s signing key issues a new webhook-signing key for one. Requests can arrive signed with the old key for a minute or two afterward, so accept either key until the new one is active.

Integrations built around Compatibility API Account SIDs see the same tree as Accounts: Create Subprojects and List accounts cover the same ground with form-encoded requests.

Move a phone number to another Project

If you bought numbers before setting up Subprojects, you can move them where they belong. Open the number from Phone Numbers, select Transfer Number, re-enter the number to confirm, and pick the destination under Transfer to.

A number can move to any Project or Subproject in the same Space that you have access to. The Dashboard blocks the transfer while the number has an E911 address assigned or while a port-in for it is in progress.

To move a number over the API, set AccountSid to the destination Project’s ID with Update an incoming phone number in the Compatibility API. The API also rejects the move while a port-in for the number is in progress.

Bill customers by Project

Each monthly statement includes a Per Project Totals section, which you can filter by Project or search by Project name, and every Subproject appears as its own row. Open it from the Space menu under Usage & Billing > Statements; statements are visible to owners and administrators.

To pull the same breakdown into your own billing system, use Retrieve a statement, which accepts a project filter, or Retrieve usage. Both authenticate with a Personal access token.

Next steps