OpenRelay Account API
The signed-in user: profile, memberships, and first-time onboarding.
The signed-in user: profile, memberships, and first-time onboarding.
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