Files
Excalidraw/api/openapi.yaml
T

696 lines
21 KiB
YAML

openapi: 3.1.0
info:
title: Excalidraw Full Workspace API
version: 0.1.0
description: Backend-owned workspace API for auth, teams, drawings, folders, projects, templates, revisions, and activity.
servers:
- url: /api
security:
- cookieSession: []
components:
securitySchemes:
cookieSession:
type: apiKey
in: cookie
name: excalidraw_session
schemas:
Error:
type: object
required: [error]
properties:
error:
type: string
User:
type: object
required: [id, name, username, email, locale, timezone, created_at, updated_at]
properties:
id: { type: string }
name: { type: string }
username: { type: string }
email: { type: string, format: email }
avatar_url: { type: [string, "null"] }
locale: { type: string }
timezone: { type: string }
created_at: { type: string, format: date-time }
updated_at: { type: string, format: date-time }
Session:
type: object
required: [id, user_id, expires_at, created_at]
properties:
id: { type: string }
user_id: { type: string }
expires_at: { type: string, format: date-time }
created_at: { type: string, format: date-time }
Team:
type: object
required: [id, name, slug, owner_user_id, plan_type, created_at, updated_at]
properties:
id: { type: string }
name: { type: string }
slug: { type: string }
owner_user_id: { type: string }
plan_type: { type: string, enum: [free, pro] }
created_at: { type: string, format: date-time }
updated_at: { type: string, format: date-time }
TeamMembership:
type: object
required: [id, team_id, user_id, role, joined_at]
properties:
id: { type: string }
team_id: { type: string }
user_id: { type: string }
role: { type: string, enum: [owner, admin, editor, viewer] }
joined_at: { type: string, format: date-time }
user:
$ref: "#/components/schemas/User"
Drawing:
type: object
required: [id, team_id, title, owner_user_id, visibility, is_archived, created_at, updated_at]
properties:
id: { type: string }
team_id: { type: string }
folder_id: { type: [string, "null"] }
project_id: { type: [string, "null"] }
slug: { type: [string, "null"] }
title: { type: string }
description: { type: [string, "null"] }
owner_user_id: { type: string }
latest_revision_id: { type: [string, "null"] }
visibility: { type: string, enum: [private, team, restricted, public-link] }
is_archived: { type: boolean }
thumbnail_asset_id: { type: [string, "null"] }
created_at: { type: string, format: date-time }
updated_at: { type: string, format: date-time }
deleted_at: { type: [string, "null"], format: date-time }
owner:
$ref: "#/components/schemas/User"
DrawingRevision:
type: object
required: [id, drawing_id, revision_number, snapshot_path, snapshot_size, content_hash, created_by, created_at]
properties:
id: { type: string }
drawing_id: { type: string }
revision_number: { type: integer }
snapshot_path: { type: string }
snapshot_size: { type: integer, format: int64 }
content_hash: { type: string }
created_by: { type: string }
created_at: { type: string, format: date-time }
change_summary: { type: [string, "null"] }
snapshot: {}
Template:
type: object
required: [id, scope, type, name, snapshot_path, metadata_json, created_by, created_at, updated_at]
properties:
id: { type: string }
team_id: { type: [string, "null"] }
scope: { type: string, enum: [system, team, personal] }
type: { type: string }
name: { type: string }
description: { type: [string, "null"] }
snapshot_path: { type: string }
metadata_json: { type: object, additionalProperties: true }
created_by: { type: string }
created_at: { type: string, format: date-time }
updated_at: { type: string, format: date-time }
ActivityEvent:
type: object
required: [id, resource_type, resource_id, event_type, metadata_json, created_at]
properties:
id: { type: string }
actor_user_id: { type: [string, "null"] }
team_id: { type: [string, "null"] }
resource_type: { type: string }
resource_id: { type: string }
event_type: { type: string }
metadata_json: { type: object, additionalProperties: true }
created_at: { type: string, format: date-time }
actor:
$ref: "#/components/schemas/User"
TeamInvite:
type: object
required: [id, team_id, email, role, invited_by, expires_at, created_at]
properties:
id: { type: string }
team_id: { type: string }
email: { type: string, format: email }
role: { type: string, enum: [admin, editor, viewer] }
invited_by: { type: string }
expires_at: { type: string, format: date-time }
created_at: { type: string, format: date-time }
PermissionGrant:
type: object
required: [id, resource_type, resource_id, subject_type, subject_id, permission, created_at]
properties:
id: { type: string }
resource_type: { type: string }
resource_id: { type: string }
subject_type: { type: string, enum: [user, team, link] }
subject_id: { type: string }
permission: { type: string, enum: [view, comment, edit, manage, share, invite] }
inherited_from: { type: [string, "null"] }
created_at: { type: string, format: date-time }
ShareLink:
type: object
required: [id, resource_type, resource_id, permission, created_by, created_at]
properties:
id: { type: string }
resource_type: { type: string, enum: [drawing, folder, project] }
resource_id: { type: string }
permission: { type: string, enum: [view, comment, edit] }
expires_at: { type: [string, "null"], format: date-time }
created_by: { type: string }
revoked_at: { type: [string, "null"], format: date-time }
created_at: { type: string, format: date-time }
DrawingAsset:
type: object
required: [id, drawing_id, kind, path, mime_type, size, uploaded_by, created_at]
properties:
id: { type: string }
drawing_id: { type: string }
kind: { type: string, enum: [image, export, attachment, thumbnail] }
path: { type: string }
mime_type: { type: string }
size: { type: integer, format: int64 }
width: { type: [integer, "null"] }
height: { type: [integer, "null"] }
uploaded_by: { type: string }
created_at: { type: string, format: date-time }
Embed:
type: object
required: [id, drawing_id, source_url, canonical_url, provider, embed_type, created_by, created_at]
properties:
id: { type: string }
drawing_id: { type: string }
source_url: { type: string, format: uri }
canonical_url: { type: string, format: uri }
provider: { type: string }
embed_type: { type: string, enum: [link, iframe, provider] }
title: { type: [string, "null"] }
preview_asset_id: { type: [string, "null"] }
safe_embed_html: { type: [string, "null"] }
created_by: { type: string }
created_at: { type: string, format: date-time }
LinkReference:
type: object
required: [id, source_resource_type, source_resource_id, target_resource_type, target_resource_id, created_by, created_at]
properties:
id: { type: string }
source_resource_type: { type: string }
source_resource_id: { type: string }
target_resource_type: { type: string, enum: [drawing, folder, project, embed] }
target_resource_id: { type: string }
label: { type: [string, "null"] }
created_by: { type: string }
created_at: { type: string, format: date-time }
WorkspaceStats:
type: object
required: [teams, members, projects, folders, drawings, templates, revisions, assets, storage_bytes]
properties:
teams: { type: integer }
members: { type: integer }
projects: { type: integer }
folders: { type: integer }
drawings: { type: integer }
templates: { type: integer }
revisions: { type: integer }
assets: { type: integer }
storage_bytes: { type: integer, format: int64 }
Project:
type: object
required: [id, team_id, name, slug, created_by, created_at, updated_at]
properties:
id: { type: string }
team_id: { type: string }
name: { type: string }
slug: { type: string }
description: { type: [string, "null"] }
created_by: { type: string }
created_at: { type: string, format: date-time }
updated_at: { type: string, format: date-time }
Folder:
type: object
required: [id, team_id, name, slug, path_cache, visibility, created_by, created_at, updated_at]
properties:
id: { type: string }
team_id: { type: string }
project_id: { type: [string, "null"] }
parent_folder_id: { type: [string, "null"] }
name: { type: string }
slug: { type: string }
path_cache: { type: string }
visibility: { type: string, enum: [private, team] }
created_by: { type: string }
created_at: { type: string, format: date-time }
updated_at: { type: string, format: date-time }
paths:
/health:
get:
security: []
summary: Health check
responses:
"200":
description: Backend healthy
"503":
description: Backend unhealthy
/auth/signup:
post:
security: []
summary: Create password account
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [name, email, password]
properties:
name: { type: string, minLength: 1, maxLength: 120 }
email: { type: string, format: email }
password: { type: string, minLength: 8, maxLength: 128 }
responses:
"201":
description: Signed up
"409":
description: Email already exists
/auth/login:
post:
security: []
summary: Login with email and password
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [email, password]
properties:
email: { type: string, format: email }
password: { type: string }
responses:
"200":
description: Logged in
"401":
description: Invalid credentials
/auth/logout:
post:
summary: Revoke current session
responses:
"200":
description: Logged out
/auth/me:
get:
summary: Current user
responses:
"200":
description: Current user
content:
application/json:
schema:
$ref: "#/components/schemas/User"
/teams:
get:
summary: List accessible teams
responses:
"200":
description: Teams
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Team"
post:
summary: Create team
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [name]
properties:
name: { type: string }
slug: { type: string }
responses:
"201":
description: Created team
/teams/{teamID}/members:
get:
summary: List team members
parameters:
- in: path
name: teamID
required: true
schema: { type: string }
responses:
"200":
description: Members
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/TeamMembership"
/teams/{teamID}/invites:
get:
summary: List pending team invites
parameters:
- in: path
name: teamID
required: true
schema: { type: string }
responses:
"200":
description: Pending invites
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/TeamInvite"
post:
summary: Create team invite
parameters:
- in: path
name: teamID
required: true
schema: { type: string }
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [email, role]
properties:
email: { type: string, format: email }
role: { type: string, enum: [admin, editor, viewer] }
responses:
"201":
description: Invite and one-time token
/invites/accept:
post:
summary: Accept invite token as current user
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [token]
properties:
token: { type: string }
responses:
"200":
description: Accepted membership
/drawings:
get:
summary: List drawings visible to current user
parameters:
- in: query
name: team_id
schema: { type: string }
responses:
"200":
description: Drawings
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Drawing"
post:
summary: Create drawing
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [title]
properties:
team_id: { type: [string, "null"] }
folder_id: { type: [string, "null"] }
project_id: { type: [string, "null"] }
title: { type: string }
description: { type: [string, "null"] }
visibility: { type: string }
snapshot: {}
responses:
"201":
description: Created drawing
/drawings/{drawingID}:
get:
summary: Get drawing metadata
parameters:
- in: path
name: drawingID
required: true
schema: { type: string }
responses:
"200":
description: Drawing
content:
application/json:
schema:
$ref: "#/components/schemas/Drawing"
patch:
summary: Update drawing metadata
parameters:
- in: path
name: drawingID
required: true
schema: { type: string }
responses:
"200":
description: Updated drawing
delete:
summary: Archive drawing
parameters:
- in: path
name: drawingID
required: true
schema: { type: string }
responses:
"204":
description: Archived
/drawings/{drawingID}/revisions:
get:
summary: List drawing revisions
parameters:
- in: path
name: drawingID
required: true
schema: { type: string }
responses:
"200":
description: Revisions
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/DrawingRevision"
post:
summary: Create immutable drawing revision
parameters:
- in: path
name: drawingID
required: true
schema: { type: string }
responses:
"201":
description: Revision created
/drawings/{drawingID}/permissions:
get:
summary: List explicit drawing permissions
parameters:
- in: path
name: drawingID
required: true
schema: { type: string }
responses:
"200":
description: Permission grants
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/PermissionGrant"
post:
summary: Grant explicit drawing permission
parameters:
- in: path
name: drawingID
required: true
schema: { type: string }
responses:
"201":
description: Created permission grant
/drawings/{drawingID}/share-links:
get:
summary: List active drawing share links
parameters:
- in: path
name: drawingID
required: true
schema: { type: string }
responses:
"200":
description: Share links without token hashes
post:
summary: Create drawing share link
parameters:
- in: path
name: drawingID
required: true
schema: { type: string }
responses:
"201":
description: Created share link and one-time token
/shared/{token}:
get:
security: []
summary: Resolve public share token
parameters:
- in: path
name: token
required: true
schema: { type: string }
responses:
"200":
description: Shared resource payload
/drawings/{drawingID}/assets:
get:
summary: List drawing asset metadata
parameters:
- in: path
name: drawingID
required: true
schema: { type: string }
responses:
"200":
description: Assets
post:
summary: Create drawing asset metadata
parameters:
- in: path
name: drawingID
required: true
schema: { type: string }
responses:
"201":
description: Created asset metadata
/drawings/{drawingID}/embeds:
get:
summary: List drawing embeds
parameters:
- in: path
name: drawingID
required: true
schema: { type: string }
responses:
"200":
description: Embeds
post:
summary: Create safe drawing embed metadata
parameters:
- in: path
name: drawingID
required: true
schema: { type: string }
responses:
"201":
description: Created embed metadata
/drawings/{drawingID}/links:
get:
summary: List drawing link references
parameters:
- in: path
name: drawingID
required: true
schema: { type: string }
responses:
"200":
description: Link references
post:
summary: Create drawing link reference
parameters:
- in: path
name: drawingID
required: true
schema: { type: string }
responses:
"201":
description: Created link reference
/templates:
get:
summary: List system and accessible team templates
parameters:
- in: query
name: team_id
schema: { type: string }
responses:
"200":
description: Templates
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Template"
/activity:
get:
summary: List recent activity for accessible teams
parameters:
- in: query
name: team_id
schema: { type: string }
responses:
"200":
description: Activity
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/ActivityEvent"
/stats:
get:
summary: Workspace counts and storage usage
parameters:
- in: query
name: team_id
schema: { type: string }
responses:
"200":
description: Workspace stats
content:
application/json:
schema:
$ref: "#/components/schemas/WorkspaceStats"
/folders:
get:
summary: List folders
responses:
"200":
description: Folders
post:
summary: Create folder
responses:
"201":
description: Created folder
/projects:
get:
summary: List projects
responses:
"200":
description: Projects
post:
summary: Create project
responses:
"201":
description: Created project