OpenRelay Account API

The signed-in user: profile, memberships, and first-time onboarding.

OpenAPI Specification

openrelay-account-api-openapi.yml Raw ↑
openapi: 3.1.0
info:
  description: 'The OpenRelay control-plane REST API. Deploy GPU VMs and inference clusters, manage organizations and billing, and automate your infrastructure. All requests are authenticated with an API key (`vl_…`) unless noted otherwise.

    '
  title: OpenRelay Account API
  version: 0.1.0
servers:
- description: Production
  url: https://api.openrelay.inc
- description: Beta
  url: https://api.beta.openrelay.inc
- description: Local development
  url: http://localhost:8083
tags:
- description: 'The signed-in user: profile, memberships, and first-time onboarding.'
  name: Account
paths:
  /v1/me:
    get:
      description: Returns the signed-in user's profile and organization memberships. Requires a dashboard session token; API keys cannot call this endpoint.
      operationId: getMe
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Me'
          description: The caller's profile + orgs
        '401':
          $ref: '#/components/responses/Unauthorized'
      security:
      - apiKey: []
      summary: Current user profile and org memberships
      tags:
      - Account
      x-openrelay-cli:
        hidden: true
      x-openrelay-mcp:
        exclude: true
  /v1/me/invites:
    get:
      description: Returns unexpired pending invites whose invited email matches the session's email. Requires a dashboard session token; API keys are org service accounts and cannot hold or accept invites.
      operationId: listMyInvites
      responses:
        '200':
          content:
            application/json:
              schema:
                items:
                  $ref: '#/components/schemas/MyInvite'
                type: array
          description: Pending invites for the caller
        '401':
          $ref: '#/components/responses/Unauthorized'
      security:
      - apiKey: []
      summary: Pending org invites addressed to the signed-in user's email
      tags:
      - Account
      x-openrelay-cli:
        hidden: true
      x-openrelay-mcp:
        exclude: true
  /v1/me/invites/{orgId}/accept:
    post:
      description: 'Creates the membership for the invite addressed to the session''s email in the given org, then consumes the invite. This is the only way an invite becomes a membership: the invitee must be authenticated with the invited email and act explicitly.'
      operationId: acceptOrgInvite
      parameters:
      - in: path
        name: orgId
        required: true
        schema:
          type: string
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AcceptInviteResult'
          description: Joined the organization
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '410':
          $ref: '#/components/responses/Gone'
      security:
      - apiKey: []
      summary: Accept a pending org invite (session only)
      tags:
      - Account
      x-openrelay-cli:
        hidden: true
      x-openrelay-mcp:
        exclude: true
  /v1/me/invites/{orgId}/decline:
    post:
      operationId: declineOrgInvite
      parameters:
      - in: path
        name: orgId
        required: true
        schema:
          type: string
      responses:
        '204':
          description: Declined (idempotent)
        '401':
          $ref: '#/components/responses/Unauthorized'
      security:
      - apiKey: []
      summary: Decline a pending org invite (session only)
      tags:
      - Account
      x-openrelay-cli:
        hidden: true
      x-openrelay-mcp:
        exclude: true
  /v1/me/profile:
    patch:
      description: Requires a signed-in dashboard session token; API keys cannot call this endpoint.
      operationId: updateProfile
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateProfileRequest'
        required: true
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserProfile'
          description: Updated
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      security:
      - apiKey: []
      summary: Update the caller's profile
      tags:
      - Account
      x-openrelay-cli:
        hidden: true
      x-openrelay-mcp:
        exclude: true
  /v1/onboarding/bootstrap:
    post:
      description: Requires a signed-in dashboard session token; API keys cannot call this endpoint.
      operationId: bootstrap
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BootstrapRequest'
        required: false
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BootstrapResult'
          description: Bootstrapped (or already existed)
        '401':
          $ref: '#/components/responses/Unauthorized'
      security:
      - apiKey: []
      summary: Create the caller's profile and first org (idempotent)
      tags:
      - Account
      x-openrelay-cli:
        hidden: true
      x-openrelay-mcp:
        exclude: true
  /v1/whoami:
    get:
      description: Returns the calling principal (API key or user session) and the organization the request acts in. For an API key that org is fixed by the key; for a session it is the active org, and availableOrgs lists every org the user belongs to. Unlike /v1/me this works for API keys and does not onboard.
      operationId: whoami
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Whoami'
          description: The caller's principal + acting org
        '401':
          $ref: '#/components/responses/Unauthorized'
      security:
      - apiKey: []
      summary: The current principal and the org it acts in
      tags:
      - Account
      x-openrelay-mcp:
        default: true
components:
  schemas:
    AcceptInviteResult:
      properties:
        organizationId:
          type: string
        role:
          type: string
      required:
      - organizationId
      - role
      type: object
    Whoami:
      properties:
        availableOrgs:
          description: Every org the user belongs to (session only).
          items:
            $ref: '#/components/schemas/OrgMembership'
          type: array
        email:
          description: Set for a user session.
          type: string
        organizationId:
          description: The org this request acts in (fixed for a key, the active org for a session; may be empty for a session mid-onboarding).
          type: string
        organizationName:
          type: string
        principalType:
          description: Whether the caller authenticated with an API key or a user session.
          enum:
          - api_key
          - user
          type: string
        role:
          description: The user's role in the acting org (session only).
          type: string
        scopes:
          description: The API key's scopes (key principal only).
          items:
            type: string
          type: array
        userId:
          description: Set for a user session.
          type: string
      required:
      - principalType
      - organizationId
      type: object
    OrgMembership:
      properties:
        features:
          $ref: '#/components/schemas/OrgFeatures'
        name:
          type: string
        organizationId:
          type: string
        role:
          type: string
      required:
      - organizationId
      - name
      - role
      - features
      type: object
    UserProfile:
      properties:
        avatarUrl:
          type: string
        defaultOrganizationId:
          type: string
        email:
          type: string
        fullName:
          type: string
        id:
          type: string
      required:
      - id
      - email
      type: object
    UpdateProfileRequest:
      properties:
        avatarUrl:
          type: string
        defaultOrganizationId:
          type: string
        fullName:
          type: string
      type: object
    Me:
      properties:
        organizations:
          items:
            $ref: '#/components/schemas/OrgMembership'
          type: array
        user:
          $ref: '#/components/schemas/UserProfile'
      required:
      - user
      - organizations
      type: object
    BootstrapResult:
      properties:
        organizationId:
          type: string
        role:
          type: string
      required:
      - organizationId
      - role
      type: object
    Error:
      properties:
        code:
          type: string
        error:
          type: string
      required:
      - error
      type: object
    BootstrapRequest:
      properties:
        orgName:
          type: string
      type: object
    MyInvite:
      properties:
        expiresAt:
          type: string
        invitedAt:
          type: string
        inviterEmail:
          description: Email of the user who sent the invite, when resolvable.
          type: string
        organizationId:
          type: string
        organizationName:
          type: string
        role:
          type: string
      required:
      - organizationId
      - role
      - invitedAt
      type: object
    OrgFeatures:
      description: Per-org feature entitlements the dashboard gates its UI on.
      properties:
        batch:
          description: The org is allowlisted for the Batch API (batch-api.md §8).
          type: boolean
        publicEndpoint:
          deprecated: true
          description: Vestigial, always false. The public-endpoint feature is GA (ungated); this field is kept only to avoid a breaking response-contract change and will be removed in a follow-up deprecation PR.
          type: boolean
      required:
      - batch
      - publicEndpoint
      type: object
  responses:
    Forbidden:
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
      description: API key lacks the required scope
    Gone:
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
      description: The resource existed but is no longer usable (e.g. an expired invite)
    NotFound:
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
      description: Resource not found
    Conflict:
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
      description: The request conflicts with existing state
    Unauthorized:
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
      description: Missing or invalid API key
  securitySchemes:
    apiKey:
      description: 'OpenRelay API key. Send it as `Authorization: Bearer vl_…`.'
      scheme: bearer
      type: http