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

# Go SDK: workspaces and members

> Create and manage workspaces, invite members, set their roles and share applications with c.Workspaces. Act on a shared app with its composite id.

A workspace shares apps with other Square Cloud users, each with a role. `c.Workspaces` manages workspaces, `c.Workspaces.Members` their members and `c.Workspaces.Apps` the shared apps.

Creating workspaces needs a Standard, Pro or Enterprise plan.

Each snippet below runs on its own inside this program: paste one at a time into `main` and run `goimports` (see [Running the examples](/en/sdks/go/client#running-the-examples)).

```go theme={"system"}
package main

import (
	"context"
	"os"

	"github.com/squarecloudofc/sdk-api-go/v3"
)

var (
	ctx         = context.Background()
	c           = squarecloud.New(os.Getenv("SQUARECLOUD_API_KEY"))
	workspaceID = "0123456789abcdef0123456789abcdef"
	appID       = "abc123def456abc123def456"
	memberID    = "1234567890" // a member's ID, from c.Workspaces.Get
)

func main() {
	// Paste one snippet here, then run goimports.
}
```

## Workspaces

```go theme={"system"}
created, err := c.Workspaces.Create(ctx, "My team")
if err != nil {
	log.Fatal(err)
}

workspace, err := c.Workspaces.Get(ctx, created.ID)
if err != nil {
	log.Fatal(err)
}

fmt.Println(workspace.Name, workspace.Owner, workspace.CreatedAt)

for _, member := range workspace.Members {
	name := "(unknown)"
	if member.Name != nil {
		name = *member.Name
	}
	fmt.Println(member.ID, name, member.Group, member.JoinedAt)
}
for _, app := range workspace.Applications {
	fmt.Println(app.ID, app.Name, app.Lang, app.RAM)
}
```

`Workspaces.List(ctx)` returns every workspace you own or belong to, with the same fields:

```go theme={"system"}
workspaces, err := c.Workspaces.List(ctx)
if err != nil {
	log.Fatal(err)
}
for _, w := range workspaces {
	fmt.Println(w.ID, w.Name, len(w.Members))
}
```

To leave a workspace as a member, or delete it as the owner:

```go theme={"system"}
if err := c.Workspaces.Leave(ctx, workspaceID); err != nil { // as a member
	log.Fatal(err)
}
if err := c.Workspaces.Delete(ctx, workspaceID); err != nil { // as the owner
	log.Fatal(err)
}
```

| Field | Description |
| - | - |
| `ID` (`id`) | 32 hex characters (older workspaces keep a 40-character id) |
| `Name` (`name`) | Workspace name (1 to 32 characters) |
| `Owner` (`owner`) | Owner's user id |
| `Members` (`members`) | `ID`, `Name`, `Group`, `JoinedAt` (`joinedAt`). `Name` is a `*string`, `nil` when it cannot be resolved (a deleted account) |
| `Applications` (`applications`) | `ID`, `Name`, `Description` (`desc`), `RAM`, `Lang`, `Domain`, `Custom`. `Description`, `Domain` and `Custom` are `*string` |
| `CreatedAt` (`createdAt`) | Creation date (`time.Time`) |

The owner cannot leave (400 `CANNOT_LEAVE_OWNER`): delete the workspace instead.

## Members

Adding a member takes an **invite code** that the member generates with `Members.InviteCode(ctx)`. The code is valid for **5 minutes**.

```go theme={"system"}
// The member runs this and sends you the code
code, err := c.Workspaces.Members.InviteCode(ctx)
if err != nil {
	log.Fatal(err)
}
fmt.Println(code)
```

```go theme={"system"}
// The owner adds them with a role
code := "5d8e1f2a3b4c4d6e9f0a1b2c3d4e5f6a" // the code the member sent you
if err := c.Workspaces.Members.Add(ctx, workspaceID, code, squarecloud.GroupMaintain); err != nil {
	log.Fatal(err)
}
```

To change a member's role or remove them, pass their `ID` from `Workspaces.Get`:

```go theme={"system"}
if err := c.Workspaces.Members.Update(ctx, workspaceID, memberID, squarecloud.GroupView); err != nil {
	log.Fatal(err)
}
if err := c.Workspaces.Members.Remove(ctx, workspaceID, memberID); err != nil {
	log.Fatal(err)
}
```

Roles (`WorkspaceGroup`): `GroupView` (`view`), `GroupManager` (`manager`), `GroupMaintain` (`maintain`) and `GroupAdmin` (`admin`). A member's `Group` is a plain `string`, since it can also be `"owner"`. Calling a method that your role does not allow is 403 `PERMISSION_DENIED`.

## Shared applications

```go theme={"system"}
if err := c.Workspaces.Apps.Add(ctx, workspaceID, appID); err != nil {
	log.Fatal(err)
}
if err := c.Workspaces.Apps.Remove(ctx, workspaceID, appID); err != nil {
	log.Fatal(err)
}
```

A workspace can hold up to 100 apps (400 `APPLICATIONS_LIMIT_REACHED`).

### Acting on a shared app

To act on an app shared with you, pass the composite id `<appId>-<workspaceId>` to any `c.Apps` method. `Workspaces.Get` and `Workspaces.List` return raw ids, so build it yourself:

```go theme={"system"}
workspace, err := c.Workspaces.Get(ctx, workspaceID)
if err != nil {
	log.Fatal(err)
}

for _, app := range workspace.Applications {
	status, err := c.Apps.Status(ctx, app.ID+"-"+workspace.ID)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(app.Name, status.Running)
}

// Status of every app of the workspace in one request
statuses, err := c.Apps.StatusAll(ctx, workspaceID)
if err != nil {
	log.Fatal(err)
}
for _, s := range statuses {
	fmt.Println(s.ID, s.Running)
}
```

## Errors

Workspace routes other than `Get` send the ids in the request body, so an empty id there is 400 `INVALID_ID` from the server (not a local error). `Get` sends the id in the path, so an empty id fails locally with `INVALID_ID` (status `0`).

| Status | Code | When |
| - | - | - |
| 400 | `INVALID_NAME` | The name is not 1 to 32 characters |
| 400 | `WORKSPACE_LIMIT_REACHED`, `MEMBERS_LIMIT_REACHED`, `APPLICATIONS_LIMIT_REACHED` | A plan or workspace limit was reached |
| 400 | `INVALID_CODE` | The invite code is missing, malformed or expired |
| 400 | `INVALID_GROUP` | The role is not `view`, `manager`, `maintain` or `admin` |
| 400 | `CANNOT_INVITE_OWNER`, `CANNOT_EDIT_OWNER`, `CANNOT_LEAVE_OWNER` | The action does not apply to the owner |
| 400 | `MEMBER_ALREADY_ADDED`, `APP_ALREADY_IN_WORKSPACE` | Already in the workspace |
| 403 | `UPGRADE_REQUIRED` | The plan cannot create workspaces |
| 403 | `PERMISSION_DENIED` | Your role does not allow the action |
| 404 | `WORKSPACE_NOT_FOUND`, `MEMBER_NOT_FOUND`, `APP_NOT_FOUND` | Not found |

## Next steps

<CardGroup cols={3}>
  <Card title="AI" icon="robot" href="/en/sdks/go/ai">
    Chat completions through the AI Gateway.
  </Card>

  <Card title="Workspace API reference" icon="code" href="/en/api-reference/endpoint/workspace/list">
    The REST endpoints behind these methods.
  </Card>

  <Card title="Workspaces from the CLI" icon="terminal" href="/en/cli-reference/workspaces">
    The same actions from the terminal.
  </Card>
</CardGroup>


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