メンバー
このグループのすべてのオペレーションの、受け付ける内容、返す内容、返しうるエラー。
オペレーション
Who is in this workspace, and what each of them can reach.
A member is two grants and not one. A ROLE says what they may do; a set of ADDRESS grants says what they may do it to, each carrying member (read the address and send as it) or viewer, which only reads. Both are checked before mail goes out, so a screen showing one of them will explain the wrong refusal with great confidence.
implied: true means nobody chose the role. Sharing shipped long before roles did and a great many people still have address grants and no membership row; rather than lock them out until a backfill has run, the widest grant they hold names a built-in. A PATCH is what turns that inference into a decision, and until it happens, widening their addresses widens what they may do.
Everybody joins by invitation: POST /members invites, GET /members/invitations lists the invitations still waiting, and they can be sent again or withdrawn. A waiting invitation grants nothing until it is accepted. The owner is the first row of GET /members, and holds everything by definition.
GET/members
List members
Everybody with access to this workspace, the owner first and the rest by email. A page at a time: follow nextCursor while hasMore is true to read everybody.
Each row carries BOTH axes and a client must not collapse them. role is what somebody may do; addresses is what they may do it to, one entry per address with its own access. Someone with emails:send and an empty addresses may send from nothing, and someone holding every address under a viewer role may send from none of them either. The send path checks both, so a screen showing one of them will confidently explain the wrong refusal.
The one exception is addresses:all. Somebody whose permissions hold it reaches every address on every domain of the workspace, including ones added later, and sends as any of them when permissions also holds emails:send, whatever addresses and domains list. Those two still hold only direct grants, which such a member may have kept from before or been given since, or none at all. Read reach from permissions first, and from those arrays only when it lacks addresses:all.
Watch for implied: true. It means nobody chose that role: sharing shipped long before roles did, so a great many people have address grants and no membership row, and the widest grant they hold names a built-in rather than leaving them locked out until a backfill has run. A PATCH is what turns the inference into a decision.
The owner IS in this list, as the first row, marked isOwner: true. They are the thing the workspace is keyed on, they hold every permission by definition, and POST, PATCH and DELETE all refuse them with member_is_owner. Exclude isOwner when you are counting seats.
Requires the members:read scope.
クエリパラメーター
limitintegerRows per page, 1 to 100.
1以上100以下既定値25cursorstringThe previous page's
nextCursor, passed back as it came. It is opaque: it holds where the last row sat in this list's order, so a row deleted or edited between pages never breaks the walk, and the next page starts at the first row that sorts after it. A value this list did not hand out is a 400invalid_cursor.
戻り値
A page of people with access, by email.
エラー
どのオペレーションも返しうるエラー400401403404422500エラー一覧
ほかの提供先
POST/members
Invite a member
Invites somebody to the workspace. Whether or not the address already has an OpenEmail account, the answer is an invitation and a 202, never a member: nobody is put into a workspace without accepting, and this endpoint is held to the same rule as the app.
The invitation carries the role, the addresses and the whole domains you name, and grants exactly those the moment it is accepted. Nothing is granted before that. An address invited in the last ten minutes answers invitation_too_soon, and asking twice refreshes the one invitation rather than sending two.
Somebody already in the workspace is refused with member_is_owner (the closest existing code). Change what an existing member may do with PATCH /members/{userId} and the address and domain grant calls, which only work on people already in.
invitedBy is left null deliberately. The column records which PERSON invited somebody, and a key is not a person.
Remember which axis this sets. A role does not reach an address, and the addresses do not widen the role. The one exception is a role holding addresses:all, which reaches every address with no ids at all.
The authority of a key is, in the same way, its own scopes intersected with the role it was issued under, so a role holding a permission the key lacks is refused with insufficient_authority, a 403. No key or token holds a console-only permission, so a role with one of those in it, addresses:all included, is handed out in the app.
Requires the members:write scope.
リクエストボディ
emailstring必須Who to invite. Lower-cased on the way in. It does not matter whether an OpenEmail account exists behind it: everybody is invited, and nobody is in the workspace until they accept.
形式emailroleIdstring必須From
GET /roles. The owner role is refused: a workspace transfer is not this.addressIdsstring[]Addresses the invitation carries, all at the same
access. They are granted the moment the person accepts, so "invite Sam as Support on help@" stays one intention.64件までdomainIdsstring[]Whole domains the invitation carries, at the same
access. A domain grant reaches every address on it, including ones made later.64件までaccessstringmemberreads the address and sends as it;vieweronly reads it. The second axis, ANDed with the role. This cannot widen what a role does not already allow.次のいずれか"member""viewer"既定値"member"
戻り値
Invited. They are in the workspace once they accept.
エラー
- 403
The key lacks the scope, or may not send as that address.
step_up_required: the call was made with an OAuth access token that has not been verified in the last 60 minutes. Ask for a code withPOST /security/step-up, send it toPOST /security/step-up/verify, then repeat the call. The person can also choose Allow changes for 60 minutes on the app in Account settings, Connected apps, on the OpenEmail website. An API key is never asked for a code.- 404
role_not_foundfor theroleId, or anaddressIds/domainIdsentry that is not on this workspace.- 409
invitation_too_soon(that address was invited in the last ten minutes) orinvitation_limit_reached.- 422
member_is_owner: the address is already in this workspace, or is the owner. Use PATCH to change what an existing member may do.
どのオペレーションも返しうるエラー400401500エラー一覧
ほかの提供先
GET/members/{userId}
Retrieve a member
Read off the same union the list computes, rather than by a query of its own. A member is the union of two populations (a membership row and a set of address grants, either of which exists perfectly well without the other), and a single-row lookup would be a second implementation of that union whose blind spot is precisely the legacy grant holders, who are most of the table today.
Requires the members:read scope.
パスパラメーター
userIdstring必須The ACCOUNT id, which is what
GET /membersreturns and not the email address. An email identifies a person to a human and is the wrong key here: it can be changed on the account, and a caller holding a stale one would quietly address the wrong grant.
戻り値
The member, with their role and their addresses.
エラー
- 404
No such member on this workspace.
どのオペレーションも返しうるエラー400401403422500エラー一覧
ほかの提供先
PATCH/members/{userId}
Change a member's role
Changes the role and nothing else, for somebody ALREADY in the workspace. It is also how a legacy grant holder stops being implied: they have address or domain grants and no membership row, this writes one, and from then on their permissions are what somebody chose rather than what their access happened to imply. Their grants are untouched.
A role holding a permission the key lacks is refused with insufficient_authority, a 403. No key or token holds a console-only permission, so moving somebody onto a role with addresses:all in it, which would reach every address for them without a single grant, is done in the app.
Addresses are deliberately not patchable from here. They are a set with a per-element access level, and an array on a PATCH would have to mean replace-whole: a silent mass revocation every time a client sends a list it read five minutes ago. The two address endpoints below move one at a time, so what happened is always what was asked for.
The owner role cannot be handed out. Making somebody an owner is a workspace transfer, which has entirely different consequences and is not an operation this API has.
Requires the members:write scope.
パスパラメーター
userIdstring必須The ACCOUNT id, which is what
GET /membersreturns and not the email address. An email identifies a person to a human and is the wrong key here: it can be changed on the account, and a caller holding a stale one would quietly address the wrong grant.
リクエストボディ
roleIdstring必須The role to move them to. Their addresses are untouched by this.
戻り値
Saved. implied is false from here on.
エラー
- 403
The key lacks the scope, or may not send as that address.
step_up_required: the call was made with an OAuth access token that has not been verified in the last 60 minutes. Ask for a code withPOST /security/step-up, send it toPOST /security/step-up/verify, then repeat the call. The person can also choose Allow changes for 60 minutes on the app in Account settings, Connected apps, on the OpenEmail website. An API key is never asked for a code.- 409
role_immutable: the owner role cannot be handed out.- 422
member_is_owner, ormember_not_foundwhen the account is not in this workspace yet. Nobody joins through PATCH: invite them withPOST /membersand they are in once they accept.
どのオペレーションも返しうるエラー400401404500エラー一覧
ほかの提供先
DELETE/members/{userId}
Remove a member
Takes somebody out of the workspace entirely: the membership row AND every address grant they hold here. Removing only the first would be the worst of both worlds. They would vanish from the list and go on reading the mail.
Idempotent, and it does NOT 404 on somebody who is not a member. The workspace owner is the one id it refuses, with 422 member_is_owner. That is not laxness about ids: the population this endpoint most needs to reach is the legacy grant holders, who have address grants and no membership row at all, so a pre-flight existence check would refuse exactly the people whose access most wants revoking. addressesRevoked reports what actually happened.
It does not touch their account, their sent mail or anything they wrote. It removes their access to this workspace.
Requires the members:write scope.
パスパラメーター
userIdstring必須The ACCOUNT id, which is what
GET /membersreturns and not the email address. An email identifies a person to a human and is the wrong key here: it can be changed on the account, and a caller holding a stale one would quietly address the wrong grant.
戻り値
Removed, with the number of address grants that went with them.
objectstring- 次のいずれか
"member" userIdstringdeletedboolean- 次のいずれか
true addressesRevokedintegerGrants actually removed. Zero is the honest report of a no-op.
エラー
- 403
The key lacks the scope, or may not send as that address.
step_up_required: the call was made with an OAuth access token that has not been verified in the last 60 minutes. Ask for a code withPOST /security/step-up, send it toPOST /security/step-up/verify, then repeat the call. The person can also choose Allow changes for 60 minutes on the app in Account settings, Connected apps, on the OpenEmail website. An API key is never asked for a code.
どのオペレーションも返しうるエラー400401404422500エラー一覧
ほかの提供先
POST/members/{userId}/addresses
Grant an address
Hands one person one address, or changes what they may do with one they already have. An upsert: there is one row per address-and-person pair, so re-posting with a different access promotes a viewer to a member rather than adding a second grant.
A POST to the sub-collection rather than a PUT on the pair, because the row has no id a caller ever names.
This is the SECOND axis and it cannot widen the first: access: "member" on somebody whose role lacks emails:send does not let them send, it lets them read. Both have to agree before a message goes out.
Gated on members:write rather than on owning the address, which is where it differs from the older sharing path in the console. Ownership is the right gate for the person who put the domain in and the wrong one for an admin who owns nothing and is running the workspace access on behalf of the owner. Both write the same row.
The whole member comes back rather than the grant alone, so a client can re-render the row it is looking at without a second request, and so the answer reads the same whether the grant was new or an amendment.
Requires the members:write scope.
パスパラメーター
userIdstring必須The ACCOUNT id, which is what
GET /membersreturns and not the email address. An email identifies a person to a human and is the wrong key here: it can be changed on the account, and a caller holding a stale one would quietly address the wrong grant.
リクエストボディ
addressIdstring必須An address on this workspace.
accessstringmemberreads the address and sends as it;vieweronly reads it. The second axis, ANDed with the role. This cannot widen what a role does not already allow.次のいずれか"member""viewer"既定値"member"
戻り値
The whole member, with the grant applied.
エラー
- 403
The key lacks the scope, or may not send as that address.
step_up_required: the call was made with an OAuth access token that has not been verified in the last 60 minutes. Ask for a code withPOST /security/step-up, send it toPOST /security/step-up/verify, then repeat the call. The person can also choose Allow changes for 60 minutes on the app in Account settings, Connected apps, on the OpenEmail website. An API key is never asked for a code.
どのオペレーションも返しうるエラー400401404422500エラー一覧
ほかの提供先
DELETE/members/{userId}/addresses/{addressId}
Revoke an address
Takes one address back and leaves the person in the workspace, with their role and their other addresses. The narrow revocation, and the one to reach for when somebody moves team.
An address that is not on this workspace is refused rather than quietly ignored: a typo in the id reporting a successful revocation that never happened is the exact failure this endpoint exists to prevent.
The member comes back rather than a tombstone, because the interesting answer is what they can still reach. A { deleted: true } here would leave a client to work that out by subtraction.
Requires the members:write scope.
パスパラメーター
userIdstring必須The ACCOUNT id, which is what
GET /membersreturns and not the email address. An email identifies a person to a human and is the wrong key here: it can be changed on the account, and a caller holding a stale one would quietly address the wrong grant.addressIdstring必須An address on THIS workspace. One belonging to another is refused, not ignored.
戻り値
The member, with what they can still reach.
エラー
- 403
The key lacks the scope, or may not send as that address.
step_up_required: the call was made with an OAuth access token that has not been verified in the last 60 minutes. Ask for a code withPOST /security/step-up, send it toPOST /security/step-up/verify, then repeat the call. The person can also choose Allow changes for 60 minutes on the app in Account settings, Connected apps, on the OpenEmail website. An API key is never asked for a code.
どのオペレーションも返しうるエラー400401404422500エラー一覧
ほかの提供先
GET/members/invitations
List pending invitations
The invitations to this workspace that are still waiting, by email: the role and the addresses and whole domains each will grant once accepted, when it expires, and whether the last email reached them. A page at a time: follow nextCursor while hasMore is true.
A waiting invitation grants nothing. It becomes access only at the moment somebody accepts it, which is why it is listed here rather than in GET /members. An expired one stays on this list with expired: true until it is sent again or withdrawn.
A key limited to particular addresses or domains lists only the invitations that grant nothing outside them.
Requires the members:read scope.
クエリパラメーター
limitintegerRows per page, 1 to 100.
1以上100以下既定値25cursorstringThe previous page's
nextCursor, passed back as it came. It is opaque: it holds where the last row sat in this list's order, so a row deleted or edited between pages never breaks the walk, and the next page starts at the first row that sorts after it. A value this list did not hand out is a 400invalid_cursor.
戻り値
A page of invitations nobody has accepted yet, by email.
エラー
どのオペレーションも返しうるエラー400401403404422500エラー一覧
ほかの提供先
DELETE/members/invitations/{invitationId}
Withdraw an invitation
Withdraws an invitation nobody has accepted. Its link stops working at once and nothing it would have granted is granted. Inviting the same address later with POST /members sends a new one.
A key limited to particular addresses or domains can withdraw only an invitation that grants nothing outside them. Any other answers 404.
Requires the members:write scope.
パスパラメーター
invitationIdstring必須The invitation id from
GET /members/invitations,winv_and 24 hex.
戻り値
Withdrawn. The link no longer works.
objectstring- 次のいずれか
"invitation" idstringemailstringrevokedboolean- 次のいずれか
true
エラー
- 404
No invitation with that id is waiting: it is unknown, or already withdrawn.
- 409
invitation_accepted: it was accepted first. Remove the member instead.
どのオペレーションも返しうるエラー400401403422500エラー一覧
ほかの提供先
POST/members/invitations/{invitationId}/resend
Send an invitation again
Sends a waiting invitation again: a new link, fourteen more days, and the old link retired, so only the newest email works. It renews an expired invitation too. delivered and deliveryError describe this send.
The per-person daily allowance is counted against the person who sent the invitation first when a key asks, and against the person an app acts for when an app does.
The invitation's role cannot hold more than the caller does, the same rule as POST /members: a role with a permission the key or token lacks, any console-only one included, is insufficient_authority, a 403. An app acting for a member is also refused with insufficient_authority when the invitation carries addresses or domains that member does not reach.
Requires the members:write scope.
パスパラメーター
invitationIdstring必須The invitation id from
GET /members/invitations,winv_and 24 hex.
戻り値
Sent again, with a new link and a new expiry.
エラー
- 403
insufficient_authority: the invitation's role holds a permission the caller does not, or an app acting for a member would send again addresses or domains that member does not reach.- 404
No invitation with that id is waiting.
- 409
invitation_too_soon(that address was sent an invitation in the last ten minutes) orinvitation_limit_reached.
どのオペレーションも返しうるエラー400401422500エラー一覧
ほかの提供先
POST/members/{userId}/domains
Grant a domain
Hands one person a whole domain: every address on it, including addresses added after the grant. An upsert, like POST /members/{userId}/addresses: posting again with a different access changes the grant rather than adding a second one.
It is the address axis, so it cannot widen the role: access: "member" lets somebody send only if their role also holds emails:send. Somebody who is not in the workspace yet is refused, so invite them first, and the owner is refused because they already reach every domain. A key or an app limited to particular addresses or domains is refused, and an app acting for a member can only give a domain that member reaches. Adding people needs a plan with team access, so a workspace without it is refused with 403 plan_required.
Requires the members:write scope.
パスパラメーター
userIdstring必須The ACCOUNT id, which is what
GET /membersreturns and not the email address. An email identifies a person to a human and is the wrong key here: it can be changed on the account, and a caller holding a stale one would quietly address the wrong grant.
リクエストボディ
domainIdstring必須A domain on this workspace.
accessstringmemberreads the address and sends as it;vieweronly reads it. The second axis, ANDed with the role. This cannot widen what a role does not already allow.次のいずれか"member""viewer"既定値"member"
戻り値
The whole member, with the grant applied.
エラー
- 403
The key lacks the scope, or may not send as that address.
step_up_required: the call was made with an OAuth access token that has not been verified in the last 60 minutes. Ask for a code withPOST /security/step-up, send it toPOST /security/step-up/verify, then repeat the call. The person can also choose Allow changes for 60 minutes on the app in Account settings, Connected apps, on the OpenEmail website. An API key is never asked for a code.
どのオペレーションも返しうるエラー400401404422500エラー一覧
ほかの提供先
DELETE/members/{userId}/domains/{domainId}
Revoke a domain
Takes a whole domain back and leaves the person in the workspace, with their role and their other grants. Addresses on the domain that were granted one by one stay granted. A domain that is not on this workspace is refused rather than quietly ignored, and the member comes back so the answer shows what they can still reach.
Requires the members:write scope.
パスパラメーター
userIdstring必須The ACCOUNT id, which is what
GET /membersreturns and not the email address. An email identifies a person to a human and is the wrong key here: it can be changed on the account, and a caller holding a stale one would quietly address the wrong grant.domainIdstring必須A domain on THIS workspace, as
GET /domainsreturns it. One belonging to another is refused, not ignored.
戻り値
The member, with what they can still reach.
エラー
- 403
The key lacks the scope, or may not send as that address.
step_up_required: the call was made with an OAuth access token that has not been verified in the last 60 minutes. Ask for a code withPOST /security/step-up, send it toPOST /security/step-up/verify, then repeat the call. The person can also choose Allow changes for 60 minutes on the app in Account settings, Connected apps, on the OpenEmail website. An API key is never asked for a code.
どのオペレーションも返しうるエラー400401404422500エラー一覧
ほかの提供先
オブジェクト
Invitationobject
objectstring- 次のいずれか
"invitation" idstringemailstringLower-cased. The only address that can accept it.
roleobjectidstringnamestringbuiltinstring- null も可次のいずれか
"owner""admin""member""viewer""developer""billing"
addressesobject[]addressIdstringaddressstringaccessstring- 次のいずれか
"member""viewer"
domainsobject[]domainIdstringdomainstringaccessstring- 次のいずれか
"member""viewer"
expiresAtstring- 形式
date-time expiredbooleanThe link no longer works. An expired invitation stays waiting until it is sent again, which renews it, or withdrawn.
lastSentAtstringWhen the invitation email last went out, the first send included.
形式date-timedeliveredbooleanWhether the invitation email left the mail server. False is worth surfacing: nothing reached them. Null when no outcome was recorded for the last send.
null も可deliveryErrorstring- null も可
createdAtstring- 形式
date-time
InvitationListobject
objectstring- 次のいずれか
"list" dataInvitation[]hasMorebooleanTrue when another page follows. Pass
nextCursorback ascursorto read it.nextCursorstringAn opaque cursor for the next page, or null on the last page. Pass it back unchanged.
null も可
Memberobject
objectstring- 次のいずれか
"member" userIdstringThe account. This is what every path here takes, not the email address.
emailstringnamestring- null も可
imagestring- null も可
roleobjectThe role they hold.
idis null when nobody chose it. Seeimplied.idstring- null も可
namestringbuiltinstring- null も可次のいずれか
"owner""admin""member""viewer""developer""billing"
isOwnerbooleanTrue on exactly one row, the account the workspace is keyed on. They sort first, hold every permission whatever their role row says, and POST, PATCH and DELETE all refuse them with member_is_owner. Exclude them when counting seats.
impliedbooleanNOBODY CHOSE THIS ROLE. Sharing shipped long before roles did, so a great many people have address grants and no membership row at all; rather than deny them their mail until a backfill has run, the widest grant they hold names a built-in and that is what is reported. Show it as implied by access rather than as a decision. Until somebody PATCHes them, widening their addresses silently widens what they may do.
permissionsstring[]The resolved list, the same one
role.permissionswould give.次のいずれか"emails:send""emails:read""drafts:read""drafts:write""threads:read""threads:write""files:read""files:write""labels:read""labels:write""contacts:read""contacts:write""audiences:read""audiences:write""calendar:read""calendar:write""templates:read""templates:write""domains:read""domains:write""webhooks:read""webhooks:write""rules:read""rules:write""connections:read""members:read""members:write""roles:read""roles:write""settings:read""settings:write""keys:write""keys:read""keys:manage""forms:read""forms:write""billing:read""billing:write""account:read""account:write""addresses:all""api-keys:read""api-keys:write""workspace:manage"addressesobject[]Which addresses on this workspace they were granted, and how. Empty is a real answer and a common one: somebody with a role and no addresses can do a great deal to nothing at all. The exception is
permissionsholdingaddresses:all, which reaches every address on every domain of the workspace, including ones added later, whatever this lists. It still lists only the addresses granted directly, which such a member may have kept from before or been given since.addressIdstringaddressstringaccessstringThe older per-address vocabulary, deliberately not overlapping with the permission names:
memberreads the address and sends as it,vieweronly reads it. ANDed with the role rather than added to it.viewerhere refuses a send from somebody whose role holdsemails:send, unless the role also holdsaddresses:all.次のいずれか"member""viewer"
domainsobject[]Whole domains they hold. A domain grant reaches every address on that domain, including ones created after the grant, at the given access. Addresses under a held domain also appear in
addressesonly when they were granted individually as well. Somebody whosepermissionsholdaddresses:allreaches every domain whether or not one is listed here.domainIdstringdomainstringaccessstring- 次のいずれか
"member""viewer"
createdAtstringWhen they were made a member. Null for the legacy grant holders, who never were.
null も可形式date-time
MemberListobject
objectstring- 次のいずれか
"list" dataMember[]hasMorebooleanTrue when another page follows. Pass
nextCursorback ascursorto read it.nextCursorstringAn opaque cursor for the next page, or null on the last page. Pass it back unchanged.
null も可