---
title: "Share the project with an existing account, by email."
method: POST
path: "/story-projects/{projectId}/members"
tags: ["Projects"]
---

# Share the project with an existing account, by email.

`POST /story-projects/{projectId}/members`

## Request

- Base URL: `https://docs.sleeperhit.studio/api/v1`
- URL: `https://docs.sleeperhit.studio/api/v1/story-projects/{projectId}/members`
- Auth: HTTP bearer

An `editor` does everything with the project's content except delete the project or manage its members, and spends their own credits; a `viewer` reads. The owner or an admin: 403 `project_owner_only` for a member. Only a product project can be shared for now (409 `project_members_product_only`). 404 `project_member_not_found` when no account has the email (the person must sign up first). Adding a member again sets their role (`changed: false` when it was already that). Audited. Scope: `story:write`. Free.

## Request body

- AddProjectMemberRequest
  - `email` string, required: The email address of an existing account.
  - `role` 'editor' | 'viewer', required: `editor` or `viewer`.

## Response `200`

The members now, and the one added.

- ProjectMemberChange
  - `projectId` string, required
  - `yourUserId` string, required: The caller's own user id.
  - `yourRole` 'owner' | 'editor' | 'viewer' | 'null', nullable, required: The caller's own role; null for an admin who is neither the owner nor a member.
  - `canManage` boolean, required: Whether the caller may add, change or remove members: the owner, or an admin.
  - `members` ProjectMember[], required: The owner first, then the members, oldest first.
    - `userId` string, required
    - `email` string, required
    - `name` string, nullable, required
    - `role` 'owner' | 'editor' | 'viewer', required: `owner` (the project's own account), `editor` or `viewer`.
    - `addedAt` string, date-time, nullable, required: When the account was added; null for the owner.
  - `changed` boolean, required: False when nothing changed: the member already had that role, or was not a member.
  - `member` ProjectMember, required
    - `userId` string, required
    - `email` string, required
    - `name` string, nullable, required
    - `role` 'owner' | 'editor' | 'viewer', required: `owner` (the project's own account), `editor` or `viewer`.
    - `addedAt` string, date-time, nullable, required: When the account was added; null for the owner.

## Other responses

- `401`: Missing, malformed, revoked, or expired API key.
- `403`: API key is valid but lacks the scope, is blocked by IP allowlist, or the account is disabled.
- `429`: Rate limit for this API key + IP + route family was exceeded.
- `500`: The API failed unexpectedly. Safe to retry with the same Idempotency-Key.

---

[API](https://skmtc.dev/sleeperhit/apis/sleeper-hit-studio-story-api.md) · [All operations](https://skmtc.dev/sleeperhit/apis/sleeper-hit-studio-story-api/llms.txt) · [OpenAPI document](https://skmtc.dev/sleeperhit/apis/sleeper-hit-studio-story-api/revisions/4534f5d25540?raw)
