---
title: "Projects — API reference"
description: "Group your services into projects (e.g. one per business, client or environment). Every service is in exactly one project; services without one are in"
url: https://www.gyrohosting.com/developers/en/api/projects.html
language: en
openapi: https://www.gyrohosting.com/developers/openapi.json
api_version: 2.30.0
---

# Projects

Group your services into projects (e.g. one per business, client or environment). Every service is in exactly one project; services without one are in the default project (id 0). Invoices are not split by project.

Base URL: `https://www.gyrohosting.com/api/v1/client` · OpenAPI: https://www.gyrohosting.com/developers/openapi.json


## GET /cloud/projects

**List projects** · operationId `listProjects` · scope `services_read` · OpenAPI fragment: https://www.gyrohosting.com/developers/spec/ops/listProjects.json

Your projects; the default project (id 0) is always first. Counts follow the key's service scope.


### Responses

- **200**: Projects
- **401**: Missing, invalid or revoked key
- **403**: Key lacks the scope, IP not allowed, or feature disabled

### Examples

```bash
curl -s 'https://www.gyrohosting.com/api/v1/client/cloud/projects' \
  -H "Authorization: Bearer $GYRO_TOKEN"
```
```bash
gyro project list
```
```hcl
# resource gyro_project: https://registry.terraform.io/providers/gyro-hosting/gyro/latest/docs/resources/project
# A project per business / client / environment. Destroying it only deletes the project:
# its services go back to the default project (id 0).
resource "gyro_project" "gyroproje" {
  name        = "Gyro Proje"
  description = "Web + API + CDN"
  color       = "blue"
  icon        = "rocket-takeoff"
}

# New servers and load balancers can be ordered straight into a project.
resource "gyro_server" "web" {
  plan          = "standart-2-4"
  region        = "tr-ist-1"
  image         = "ubuntu-24.04"
  confirm_order = true
  project_id    = tonumber(gyro_project.gyroproje.id)
}
```
```python
import os, uuid, requests

h = {"Authorization": "Bearer " + os.environ["GYRO_TOKEN"]}
r = requests.get("https://www.gyrohosting.com/api/v1/client/cloud/projects", headers=h, timeout=60)
r.raise_for_status()
print(r.json()["data"])
```
```js
const res = await fetch("https://www.gyrohosting.com/api/v1/client/cloud/projects", {
  method: "GET",
  headers: {
    "Authorization": `Bearer ${process.env.GYRO_TOKEN}`,
  },
});
const { data, error } = await res.json();
if (!res.ok) throw new Error(`${error.code}: ${error.message}`);
```


## POST /cloud/projects

**Create a project** · operationId `createProject` · scope `services_write` · OpenAPI fragment: https://www.gyrohosting.com/developers/spec/ops/createProject.json

At most 50 projects per account (409 `project_limit`). Optional `service_ids` move services in at once. Writes: 60 per minute per key (429 `rate_limited`). Sub-account keys cannot create, rename or delete projects (403 `subkey_forbidden`). Errors: 422 `invalid_name`, `name_reserved`, `invalid_color`, `invalid_icon`, `invalid_description`, `invalid_service_ids`; 409 `name_taken`; 404 `service_not_found`.


### Request body

| Field | Type | Description |
|---|---|---|
| `name` (required) | string | Letter or digit first; then letters, digits, space and . _ - / + # & ( ). Unique per account (case-insensitive). Reserved: Genel, General, Default. |
| `description` | string / null |  |
| `color` | string (gray, blue, green, red, orange, yellow, purple, pink, teal, indigo) |  |
| `icon` | string (folder, briefcase, building, cart3, cloud, code-slash, controller, globe2, heart, house, kanban, lightning, people, rocket-takeoff, shield-lock, shop, star, tools, truck, box-seam, mortarboard, camera) |  |
| `service_ids` | array<integer> | Optional: move these services into the new project at once |

### Responses

- **201**: Created
- **409**: name_taken / project_limit
- **422**: Validation error
- **401**: Missing, invalid or revoked key
- **403**: Key lacks the scope, IP not allowed, or feature disabled
- **404**: Not found — also returned for objects owned by someone else
- **429**: Too many requests (`rate_limited`); see the `Retry-After` and `X-RateLimit-*` headers

### Examples

```bash
curl -s -X POST 'https://www.gyrohosting.com/api/v1/client/cloud/projects' \
  -H "Authorization: Bearer $GYRO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "Gyro Proje", "color": "blue", "icon": "rocket-takeoff", "service_ids": [12345]}'
```
```bash
gyro project create --help    # all flags
```
```hcl
# resource gyro_project: https://registry.terraform.io/providers/gyro-hosting/gyro/latest/docs/resources/project
# A project per business / client / environment. Destroying it only deletes the project:
# its services go back to the default project (id 0).
resource "gyro_project" "gyroproje" {
  name        = "Gyro Proje"
  description = "Web + API + CDN"
  color       = "blue"
  icon        = "rocket-takeoff"
}

# New servers and load balancers can be ordered straight into a project.
resource "gyro_server" "web" {
  plan          = "standart-2-4"
  region        = "tr-ist-1"
  image         = "ubuntu-24.04"
  confirm_order = true
  project_id    = tonumber(gyro_project.gyroproje.id)
}
```
```python
import os, uuid, requests

h = {"Authorization": "Bearer " + os.environ["GYRO_TOKEN"]}
r = requests.post("https://www.gyrohosting.com/api/v1/client/cloud/projects", headers=h, json={"name": "Gyro Proje", "color": "blue", "icon": "rocket-takeoff", "service_ids": [12345]}, timeout=60)
r.raise_for_status()
print(r.json()["data"])
```
```js
const res = await fetch("https://www.gyrohosting.com/api/v1/client/cloud/projects", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.GYRO_TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({"name": "Gyro Proje", "color": "blue", "icon": "rocket-takeoff", "service_ids": [12345]}),
});
const { data, error } = await res.json();
if (!res.ok) throw new Error(`${error.code}: ${error.message}`);
```


## GET /cloud/projects/{id}

**Get a project with its service ids** · operationId `getProject` · scope `services_read` · OpenAPI fragment: https://www.gyrohosting.com/developers/spec/ops/getProject.json

Another account's project answers 404 `project_not_found`.


### Parameters

| Field | in | Type | Description |
|---|---|---|---|
| `id` (required) | path | integer | Project id (0 = default project) |

### Responses

- **200**: Project
- **401**: Missing, invalid or revoked key
- **403**: Key lacks the scope, IP not allowed, or feature disabled
- **404**: Not found — also returned for objects owned by someone else
- **429**: Too many requests (`rate_limited`); see the `Retry-After` and `X-RateLimit-*` headers

### Examples

```bash
curl -s 'https://www.gyrohosting.com/api/v1/client/cloud/projects/12345' \
  -H "Authorization: Bearer $GYRO_TOKEN"
```
```bash
gyro project get 12345
```
```hcl
# resource gyro_project: https://registry.terraform.io/providers/gyro-hosting/gyro/latest/docs/resources/project
# A project per business / client / environment. Destroying it only deletes the project:
# its services go back to the default project (id 0).
resource "gyro_project" "gyroproje" {
  name        = "Gyro Proje"
  description = "Web + API + CDN"
  color       = "blue"
  icon        = "rocket-takeoff"
}

# New servers and load balancers can be ordered straight into a project.
resource "gyro_server" "web" {
  plan          = "standart-2-4"
  region        = "tr-ist-1"
  image         = "ubuntu-24.04"
  confirm_order = true
  project_id    = tonumber(gyro_project.gyroproje.id)
}
```
```python
import os, uuid, requests

h = {"Authorization": "Bearer " + os.environ["GYRO_TOKEN"]}
r = requests.get("https://www.gyrohosting.com/api/v1/client/cloud/projects/12345", headers=h, timeout=60)
r.raise_for_status()
print(r.json()["data"])
```
```js
const res = await fetch("https://www.gyrohosting.com/api/v1/client/cloud/projects/12345", {
  method: "GET",
  headers: {
    "Authorization": `Bearer ${process.env.GYRO_TOKEN}`,
  },
});
const { data, error } = await res.json();
if (!res.ok) throw new Error(`${error.code}: ${error.message}`);
```


## PATCH /cloud/projects/{id}

**Rename / recolour a project** · operationId `updateProject` · scope `services_write` · OpenAPI fragment: https://www.gyrohosting.com/developers/spec/ops/updateProject.json

Send any of name, description, color, icon. The default project cannot be changed (409 `default_project`). Writes: 60 per minute per key (429 `rate_limited`). Sub-account keys cannot create, rename or delete projects (403 `subkey_forbidden`).


### Parameters

| Field | in | Type | Description |
|---|---|---|---|
| `id` (required) | path | integer | Project id (0 = default project) |

### Request body

| Field | Type | Description |
|---|---|---|
| `name` | string | Letter or digit first; then letters, digits, space and . _ - / + # & ( ). Unique per account (case-insensitive). Reserved: Genel, General, Default. |
| `description` | string / null |  |
| `color` | string (gray, blue, green, red, orange, yellow, purple, pink, teal, indigo) |  |
| `icon` | string (folder, briefcase, building, cart3, cloud, code-slash, controller, globe2, heart, house, kanban, lightning, people, rocket-takeoff, shield-lock, shop, star, tools, truck, box-seam, mortarboard, camera) |  |

### Responses

- **200**: Updated
- **409**: name_taken / default_project
- **401**: Missing, invalid or revoked key
- **403**: Key lacks the scope, IP not allowed, or feature disabled
- **404**: Not found — also returned for objects owned by someone else
- **429**: Too many requests (`rate_limited`); see the `Retry-After` and `X-RateLimit-*` headers

### Examples

```bash
curl -s -X PATCH 'https://www.gyrohosting.com/api/v1/client/cloud/projects/12345' \
  -H "Authorization: Bearer $GYRO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "string", "description": "string", "color": "gray", "icon": "folder"}'
```
```bash
gyro project rename 12345 --help    # all flags
```
```hcl
# resource gyro_project: https://registry.terraform.io/providers/gyro-hosting/gyro/latest/docs/resources/project
# A project per business / client / environment. Destroying it only deletes the project:
# its services go back to the default project (id 0).
resource "gyro_project" "gyroproje" {
  name        = "Gyro Proje"
  description = "Web + API + CDN"
  color       = "blue"
  icon        = "rocket-takeoff"
}

# New servers and load balancers can be ordered straight into a project.
resource "gyro_server" "web" {
  plan          = "standart-2-4"
  region        = "tr-ist-1"
  image         = "ubuntu-24.04"
  confirm_order = true
  project_id    = tonumber(gyro_project.gyroproje.id)
}
```
```python
import os, uuid, requests

h = {"Authorization": "Bearer " + os.environ["GYRO_TOKEN"]}
r = requests.patch("https://www.gyrohosting.com/api/v1/client/cloud/projects/12345", headers=h, json={"name": "string", "description": "string", "color": "gray", "icon": "folder"}, timeout=60)
r.raise_for_status()
print(r.json()["data"])
```
```js
const res = await fetch("https://www.gyrohosting.com/api/v1/client/cloud/projects/12345", {
  method: "PATCH",
  headers: {
    "Authorization": `Bearer ${process.env.GYRO_TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({"name": "string", "description": "string", "color": "gray", "icon": "folder"}),
});
const { data, error } = await res.json();
if (!res.ok) throw new Error(`${error.code}: ${error.message}`);
```


## DELETE /cloud/projects/{id}

**Delete a project** · operationId `deleteProject` · scope `services_write` · OpenAPI fragment: https://www.gyrohosting.com/developers/spec/ops/deleteProject.json

Only the project is deleted: its services go back to the default project, nothing else changes. Writes: 60 per minute per key (429 `rate_limited`). Sub-account keys cannot create, rename or delete projects (403 `subkey_forbidden`).


### Parameters

| Field | in | Type | Description |
|---|---|---|---|
| `id` (required) | path | integer | Project id (0 = default project) |

### Responses

- **200**: Deleted
- **409**: default_project
- **401**: Missing, invalid or revoked key
- **403**: Key lacks the scope, IP not allowed, or feature disabled
- **404**: Not found — also returned for objects owned by someone else
- **429**: Too many requests (`rate_limited`); see the `Retry-After` and `X-RateLimit-*` headers

### Examples

```bash
curl -s -X DELETE 'https://www.gyrohosting.com/api/v1/client/cloud/projects/12345' \
  -H "Authorization: Bearer $GYRO_TOKEN"
```
```bash
gyro project delete 12345
```
```hcl
# resource gyro_project: https://registry.terraform.io/providers/gyro-hosting/gyro/latest/docs/resources/project
# A project per business / client / environment. Destroying it only deletes the project:
# its services go back to the default project (id 0).
resource "gyro_project" "gyroproje" {
  name        = "Gyro Proje"
  description = "Web + API + CDN"
  color       = "blue"
  icon        = "rocket-takeoff"
}

# New servers and load balancers can be ordered straight into a project.
resource "gyro_server" "web" {
  plan          = "standart-2-4"
  region        = "tr-ist-1"
  image         = "ubuntu-24.04"
  confirm_order = true
  project_id    = tonumber(gyro_project.gyroproje.id)
}
```
```python
import os, uuid, requests

h = {"Authorization": "Bearer " + os.environ["GYRO_TOKEN"]}
r = requests.delete("https://www.gyrohosting.com/api/v1/client/cloud/projects/12345", headers=h, timeout=60)
r.raise_for_status()
print(r.json()["data"])
```
```js
const res = await fetch("https://www.gyrohosting.com/api/v1/client/cloud/projects/12345", {
  method: "DELETE",
  headers: {
    "Authorization": `Bearer ${process.env.GYRO_TOKEN}`,
  },
});
const { data, error } = await res.json();
if (!res.ok) throw new Error(`${error.code}: ${error.message}`);
```


## POST /cloud/projects/{id}/services

**Move services into a project** · operationId `moveServicesToProject` · scope `services_write` · OpenAPI fragment: https://www.gyrohosting.com/developers/spec/ops/moveServicesToProject.json

All ids must be your services within the key's scope, else 404 `service_not_found` and nothing moves. Up to 500 per call; id 0 = default project. Sub-account keys need the `project:move` action. Writes: 60 per minute per key (429 `rate_limited`).


### Parameters

| Field | in | Type | Description |
|---|---|---|---|
| `id` (required) | path | integer | Project id (0 = default project) |

### Request body

| Field | Type | Description |
|---|---|---|
| `service_ids` (required) | array<integer> |  |

### Responses

- **200**: Moved
- **401**: Missing, invalid or revoked key
- **403**: Key lacks the scope, IP not allowed, or feature disabled
- **404**: Not found — also returned for objects owned by someone else
- **429**: Too many requests (`rate_limited`); see the `Retry-After` and `X-RateLimit-*` headers

### Examples

```bash
curl -s -X POST 'https://www.gyrohosting.com/api/v1/client/cloud/projects/12345/services' \
  -H "Authorization: Bearer $GYRO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"service_ids": [12345, 12346]}'
```
```bash
gyro project move 12345 --help    # all flags
```
```hcl
# resource gyro_project: https://registry.terraform.io/providers/gyro-hosting/gyro/latest/docs/resources/project
# A project per business / client / environment. Destroying it only deletes the project:
# its services go back to the default project (id 0).
resource "gyro_project" "gyroproje" {
  name        = "Gyro Proje"
  description = "Web + API + CDN"
  color       = "blue"
  icon        = "rocket-takeoff"
}

# New servers and load balancers can be ordered straight into a project.
resource "gyro_server" "web" {
  plan          = "standart-2-4"
  region        = "tr-ist-1"
  image         = "ubuntu-24.04"
  confirm_order = true
  project_id    = tonumber(gyro_project.gyroproje.id)
}
```
```python
import os, uuid, requests

h = {"Authorization": "Bearer " + os.environ["GYRO_TOKEN"]}
r = requests.post("https://www.gyrohosting.com/api/v1/client/cloud/projects/12345/services", headers=h, json={"service_ids": [12345, 12346]}, timeout=60)
r.raise_for_status()
print(r.json()["data"])
```
```js
const res = await fetch("https://www.gyrohosting.com/api/v1/client/cloud/projects/12345/services", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.GYRO_TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({"service_ids": [12345, 12346]}),
});
const { data, error } = await res.json();
if (!res.ok) throw new Error(`${error.code}: ${error.message}`);
```


## PUT /cloud/services/{id}/project

**Set the project of a service** · operationId `setServiceProject` · scope `services_write` · OpenAPI fragment: https://www.gyrohosting.com/developers/spec/ops/setServiceProject.json

`project_id` 0 = default project. Answers the service (with `project`). Sub-account keys need the `project:move` action.


### Parameters

| Field | in | Type | Description |
|---|---|---|---|
| `id` (required) | path | integer | Service id |

### Request body

| Field | Type | Description |
|---|---|---|
| `project_id` (required) | integer |  |

### Responses

- **200**: Service
- **422**: project_id_required / invalid_project_id
- **401**: Missing, invalid or revoked key
- **403**: Key lacks the scope, IP not allowed, or feature disabled
- **404**: Not found — also returned for objects owned by someone else
- **429**: Too many requests (`rate_limited`); see the `Retry-After` and `X-RateLimit-*` headers

### Examples

```bash
curl -s -X PUT 'https://www.gyrohosting.com/api/v1/client/cloud/services/12345/project' \
  -H "Authorization: Bearer $GYRO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"project_id": 1}'
```
```bash
gyro service project set 12345 --help    # all flags
```
```hcl
# resource gyro_service_project: https://registry.terraform.io/providers/gyro-hosting/gyro/latest/docs/resources/service_project
# Put any existing service (DNS, storage, mail, containers, VDS ...) into a project.
resource "gyro_service_project" "dns" {
  service_id = 12345
  project_id = tonumber(gyro_project.gyroproje.id)
}
```
```python
import os, uuid, requests

h = {"Authorization": "Bearer " + os.environ["GYRO_TOKEN"]}
r = requests.put("https://www.gyrohosting.com/api/v1/client/cloud/services/12345/project", headers=h, json={"project_id": 1}, timeout=60)
r.raise_for_status()
print(r.json()["data"])
```
```js
const res = await fetch("https://www.gyrohosting.com/api/v1/client/cloud/services/12345/project", {
  method: "PUT",
  headers: {
    "Authorization": `Bearer ${process.env.GYRO_TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({"project_id": 1}),
});
const { data, error } = await res.json();
if (!res.ok) throw new Error(`${error.code}: ${error.message}`);
```
