Bỏ qua tới phần tài liệu
API

Cấp và thu hồi một địa chỉ

Trục thứ hai: một người có thể truy cập những địa chỉ nào, và ở mức nào.

POSTapi.openemail.uk/members/{userId}/addresses

Chạy bất kỳ lệnh nào trong 2 lệnh gọi trên trang này với không gian làm việc của bạn, bằng khóa của chính bạn.

POST /members/{userId}/addresses

Trục thứ hai: một người có thể truy cập những địa chỉ nào, và ở mức nào.

Cấp quyền không phải là vai trò

access là bộ từ vựng cũ theo từng địa chỉ và được cố ý không trùng với tên quyền: member đọc địa chỉ và gửi thư với tư cách địa chỉ đó, viewer chỉ đọc. Nó không nói gì về việc người đó có được gửi thư hay không, điều đó do vai trò của họ quyết định, và cả hai phải cho phép thì thư mới được gửi.

Vai trò của họQuyền được cấp trên billing@Họ có thể gửi với tư cách billing@ không
có `emails:send`memberCó.
có `emails:send`viewerKhông, quyền được cấp từ chối.
không có `emails:send`memberKhông, vai trò từ chối.
có `emails:send`hoàn toàn không được cấpKhông, địa chỉ này không bao giờ nằm trong danh sách mà lệnh gửi được kiểm tra đối chiếu.

Gán vai trò cho ai đó không cho họ địa chỉ nào. Một thành viên có vai trò nhưng không được cấp địa chỉ nào sẽ mở một hộp thư TRỐNG thay vì hộp thư của mọi người, và đó là kiểu thất bại đúng đắn khi bạn vẫn đang quyết định họ nên thấy gì.

Cấp một địa chỉ

Cần members:write. POST /members/{userId}/addresses với { addressId, access }; access mặc định là member. Trả về toàn bộ thông tin thành viên ở trạng thái hiện tại.

curl
curl -X POST "$OE/members/nQ8vBz1aRd4tYwKx7fQ2mN8vBz1aRd4t/addresses" -H "$AUTH" \    -H "Content-Type: application/json" \    -d '{ "addressId": "c40a95f2-1cc6-4d31-82a8-9e075d31c2a8", "access": "viewer" }'
Phản hồi
{    "object": "member",    "userId": "nQ8vBz1aRd4tYwKx7fQ2mN8vBz1aRd4t",    "email": "[email protected]",    "name": "Sam Okonjo",    "image": null,    "role": {      "id": "role_2b81de079c1f0a4b7e05d386",      "name": "Support",      "builtin": null    },    "implied": false,    "permissions": ["emails:send", "emails:read", "threads:read", "threads:write"],    "addresses": [      {        "addressId": "2b81de07-9c1f-4a4b-8e05-d3862c1f0a44",        "address": "[email protected]",        "access": "member"      },      {        "addressId": "c40a95f2-1cc6-4d31-82a8-9e075d31c2a8",        "address": "[email protected]",        "access": "viewer"      }    ],    "createdAt": "2026-08-12T14:20:00.000Z"  }

Dùng POST trên tập con thay vì PUT trên cặp, vì dù sao đây cũng là upsert và id của hàng không phải thứ mà bên gọi bao giờ chỉ định. Gửi lại với access khác là cách để một viewer trở thành member: mỗi cặp (địa chỉ, người) chỉ có một hàng, nên lệnh gọi thứ hai thay đổi mức truy cập thay vì thêm một quyền cấp thứ hai. Điều đó cũng khiến đây là một trong số ít lệnh POST có thể lặp lại an toàn.

Được kiểm soát bằng members:write thay vì quyền sở hữu địa chỉ, đó là điểm khác biệt giữa lệnh này và đường cấp quyền cũ trên router domains. Quyền sở hữu là điều kiện đúng cho người đã thêm tên miền và là điều kiện sai cho một quản trị viên không sở hữu gì nhưng đang quản lý quyền truy cập của không gian làm việc thay mặt chủ sở hữu. Cả hai đều ghi cùng một hàng.

Toàn bộ thông tin thành viên được trả về thay vì chỉ quyền được cấp, để hàng trên màn hình có thể được hiển thị lại mà không cần yêu cầu thứ hai, và để câu trả lời giống nhau dù quyền cấp là mới hay là bản sửa đổi.

Một địa chỉ không thuộc không gian làm việc này sẽ nhận member_not_found, mã 422, kèm param: "addressId". Một khóa chỉ có thể cấp các địa chỉ thuộc không gian làm việc mà khóa được cấp cho.

Cấp quyền cho CHỦ SỞ HỮU không gian làm việc sẽ nhận member_is_owner, mã 422. Họ đã có mọi địa chỉ trên đó, nên lệnh gọi không có gì để thêm.

Thu hồi một địa chỉ

Cần members:write. DELETE /members/{userId}/addresses/{addressId}. Trả về thành viên, không còn địa chỉ đó.

curl
curl -X DELETE \    "$OE/members/nQ8vBz1aRd4tYwKx7fQ2mN8vBz1aRd4t/addresses/c40a95f2-1cc6-4d31-82a8-9e075d31c2a8" \    -H "$AUTH"
Phản hồi
{    "object": "member",    "userId": "nQ8vBz1aRd4tYwKx7fQ2mN8vBz1aRd4t",    "email": "[email protected]",    "name": "Sam Okonjo",    "image": null,    "role": {      "id": "role_2b81de079c1f0a4b7e05d386",      "name": "Support",      "builtin": null    },    "implied": false,    "permissions": ["emails:send", "emails:read", "threads:read", "threads:write"],    "addresses": [      {        "addressId": "2b81de07-9c1f-4a4b-8e05-d3862c1f0a44",        "address": "[email protected]",        "access": "member"      }    ],    "createdAt": "2026-08-12T14:20:00.000Z"  }

Thu hồi ở phạm vi hẹp, và là lệnh nên dùng khi ai đó chuyển nhóm: họ giữ vai trò và các địa chỉ khác, và không còn thấy địa chỉ này.

Một địa chỉ không thuộc không gian làm việc này sẽ bị từ chối thay vì bị lặng lẽ bỏ qua. Nếu không, một lỗi gõ trong id sẽ báo thu hồi thành công dù điều đó chưa bao giờ xảy ra, và đó chính là lỗi mà endpoint này tồn tại để ngăn chặn.

Thành viên được trả về thay vì một tombstone, vì câu trả lời đáng quan tâm là những gì họ vẫn còn truy cập được. Một { deleted: true } ở đây sẽ buộc client phải tự suy ra điều đó bằng phép trừ.

Để thu hồi mọi thứ cùng lúc, DELETE /members/{userId} xóa vai trò cùng mọi quyền được cấp và báo cáo số lượng đã bị xóa.