# Shared spaces API

Source: https://frameleaf.app/docs/api/reference/shared-spaces/

Use your own server and its scoped API keys.

## List shared space invitations

GET /api/shared-spaces/invitations

Shared spaces the authenticated user has been invited to and has not answered. Each entry is the same safe preview as GET /shared-spaces/{id}/preview: no assets, and counts that exclude media marked sensitive and Locked media.

```json
{
  "description": "Shared spaces the authenticated user has been invited to and has not answered. Each entry is the same safe preview as GET /shared-spaces/{id}/preview: no assets, and counts that exclude media marked sensitive and Locked media.",
  "operationId": "getSharedSpaceInvitations",
  "parameters": [],
  "responses": {
    "200": {
      "content": {
        "application/json": {
          "schema": {
            "items": {
              "$ref": "#/components/schemas/SharedSpacePreviewResponseDto"
            },
            "type": "array"
          }
        }
      },
      "description": ""
    }
  },
  "security": [
    {
      "api_key": []
    }
  ],
  "summary": "List shared space invitations",
  "tags": [
    "Shared spaces"
  ],
  "x-frameleaf-permission": "album.read"
}
```

## List recipient groups

GET /api/shared-spaces/recipient-groups

The authenticated user's own named groups of people to invite to a shared space together. A group is a shortcut only: it grants nothing, and its name is never shown to anyone but its owner.

```json
{
  "description": "The authenticated user's own named groups of people to invite to a shared space together. A group is a shortcut only: it grants nothing, and its name is never shown to anyone but its owner.",
  "operationId": "getRecipientGroups",
  "parameters": [],
  "responses": {
    "200": {
      "content": {
        "application/json": {
          "schema": {
            "items": {
              "$ref": "#/components/schemas/RecipientGroupResponseDto"
            },
            "type": "array"
          }
        }
      },
      "description": ""
    }
  },
  "security": [
    {
      "api_key": []
    }
  ],
  "summary": "List recipient groups",
  "tags": [
    "Shared spaces"
  ],
  "x-frameleaf-permission": "album.read"
}
```

## Create a recipient group

POST /api/shared-spaces/recipient-groups

Save a named group of people to invite together. Nobody is invited or given access until the group is applied to a shared space and its invitations are sent.

```json
{
  "description": "Save a named group of people to invite together. Nobody is invited or given access until the group is applied to a shared space and its invitations are sent.",
  "operationId": "createRecipientGroup",
  "parameters": [],
  "requestBody": {
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/RecipientGroupCreateDto"
        }
      }
    },
    "required": true
  },
  "responses": {
    "201": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/RecipientGroupResponseDto"
          }
        }
      },
      "description": ""
    }
  },
  "security": [
    {
      "api_key": []
    }
  ],
  "summary": "Create a recipient group",
  "tags": [
    "Shared spaces"
  ],
  "x-frameleaf-permission": "album.share"
}
```

## Delete a recipient group

DELETE /api/shared-spaces/recipient-groups/{id}

Delete one of your recipient groups. Nobody loses access to anything.

```json
{
  "description": "Delete one of your recipient groups. Nobody loses access to anything.",
  "operationId": "deleteRecipientGroup",
  "parameters": [
    {
      "name": "id",
      "required": true,
      "in": "path",
      "schema": {
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
        "type": "string"
      }
    }
  ],
  "responses": {
    "204": {
      "description": ""
    }
  },
  "security": [
    {
      "api_key": []
    }
  ],
  "summary": "Delete a recipient group",
  "tags": [
    "Shared spaces"
  ],
  "x-frameleaf-permission": "album.share"
}
```

## Update a recipient group

PUT /api/shared-spaces/recipient-groups/{id}

Rename a group or change who is in it. Existing invitations and memberships are never changed; only the owner's own groups can be updated (anyone else's reads as not found).

```json
{
  "description": "Rename a group or change who is in it. Existing invitations and memberships are never changed; only the owner's own groups can be updated (anyone else's reads as not found).",
  "operationId": "updateRecipientGroup",
  "parameters": [
    {
      "name": "id",
      "required": true,
      "in": "path",
      "schema": {
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
        "type": "string"
      }
    }
  ],
  "requestBody": {
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/RecipientGroupUpdateDto"
        }
      }
    },
    "required": true
  },
  "responses": {
    "200": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/RecipientGroupResponseDto"
          }
        }
      },
      "description": ""
    }
  },
  "security": [
    {
      "api_key": []
    }
  ],
  "summary": "Update a recipient group",
  "tags": [
    "Shared spaces"
  ],
  "x-frameleaf-permission": "album.share"
}
```

## Accept a shared space invitation

POST /api/shared-spaces/{id}/accept

Join the shared space with the role its owner offered. The role comes from the stored invitation, never from the request. This is the only way to become a member of a space.

```json
{
  "description": "Join the shared space with the role its owner offered. The role comes from the stored invitation, never from the request. This is the only way to become a member of a space.",
  "operationId": "acceptSharedSpaceInvitation",
  "parameters": [
    {
      "name": "id",
      "required": true,
      "in": "path",
      "schema": {
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
        "type": "string"
      }
    }
  ],
  "responses": {
    "201": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/AlbumResponseDto"
          }
        }
      },
      "description": ""
    }
  },
  "security": [
    {
      "api_key": []
    }
  ],
  "summary": "Accept a shared space invitation",
  "tags": [
    "Shared spaces"
  ],
  "x-frameleaf-permission": "albumUser.update"
}
```

## What happened in a shared space

GET /api/shared-spaces/{id}/activity

The shared space’s activity feed, newest first: items added and removed, albums and people linked and unlinked, members joining, leaving, being removed or changing role, comments and likes — by every member. Only current members may read it. Every event is narrowed to the caller before it is sent: an item the caller cannot see (Locked, marked sensitive, hidden by their own settings, or no longer in the space) is never named, and an event with nothing visible left is not sent at all, so nothing can be inferred from a count. `unreadCount` is the events by other members since the caller last marked the space seen, computed the same way. Page with `before` and `take`.

```json
{
  "description": "The shared space’s activity feed, newest first: items added and removed, albums and people linked and unlinked, members joining, leaving, being removed or changing role, comments and likes — by every member. Only current members may read it. Every event is narrowed to the caller before it is sent: an item the caller cannot see (Locked, marked sensitive, hidden by their own settings, or no longer in the space) is never named, and an event with nothing visible left is not sent at all, so nothing can be inferred from a count. `unreadCount` is the events by other members since the caller last marked the space seen, computed the same way. Page with `before` and `take`.",
  "operationId": "getSharedSpaceActivity",
  "parameters": [
    {
      "name": "before",
      "required": false,
      "in": "query",
      "description": "Only events before this moment, for paging",
      "schema": {
        "format": "date-time",
        "type": "string"
      }
    },
    {
      "name": "id",
      "required": true,
      "in": "path",
      "schema": {
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
        "type": "string"
      }
    },
    {
      "name": "take",
      "required": false,
      "in": "query",
      "description": "Page size, 50 by default",
      "schema": {
        "minimum": 1,
        "maximum": 200,
        "type": "integer"
      }
    }
  ],
  "responses": {
    "200": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/SharedSpaceActivityResponseDto"
          }
        }
      },
      "description": ""
    }
  },
  "security": [
    {
      "api_key": []
    }
  ],
  "summary": "What happened in a shared space",
  "tags": [
    "Shared spaces"
  ],
  "x-frameleaf-permission": "album.read"
}
```

## List albums linked into a shared space

GET /api/shared-spaces/{id}/albums

The albums members have linked into the shared space, one level: a space links albums, never another space and never a collection. A link is a reference, not a move and not a share — the album keeps its owner, its members, its access rules and its place in its owner’s tree, and this response grants no access to it. The count and the tile picture come only from items that are in both the album and the space, with media marked sensitive and Locked media excluded.

```json
{
  "description": "The albums members have linked into the shared space, one level: a space links albums, never another space and never a collection. A link is a reference, not a move and not a share — the album keeps its owner, its members, its access rules and its place in its owner’s tree, and this response grants no access to it. The count and the tile picture come only from items that are in both the album and the space, with media marked sensitive and Locked media excluded.",
  "operationId": "getSharedSpaceAlbums",
  "parameters": [
    {
      "name": "id",
      "required": true,
      "in": "path",
      "schema": {
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/SharedSpaceAlbumsResponseDto"
          }
        }
      },
      "description": ""
    }
  },
  "security": [
    {
      "api_key": []
    }
  ],
  "summary": "List albums linked into a shared space",
  "tags": [
    "Shared spaces"
  ],
  "x-frameleaf-permission": "album.read"
}
```

## Unlink an album from a shared space

DELETE /api/shared-spaces/{id}/albums/{albumId}

Remove the reference and only the reference. The album, its items, its members and the shared space’s own items are untouched. The member who made the link, and the shared space owner, may remove it.

```json
{
  "description": "Remove the reference and only the reference. The album, its items, its members and the shared space’s own items are untouched. The member who made the link, and the shared space owner, may remove it.",
  "operationId": "unlinkSharedSpaceAlbum",
  "parameters": [
    {
      "name": "albumId",
      "required": true,
      "in": "path",
      "description": "The album to link or unlink",
      "schema": {
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
        "type": "string"
      }
    },
    {
      "name": "id",
      "required": true,
      "in": "path",
      "description": "Shared space ID",
      "schema": {
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
        "type": "string"
      }
    }
  ],
  "responses": {
    "204": {
      "description": ""
    }
  },
  "security": [
    {
      "api_key": []
    }
  ],
  "summary": "Unlink an album from a shared space",
  "tags": [
    "Shared spaces"
  ],
  "x-frameleaf-permission": "album.update"
}
```

## Link an album into a shared space

PUT /api/shared-spaces/{id}/albums/{albumId}

Point the shared space at an album the caller can already read. Nothing else happens: no item moves or is copied, no album membership changes, and the album stays where its owner put it. Linking the same album twice is the same single link. An owner or editor of the space may link; a viewer may not.

```json
{
  "description": "Point the shared space at an album the caller can already read. Nothing else happens: no item moves or is copied, no album membership changes, and the album stays where its owner put it. Linking the same album twice is the same single link. An owner or editor of the space may link; a viewer may not.",
  "operationId": "linkSharedSpaceAlbum",
  "parameters": [
    {
      "name": "albumId",
      "required": true,
      "in": "path",
      "description": "The album to link or unlink",
      "schema": {
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
        "type": "string"
      }
    },
    {
      "name": "id",
      "required": true,
      "in": "path",
      "description": "Shared space ID",
      "schema": {
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/SharedSpaceAlbumsResponseDto"
          }
        }
      },
      "description": ""
    }
  },
  "security": [
    {
      "api_key": []
    }
  ],
  "summary": "Link an album into a shared space",
  "tags": [
    "Shared spaces"
  ],
  "x-frameleaf-permission": "album.update"
}
```

## List comments in a shared space

GET /api/shared-spaces/{id}/comments

The comments on one item in the shared space (`assetId`), or on the space itself when `assetId` is left out. Oldest first. Only current members may read them, and an item the caller cannot see is not in the space as far as they are concerned (404). Mentions stay as `@{userId}` tokens in the text and are resolved in `mentions`. Threads are one level deep: a reply names its top-level comment in `parentId`, and a top-level comment carries its `replyCount`.

```json
{
  "description": "The comments on one item in the shared space (`assetId`), or on the space itself when `assetId` is left out. Oldest first. Only current members may read them, and an item the caller cannot see is not in the space as far as they are concerned (404). Mentions stay as `@{userId}` tokens in the text and are resolved in `mentions`. Threads are one level deep: a reply names its top-level comment in `parentId`, and a top-level comment carries its `replyCount`.",
  "operationId": "getSharedSpaceComments",
  "parameters": [
    {
      "name": "assetId",
      "required": false,
      "in": "query",
      "description": "Comments on this item. Left out, the comments on the space itself.",
      "schema": {
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
        "type": "string"
      }
    },
    {
      "name": "id",
      "required": true,
      "in": "path",
      "schema": {
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/SharedSpaceCommentsResponseDto"
          }
        }
      },
      "description": ""
    }
  },
  "security": [
    {
      "api_key": []
    }
  ],
  "summary": "List comments in a shared space",
  "tags": [
    "Shared spaces"
  ],
  "x-frameleaf-permission": "activity.read"
}
```

## Comment in a shared space

POST /api/shared-spaces/{id}/comments

Write a comment on one item in the shared space, or on the space itself when `assetId` is left out. Commenting must be enabled on the space, and the item must be one the caller can see. Mention a member with `@{userId}`: mentions are by id, never by name, every mention must name a current member (400 otherwise), and each mentioned member other than the author is notified. Reply with `parentId`: a reply to a reply joins the same thread under its top-level comment, is on the same item, and notifies the top-level comment’s author in the app.

```json
{
  "description": "Write a comment on one item in the shared space, or on the space itself when `assetId` is left out. Commenting must be enabled on the space, and the item must be one the caller can see. Mention a member with `@{userId}`: mentions are by id, never by name, every mention must name a current member (400 otherwise), and each mentioned member other than the author is notified. Reply with `parentId`: a reply to a reply joins the same thread under its top-level comment, is on the same item, and notifies the top-level comment’s author in the app.",
  "operationId": "createSharedSpaceComment",
  "parameters": [
    {
      "name": "id",
      "required": true,
      "in": "path",
      "schema": {
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
        "type": "string"
      }
    }
  ],
  "requestBody": {
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/SharedSpaceCommentCreateDto"
        }
      }
    },
    "required": true
  },
  "responses": {
    "201": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/SharedSpaceCommentResponseDto"
          }
        }
      },
      "description": ""
    }
  },
  "security": [
    {
      "api_key": []
    }
  ],
  "summary": "Comment in a shared space",
  "tags": [
    "Shared spaces"
  ],
  "x-frameleaf-permission": "activity.create"
}
```

## Remove a shared space comment

DELETE /api/shared-spaces/{id}/comments/{commentId}

Remove a comment. Its author may, and so may a shared space owner or editor — that is how a space is moderated. A viewer removes only their own. The comment’s mentions and its entry in the activity feed go with it, and removing a top-level comment removes its replies.

```json
{
  "description": "Remove a comment. Its author may, and so may a shared space owner or editor — that is how a space is moderated. A viewer removes only their own. The comment’s mentions and its entry in the activity feed go with it, and removing a top-level comment removes its replies.",
  "operationId": "deleteSharedSpaceComment",
  "parameters": [
    {
      "name": "commentId",
      "required": true,
      "in": "path",
      "description": "The comment",
      "schema": {
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
        "type": "string"
      }
    },
    {
      "name": "id",
      "required": true,
      "in": "path",
      "description": "Shared space ID",
      "schema": {
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
        "type": "string"
      }
    }
  ],
  "responses": {
    "204": {
      "description": ""
    }
  },
  "security": [
    {
      "api_key": []
    }
  ],
  "summary": "Remove a shared space comment",
  "tags": [
    "Shared spaces"
  ],
  "x-frameleaf-permission": "activity.delete"
}
```

## Edit a shared space comment

PUT /api/shared-spaces/{id}/comments/{commentId}

Change what a comment says. Only its author may. Mentions are re-read from the new text under the same rules, and members newly mentioned are notified.

```json
{
  "description": "Change what a comment says. Only its author may. Mentions are re-read from the new text under the same rules, and members newly mentioned are notified.",
  "operationId": "updateSharedSpaceComment",
  "parameters": [
    {
      "name": "commentId",
      "required": true,
      "in": "path",
      "description": "The comment",
      "schema": {
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
        "type": "string"
      }
    },
    {
      "name": "id",
      "required": true,
      "in": "path",
      "description": "Shared space ID",
      "schema": {
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
        "type": "string"
      }
    }
  ],
  "requestBody": {
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/SharedSpaceCommentUpdateDto"
        }
      }
    },
    "required": true
  },
  "responses": {
    "200": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/SharedSpaceCommentResponseDto"
          }
        }
      },
      "description": ""
    }
  },
  "security": [
    {
      "api_key": []
    }
  ],
  "summary": "Edit a shared space comment",
  "tags": [
    "Shared spaces"
  ],
  "x-frameleaf-permission": "activity.update"
}
```

## Decline a shared space invitation

DELETE /api/shared-spaces/{id}/invitation

Decline the invitation. Nothing else changes: the shared space and its photos are untouched, and the owner may invite again later.

```json
{
  "description": "Decline the invitation. Nothing else changes: the shared space and its photos are untouched, and the owner may invite again later.",
  "operationId": "declineSharedSpaceInvitation",
  "parameters": [
    {
      "name": "id",
      "required": true,
      "in": "path",
      "schema": {
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
        "type": "string"
      }
    }
  ],
  "responses": {
    "204": {
      "description": ""
    }
  },
  "security": [
    {
      "api_key": []
    }
  ],
  "summary": "Decline a shared space invitation",
  "tags": [
    "Shared spaces"
  ],
  "x-frameleaf-permission": "albumUser.delete"
}
```

## Withdraw a shared space invitation

DELETE /api/shared-spaces/{id}/invitations/{userId}

Withdraw a pending invitation. Only the shared space owner can do this, and it only reaches people who have not joined; removing a member is DELETE /albums/{id}/user/{userId}.

```json
{
  "description": "Withdraw a pending invitation. Only the shared space owner can do this, and it only reaches people who have not joined; removing a member is DELETE /albums/{id}/user/{userId}.",
  "operationId": "removeSharedSpaceInvitation",
  "parameters": [
    {
      "name": "id",
      "required": true,
      "in": "path",
      "description": "Shared space ID",
      "schema": {
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
        "type": "string"
      }
    },
    {
      "name": "userId",
      "required": true,
      "in": "path",
      "description": "The invited user",
      "schema": {
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
        "type": "string"
      }
    }
  ],
  "responses": {
    "204": {
      "description": ""
    }
  },
  "security": [
    {
      "api_key": []
    }
  ],
  "summary": "Withdraw a shared space invitation",
  "tags": [
    "Shared spaces"
  ],
  "x-frameleaf-permission": "albumUser.delete"
}
```

## List shared space members

GET /api/shared-spaces/{id}/members

Everyone in the shared space and everyone invited to it who has not answered. Any member may read the roster; only the owner may change it.

```json
{
  "description": "Everyone in the shared space and everyone invited to it who has not answered. Any member may read the roster; only the owner may change it.",
  "operationId": "getSharedSpaceMembers",
  "parameters": [
    {
      "name": "id",
      "required": true,
      "in": "path",
      "schema": {
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/SharedSpaceMembersResponseDto"
          }
        }
      },
      "description": ""
    }
  },
  "security": [
    {
      "api_key": []
    }
  ],
  "summary": "List shared space members",
  "tags": [
    "Shared spaces"
  ],
  "x-frameleaf-permission": "album.read"
}
```

## What is new in a shared space since your last visit

GET /api/shared-spaces/{id}/new

Items other members added since the caller last marked this shared space seen. The marker is per member. If the caller has never marked it seen, everything in the space counts as new to them. The caller’s own additions are left out, and media marked sensitive and Locked media are excluded.

```json
{
  "description": "Items other members added since the caller last marked this shared space seen. The marker is per member. If the caller has never marked it seen, everything in the space counts as new to them. The caller’s own additions are left out, and media marked sensitive and Locked media are excluded.",
  "operationId": "getSharedSpaceNew",
  "parameters": [
    {
      "name": "id",
      "required": true,
      "in": "path",
      "schema": {
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/SharedSpaceNewResponseDto"
          }
        }
      },
      "description": ""
    }
  },
  "security": [
    {
      "api_key": []
    }
  ],
  "summary": "What is new in a shared space since your last visit",
  "tags": [
    "Shared spaces"
  ],
  "x-frameleaf-permission": "album.read"
}
```

## People in a shared space

GET /api/shared-spaces/{id}/people

Two lists. `linked` is who members have published into the space, carrying the space’s own name for each one and a picture that is already in the space — never the owner’s private name, thumbnail, birth date or person ID. `candidates` is the caller’s own people seen on the space’s items, so they can publish one; no other member’s people are ever listed. Counts exclude media marked sensitive and Locked media.

```json
{
  "description": "Two lists. `linked` is who members have published into the space, carrying the space’s own name for each one and a picture that is already in the space — never the owner’s private name, thumbnail, birth date or person ID. `candidates` is the caller’s own people seen on the space’s items, so they can publish one; no other member’s people are ever listed. Counts exclude media marked sensitive and Locked media.",
  "operationId": "getSharedSpacePeople",
  "parameters": [
    {
      "name": "id",
      "required": true,
      "in": "path",
      "schema": {
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/SharedSpacePeopleResponseDto"
          }
        }
      },
      "description": ""
    }
  },
  "security": [
    {
      "api_key": []
    }
  ],
  "summary": "People in a shared space",
  "tags": [
    "Shared spaces"
  ],
  "x-frameleaf-permission": "album.read"
}
```

## Link a person into a shared space

POST /api/shared-spaces/{id}/people

Publish one of the caller’s own people into the shared space under a name the space uses. The name is independent: it never renames the caller’s own person, and renaming that person does not rename it here. The caller’s person record is not disclosed to anybody. Linking the same person again rewrites the link rather than adding a second one.

```json
{
  "description": "Publish one of the caller’s own people into the shared space under a name the space uses. The name is independent: it never renames the caller’s own person, and renaming that person does not rename it here. The caller’s person record is not disclosed to anybody. Linking the same person again rewrites the link rather than adding a second one.",
  "operationId": "linkSharedSpacePerson",
  "parameters": [
    {
      "name": "id",
      "required": true,
      "in": "path",
      "schema": {
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
        "type": "string"
      }
    }
  ],
  "requestBody": {
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/SharedSpacePersonLinkDto"
        }
      }
    },
    "required": true
  },
  "responses": {
    "200": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/SharedSpacePeopleResponseDto"
          }
        }
      },
      "description": ""
    }
  },
  "security": [
    {
      "api_key": []
    }
  ],
  "summary": "Link a person into a shared space",
  "tags": [
    "Shared spaces"
  ],
  "x-frameleaf-permission": "person.update"
}
```

## Unlink a person from a shared space

DELETE /api/shared-spaces/{id}/people/{linkId}

Remove the link and only the link. The person, their name, their faces and every item that shows them are untouched, and so are the shared space’s items. The member who made the link, and the shared space owner, may remove it.

```json
{
  "description": "Remove the link and only the link. The person, their name, their faces and every item that shows them are untouched, and so are the shared space’s items. The member who made the link, and the shared space owner, may remove it.",
  "operationId": "unlinkSharedSpacePerson",
  "parameters": [
    {
      "name": "id",
      "required": true,
      "in": "path",
      "description": "Shared space ID",
      "schema": {
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
        "type": "string"
      }
    },
    {
      "name": "linkId",
      "required": true,
      "in": "path",
      "description": "The person link to remove",
      "schema": {
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
        "type": "string"
      }
    }
  ],
  "responses": {
    "204": {
      "description": ""
    }
  },
  "security": [
    {
      "api_key": []
    }
  ],
  "summary": "Unlink a person from a shared space",
  "tags": [
    "Shared spaces"
  ],
  "x-frameleaf-permission": "person.update"
}
```

## Preview a shared space

GET /api/shared-spaces/{id}/preview

What the shared space exposes, for someone holding an invitation to it or already in it. The preview carries no asset: no ids, no thumbnails, no file names, no people and no places. Counts and dates exclude media marked sensitive and Locked media. Anyone without an invitation or membership gets 404.

```json
{
  "description": "What the shared space exposes, for someone holding an invitation to it or already in it. The preview carries no asset: no ids, no thumbnails, no file names, no people and no places. Counts and dates exclude media marked sensitive and Locked media. Anyone without an invitation or membership gets 404.",
  "operationId": "getSharedSpacePreview",
  "parameters": [
    {
      "name": "id",
      "required": true,
      "in": "path",
      "schema": {
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/SharedSpacePreviewResponseDto"
          }
        }
      },
      "description": ""
    }
  },
  "security": [
    {
      "api_key": []
    }
  ],
  "summary": "Preview a shared space",
  "tags": [
    "Shared spaces"
  ],
  "x-frameleaf-permission": "album.read"
}
```

## Mark a shared space seen

POST /api/shared-spaces/{id}/visit

Move the caller’s own last-seen marker to now and return what is new after doing so. This is deliberately explicit rather than something opening the page does, so glancing at a space on a phone does not silently clear the list of what has not been looked at.

```json
{
  "description": "Move the caller’s own last-seen marker to now and return what is new after doing so. This is deliberately explicit rather than something opening the page does, so glancing at a space on a phone does not silently clear the list of what has not been looked at.",
  "operationId": "markSharedSpaceVisited",
  "parameters": [
    {
      "name": "id",
      "required": true,
      "in": "path",
      "schema": {
        "format": "uuid",
        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/SharedSpaceNewResponseDto"
          }
        }
      },
      "description": ""
    }
  },
  "security": [
    {
      "api_key": []
    }
  ],
  "summary": "Mark a shared space seen",
  "tags": [
    "Shared spaces"
  ],
  "x-frameleaf-permission": "album.read"
}
```
