> Fetch clean Markdown by appending `.md` to any page URL under https://signalwire.com/docs or requesting it with the HTTP header `Accept: text/markdown`. The root index at https://signalwire.com/docs/llms.txt lists the available documentation indexes. # Create a project POST https://%7BYour_Space_Name%7D.signalwire.com/api/projects Content-Type: application/json Creates a project. Which kind depends on the credential: - With a **project API token**, the new project is always a subproject of the authenticated root project, and `parent_project_id` is ignored. Creating while authenticated as a subproject fails with `422 nested_subprojects_not_allowed`, since a subproject cannot contain subprojects. - With a **Personal access token**, omit `parent_project_id` to create a root project, or set it to create a subproject of that project. The parent must be a root project the token holder can reach (`invalid_parent_project_id`, `nested_subprojects_not_allowed`). A new root project has no API token yet. Give it one with [Create API token](/docs/apis/rest/project-tokens/create-token), passing its id as `project_id`. The response includes the `signing_key`. This is the only time it is returned — it cannot be retrieved through the API afterward, so capture it from this response. Use a subproject to isolate settings and resources beneath a root project. Integrations built around Compatibility API Account SIDs can use [Create subprojects](/docs/compatibility-api/rest/accounts/create-subprojects) instead. #### Permissions With a project API token, the token must have the following scope(s) enabled to make a successful request: _Management_. With a [Personal access token](/docs/apis/authorization#personal-access-tokens) there are no scopes. The token holder must be an owner or admin of the space, and the request reaches only the projects the holder is enabled for, plus their subprojects. [Learn more about API scopes](/docs/platform/your-signalwire-api-space). Reference: https://signalwire.com/docs/apis/rest/projects/create-subproject ## Authentication - `Authorization` header (basic auth, required) — SignalWire Basic Authentication using Project ID and API Token. The client sends HTTP requests with the Authorization header containing the word Basic followed by a space and a base64-encoded string of project_id:token. The project ID will be used as the username and the API token as the password. Example: ``` Authorization: Basic base64(project_id:token) ``` - `Authorization` header (basic auth, required) — Personal access token authentication for space-wide administration. Send HTTP Basic auth with an empty username and the Personal access token as the password. A Personal access token carries your own authority rather than a project's: it is created from your user menu in the Dashboard, is prefixed `pat_`, and has no scopes. The holder must be an owner or admin of the space named by the subdomain, and the token acts only on that space. Example: ``` Authorization: Basic base64(:pat_...) ``` ## Request ### Body (application/json) This endpoint expects a Projects.CreateProjectRequest. - `name` (string, required) — The name of the project. - `parent_project_id` (string, optional) — Personal access token only. The root project to create the new project under. Omit it to create a root project. Must name a root project the token holder can reach (`invalid_parent_project_id`, `nested_subprojects_not_allowed`). Ignored with a project API token, which always creates a subproject of its own project. - `protect_recordings` (boolean, optional) — When enabled, recordings created within the project require authentication to access. - `protect_message_media` (boolean, optional) — When enabled, message media created within the project requires authentication to access. - `protect_fax_media` (boolean, optional) — When enabled, fax media created within the project requires authentication to access. - `force_https_requests` (boolean, optional) — When enabled, requests made to the project's webhooks and callbacks must use HTTPS. ## Response ### 201 The request has succeeded and a new resource has been created as a result. - `id` (string, required) — The unique identifier of the project. - `name` (string, required) — The name of the project. - `parent_project_id` (string, required, nullable) — The unique identifier of the root project. `null` when this project is itself a root project. - `subproject` (boolean, required) — `true` when this project is a subproject. - `region_preference` (string, required) — The effective region preference for the project. Returned in all responses; it is not currently settable through this API. - `protect_recordings` (boolean, required) — When enabled, recordings created within the project require authentication to access. - `protect_message_media` (boolean, required) — When enabled, message media created within the project requires authentication to access. - `protect_fax_media` (boolean, required) — When enabled, fax media created within the project requires authentication to access. - `force_https_requests` (boolean, required) — When enabled, requests made to the project's webhooks and callbacks must use HTTPS. - `created_at` (datetime, required) — The date and time when the project was created. - `updated_at` (datetime, required) — The date and time when the project was last updated. - `signing_key` (string, required) — The project's signing key. Only returned on create and signing-key rotation responses; it cannot be retrieved through the API afterward. ## Errors ### 401 Unauthorized Error Access is unauthorized. - `error` (enum, required) - Allowed values: `Unauthorized` ### 422 Unprocessable Entity Error The request could not be processed. Creating while authenticated as a subproject, or naming a subproject as `parent_project_id`, returns `nested_subprojects_not_allowed`. A `parent_project_id` the caller cannot reach returns `invalid_parent_project_id`. A blank or overly long `name` returns a standard validation error. - `errors` (list of Types.StatusCodes.RestApiErrorItem, required) — List of validation errors. ### 500 Internal Server Error An internal server error occurred. - `error` (enum, required) - Allowed values: `Internal Server Error` ## Types ### Types.StatusCodes.RestApiErrorItem Details about a specific error. - `type` (string, required) — The category of error. - `code` (string, required) — A specific error code. - `message` (string, required) — A description of what caused the error. - `url` (string, required) — A link to documentation about this error. - `attribute` (string, optional, nullable) — The request parameter that caused the error, if applicable. ## Examples **Request** ```json { "name": "Acme Staging" } ``` **Response** ```json { "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": "PSK_4d8c2b1a9f3e7c6d5b4a3e2f1d0c9b8a" } ``` **SDK Code** ```python import requests url = "https://{your_space_name}.signalwire.com/api/projects" payload = { "name": "Acme Staging" } headers = { "Content-Type": "application/json" } response = requests.post(url, json=payload, headers=headers, auth=("", "")) print(response.json()) ``` ```javascript const url = 'https://{your_space_name}.signalwire.com/api/projects'; const credentials = btoa(":"); const options = { method: 'POST', headers: { Authorization: `Basic ${credentials}`, 'Content-Type': 'application/json' }, body: '{"name":"Acme Staging"}' }; try { const response = await fetch(url, options); const data = await response.json(); console.log(data); } catch (error) { console.error(error); } ``` ```go package main import ( "fmt" "strings" "net/http" "io" ) func main() { url := "https://{your_space_name}.signalwire.com/api/projects" payload := strings.NewReader("{\n \"name\": \"Acme Staging\"\n}") req, _ := http.NewRequest("POST", url, payload) req.SetBasicAuth("", "") req.Header.Add("Content-Type", "application/json") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := io.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) } ``` ```ruby require 'uri' require 'net/http' url = URI("https://{your_space_name}.signalwire.com/api/projects") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true request = Net::HTTP::Post.new(url) request.basic_auth("", "") request["Content-Type"] = 'application/json' request.body = "{\n \"name\": \"Acme Staging\"\n}" response = http.request(request) puts response.read_body ``` ```java import com.mashape.unirest.http.HttpResponse; import com.mashape.unirest.http.Unirest; HttpResponse response = Unirest.post("https://{your_space_name}.signalwire.com/api/projects") .basicAuth("", "") .header("Content-Type", "application/json") .body("{\n \"name\": \"Acme Staging\"\n}") .asString(); ``` ```php request('POST', 'https://{your_space_name}.signalwire.com/api/projects', [ 'body' => '{ "name": "Acme Staging" }', 'headers' => [ 'Content-Type' => 'application/json', ], 'auth' => ['', ''], ]); echo $response->getBody(); ``` ```csharp using RestSharp; using RestSharp.Authenticators; var client = new RestClient("https://{your_space_name}.signalwire.com/api/projects"); client.Authenticator = new HttpBasicAuthenticator("", ""); var request = new RestRequest(Method.POST); request.AddHeader("Content-Type", "application/json"); request.AddParameter("application/json", "{\n \"name\": \"Acme Staging\"\n}", ParameterType.RequestBody); IRestResponse response = client.Execute(request); ``` ```swift import Foundation let credentials = Data(":".utf8).base64EncodedString() let headers = [ "Authorization": "Basic \(credentials)", "Content-Type": "application/json" ] let parameters = ["name": "Acme Staging"] as [String : Any] let postData = JSONSerialization.data(withJSONObject: parameters, options: []) let request = NSMutableURLRequest(url: NSURL(string: "https://{your_space_name}.signalwire.com/api/projects")! as URL, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0) request.httpMethod = "POST" request.allHTTPHeaderFields = headers request.httpBody = postData as Data let session = URLSession.shared let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in if (error != nil) { print(error as Any) } else { let httpResponse = response as? HTTPURLResponse print(httpResponse) } }) dataTask.resume() ```