Openwork Organizations API

Top-level organization creation and context routes.

OpenAPI Specification

openwork-organizations-api-openapi.yml Raw ↑
openapi: 3.1.0
info:
  title: Den Admin Organizations API
  description: 'OpenAPI spec for the Den control plane API.


    Authentication:

    - Use `Authorization: Bearer <session-token>` for user-authenticated routes that require a Den session.

    - Use `x-api-key: <den-api-key>` for API-key-authenticated routes that accept organization API keys.

    - Public routes like health and documentation do not require authentication.


    Swagger tip: use the security schemes in the Authorize dialog to set either `bearerAuth` or `denApiKey` before trying protected endpoints.'
  version: dev
servers:
- url: https://api.openworklabs.com
tags:
- name: Organizations
  description: Top-level organization creation and context routes.
paths:
  /v1/org:
    patch:
      operationId: patchV1Org
      tags:
      - Organizations
      summary: Update organization
      description: Updates organization fields. Workspace admins can change allowed desktop versions; all other fields remain owner-only. The slug is immutable to avoid breaking dashboard URLs.
      responses:
        '200':
          description: Organization updated successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrganizationResponse'
        '400':
          description: The organization update request body was invalid, contained malformed email domains, or contained an invalid brand icon URL.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UpdateOrganizationBadRequest'
        '401':
          description: The caller must be signed in to update an organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '402':
          description: Enabling enforced SSO or desktop version controls requires an Enterprise plan.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EnterprisePlanRequiredError'
        '403':
          description: The caller does not have permission to update the requested organization fields.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenError'
        '404':
          description: The organization could not be found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFoundError'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  minLength: 2
                  maxLength: 120
                allowedEmailDomains:
                  anyOf:
                  - maxItems: 100
                    type: array
                    items:
                      type: string
                      minLength: 1
                      maxLength: 255
                  - type: 'null'
                allowedDesktopVersions:
                  anyOf:
                  - maxItems: 200
                    type: array
                    items:
                      type: string
                      minLength: 1
                      maxLength: 32
                  - type: 'null'
                requireSso:
                  type: boolean
                brandAppName:
                  anyOf:
                  - type: string
                    minLength: 1
                    maxLength: 64
                  - type: 'null'
                brandLogoUrl:
                  anyOf:
                  - type: string
                    maxLength: 2048
                    format: uri
                  - type: 'null'
                brandIconUrl:
                  anyOf:
                  - type: string
                    maxLength: 2048
                    format: uri
                  - type: 'null'
                brandAccentColor:
                  anyOf:
                  - type: string
                    minLength: 1
                    maxLength: 32
                  - type: 'null'
    get:
      operationId: getV1Org
      tags:
      - Organizations
      summary: Get active organization
      description: Returns the active organization from the current session, including its owner, the current member record, and their team memberships.
      responses:
        '200':
          description: Organization context returned successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrganizationContextResponse'
        '401':
          description: The caller must be signed in to load organization context.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '404':
          description: The organization could not be found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFoundError'
  /v1/brand-assets/{organizationId}/{kind}/{version}:
    get:
      operationId: getV1BrandAssetsByOrganizationIdByKindByVersion
      tags:
      - Organizations
      summary: Read an immutable organization brand asset
      description: Serves a capability-signed, content-addressed organization logo or app icon from this Den deployment.
      responses:
        '200':
          description: Immutable brand image bytes.
        '404':
          description: The managed brand asset could not be found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFoundError'
      parameters:
      - schema:
          type: string
        in: path
        name: organizationId
        required: true
      - schema:
          type: string
        in: path
        name: kind
        required: true
      - schema:
          type: string
        in: path
        name: version
        required: true
  /v1/org/brand-assets:
    post:
      operationId: postV1OrgBrandAssets
      tags:
      - Organizations
      summary: Upload organization brand assets
      description: Validates and stores owner-supplied wordmark and app icon files inside the Den deployment.
      responses:
        '200':
          description: Managed brand assets were saved.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ManagedBrandAssetUploadResponse'
        '400':
          description: A supplied brand asset was invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InvalidManagedBrandAssetError'
        '401':
          description: The caller must be signed in.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '403':
          description: Only workspace owners can upload brand assets.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ForbiddenError'
        '413':
          description: The upload exceeded the request size limit.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InvalidManagedBrandAssetError'
  /v1/orgs/{organizationId}/install-links:
    post:
      operationId: postV1OrgsByOrganizationIdInstallLinks
      tags:
      - Organizations
      summary: Create organization install link
      description: Mints a shareable OpenWork desktop install link for a signed-in organization member. Older active links remain valid unless an owner or admin explicitly requests rotation.
      responses:
        '200':
          description: Install link created successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateInstallLinkResponse'
        '400':
          description: The install-link request was invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InvalidRequestError'
        '401':
          description: The caller must be signed in to create install links.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '403':
          description: The organization needs the installLinks capability enabled, and only workspace owners and admins can rotate existing links.
          content:
            application/json:
              schema:
                anyOf:
                - $ref: '#/components/schemas/ForbiddenError'
                - $ref: '#/components/schemas/CapabilityDisabledError'
        '404':
          description: The organization could not be found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFoundError'
        '429':
          description: The member has created too many install links.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RateLimitedError'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateInstallLinkRequest'
      parameters:
      - schema:
          type: string
        in: path
        name: organizationId
        required: true
  /v1/install-config:
    get:
      operationId: getV1InstallConfig
      tags:
      - Organizations
      summary: Resolve install-link configuration
      description: Returns organization setup details and a fresh desktop connection handoff for a valid install link token.
      responses:
        '200':
          description: Install configuration resolved successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InstallExperienceConfig'
        '400':
          description: The install-link token was invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InvalidRequestError'
        '404':
          description: The install link was missing, expired, or revoked.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InstallLinkNotFoundError'
        '429':
          description: Too many install-link attempts.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RateLimitedError'
      parameters:
      - in: query
        name: token
        schema:
          type: string
          maxLength: 255
          pattern: ^[A-Za-z0-9_-]{8,}$
        required: true
  /v1/install-connect/preview:
    post:
      operationId: postV1InstallConnectPreview
      tags:
      - Organizations
      summary: Preview desktop connection
      description: Resolves a short-lived organization connection code without consuming it.
      responses:
        '200':
          description: Desktop connection resolved successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DesktopConnectGrantResponse'
        '400':
          description: The connection code body was invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InvalidRequestError'
        '404':
          description: The connection code was not found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DesktopConnectGrantFailure'
        '409':
          description: The connection code was already consumed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DesktopConnectGrantFailure'
        '410':
          description: The connection code expired.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DesktopConnectGrantFailure'
        '429':
          description: Too many connection attempts.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RateLimitedError'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                code:
                  type: string
                  pattern: ^[A-Za-z0-9_-]{24,128}$
              required:
              - code
  /v1/install-connect/exchange:
    post:
      operationId: postV1InstallConnectExchange
      tags:
      - Organizations
      summary: Accept desktop connection
      description: Consumes a short-lived organization connection code exactly once.
      responses:
        '200':
          description: Desktop connection resolved successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DesktopConnectGrantResponse'
        '400':
          description: The connection code body was invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InvalidRequestError'
        '404':
          description: The connection code was not found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DesktopConnectGrantFailure'
        '409':
          description: The connection code was already consumed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DesktopConnectGrantFailure'
        '410':
          description: The connection code expired.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DesktopConnectGrantFailure'
        '429':
          description: Too many connection attempts.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RateLimitedError'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                code:
                  type: string
                  pattern: ^[A-Za-z0-9_-]{24,128}$
              required:
              - code
  /v1/install/{platform}:
    get:
      operationId: getV1InstallByPlatform
      tags:
      - Organizations
      summary: Download OpenWork desktop
      description: Streams an explicitly provisioned standard OpenWork installer or redirects directly to the configured standard release. Organization setup remains a separate Den deep-link step.
      responses:
        '200':
          description: Installer artifact returned successfully.
          content:
            text/plain:
              schema:
                type: string
        '302':
          description: Den redirected the browser to a verified normal desktop download.
        '400':
          description: The install-link token or platform was invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InvalidRequestError'
        '404':
          description: The install link was missing, expired, or revoked.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InstallLinkNotFoundError'
        '429':
          description: Too many installer download attempts.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RateLimitedError'
      parameters:
      - in: query
        name: token
        schema:
          type: string
          maxLength: 255
          pattern: ^[A-Za-z0-9_-]{8,}$
        required: true
      - schema:
          type: string
        in: path
        name: platform
        required: true
components:
  schemas:
    RateLimitedError:
      type: object
      properties:
        error:
          type: string
          const: rate_limited
        message:
          type: string
      required:
      - error
      - message
    CreateInstallLinkRequest:
      type: object
      properties:
        rotate:
          default: false
          type: boolean
    OrganizationResponse:
      type: object
      properties:
        organization:
          anyOf:
          - type: object
            properties: {}
            additionalProperties: {}
          - type: 'null'
      required:
      - organization
    ConnectLinkClaims:
      type: object
      properties:
        iss:
          type: string
          format: uri
        aud:
          type: string
          const: openwork-desktop-connect
        iat:
          type: integer
          minimum: 0
          maximum: 9007199254740991
        exp:
          type: integer
          minimum: 0
          maximum: 9007199254740991
        jti:
          type: string
          minLength: 8
        v:
          type: number
          const: 1
        org:
          type: object
          properties:
            name:
              type: string
              minLength: 1
              maxLength: 128
          required:
          - name
        brand:
          type: object
          properties:
            appName:
              type: string
              minLength: 1
              maxLength: 64
            logoUrl:
              anyOf:
              - type: string
                format: uri
              - type: 'null'
            iconUrl:
              anyOf:
              - type: string
                format: uri
              - type: 'null'
          required:
          - appName
          - logoUrl
          - iconUrl
        den:
          type: object
          properties:
            baseUrl:
              type: string
              format: uri
            apiBaseUrl:
              anyOf:
              - type: string
                format: uri
              - type: 'null'
          required:
          - baseUrl
        requireSignin:
          type: boolean
      required:
      - iss
      - aud
      - iat
      - exp
      - jti
      - v
      - org
      - brand
      - den
      - requireSignin
    EnterprisePlanRequiredError:
      type: object
      properties:
        error:
          type: string
          const: enterprise_plan_required
        feature:
          type: string
        message:
          type: string
      required:
      - error
      - feature
      - message
    InvalidBrandIconError:
      type: object
      properties:
        error:
          type: string
          const: invalid_brand_icon
        reason:
          type: string
        message:
          type: string
      required:
      - error
      - reason
      - message
    UpdateOrganizationBadRequest:
      anyOf:
      - $ref: '#/components/schemas/InvalidRequestError'
      - $ref: '#/components/schemas/InvalidEmailDomainError'
      - $ref: '#/components/schemas/InvalidBrandIconError'
    OrganizationOwner:
      type: object
      properties:
        memberId:
          description: Den TypeID with 'om_' prefix and a 26-character base32 suffix.
          format: typeid
          type: string
          minLength: 29
          maxLength: 29
          pattern: ^om_.*
        userId:
          description: Den TypeID with 'usr_' prefix and a 26-character base32 suffix.
          format: typeid
          type: string
          minLength: 30
          maxLength: 30
          pattern: ^usr_.*
        name:
          anyOf:
          - type: string
          - type: 'null'
        email:
          anyOf:
          - type: string
            format: email
            pattern: ^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$
          - type: 'null'
        image:
          anyOf:
          - type: string
          - type: 'null'
      required:
      - memberId
      - userId
      - name
      - email
    UnauthorizedError:
      type: object
      properties:
        error:
          type: string
          const: unauthorized
      required:
      - error
    InstallExperienceConfig:
      type: object
      properties:
        appName:
          default: OpenWork
          type: string
          minLength: 1
          maxLength: 64
        clientName:
          type: string
          minLength: 1
        webUrl:
          type: string
          format: uri
        apiUrl:
          type: string
          format: uri
        requireSignin:
          type: boolean
        logoUrl:
          anyOf:
          - type: string
            format: uri
          - type: 'null'
        iconUrl:
          default: null
          anyOf:
          - type: string
            format: uri
          - type: 'null'
        connectUrl:
          type: string
        connectExpiresAt:
          type: string
          format: date-time
          pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z))$
      required:
      - clientName
      - webUrl
      - apiUrl
      - requireSignin
      - logoUrl
      - connectUrl
      - connectExpiresAt
    NotFoundError:
      type: object
      properties:
        error:
          type: string
        message:
          type: string
      required:
      - error
    InvalidEmailDomainError:
      type: object
      properties:
        error:
          type: string
          const: invalid_email_domain
        message:
          type: string
        invalidDomains:
          type: array
          items:
            type: string
      required:
      - error
      - message
      - invalidDomains
    ForbiddenError:
      type: object
      properties:
        error:
          type: string
          enum:
          - forbidden
          - reauth
        reason:
          type: string
        message:
          type: string
      required:
      - error
    InstallLinkNotFoundError:
      type: object
      properties:
        error:
          type: string
          const: install_link_not_found
      required:
      - error
    InvalidManagedBrandAssetError:
      type: object
      properties:
        error:
          type: string
          const: invalid_brand_asset
        kind:
          anyOf:
          - type: string
            enum:
            - logo
            - icon
          - type: 'null'
        reason:
          type: string
        message:
          type: string
      required:
      - error
      - kind
      - reason
      - message
    DesktopConnectGrantFailure:
      type: object
      properties:
        error:
          type: string
          enum:
          - connect_grant_invalid
          - connect_grant_expired
          - connect_grant_replayed
      required:
      - error
    CapabilityDisabledError:
      type: object
      properties:
        error:
          type: string
          const: capability_disabled
        capability:
          type: string
          enum:
          - installLinks
          - mcpConnections
      required:
      - error
      - capability
    DesktopConnectGrantResponse:
      type: object
      properties:
        claims:
          $ref: '#/components/schemas/ConnectLinkClaims'
      required:
      - claims
    InvalidRequestError:
      type: object
      properties:
        error:
          type: string
          const: invalid_request
        details:
          type: array
          items:
            type: object
            properties:
              message:
                type: string
              path:
                type: array
                items:
                  anyOf:
                  - type: string
                  - type: number
            required:
            - message
            additionalProperties: {}
      required:
      - error
      - details
    CreateInstallLinkResponse:
      type: object
      properties:
        token:
          type: string
        installPageUrl:
          type: string
          format: uri
      required:
      - token
      - installPageUrl
    OrganizationContextResponse:
      type: object
      properties:
        organization:
          type: object
          properties:
            owner:
              anyOf:
              - $ref: '#/components/schemas/OrganizationOwner'
              - type: 'null'
          additionalProperties: {}
        currentMember:
          type: object
          properties: {}
          additionalProperties: {}
        currentMemberTeams:
          type: array
          items:
            type: object
            properties: {}
            additionalProperties: {}
      required:
      - organization
      - currentMember
      - currentMemberTeams
      additionalProperties: {}
    ManagedBrandAssetUploadResponse:
      type: object
      properties:
        assets:
          type: object
          properties:
            logo:
              type: object
              properties:
                kind:
                  type: string
                  enum:
                  - logo
                  - icon
                version:
                  type: string
                  pattern: ^[a-f0-9]{64}$
                extension:
                  type: string
                  enum:
                  - png
                  - jpg
                contentType:
                  type: string
                  enum:
                  - image/png
                  - image/jpeg
                url:
                  type: string
                  format: uri
                width:
                  type: integer
                  exclusiveMinimum: 0
                  maximum: 9007199254740991
                height:
                  type: integer
                  exclusiveMinimum: 0
                  maximum: 9007199254740991
                byteLength:
                  type: integer
                  exclusiveMinimum: 0
                  maximum: 9007199254740991
                originalName:
                  type: string
                uploadedAt:
                  type: string
              required:
              - kind
              - version
              - extension
              - contentType
              - url
              - width
              - height
              - byteLength
              - originalName
              - uploadedAt
            icon:
              type: object
              properties:
                kind:
                  type: string
                  enum:
                  - logo
                  - icon
                version:
                  type: string
                  pattern: ^[a-f0-9]{64}$
                extension:
                  type: string
                  enum:
                  - png
                  - jpg
                contentType:
                  type: string
                  enum:
                  - image/png
                  - image/jpeg
                url:
                  type: string
                  format: uri
                width:
                  type: integer
                  exclusiveMinimum: 0
                  maximum: 9007199254740991
                height:
                  type: integer
                  exclusiveMinimum: 0
                  maximum: 9007199254740991
                byteLength:
                  type: integer
                  exclusiveMinimum: 0
                  maximum: 9007199254740991
                originalName:
                  type: string
                uploadedAt:
                  type: string
              required:
              - kind
              - version
              - extension
              - contentType
              - url
              - width
              - height
              - byteLength
              - originalName
              - uploadedAt
      required:
      - assets
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: session-token
      description: 'Session token passed as `Authorization: Bearer <session-token>` for user-authenticated Den routes.'
    denApiKey:
      type: apiKey
      in: header
      name: x-api-key
      description: Organization API key passed as the `x-api-key` header for API-key-authenticated Den routes.