Skip to content

Invite an address

POST
/v1/members
curl --request POST \
--url https://beta-api.plune.ai/v1/members \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "email": "[email protected]", "role": "reader" }'

Owner only (api.tsinviteMember, the Invite form). Two outcomes, told apart by kind: an address that already has a Plune account is a member at once; any other address gets an invitation — a mail says where to sign in, the beta door lets the address through, and the sign-in itself turns the invitation into a membership. No token in the mail: the magic link is the proof. The address is lower-cased before it is compared or stored. Twice for the same address is 409, and so is a project at its member limit.

X-Plune-Project
string

Which of your projects to act in — an id from GET /v1/projects. Absent, your default project. A project you are not a member of answers 404, the same as one that does not exist. Ignored under a bearer token, which is bound to the project it was minted in.

Media type application/json
object
email
required
string format: email
role
required

What a member may do (B8-team). owner runs the project — members, roles, its name; member does everything else; reader is refused every write at the boundary, before a handler runs.

string
Allowed values: owner member reader
Examples

An address without an account — an invitation

{
"email": "[email protected]",
"role": "reader"
}

Invited — kind says which of the two it became

Media type application/json
One of:

What inviting an address produced: a member at once when an account holds it (kind: member), else an invitation for the address to sign in with (kind: invitation).

object
kind
required
string
Allowed values: member
userId
required
string format: uuid
email
required
string format: email
name
required

The display name, once people have one (T3); null until then.

string
nullable
role
required

What a member may do (B8-team). owner runs the project — members, roles, its name; member does everything else; reader is refused every write at the boundary, before a handler runs.

string
Allowed values: owner member reader
joinedAt
required
string format: date-time
invitedBy
required

Who invited them (a userId); null for the person the project was created by.

string
nullable
Example
{
"kind": "invitation",
"id": "6f1c2b3a-0000-4000-8000-0000000000a3",
"email": "[email protected]",
"role": "reader",
"invitedBy": "u-shop",
"createdAt": "2026-09-16T09:12:04.151Z"
}

Invalid body — an email address and one of the three roles

Media type application/json
object
error
required
string
Example generated
{
"error": "example"
}

No / invalid token or session

A member or a reader asked

Media type application/json
object
error
required
string
Example
{
"error": "project owner only"
}

The header names a project you are not in

Media type application/json
object
error
required
string
Example generated
{
"error": "example"
}

Already in, already invited, or the project is at its member limit

Media type application/json
object
error
required
string
Example
{
"error": "[email protected] is already in this project, or already invited"
}

Rate-limited: either the per-route throttle or a tenant quota. Retry-After carries the seconds until the window rolls over.

Media type application/json
object
error
required
string
Example generated
{
"error": "example"
}
Retry-After
integer

Seconds until the window rolls over