भूमिकाएँ सूचीबद्ध करें
वर्कस्पेस की हर भूमिका, पहले बिल्ट-इन, और हर एक को कितने लोग व कुंजियाँ रखती हैं।
असली कॉल आपकी अपनी कुंजी से आपके वर्कस्पेस पर चलाता है।
GET /roles
वर्कस्पेस की हर भूमिका, पहले बिल्ट-इन, और हर एक को कितने लोग व कुंजियाँ रखती हैं।
दो अक्ष, और वे एक ही सवाल नहीं हैं
export OE=https://api.openemail.ukexport AUTH="Authorization: Bearer $OPENEMAIL_API_KEY"भूमिका बताती है कि कोई इस वर्कस्पेस में क्या कर सकता है: मेल पढ़ना, भेजना, टेम्पलेट संपादित करना, डोमेन जोड़ना। ग्रांट बताता है कि वे यह किन पतों पर कर सकते हैं, और वह बगल में /members/{userId}/addresses पर रहता है — member (पता पढ़ता है और उसके रूप में भेजता है) या viewer (केवल पढ़ता है)। संदेश जाने से पहले दोनों को सहमत होना पड़ता है: emails:send रखने वाली भूमिका बिना ग्रांट के कहीं से नहीं भेज सकती, और viewer ग्रांट के नीचे वर्कस्पेस का हर पता भी कहीं से नहीं भेज सकता।
हर वर्कस्पेस में वही छह भूमिकाएँ seed होती हैं। Owner, Admin, Member और Viewer एक सीढ़ी बनाती हैं। हर एक वह सब रखती है जो अगली रखती है, इसलिए किसी को नीचे करना उनके एक्सेस को किसी दूसरे टुकड़े से बदलने के बजाय संकरा करता है। Developer और Billing इस सीढ़ी के पायदान नहीं हैं: Developer इंटीग्रेशन बनाता है (कुंजियाँ, webhooks, टेम्पलेट, भेजना) और वर्कस्पेस की कोई मेल नहीं पढ़ता, और Billing प्लान तथा इनवॉइस देखता है और कुछ नहीं। दोनों पूरी तरह Admin के भीतर हैं। वे वर्कस्पेस बनते समय नहीं, पहली बार पढ़े जाने पर seed होती हैं, इसलिए इस फ़ीचर से पुराना वर्कस्पेस उन्हें तभी उगा लेता है जब कुछ पूछता है। builtin बताता है कि row किस seed से आई, और बस इतना ही बताता है: ये छह एक शुरुआती बिंदु हैं जिन्हें वर्कस्पेस को अपने हिसाब से ढालना है, और Owner को छोड़कर हर एक का नाम बदला, अनुमतियाँ बदली और हटाया जा सकता है। नाम के बजाय editable और deletable पर शाखा लगाएँ: नाम बदली भूमिका भी इन दोनों का सही जवाब देती है, और उसका नाम अब आपको कुछ नहीं बताता।
Owner ही इकलौता अपवाद है, और वह हर दिशा में अपवाद है: editable: false, deletable: false, और PATCH /members/{userId} पर लक्ष्य के रूप में अस्वीकृत। वह उस खाते का वर्णन करता है जिस पर वर्कस्पेस टिका है और हर अनुमति रखता है, उन अनुमतियों समेत जो किसी बाद की रिलीज़ में जुड़ें — इसीलिए उसकी सूची संग्रहित नहीं, गणना की जाती है। किसी और को मालिक बनाना वर्कस्पेस हस्तांतरण है; यहाँ ऐसा कोई एंडपॉइंट नहीं जो वह करता हो।
बाकी पाँच सब कुछ स्वीकार करती हैं: नई अनुमति-सूची, नया विवरण, नया नाम, एक DELETE। वे स्थायी ढाँचे नहीं, seed किए गए डिफ़ॉल्ट हैं: जो वर्कस्पेस कभी कोई इंटीग्रेशन नहीं बनाता उसे Developer से छुटकारा पाने में सक्षम होना चाहिए, और जहाँ “Member” का अर्थ कुछ संकरा है, वहाँ उसे अपने शब्दों में यह कहने में। केवल मालिक मना करता है, और वह सब कुछ एक ही कोड के तहत मना करता है: role_immutable, param: "roleId" लिए हुए एक 409, चाहे PATCH में नाम हो या अनुमति-सूची। अब कोई भी नाम-बदलाव अपने आप में मना नहीं होता, इसलिए param: "name" वाली अपरिवर्तनीयता से निपटने की ज़रूरत नहीं; नाम अब भी जो इकलौता 409 उठा सकता है वह है role_name_taken, जब वर्कस्पेस की कोई दूसरी भूमिका पहले से उस नाम से जानी जाती है।
इन छह के अलावा, वर्कस्पेस अपनी 24 तक भूमिकाएँ लिख सकता है। सीमा केवल उन्हीं को गिनती है, इसलिए seed की गई भूमिका हटाने से उसमें जगह नहीं मिलती। अनुमतियाँ शब्दशः लेने के बजाय आते समय विस्तारित की जाती हैं (अकेला templates:write templates:read और templates:write के रूप में संग्रहित होता है), इसलिए यह मानने के बजाय कि वह वही है जो आपने भेजी, सूची को रिस्पॉन्स से वापस पढ़ें।
भूमिका API कुंजी की सीमा भी है। उसके विरुद्ध जारी कुंजी key.scopes ∩ role.permissions कर सकती है और उससे ज़्यादा नहीं, जो सीमा पर हर अनुरोध के लिए हल किया जाता है — इसलिए भूमिका संपादित करना उसकी कुंजियों के अगले ही कॉल पर बदल देता है कि वे क्या कर सकती हैं, और बिना भूमिका वाली कुंजी पर कोई सीमा होती ही नहीं। Scopes पेज पर यह पूरा विषय है।
उदाहरण
roles:read चाहिए। बिना कर्सर के। लिफ़ाफ़े में hasMore और nextCursor होते हैं ताकि क्लाइंट उसे हर दूसरे कलेक्शन वाले उसी सूची-कोड को दे सके, और दूसरा पेज कभी होता ही नहीं।
curl "$OE/roles" -H "$AUTH"{ "object": "list", "data": [ { "object": "role", "id": "role_1c94e05d3862c1f0a44b7f3a", "name": "Owner", "description": "The person the workspace belongs to. Holds everything, including additions.", "permissions": ["emails:send", "emails:read", "…", "workspace:manage"], "builtin": "owner", "editable": false, "deletable": false, "members": 0, "apiKeys": 2, "createdAt": "2026-08-01T09:00:00.000Z", "updatedAt": "2026-08-01T09:00:00.000Z" }, { "object": "role", "id": "role_c40a95f21cc65d31c2a89e07", "name": "Viewer", "description": "Reads the mail on the addresses they hold, and changes nothing.", "permissions": [ "emails:read", "drafts:read", "threads:read", "labels:read", "contacts:read", "calendar:read", "templates:read", "rules:read", "connections:read", "settings:read" ], "builtin": "viewer", "editable": true, "deletable": true, "members": 3, "apiKeys": 1, "createdAt": "2026-08-01T09:00:00.000Z", "updatedAt": "2026-08-01T09:00:00.000Z" } ], "hasMore": false, "nextCursor": null}बाकी API की तरह नवीनतम-पहले के बजाय बिल्ट-इन रैंक और फिर नाम से क्रमित (owner, admin, member, viewer, developer, billing, फिर बाकी वर्णक्रम में)। अनुमति-मैट्रिक्स सीढ़ी की तरह पढ़ी जाती है, और उसे createdAt से क्रमित करना सबसे चौड़ी भूमिका को हर हफ़्ते अलग row में रख देता है।
जिस वर्कस्पेस पर कभी कोई भूमिका नहीं रही, वहाँ यही सूची पढ़ना उन छह को seed करता है। seeding एक यूनीक इंडेक्स पर टकराकर दूसरी बार कुछ नहीं करती, इसलिए कॉल idempotent है और केवल पहली बार ही लिखती है — इसी वजह से POST /members हमेशा ऐसी roleId का नाम ले सकता है जो मौजूद हो।
यह एक ही बार seed करता है। वर्कस्पेस दर्ज कर लेता है कि उसे seed किया जा चुका है, इसलिए यह पढ़ना फ़ीचर से पुराने वर्कस्पेस को भर देता है और फिर कभी नहीं लिखता — और इसी से seed की गई भूमिका हटाना स्थायी बनता है। एक पुराने बिल्ड में हर बार पढ़ने पर जो भी टेम्पलेट row गायब होती थी वह दोबारा डाली जाती थी, इसलिए हटाया गया Billing अगले पेज लोड पर नई id के साथ लौट आता था; अब ऐसा नहीं होता।
members और apiKeys वही हैं जिन्हें भूमिका हटाए जाने से पहले कहीं और ले जाना होगा, और इसी से क्लाइंट 409 के बाद नहीं, delete दिखाने से पहले चेतावनी दे सकता है। मालिक की row में आमतौर पर members: 0 होता है: मालिक अपने ही वर्कस्पेस का सदस्य नहीं होता, वह वही खाता है जिस पर वह टिका है।
24 कस्टम भूमिकाओं की कड़ी सीमा ठीक इसीलिए है ताकि यह एक ही रिस्पॉन्स हो सके। चालीस भूमिकाओं वाला वर्कस्पेस “billing@ के रूप में कौन भेज सकता है” का जवाब देखकर नहीं दे सकता, और यही इकलौता सवाल है जिसका जवाब देने के लिए यह फ़ीचर मौजूद है।