Superb AI MLOps Platform API

Multi-tenant REST backend for the Superb Platform. 164 operations across tenants, workspaces, image datasets and assets, projects and labeling workflow, annotations, comments, auto-label runs, model training, foundation models, deployments and exports. Bearer-token (Amazon Cognito) authentication with per-request workspace membership resolution, cursor pagination, an Idempotency-Key header on bulk operations, and a stable machine-readable error-code enum.

Operations 164

POST /tenants Create Tenant #
GET /auth/authorize Authorize #
POST /auth/callback Callback #
POST /auth/refresh Refresh #
POST /auth/logout Logout #
GET /me/tenants List My Tenants #
POST /me/tenants Create My Tenant #
GET /me/invitations List My Invitations #
POST /me/invitations/{invitation_id}/accept Accept Invitation #
POST /me/invitations/{invitation_id}/decline Decline Invitation #
POST /tenants/{slug}/invitations Create Invitation #
GET /tenants/{slug}/invitations List Invitations #
POST /tenants/{slug}/invitations/{invitation_id}/revoke Revoke Invitation Route #
POST /tenants/{slug}/users Create User Seeded #
GET /tenants/{slug}/users List Users #
DELETE /tenants/{slug}/users/me Leave Workspace #
GET /tenants/{slug}/users/me Get Me #
PATCH /tenants/{slug}/users/me Update Me #
POST /tenants/{slug}/users/me/password Change My Password #
PATCH /tenants/{slug}/users/{user_id} Update User Role #
DELETE /tenants/{slug}/users/{user_id} Remove Member #
POST /tenants/{slug}/users/me/api-keys Create a new API key for the calling user. #
GET /tenants/{slug}/users/me/api-keys List the calling user's active API keys. #
DELETE /tenants/{slug}/users/me/api-keys/{key_id} Revoke (soft-delete) an API key. #
GET /tenants/{slug}/datasets List All Datasets #
POST /tenants/{slug}/datasets/images Create Image Dataset #
GET /tenants/{slug}/datasets/images/{dataset_id} Get Image Dataset #
PATCH /tenants/{slug}/datasets/images/{dataset_id} Update Image Dataset #
DELETE /tenants/{slug}/datasets/images/{dataset_id} Delete Image Dataset #
GET /tenants/{slug}/datasets/images/{dataset_id}/stats Get Image Dataset Stats #
POST /tenants/{slug}/datasets/images/{dataset_id}/embed Embed Image Dataset #
POST /tenants/{slug}/datasets/images/{dataset_id}/assets/upload-init Upload Init #
POST /tenants/{slug}/datasets/images/{dataset_id}/assets/upload-init/batch Upload Init Batch #
POST /tenants/{slug}/datasets/images/{dataset_id}/assets/upload-init/{upload_id}/complete Upload Complete #
GET /tenants/{slug}/datasets/images/{dataset_id}/assets List Assets #
GET /tenants/{slug}/datasets/images/{dataset_id}/assets/{asset_id} Get Asset #
GET /tenants/{slug}/datasets/images/{dataset_id}/assets/{asset_id}/download-url Get Asset Download Url #
GET /tenants/{slug}/datasets/images/{dataset_id}/assets/{asset_id}/thumbnail-url Get Asset Thumbnail Url #
POST /tenants/{slug}/datasets/images/{dataset_id}/assets/search Search Assets #
POST /tenants/{slug}/datasets/images/{dataset_id}/assets/bulk-delete Bulk Delete #
POST /tenants/{slug}/datasets/images/{dataset_id}/assets/batch-delete Batch Delete Image Assets #
GET /tenants/{slug}/jobs/{job_id} Get Job #
GET /tenants/{slug}/jobs List Jobs #
GET /tenants/{slug}/versions List Tenant Versions #
POST /tenants/{slug}/projects Create Project #
GET /tenants/{slug}/projects List Projects #
GET /tenants/{slug}/projects/{project_id} Get Project Endpoint #
PATCH /tenants/{slug}/projects/{project_id} Update Project #
DELETE /tenants/{slug}/projects/{project_id} Delete Project #
GET /tenants/{slug}/projects/{project_id}/progress Get Project Progress #
GET /tenants/{slug}/projects/{project_id}/classes List Classes #
POST /tenants/{slug}/projects/{project_id}/classes Create Class #
PATCH /tenants/{slug}/projects/{project_id}/classes/{class_id} Update Class #
DELETE /tenants/{slug}/projects/{project_id}/classes/{class_id} Delete Class #
POST /tenants/{slug}/projects/{project_id}/classes/{class_id}/attributes Create Attribute #
PATCH /tenants/{slug}/projects/{project_id}/classes/{class_id}/attributes/{attribute_id} Update Attribute #
DELETE /tenants/{slug}/projects/{project_id}/classes/{class_id}/attributes/{attribute_id} Delete Attribute #
POST /tenants/{slug}/projects/{project_id}/members Add Member #
GET /tenants/{slug}/projects/{project_id}/members List Members #
PATCH /tenants/{slug}/projects/{project_id}/members/{user_id} Update Member #
DELETE /tenants/{slug}/projects/{project_id}/members/{user_id} Remove Member #
POST /tenants/{slug}/projects/{project_id}/versions Create Version #
GET /tenants/{slug}/projects/{project_id}/versions List Versions #
GET /tenants/{slug}/projects/{project_id}/versions/{version_id} Get Version #
PATCH /tenants/{slug}/projects/{project_id}/versions/{version_id} Update Version #
DELETE /tenants/{slug}/projects/{project_id}/versions/{version_id} Delete Version #
GET /tenants/{slug}/projects/{project_id}/versions/{version_id}/assets List Version Assets #
GET /tenants/{slug}/projects/{project_id}/versions/{version_id}/assets/{asset_id} Get Version Asset #
POST /tenants/{slug}/projects/{project_id}/duplicate Duplicate Project #
POST /tenants/{slug}/projects/{project_id}/assets/bulk-update-tags Project Bulk Update Tags #
POST /tenants/{slug}/projects/{project_id}/assets/batch-update-tags Project Assets Batch Update #
GET /tenants/{slug}/projects/{project_id}/tags List Project Tags #
POST /tenants/{slug}/projects/{project_id}/tags Create Project Tag #
PATCH /tenants/{slug}/projects/{project_id}/tags Update Project Tag #
DELETE /tenants/{slug}/projects/{project_id}/tags Delete Project Tag #
POST /tenants/{slug}/projects/{project_id}/assets/tag-summary Project Tag Summary #
POST /tenants/{slug}/projects/{project_id}/assets/bulk-add Project Bulk Add Assets #
POST /tenants/{slug}/projects/{project_id}/assets/bulk-remove Project Bulk Remove Assets #
POST /tenants/{slug}/projects/{project_id}/assets/batch-add Project Assets Batch Add #
POST /tenants/{slug}/projects/{project_id}/assets/batch-remove Project Assets Batch Remove #
POST /tenants/{slug}/projects/{project_id}/assets/bulk-delete-annotations Project Bulk Delete Annotations #
POST /tenants/{slug}/projects/{project_id}/assets/batch-delete-annotations Project Batch Delete Annotations #
POST /tenants/{slug}/projects/{project_id}/assets/bulk-assign Project Bulk Assign #
POST /tenants/{slug}/projects/{project_id}/assets/batch-assign Project Batch Assign #
POST /tenants/{slug}/projects/{project_id}/assets/bulk-unassign Project Bulk Unassign #
POST /tenants/{slug}/projects/{project_id}/assets/batch-unassign Project Batch Unassign #
POST /tenants/{slug}/projects/{project_id}/assets/bulk-approve Project Bulk Approve #
POST /tenants/{slug}/projects/{project_id}/assets/batch-approve Project Batch Approve #
POST /tenants/{slug}/projects/{project_id}/assets/bulk-reject Project Bulk Reject #
POST /tenants/{slug}/projects/{project_id}/assets/batch-reject Project Batch Reject #
POST /tenants/{slug}/projects/{project_id}/assets/bulk-set-status Project Bulk Set Status #
POST /tenants/{slug}/projects/{project_id}/assets/batch-set-status Project Batch Set Status #
POST /tenants/{slug}/projects/{project_id}/assets/{asset_id}/claim Claim Asset #
POST /tenants/{slug}/projects/{project_id}/assets/{asset_id}/assign Assign Asset #
POST /tenants/{slug}/projects/{project_id}/assets/{asset_id}/unassign Unassign Asset #
POST /tenants/{slug}/projects/{project_id}/assets/{asset_id}/submit Submit Asset #
POST /tenants/{slug}/projects/{project_id}/assets/{asset_id}/approve Approve Asset #
POST /tenants/{slug}/projects/{project_id}/assets/{asset_id}/reject Reject Asset #
POST /tenants/{slug}/projects/{project_id}/assets/{asset_id}/skip Skip Asset #
POST /tenants/{slug}/projects/{project_id}/assets/{asset_id}/reopen Reopen Asset #
GET /tenants/{slug}/projects/{project_id}/queue Get My Queue #
GET /tenants/{slug}/projects/{project_id}/queue/stats Queue Stats #
GET /tenants/{slug}/projects/{project_id}/assets List Asset States #
GET /tenants/{slug}/projects/{project_id}/assets/{asset_id} Get Labeling Context #
POST /tenants/{slug}/projects/{project_id}/assets/{asset_id}/annotations Create Annotation #
POST /tenants/{slug}/projects/{project_id}/assets/{asset_id}/annotations/batch-create Batch Create Annotations #
PATCH /tenants/{slug}/projects/{project_id}/annotations/{annotation_id} Update Annotation #
DELETE /tenants/{slug}/projects/{project_id}/annotations/{annotation_id} Delete Annotation #
GET /tenants/{slug}/projects/{project_id}/annotations List Annotations #
POST /tenants/{slug}/projects/{project_id}/annotations/batch-delete Batch Delete Annotations #
POST /tenants/{slug}/projects/{project_id}/annotations/batch-create Project Batch Create Annotations #
POST /tenants/{slug}/projects/{project_id}/annotations/import-init Annotation Import Init #
POST /tenants/{slug}/projects/{project_id}/annotations/bulk-create Project Bulk Create Annotations #
POST /tenants/{slug}/projects/{project_id}/annotations/batch Batch Edit Annotations #
GET /tenants/{slug}/projects/{project_id}/assets/{asset_id}/revisions List Asset Revisions #
GET /tenants/{slug}/projects/{project_id}/assets/{asset_id}/revisions/{seq} Get Asset Revision #
GET /tenants/{slug}/projects/{project_id}/annotations/{annotation_id}/revisions List Annotation Revisions #
POST /tenants/{slug}/projects/{project_id}/assets/{asset_id}/comments Create Comment #
GET /tenants/{slug}/projects/{project_id}/assets/{asset_id}/comments List Asset Comments #
GET /tenants/{slug}/projects/{project_id}/comments List Project Comments #
PATCH /tenants/{slug}/projects/{project_id}/comments/{comment_id} Update Comment #
DELETE /tenants/{slug}/projects/{project_id}/comments/{comment_id} Delete Comment #
POST /tenants/{slug}/projects/{project_id}/comments/{comment_id}/resolve Resolve Comment #
POST /tenants/{slug}/projects/{project_id}/comments/{comment_id}/reopen Reopen Comment #
GET /tenants/{slug}/projects/{project_id}/guideline Read the project guideline (Markdown). #
PUT /tenants/{slug}/projects/{project_id}/guideline Upsert the project guideline. Project managers + workspace admin only. #
POST /tenants/{slug}/projects/{project_id}/guideline/images/upload-init Mint a presigned PUT URL for a guideline image. Manager-only. #
POST /tenants/{slug}/projects/{project_id}/labeling-time/heartbeat Record active seconds for the calling user. Any project member. #
GET /tenants/{slug}/projects/{project_id}/labeling-time Aggregated active-seconds report. group_by drives the row shape. #
POST /tenants/{slug}/projects/{project_id}/versions/{version_id}/exports Create Export #
GET /tenants/{slug}/projects/{project_id}/versions/{version_id}/exports List Exports #
GET /tenants/{slug}/projects/{project_id}/versions/{version_id}/exports/{export_id}/download Get Export Download #
DELETE /tenants/{slug}/projects/{project_id}/versions/{version_id}/exports/{export_id} Delete Export #
POST /tenants/{slug}/projects/{project_id}/versions/{version_id}/training-runs Create Training Run #
GET /tenants/{slug}/projects/{project_id}/versions/{version_id}/training-runs List Training Runs #
GET /tenants/{slug}/projects/{project_id}/versions/{version_id}/training-runs/{run_id} Get Training Run #
GET /tenants/{slug}/projects/{project_id}/versions/{version_id}/training-runs/{run_id}/metrics Get Training Metrics #
POST /tenants/{slug}/projects/{project_id}/versions/{version_id}/training-runs/{run_id}/cancel Cancel Training Run #
GET /tenants/{slug}/projects/{project_id}/versions/{version_id}/training-stats Get Training Stats #
GET /tenants/{slug}/projects/{project_id}/auto-label/config Get Config #
PUT /tenants/{slug}/projects/{project_id}/auto-label/config Put Config #
POST /tenants/{slug}/projects/{project_id}/auto-label/runs Create Run #
GET /tenants/{slug}/projects/{project_id}/auto-label/runs List Runs #
POST /tenants/{slug}/projects/{project_id}/auto-label/runs/{job_id}/cancel Cancel Run #
POST /tenants/{slug}/projects/{project_id}/assets/{asset_id}/auto-label Suggest #
POST /tenants/{slug}/projects/{project_id}/assets/{asset_id}/segment Segment #
GET /tenants/{slug}/models List Models #
GET /tenants/{slug}/models/{model_id} Get Model #
PATCH /tenants/{slug}/models/{model_id} Update Model #
DELETE /tenants/{slug}/models/{model_id} Delete Model #
POST /tenants/{slug}/models/{model_id}/deployments Deploy Model #
GET /tenants/{slug}/deployments List Deployments #
GET /tenants/{slug}/deployments/{deployment_id} Get Deployment #
DELETE /tenants/{slug}/deployments/{deployment_id} Stop Deployment #
POST /tenants/{slug}/deployments/{deployment_id}/predict Predict #
GET /tenants/{slug}/foundation-models List Foundation Models #
GET /tenants/{slug}/foundation-models/{key} Get Foundation Model #
POST /tenants/{slug}/foundation-models/{key}/predict Predict #
GET /tenants/{slug}/training/catalog Get Training Catalog #
GET /tenants/{slug}/datasets/images/{dataset_id}/assets/{asset_id}/annotations Annotations Multi Source #
GET /tenants/{slug}/activity List Tenant Activity #
GET /tenants/{slug}/projects/{project_id}/activity List Project Activity #
GET /tenants/{slug}/datasets/images/{dataset_id}/activity List Dataset Activity #
GET /health Health #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/superb-ai-mlops-platform-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no email required.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

superb-ai-mlops-platform-openapi.json Raw ↑
{"openapi":"3.1.0","info":{"title":"MLOps Platform API","description":"Multi-tenant labeling-platform backend. Login is account-level (ADR-0113): `GET /auth/authorize` → hosted sign-in → `POST /auth/callback` → Bearer token. Workspace membership is resolved per-request: endpoints under `/tenants/{slug}` match the token's `sub` against that tenant's membership table; non-members are rejected with 403. The account surface (`/me/*`) lists workspaces and handles invitation accept/decline.\n\n**Error envelope** (any 4xx/5xx, ADR-0034): `{\"error\": {\"code\": str, \"message\": str, \"hint\": str|null, \"details\": object|null, \"request_id\": str}}`. The `code` field is a stable enum (`components.schemas.ErrorCode`); pattern-match on `code`, not on `message`. The `hint` field, when present, suggests a concrete next step.\n\n**Pagination** (cursor-based, see ADR-0012): list endpoints return `{\"items\": [...], \"next_cursor\": str | null}`. Pass `?cursor=` for the next page. No total counts.\n\n**Idempotency**: bulk-op POSTs accept an `Idempotency-Key` header to deduplicate retries (ADR-0023).","version":"0.1.0"},"paths":{"/tenants":{"post":{"tags":["tenants"],"summary":"Create Tenant","operationId":"tenants-create_tenant","parameters":[{"name":"x-bootstrap-secret","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Bootstrap-Secret"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenantCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenantResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"409":{"description":"Conflict — resource state prevents this action","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate-limited (per-tenant token bucket)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/auth/authorize":{"get":{"tags":["auth"],"summary":"Authorize","description":"Return the hosted-AuthKit URL for the FE to redirect the user to.\nAccount-level: no organization scoping — workspace choice happens in-app\nafter login (`GET /me/tenants`).","operationId":"auth-authorize","parameters":[{"name":"redirect_uri","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"FE callback URL to return to after login. Must be in the allowlist; defaults to the first allowed URI.","title":"Redirect Uri"},"description":"FE callback URL to return to after login. Must be in the allowlist; defaults to the first allowed URI."},{"name":"state","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque FE state, round-tripped to the callback unchanged (e.g. a return-to path). No longer carries a tenant — login is account-level (ADR-0113).","title":"State"},"description":"Opaque FE state, round-tripped to the callback unchanged (e.g. a return-to path). No longer carries a tenant — login is account-level (ADR-0113)."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthorizeResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"409":{"description":"Conflict — resource state prevents this action","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate-limited (per-tenant token bucket)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/auth/callback":{"post":{"tags":["auth"],"summary":"Callback","description":"Exchange the AuthKit `code` for an account-level token pair. Works for\nevery arrival — normal login, fresh sign-up, and the invitation-email\nlanding — because no tenant context is needed: the FE follows up with\n`GET /me/tenants` / `GET /me/invitations` to route the user.","operationId":"auth-callback","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallbackRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthTokens"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"409":{"description":"Conflict — resource state prevents this action","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate-limited (per-tenant token bucket)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/auth/refresh":{"post":{"tags":["auth"],"summary":"Refresh","operationId":"auth-refresh","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthTokens"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"409":{"description":"Conflict — resource state prevents this action","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate-limited (per-tenant token bucket)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/auth/logout":{"post":{"tags":["auth"],"summary":"Logout","description":"Revoke the WorkOS session behind the presented access token. Idempotent —\nan invalid/expired token means there's nothing to revoke. Account-level:\nneeds no tenant, and works for an account with zero memberships.","operationId":"auth-logout","parameters":[{"name":"authorization","in":"header","required":true,"schema":{"type":"string","description":"Bearer access token (the session to revoke is read from it)","title":"Authorization"},"description":"Bearer access token (the session to revoke is read from it)"}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"409":{"description":"Conflict — resource state prevents this action","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate-limited (per-tenant token bucket)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/me/tenants":{"get":{"tags":["me"],"summary":"List My Tenants","description":"Every workspace this account belongs to, newest membership first.","operationId":"me-list_my_tenants","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MyTenantsResponse"}}}},"401":{"description":"Unauthenticated — missing, malformed, or expired Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Authenticated but not authorized for this resource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict — resource state prevents this action","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate-limited (per-tenant token bucket)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"HTTPBearer":[]}]},"post":{"tags":["me"],"summary":"Create My Tenant","description":"Create a workspace as the authenticated account, who becomes its admin.\nThe membership row copies the account's profile (email/name) from WorkOS.","operationId":"me-create_my_tenant","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenantCreateMe"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenantMembership"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"401":{"description":"Unauthenticated — missing, malformed, or expired Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Authenticated but not authorized for this resource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict — resource state prevents this action","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate-limited (per-tenant token bucket)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"HTTPBearer":[]}]}},"/me/invitations":{"get":{"tags":["me"],"summary":"List My Invitations","description":"Pending, unexpired invitations addressed to this account's email —\nthe exact-match rule (ADR-0113): the invited address must equal the\naccount's email, case-insensitively; domains don't count.","operationId":"me-list_my_invitations","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MyInvitationsResponse"}}}},"401":{"description":"Unauthenticated — missing, malformed, or expired Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Authenticated but not authorized for this resource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict — resource state prevents this action","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate-limited (per-tenant token bucket)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"security":[{"HTTPBearer":[]}]}},"/me/invitations/{invitation_id}/accept":{"post":{"tags":["me"],"summary":"Accept Invitation","description":"Join the workspace: membership row with the invited role (profile copied\nfrom the account), WorkOS org membership mirrored, transport invitation\nrevoked. Idempotence: an already-member account gets 409 USER_EMAIL_TAKEN\nonly via a re-created invitation — this row goes terminal on success.","operationId":"me-accept_invitation","security":[{"HTTPBearer":[]}],"parameters":[{"name":"invitation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Invitation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenantMembership"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"401":{"description":"Unauthenticated — missing, malformed, or expired Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Authenticated but not authorized for this resource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict — resource state prevents this action","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate-limited (per-tenant token bucket)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/me/invitations/{invitation_id}/decline":{"post":{"tags":["me"],"summary":"Decline Invitation","description":"Turn the invitation down. Terminal; the admin can re-invite later.","operationId":"me-decline_invitation","security":[{"HTTPBearer":[]}],"parameters":[{"name":"invitation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Invitation Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"401":{"description":"Unauthenticated — missing, malformed, or expired Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Authenticated but not authorized for this resource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict — resource state prevents this action","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate-limited (per-tenant token bucket)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/tenants/{slug}/invitations":{"post":{"tags":["invitations"],"summary":"Create Invitation","description":"Invite an email into this workspace. One live invitation per email; a\nmember's email can't be re-invited. Counts toward the user quota so accepts\ncan't blow past the cap.","operationId":"invitations-create_invitation","security":[{"HTTPBearer":[]}],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvitationCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvitationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"401":{"description":"Unauthenticated — missing, malformed, or expired Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Authenticated but not authorized for this resource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Resource not found in this tenant","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict — resource state prevents this action","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate-limited (per-tenant token bucket)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"get":{"tags":["invitations"],"summary":"List Invitations","operationId":"invitations-list_invitations","security":[{"HTTPBearer":[]}],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/InvitationStatus"},{"type":"null"}],"description":"Filter to one lifecycle state (default: all, newest first).","title":"Status"},"description":"Filter to one lifecycle state (default: all, newest first)."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvitationPage"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"401":{"description":"Unauthenticated — missing, malformed, or expired Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Authenticated but not authorized for this resource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Resource not found in this tenant","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict — resource state prevents this action","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate-limited (per-tenant token bucket)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/tenants/{slug}/invitations/{invitation_id}/revoke":{"post":{"tags":["invitations"],"summary":"Revoke Invitation Route","description":"Withdraw a pending invitation (the emailed link dies). Terminal rows\ncan't be revoked — 409 with the current state.","operationId":"invitations-revoke_invitation_route","security":[{"HTTPBearer":[]}],"parameters":[{"name":"invitation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Invitation Id"}},{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvitationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"401":{"description":"Unauthenticated — missing, malformed, or expired Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Authenticated but not authorized for this resource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Resource not found in this tenant","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict — resource state prevents this action","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate-limited (per-tenant token bucket)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/tenants/{slug}/users":{"post":{"tags":["users"],"summary":"Create User Seeded","description":"Programmatic seeding (ADR-0113): create a ready-to-login member directly —\nWorkOS account with a password, org membership mirror, membership row. No\nemail is sent. Humans join via invitations + in-app accept (routes/me.py,\nroutes/invitations.py).","operationId":"users-create_user_seeded","security":[{"HTTPBearer":[]}],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserSeedCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"401":{"description":"Unauthenticated — missing, malformed, or expired Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Authenticated but not authorized for this resource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Resource not found in this tenant","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict — resource state prevents this action","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate-limited (per-tenant token bucket)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"get":{"tags":["users"],"summary":"List Users","description":"List workspace users. `?q=` matches (case-insensitively) against email,\nfirst_name, and last_name.","operationId":"users-list_users","security":[{"HTTPBearer":[]}],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Max rows per page.","default":50,"title":"Limit"},"description":"Max rows per page."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque pagination cursor from a previous response's `next_cursor`; omit for the first page.","title":"Cursor"},"description":"Opaque pagination cursor from a previous response's `next_cursor`; omit for the first page."},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string","minLength":1,"maxLength":255},{"type":"null"}],"description":"Case-insensitive substring search (min 1 char). Wildcards are matched literally.","title":"Q"},"description":"Case-insensitive substring search (min 1 char). Wildcards are matched literally."},{"name":"role","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/WorkspaceRole"},{"type":"null"}],"description":"`admin` or `member`. Filters to that workspace role.","title":"Role"},"description":"`admin` or `member`. Filters to that workspace role."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserPage"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"401":{"description":"Unauthenticated — missing, malformed, or expired Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Authenticated but not authorized for this resource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Resource not found in this tenant","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict — resource state prevents this action","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate-limited (per-tenant token bucket)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/tenants/{slug}/users/me":{"delete":{"tags":["users"],"summary":"Leave Workspace","description":"Leave this workspace (ADR-0113). The account survives; only the\nmembership goes. The last admin can't leave — hand off first.","operationId":"users-leave_workspace","security":[{"HTTPBearer":[]}],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"401":{"description":"Unauthenticated — missing, malformed, or expired Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Authenticated but not authorized for this resource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Resource not found in this tenant","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict — resource state prevents this action","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate-limited (per-tenant token bucket)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"get":{"tags":["users"],"summary":"Get Me","operationId":"users-get_me","security":[{"HTTPBearer":[]}],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"401":{"description":"Unauthenticated — missing, malformed, or expired Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Authenticated but not authorized for this resource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Resource not found in this tenant","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict — resource state prevents this action","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate-limited (per-tenant token bucket)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"patch":{"tags":["users"],"summary":"Update Me","description":"Edit your own first/last name. Email + password have dedicated flows.","operationId":"users-update_me","security":[{"HTTPBearer":[]}],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserSelfUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"401":{"description":"Unauthenticated — missing, malformed, or expired Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Authenticated but not authorized for this resource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Resource not found in this tenant","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict — resource state prevents this action","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate-limited (per-tenant token bucket)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/tenants/{slug}/users/me/password":{"post":{"tags":["users"],"summary":"Change My Password","description":"Change your own password. Verifies `previous_password` against the identity\nprovider (WorkOS), then sets `new_password` (subject to the provider's strength\npolicy). 401 if the current password is wrong; 422 if the new one is rejected\n(too short / common). No response body on success (204).","operationId":"users-change_my_password","security":[{"HTTPBearer":[]}],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangePasswordRequest"}}}},"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"401":{"description":"Unauthenticated — missing, malformed, or expired Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Authenticated but not authorized for this resource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Resource not found in this tenant","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict — resource state prevents this action","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate-limited (per-tenant token bucket)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/tenants/{slug}/users/{user_id}":{"patch":{"tags":["users"],"summary":"Update User Role","description":"Change a workspace user's role. Admin-only.\n\nLast-admin guard: demoting the only remaining admin (whether yourself\nor someone else) is blocked with 400 — otherwise the workspace could\nbe left with no one able to invite users, create datasets/projects, or\ndelete exports. Promote a new admin first.","operationId":"users-update_user_role","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"User Id"}},{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserRoleUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"401":{"description":"Unauthenticated — missing, malformed, or expired Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Authenticated but not authorized for this resource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Resource not found in this tenant","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict — resource state prevents this action","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate-limited (per-tenant token bucket)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"tags":["users"],"summary":"Remove Member","description":"Remove a member from this workspace (admin; ADR-0113). Their account is\nuntouched — only the membership (and its API keys, via cascade) goes.\nRemoving yourself is `DELETE /users/me` (leave); the last admin is guarded\neither way.","operationId":"users-remove_member","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"User Id"}},{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"401":{"description":"Unauthenticated — missing, malformed, or expired Bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Authenticated but not authorized for this resource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Resource not found in this tenant","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict — resource state prevents this action","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate-limited (per-tenant token bucket)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/tenants/{slug}/users/me/api-keys":{"post":{"tags":["api-keys"],"summary":"Create a new API key for the calling user.","description":"Mints a new long-lived credential bound to the calling user. The plaintext is returned **once** in this response — store it securely (env var, secret manager). The server only retains an argon2id hash, so a lost plaintext cannot be recovered; revoke and re-create.\n\nUse the returned `plaintext` as a `Authorization: Bearer <plaintext>` header to authenticate subsequent requests. The key inherits the user's role; v1 has no scoping.\n\n**Capped at 1 active key per user.** To rotate, `DELETE` your existing key first, then `POST` to mint a fresh one. Without scopes there's no functional reason to hold more than one.","operationId":"api-keys-create_api_key","security":[{"HTTPBearer":[]}],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyCreate"}}}},"responses":{"201":{"description":"Successful Response","con

# --- truncated at 32 KB (524 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/superb-ai/refs/heads/main/openapi/superb-ai-mlops-platform-openapi.json