Mount IT contacts on the Organizations service - #110
Conversation
Default resolution produced organizationsItContacts.listOrganizationItContacts and createItContactInvite. Mount the OrganizationsItContacts tag on ItContacts and name the operations after the resource/action, matching Groups. No SDK has generated IT Contacts yet, so no compat baseline is affected. Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Original prompt from jonatas
|
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
Greptile SummaryThis PR adds generation policy for organization-scoped IT Contacts.
Confidence Score: 5/5The PR appears safe to merge because no eligible blocking failure remains from the available previous-review context. No blocking failure remains. Important Files Changed
Reviews (2): Last reviewed commit: "Mount IT contacts on Organizations" | Re-trigger Greptile |
| // Org-scoped IT contacts -> ItContacts (own service, like Groups) | ||
| OrganizationsItContacts: 'ItContacts', |
There was a problem hiding this comment.
Do we want this as a top-level mount if we created this as a subresource? Should we create it as a top-level resource in the API instead?
There was a problem hiding this comment.
This mount only changes the generated SDK surface, not the API — the HTTP paths stay /organizations/{organization_id}/it_contacts either way.
Precedent for keeping it top-level: Groups is exactly the same shape (/organizations/{organizationId}/groups, .../groups/{groupId}/organization-memberships) and is mounted as its own Groups service, with organizationId passed as an option — workos.groups.listGroups({ organizationId }). Org API keys and authorized applications go the other way (mounted onto ApiKeys / Organizations), which is why the policy needs an explicit rule here. IT contacts have their own object type (it_contact), their own lifecycle and their own actions (invite/revoke), so they read more like Groups than like organizations.listAuthorizedApplications, and mounting them on Organizations would give workos.organizations.listItContacts(...) alongside unrelated org CRUD. jonatas confirmed workos.itContacts.* as the desired surface.
Making it a top-level resource in the API (/it_contacts?organization_id=...) is a bigger, separate call — it would break the shipped endpoints, and no SDK exposes them yet so nothing forces it now. Happy to switch this to Organizations (or hold pending an API change) if you'd rather; that's just editing these two policy entries and regenerating workos/workos-node#1681.
There was a problem hiding this comment.
More-so what I'm saying is it seems like we want it to be both a top-level resource and a sub-resource, but feels like we should choose one.
There was a problem hiding this comment.
Yeah... It needs to be a subresource of organization.
There was a problem hiding this comment.
Got it — the inconsistency you're pointing at is real: API says subresource, this policy says top-level.
Two consistent options:
- Keep the API as-is and mount on
Organizations→workos.organizations.listItContacts({ organizationId }). Two-line change here plus a regen of feat: Add IT Contacts API workos-node#1681. - Make it top-level in the API too (
/it_contactswithorganization_id) and keep this mount. That's a breaking change to already-shipped endpoints, so it needs its own decision — though no SDK exposes IT contacts yet, so the blast radius is limited to direct API users.
Worth noting Groups sits in the same "inconsistent" spot today (/organizations/{organizationId}/groups mounted as top-level Groups), so option 1 makes IT contacts stricter than the closest existing precedent. I don't have a stake either way — @jonatascastro12 asked for workos.itContacts.*, so I'll follow whichever you two land on. Tell me which and I'll push it.
There was a problem hiding this comment.
Keep the API as-is and mount on Organizations
There was a problem hiding this comment.
Done — option 1 is pushed here (OrganizationsItContacts: 'Organizations', commit 7739c4b), and workos/workos-node#1681 now exposes workos.organizations.listItContacts/createItContact/deleteItContact/inviteItContact/revokeItContact({ organizationId, ... }). CI green on both.
IT contacts are a subresource of organization in the API, so keep the SDK surface consistent: workos.organizations.listItContacts(...). Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
| }, | ||
| 'POST /organizations/{organization_id}/it_contacts/{contact_id}/revoke': { | ||
| name: 'revoke_it_contact', | ||
| }, |
There was a problem hiding this comment.
Based on the change above, what do the SDK methods end up looking like?
There was a problem hiding this comment.
Node (other langs get the same names in their own casing):
await workos.organizations.listItContacts({ organizationId });
await workos.organizations.createItContact({ organizationId, email });
await workos.organizations.deleteItContact({ organizationId, contactId });
await workos.organizations.inviteItContact({ organizationId, contactId, intents: ['sso'] });
await workos.organizations.revokeItContact({ organizationId, contactId });Without the hints they'd be workos.organizationsItContacts.listOrganizationItContacts(...) etc. See workos/workos-node#1681 for the actual implementation.
There was a problem hiding this comment.
What do we do for organization domains currently?
There was a problem hiding this comment.
Organization domains are the other shape: the API itself is top-level, not nested — POST /organization_domains (with organization_id in the body), GET|DELETE /organization_domains/{id}, POST /organization_domains/{id}/verify — so they need no mount rule or hints, and the SDK gets workos.organizationDomains.createOrganizationDomain({ organizationId, domain }) / getOrganizationDomain(id) / verifyOrganizationDomain(id) / deleteOrganizationDomain(id).
IT contacts can't follow that without changing the shipped API paths, which is the option we ruled out above. The closest nested precedent is Groups (/organizations/{organizationId}/groups), which is mounted top-level as workos.groups.* — this PR deliberately doesn't follow that one per jonatas' call to keep the SDK consistent with the API hierarchy.
Summary
Adds SDK generation policy for the org-scoped IT Contacts endpoints, which currently resolve to a
OrganizationsItContactsservice with path-derived names (listOrganizationItContacts, etc.).Resulting surface (per review discussion — IT contacts stay a subresource of organization, matching the API):
workos.organizations.listItContacts({ organizationId }),createItContact,deleteItContact,inviteItContact,revokeItContact.npm run sdk:resolveshows all five operations resolving toOrganizationswith those names. Node SDK side: workos/workos-node#1681.Link to Devin session: https://app.devin.ai/sessions/2633e183d1b146d6a18a87e0e1b9c42b
Requested by: @jonatascastro12