diff --git a/specification/DigitalOcean-public.v2.yaml b/specification/DigitalOcean-public.v2.yaml index b8c29b46..ae990ea6 100644 --- a/specification/DigitalOcean-public.v2.yaml +++ b/specification/DigitalOcean-public.v2.yaml @@ -419,6 +419,14 @@ tags: NFS actions are tasks that can be executed on an NFS share. These can be things like resizing, snapshotting, etc. + - name: Organizations + description: |- + Organizations group multiple teams under a shared administrative boundary. + The Organizations API lets you create teams within an organization and + list the teams that belong to it. + + These endpoints must be called in an organization context. + - name: Partner Network Connect description: |- Partner Network Connect lets you establish high-bandwidth, low-latency @@ -690,6 +698,7 @@ x-tagGroups: - Monitoring - NFS - NFS Actions + - Organizations - Partner Network Connect - Project Resources - Projects @@ -1994,6 +2003,14 @@ paths: delete: $ref: "resources/nfs/nfs_access_point_delete.yml" + /v2/organizations/team: + post: + $ref: "resources/organizations/organizations_create_team.yml" + + /v2/organizations/teams: + get: + $ref: "resources/organizations/organizations_list_teams.yml" + /v2/partner_network_connect/attachments: get: $ref: "resources/partner_network_connect/partner_attachment_list.yml" diff --git a/specification/resources/organizations/examples/curl/organizations_create_team.yml b/specification/resources/organizations/examples/curl/organizations_create_team.yml new file mode 100644 index 00000000..b4b2650c --- /dev/null +++ b/specification/resources/organizations/examples/curl/organizations_create_team.yml @@ -0,0 +1,7 @@ +lang: cURL +source: |- + curl -X POST \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer $DIGITALOCEAN_TOKEN" \ + -d '{"name":"production","invitations":[{"email":"member@example.com","role":"member"},{"email":"biller@example.com","role":"biller"}]}' \ + "https://api.digitalocean.com/v2/organizations/team" diff --git a/specification/resources/organizations/examples/curl/organizations_list_teams.yml b/specification/resources/organizations/examples/curl/organizations_list_teams.yml new file mode 100644 index 00000000..ffcbd0f3 --- /dev/null +++ b/specification/resources/organizations/examples/curl/organizations_list_teams.yml @@ -0,0 +1,6 @@ +lang: cURL +source: |- + curl -X GET \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer $DIGITALOCEAN_TOKEN" \ + "https://api.digitalocean.com/v2/organizations/teams" diff --git a/specification/resources/organizations/models/create_team_request.yml b/specification/resources/organizations/models/create_team_request.yml new file mode 100644 index 00000000..36feb4bc --- /dev/null +++ b/specification/resources/organizations/models/create_team_request.yml @@ -0,0 +1,22 @@ +type: object +required: + - name +properties: + name: + type: string + example: production + description: The human-readable name for the team to create. + + invitations: + type: array + description: > + Optional invitations to send when creating the team. Each invitation + includes an email address and a role. The `owner` role cannot be + assigned via invitation. + items: + $ref: 'organization_team.yml#/team_invitation' + example: + - email: member@example.com + role: member + - email: biller@example.com + role: biller diff --git a/specification/resources/organizations/models/organization_team.yml b/specification/resources/organizations/models/organization_team.yml new file mode 100644 index 00000000..d9f52b4d --- /dev/null +++ b/specification/resources/organizations/models/organization_team.yml @@ -0,0 +1,114 @@ +organization_team: + type: object + description: A team that belongs to an organization. + properties: + id: + type: integer + format: uint64 + readOnly: true + example: 4126873 + description: A unique identifier for the team. + + uuid: + type: string + format: uuid + readOnly: true + example: 4e1bfbc3-dc3e-41f2-a18f-1b4d7ba71679 + description: A unique universal identifier for the team. + + name: + type: string + example: production + description: The human-readable name for the team. + + email: + type: string + format: email + example: sammy@example.com + description: The email address associated with the team. + + member_count: + type: integer + format: uint64 + readOnly: true + example: 3 + description: The number of members on the team. + + status: + type: string + enum: + - joined + - pending + example: joined + description: The team's membership status within the organization. + + joined_organization_at: + type: string + format: date-time + readOnly: true + example: "2024-06-12T15:04:05Z" + description: > + A time value given in ISO8601 combined date and time format that + represents when the team joined the organization. + + company: + type: string + example: DigitalOcean + description: The company name associated with the team, if set. + +create_team: + type: object + description: The team resource returned when a team is created in an organization. + required: + - uuid + - name + properties: + uuid: + type: string + format: uuid + readOnly: true + example: 4e1bfbc3-dc3e-41f2-a18f-1b4d7ba71679 + description: A unique universal identifier for the newly created team. + + name: + type: string + example: production + description: The human-readable name for the newly created team. + +team_invitation: + type: object + description: An invitation to join a newly created team. + required: + - email + - role + properties: + email: + type: string + format: email + example: member@example.com + description: The email address of the user to invite. + + role: + type: string + enum: + - member + - biller + - billing viewer + - resource viewer + - modifier + example: member + description: > + The role to assign to the invited user. The `owner` role cannot be + assigned via invitation. + +team_invitation_status: + type: object + description: The result of attempting to send a team invitation. + properties: + status: + type: string + enum: + - ok + - daily_invite_limit_reached + example: ok + description: The invitation delivery status for the email address. diff --git a/specification/resources/organizations/organizations_create_team.yml b/specification/resources/organizations/organizations_create_team.yml new file mode 100644 index 00000000..14d329e0 --- /dev/null +++ b/specification/resources/organizations/organizations_create_team.yml @@ -0,0 +1,67 @@ +operationId: organizations_create_team + +summary: Create a Team in an Organization + +description: | + To create a new team within an organization, send a POST request to + `/v2/organizations/team`. + + This endpoint must be called in an organization context. Optionally include + `invitations` to invite users to the new team. The `owner` role cannot be + assigned via invitation. + +tags: + - Organizations + +requestBody: + required: true + + content: + application/json: + schema: + $ref: 'models/create_team_request.yml' + + examples: + Create Team: + value: + name: production + Create Team With Invitations: + value: + name: production + invitations: + - email: member@example.com + role: member + - email: biller@example.com + role: biller + +responses: + '201': + $ref: 'responses/create_team.yml' + + '400': + $ref: '../../shared/responses/bad_request.yml' + + '401': + $ref: '../../shared/responses/unauthorized.yml' + + '403': + $ref: '../../shared/responses/forbidden.yml' + + '412': + $ref: 'responses/precondition_failed.yml' + + '429': + $ref: '../../shared/responses/too_many_requests.yml' + + '500': + $ref: '../../shared/responses/server_error.yml' + + default: + $ref: '../../shared/responses/unexpected_error.yml' + +x-codeSamples: + - $ref: 'examples/curl/organizations_create_team.yml' + +security: + - bearer_auth: + - 'organization:create' diff --git a/specification/resources/organizations/organizations_list_teams.yml b/specification/resources/organizations/organizations_list_teams.yml new file mode 100644 index 00000000..3459ea61 --- /dev/null +++ b/specification/resources/organizations/organizations_list_teams.yml @@ -0,0 +1,41 @@ +operationId: organizations_list_teams + +summary: List Teams in an Organization + +description: | + To list all teams in an organization, send a GET request to + `/v2/organizations/teams`. + + This endpoint must be called in an organization context. + +tags: + - Organizations + +responses: + '200': + $ref: 'responses/list_teams.yml' + + '401': + $ref: '../../shared/responses/unauthorized.yml' + + '403': + $ref: '../../shared/responses/forbidden.yml' + + '412': + $ref: 'responses/precondition_failed.yml' + + '429': + $ref: '../../shared/responses/too_many_requests.yml' + + '500': + $ref: '../../shared/responses/server_error.yml' + + default: + $ref: '../../shared/responses/unexpected_error.yml' + +x-codeSamples: + - $ref: 'examples/curl/organizations_list_teams.yml' + +security: + - bearer_auth: + - 'organization:read' diff --git a/specification/resources/organizations/responses/create_team.yml b/specification/resources/organizations/responses/create_team.yml new file mode 100644 index 00000000..450c9315 --- /dev/null +++ b/specification/resources/organizations/responses/create_team.yml @@ -0,0 +1,42 @@ +description: > + The response will be a JSON object with a `team` key containing the created + team and an optional `invitations` key mapping invitee email addresses to + invitation status objects. + +headers: + ratelimit-limit: + $ref: '../../../shared/headers.yml#/ratelimit-limit' + ratelimit-remaining: + $ref: '../../../shared/headers.yml#/ratelimit-remaining' + ratelimit-reset: + $ref: '../../../shared/headers.yml#/ratelimit-reset' + +content: + application/json: + schema: + type: object + required: + - team + properties: + team: + $ref: '../models/organization_team.yml#/create_team' + invitations: + type: object + additionalProperties: + $ref: '../models/organization_team.yml#/team_invitation_status' + description: > + A map of invitee email addresses to invitation status results. + example: + member@example.com: + status: ok + biller@example.com: + status: ok + example: + team: + uuid: 4e1bfbc3-dc3e-41f2-a18f-1b4d7ba71679 + name: production + invitations: + member@example.com: + status: ok + biller@example.com: + status: ok diff --git a/specification/resources/organizations/responses/list_teams.yml b/specification/resources/organizations/responses/list_teams.yml new file mode 100644 index 00000000..c5f25cc7 --- /dev/null +++ b/specification/resources/organizations/responses/list_teams.yml @@ -0,0 +1,40 @@ +description: > + The response will be a JSON object with a `teams` key. This will be set to + an array of team objects belonging to the organization. + +headers: + ratelimit-limit: + $ref: '../../../shared/headers.yml#/ratelimit-limit' + ratelimit-remaining: + $ref: '../../../shared/headers.yml#/ratelimit-remaining' + ratelimit-reset: + $ref: '../../../shared/headers.yml#/ratelimit-reset' + +content: + application/json: + schema: + type: object + required: + - teams + properties: + teams: + type: array + items: + $ref: '../models/organization_team.yml#/organization_team' + example: + teams: + - id: 4126873 + uuid: 4e1bfbc3-dc3e-41f2-a18f-1b4d7ba71679 + name: production + email: sammy@example.com + member_count: 3 + status: joined + joined_organization_at: "2024-06-12T15:04:05Z" + company: DigitalOcean + - id: 4126874 + uuid: addb4547-6bab-419a-8542-76263a033cf6 + name: staging + email: staging@example.com + member_count: 2 + status: joined + joined_organization_at: "2024-07-01T10:00:00Z" diff --git a/specification/resources/organizations/responses/precondition_failed.yml b/specification/resources/organizations/responses/precondition_failed.yml new file mode 100644 index 00000000..5a7073ef --- /dev/null +++ b/specification/resources/organizations/responses/precondition_failed.yml @@ -0,0 +1,19 @@ +description: > + The request could not be completed because a required precondition was not + met. + +headers: + ratelimit-limit: + $ref: '../../../shared/headers.yml#/ratelimit-limit' + ratelimit-remaining: + $ref: '../../../shared/headers.yml#/ratelimit-remaining' + ratelimit-reset: + $ref: '../../../shared/headers.yml#/ratelimit-reset' + +content: + application/json: + schema: + $ref: '../../../shared/models/error.yml' + example: + id: precondition_failed + message: teamgroup limit reached