{
  "openapi": "3.1.0",
  "info": {
    "title": "Spark API",
    "version": "0.2.0",
    "description": "Public machine API for Spark workspaces. Authenticate with a bearer API key. Every management path is under /v1/workspaces/{workspaceId}. This document omits marketing /www routes and health probes."
  },
  "paths": {
    "/v1/workspaces/{workspaceId}": {
      "get": {
        "tags": ["Workspaces"],
        "operationId": "get_workspace",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Workspace access result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkspaceView"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with workspace rules, such as last-admin or membership limit.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The change conflicts with workspace rules, such as last-admin or membership limit."
                }
              }
            }
          }
        },
        "description": "Confirms that the caller can access the workspace. The response includes the workspace id.",
        "summary": "Get a workspace",
        "x-spark-phase": 1,
        "x-spark-mode": "real"
      }
    },
    "/v1/workspaces/{workspaceId}/members": {
      "get": {
        "tags": ["Members"],
        "operationId": "list_members",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "query",
            "in": "query",
            "schema": {
              "type": "string",
              "description": "Case-insensitive filter on display name or email."
            },
            "required": false,
            "description": "Case-insensitive filter on display name or email."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "A list of memberships.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MembershipList"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with workspace rules, such as last-admin or membership limit.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The change conflicts with workspace rules, such as last-admin or membership limit."
                }
              }
            }
          }
        },
        "description": "Lists active members in the workspace. A viewer key can call this route. Use query to filter by display name or email.",
        "summary": "List members",
        "x-spark-phase": 1,
        "x-spark-mode": "real"
      }
    },
    "/v1/workspaces/{workspaceId}/members/{memberId}": {
      "patch": {
        "tags": ["Members"],
        "operationId": "update_member",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "memberId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The membership id.",
              "examples": ["memA1b2C3d4E5"]
            },
            "required": true,
            "description": "The membership id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "One workspace membership.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MembershipView"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with workspace rules, such as last-admin or membership limit.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The change conflicts with workspace rules, such as last-admin or membership limit."
                }
              }
            }
          }
        },
        "description": "Changes a member's role. Requires an admin key. The last admin cannot become a viewer or editor.",
        "summary": "Update a member role",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateMemberRequest"
              }
            }
          },
          "required": true
        },
        "x-spark-phase": 1,
        "x-spark-mode": "real"
      },
      "delete": {
        "tags": ["Members"],
        "operationId": "remove_member",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "memberId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The membership id.",
              "examples": ["memA1b2C3d4E5"]
            },
            "required": true,
            "description": "The membership id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "204": {
            "description": "Success"
          },
          "400": {
            "description": "The request body or query is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with workspace rules, such as last-admin or membership limit.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The change conflicts with workspace rules, such as last-admin or membership limit."
                }
              }
            }
          }
        },
        "description": "Removes a member from the workspace. Requires an admin key. The last admin cannot be removed. Self-leave at /members/me is not available on this API.",
        "summary": "Remove a member",
        "x-spark-phase": 1,
        "x-spark-mode": "real"
      }
    },
    "/v1/workspaces/{workspaceId}/members/{memberId}/api-keys": {
      "get": {
        "tags": ["Members"],
        "operationId": "list_member_api_keys",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "memberId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The membership id.",
              "examples": ["memA1b2C3d4E5"]
            },
            "required": true,
            "description": "The membership id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "A list of API keys.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyList"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with workspace rules, such as last-admin or membership limit.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The change conflicts with workspace rules, such as last-admin or membership limit."
                }
              }
            }
          }
        },
        "description": "Lists personal API keys for another member. Requires an admin key. Secrets are never returned.",
        "summary": "List a member's API keys",
        "x-spark-phase": 1,
        "x-spark-mode": "real"
      }
    },
    "/v1/workspaces/{workspaceId}/invitations": {
      "get": {
        "tags": ["Invitations"],
        "operationId": "list_invitations",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "A list of invitations.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvitationList"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with workspace rules, such as last-admin or membership limit.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The change conflicts with workspace rules, such as last-admin or membership limit."
                }
              }
            }
          }
        },
        "description": "Lists pending invitations for the workspace. Requires an admin key.",
        "summary": "List invitations",
        "x-spark-phase": 1,
        "x-spark-mode": "real"
      },
      "post": {
        "tags": ["Invitations"],
        "operationId": "create_invitations",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "description": "Per-address results from a batch invite.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["results"],
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/InvitationBatchItem"
                      },
                      "description": "One result per submitted email, in request order."
                    }
                  },
                  "additionalProperties": false,
                  "description": "Per-address results from a batch invite.",
                  "title": "InvitationBatchResult",
                  "examples": [
                    {
                      "results": [
                        {
                          "email": "grace@example.com",
                          "outcome": "created",
                          "invitation": {
                            "id": "invC3d4E5f6G7",
                            "workspaceId": "wspQ7WsH2Np5L",
                            "email": "grace@example.com",
                            "role": "editor",
                            "state": "pending",
                            "delivery": "queued",
                            "expiresAt": "2026-09-21T18:00:00.000Z",
                            "revision": 1
                          }
                        }
                      ]
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with workspace rules, such as last-admin or membership limit.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The change conflicts with workspace rules, such as last-admin or membership limit."
                }
              }
            }
          },
          "413": {
            "description": "The JSON body is larger than 16,384 bytes.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The JSON body is larger than 16,384 bytes."
                }
              }
            }
          }
        },
        "description": "Invites one or more email addresses with the same role. Requires an admin key. Send between 1 and 50 addresses. Each address returns its own outcome.",
        "summary": "Invite members",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateInvitationsRequest"
              }
            }
          },
          "required": true
        },
        "x-spark-phase": 1,
        "x-spark-mode": "real"
      }
    },
    "/v1/workspaces/{workspaceId}/invitations/{invitationId}/resend": {
      "post": {
        "tags": ["Invitations"],
        "operationId": "resend_invitation",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "invitationId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The invitation id.",
              "examples": ["invC3d4E5f6G7"]
            },
            "required": true,
            "description": "The invitation id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "One workspace invitation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvitationView"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with workspace rules, such as last-admin or membership limit.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The change conflicts with workspace rules, such as last-admin or membership limit."
                }
              }
            }
          }
        },
        "description": "Sends the invitation email again. Requires an admin key. The invitation must still be pending.",
        "summary": "Resend an invitation",
        "x-spark-phase": 1,
        "x-spark-mode": "real"
      }
    },
    "/v1/workspaces/{workspaceId}/invitations/{invitationId}": {
      "patch": {
        "tags": ["Invitations"],
        "operationId": "update_invitation",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "invitationId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The invitation id.",
              "examples": ["invC3d4E5f6G7"]
            },
            "required": true,
            "description": "The invitation id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "One workspace invitation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvitationView"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with workspace rules, such as last-admin or membership limit.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The change conflicts with workspace rules, such as last-admin or membership limit."
                }
              }
            }
          }
        },
        "description": "Changes the role on a pending invitation. Requires an admin key.",
        "summary": "Update an invitation role",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateInvitationRequest"
              }
            }
          },
          "required": true
        },
        "x-spark-phase": 1,
        "x-spark-mode": "real"
      },
      "delete": {
        "tags": ["Invitations"],
        "operationId": "revoke_invitation",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "invitationId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The invitation id.",
              "examples": ["invC3d4E5f6G7"]
            },
            "required": true,
            "description": "The invitation id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "204": {
            "description": "Success"
          },
          "400": {
            "description": "The request body or query is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with workspace rules, such as last-admin or membership limit.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The change conflicts with workspace rules, such as last-admin or membership limit."
                }
              }
            }
          }
        },
        "description": "Revokes a pending invitation. Requires an admin key. This does not remove an accepted member.",
        "summary": "Revoke an invitation",
        "x-spark-phase": 1,
        "x-spark-mode": "real"
      }
    },
    "/v1/workspaces/{workspaceId}/service-accounts": {
      "get": {
        "tags": ["Service accounts"],
        "operationId": "list_service_accounts",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "A list of service accounts.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceAccountList"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with workspace rules, such as last-admin or membership limit.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The change conflicts with workspace rules, such as last-admin or membership limit."
                }
              }
            }
          }
        },
        "description": "Lists active service accounts in the workspace. Requires an admin key.",
        "summary": "List service accounts",
        "x-spark-phase": 1,
        "x-spark-mode": "real"
      },
      "post": {
        "tags": ["Service accounts"],
        "operationId": "create_service_account",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "description": "One service account.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "id",
                    "workspaceId",
                    "name",
                    "description",
                    "role",
                    "status",
                    "createdBy",
                    "createdByName",
                    "createdAt",
                    "keyCount",
                    "revision"
                  ],
                  "properties": {
                    "id": {
                      "type": "string",
                      "description": "The service account id."
                    },
                    "workspaceId": {
                      "type": "string",
                      "description": "The workspace id."
                    },
                    "name": {
                      "type": "string",
                      "description": "Display name."
                    },
                    "description": {
                      "type": "string",
                      "description": "Optional notes."
                    },
                    "role": {
                      "type": "string",
                      "enum": ["viewer", "editor", "admin"],
                      "description": "Workspace role for keys this account owns.",
                      "title": "Role"
                    },
                    "status": {
                      "type": "string",
                      "enum": ["active", "deleted"],
                      "description": "Service account state."
                    },
                    "createdBy": {
                      "type": "string",
                      "description": "User id of the creator."
                    },
                    "createdByName": {
                      "type": "string",
                      "description": "Display name of the creator."
                    },
                    "createdAt": {
                      "type": "string",
                      "description": "When the account was created, in UTC."
                    },
                    "keyCount": {
                      "type": "number",
                      "description": "Number of active keys on this account."
                    },
                    "revision": {
                      "type": "number",
                      "description": "Monotonic service-account revision."
                    }
                  },
                  "additionalProperties": false,
                  "description": "One service account.",
                  "title": "ServiceAccountView",
                  "examples": [
                    {
                      "id": "sacD4e5F6g7H8",
                      "workspaceId": "wspQ7WsH2Np5L",
                      "name": "CI runner",
                      "description": "Deploys from GitHub Actions.",
                      "role": "viewer",
                      "status": "active",
                      "createdBy": "usrB2c3D4e5F6",
                      "createdByName": "Ada Lovelace",
                      "createdAt": "2026-09-14T18:00:00.000Z",
                      "keyCount": 0,
                      "revision": 1
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with workspace rules, such as last-admin or membership limit.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The change conflicts with workspace rules, such as last-admin or membership limit."
                }
              }
            }
          },
          "413": {
            "description": "The JSON body is larger than 16,384 bytes.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The JSON body is larger than 16,384 bytes."
                }
              }
            }
          }
        },
        "description": "Creates a service account. Requires an admin key. The default role is viewer. Creation does not issue an API key.",
        "summary": "Create a service account",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateServiceAccountRequest"
              }
            }
          },
          "required": true
        },
        "x-spark-phase": 1,
        "x-spark-mode": "real"
      }
    },
    "/v1/workspaces/{workspaceId}/service-accounts/{serviceAccountId}": {
      "get": {
        "tags": ["Service accounts"],
        "operationId": "get_service_account",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "serviceAccountId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The service account id.",
              "examples": ["sacD4e5F6g7H8"]
            },
            "required": true,
            "description": "The service account id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "One service account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceAccountView"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with workspace rules, such as last-admin or membership limit.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The change conflicts with workspace rules, such as last-admin or membership limit."
                }
              }
            }
          }
        },
        "description": "Returns one service account. Requires an admin key.",
        "summary": "Get a service account",
        "x-spark-phase": 1,
        "x-spark-mode": "real"
      },
      "patch": {
        "tags": ["Service accounts"],
        "operationId": "update_service_account",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "serviceAccountId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The service account id.",
              "examples": ["sacD4e5F6g7H8"]
            },
            "required": true,
            "description": "The service account id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "One service account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceAccountView"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with workspace rules, such as last-admin or membership limit.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The change conflicts with workspace rules, such as last-admin or membership limit."
                }
              }
            }
          }
        },
        "description": "Updates the name, description, or role of a service account. Requires an admin key. Omit a field to leave it unchanged.",
        "summary": "Update a service account",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateServiceAccountRequest"
              }
            }
          },
          "required": true
        },
        "x-spark-phase": 1,
        "x-spark-mode": "real"
      },
      "delete": {
        "tags": ["Service accounts"],
        "operationId": "delete_service_account",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "serviceAccountId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The service account id.",
              "examples": ["sacD4e5F6g7H8"]
            },
            "required": true,
            "description": "The service account id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "204": {
            "description": "Success"
          },
          "400": {
            "description": "The request body or query is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with workspace rules, such as last-admin or membership limit.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The change conflicts with workspace rules, such as last-admin or membership limit."
                }
              }
            }
          }
        },
        "description": "Deletes a service account and revokes its keys. Requires an admin key.",
        "summary": "Delete a service account",
        "x-spark-phase": 1,
        "x-spark-mode": "real"
      }
    },
    "/v1/workspaces/{workspaceId}/api-keys": {
      "get": {
        "tags": ["API keys"],
        "operationId": "list_api_keys",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "owner",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": ["me", "service_account"],
              "description": "Which keys to list. Defaults to me."
            },
            "required": false,
            "description": "Which keys to list. Defaults to me."
          },
          {
            "name": "serviceAccountId",
            "in": "query",
            "schema": {
              "type": "string",
              "description": "Required when owner is service_account."
            },
            "required": false,
            "description": "Required when owner is service_account."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "A list of API keys.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyList"
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with workspace rules, such as last-admin or membership limit.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The change conflicts with workspace rules, such as last-admin or membership limit."
                }
              }
            }
          }
        },
        "description": "Lists API keys. owner=me returns the caller's personal keys and needs a viewer key. owner=service_account requires an admin key and serviceAccountId. Secrets are never returned.",
        "summary": "List API keys",
        "x-spark-phase": 1,
        "x-spark-mode": "real"
      },
      "post": {
        "tags": ["API keys"],
        "operationId": "create_api_key",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "description": "Create result. Store secret and bearerToken. Spark does not show them again.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["key", "secret", "bearerToken"],
                  "properties": {
                    "key": {
                      "type": "object",
                      "required": [
                        "id",
                        "workspaceId",
                        "name",
                        "accessKeyId",
                        "ownerKind",
                        "ownerId",
                        "role",
                        "createdAt",
                        "lastUsedAt",
                        "expiresAt",
                        "revokedAt",
                        "revision"
                      ],
                      "properties": {
                        "id": {
                          "type": "string",
                          "description": "The API key id."
                        },
                        "workspaceId": {
                          "type": "string",
                          "description": "The workspace id."
                        },
                        "name": {
                          "type": "string",
                          "description": "Display name."
                        },
                        "accessKeyId": {
                          "type": "string",
                          "description": "Public access-key id. It starts with GSK."
                        },
                        "ownerKind": {
                          "type": "string",
                          "enum": ["user", "service_account"],
                          "description": "Whether a person or a service account owns the key."
                        },
                        "ownerId": {
                          "type": "string",
                          "description": "User id or service account id of the owner."
                        },
                        "role": {
                          "type": "string",
                          "enum": ["viewer", "editor", "admin"],
                          "description": "Role granted by this key.",
                          "title": "Role"
                        },
                        "createdAt": {
                          "type": "string",
                          "description": "When the key was created, in UTC."
                        },
                        "lastUsedAt": {
                          "anyOf": [
                            {
                              "type": "string",
                              "description": "When the key was last used, or null."
                            },
                            {
                              "type": "null"
                            }
                          ],
                          "description": "When the key was last used, or null."
                        },
                        "expiresAt": {
                          "anyOf": [
                            {
                              "type": "string",
                              "description": "When the key expires, or null if it does not expire."
                            },
                            {
                              "type": "null"
                            }
                          ],
                          "description": "When the key expires, or null if it does not expire."
                        },
                        "revokedAt": {
                          "anyOf": [
                            {
                              "type": "string",
                              "description": "When the key was revoked, or null."
                            },
                            {
                              "type": "null"
                            }
                          ],
                          "description": "When the key was revoked, or null."
                        },
                        "revision": {
                          "type": "number",
                          "description": "Monotonic API key revision."
                        }
                      },
                      "additionalProperties": false,
                      "description": "The new key record. It does not include the secret.",
                      "title": "ApiKeyView",
                      "examples": [
                        {
                          "id": "keyE5f6G7h8I9",
                          "workspaceId": "wspQ7WsH2Np5L",
                          "name": "Local CLI",
                          "accessKeyId": "GSK0123456789ABCDE",
                          "ownerKind": "user",
                          "ownerId": "usrB2c3D4e5F6",
                          "role": "viewer",
                          "createdAt": "2026-09-14T18:00:00.000Z",
                          "lastUsedAt": null,
                          "expiresAt": null,
                          "revokedAt": null,
                          "revision": 1
                        }
                      ]
                    },
                    "secret": {
                      "type": "string",
                      "description": "Key secret. Shown once."
                    },
                    "bearerToken": {
                      "type": "string",
                      "description": "Full Authorization token in the form gsk_{accessKeyId}.{secret}. Shown once."
                    }
                  },
                  "additionalProperties": false,
                  "description": "Create result. Store secret and bearerToken. Spark does not show them again.",
                  "title": "CreatedApiKey",
                  "examples": [
                    {
                      "key": {
                        "id": "keyE5f6G7h8I9",
                        "workspaceId": "wspQ7WsH2Np5L",
                        "name": "Local CLI",
                        "accessKeyId": "GSK0123456789ABCDE",
                        "ownerKind": "user",
                        "ownerId": "usrB2c3D4e5F6",
                        "role": "viewer",
                        "createdAt": "2026-09-14T18:00:00.000Z",
                        "lastUsedAt": null,
                        "expiresAt": null,
                        "revokedAt": null,
                        "revision": 1
                      },
                      "secret": "<secret shown once>",
                      "bearerToken": "gsk_<accessKeyId>.<secret>"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request body or query is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with workspace rules, such as last-admin or membership limit.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The change conflicts with workspace rules, such as last-admin or membership limit."
                }
              }
            }
          },
          "413": {
            "description": "The JSON body is larger than 16,384 bytes.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The JSON body is larger than 16,384 bytes."
                }
              }
            }
          }
        },
        "description": "Creates a personal API key for the caller, or a service-account key when owner.kind is service_account. A viewer key can create a personal key. An admin key is required for a service-account key. The secret and bearer token appear once.",
        "summary": "Create an API key",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateApiKeyRequest"
              }
            }
          },
          "required": true
        },
        "x-spark-phase": 1,
        "x-spark-mode": "real"
      }
    },
    "/v1/workspaces/{workspaceId}/api-keys/{keyId}": {
      "delete": {
        "tags": ["API keys"],
        "operationId": "revoke_api_key",
        "parameters": [
          {
            "name": "workspaceId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The workspace id.",
              "examples": ["wspQ7WsH2Np5L"]
            },
            "required": true,
            "description": "The workspace id."
          },
          {
            "name": "keyId",
            "in": "path",
            "schema": {
              "type": "string",
              "description": "The API key id.",
              "examples": ["keyE5f6G7h8I9"]
            },
            "required": true,
            "description": "The API key id."
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "204": {
            "description": "Success"
          },
          "400": {
            "description": "The request body or query is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The request body or query is invalid."
                }
              }
            }
          },
          "401": {
            "description": "The bearer token is missing, invalid, expired, or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The bearer token is missing, invalid, expired, or revoked."
                }
              }
            }
          },
          "403": {
            "description": "The key is valid but lacks the required role.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The key is valid but lacks the required role."
                }
              }
            }
          },
          "404": {
            "description": "The workspace or resource does not exist, or this caller cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The workspace or resource does not exist, or this caller cannot see it."
                }
              }
            }
          },
          "409": {
            "description": "The change conflicts with workspace rules, such as last-admin or membership limit.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ApiError"
                    }
                  ],
                  "description": "The change conflicts with workspace rules, such as last-admin or membership limit."
                }
              }
            }
          }
        },
        "description": "Revokes an API key. The owner can revoke their own key with a viewer key. An admin can revoke any workspace key.",
        "summary": "Revoke an API key",
        "x-spark-phase": 1,
        "x-spark-mode": "real"
      }
    }
  },
  "components": {
    "schemas": {
      "WorkspaceView": {
        "type": "object",
        "required": ["id"],
        "properties": {
          "id": {
            "type": "string",
            "description": "The workspace id."
          }
        },
        "additionalProperties": false,
        "description": "Workspace access result.",
        "title": "WorkspaceView",
        "examples": [
          {
            "id": "wspQ7WsH2Np5L"
          }
        ]
      },
      "ApiError": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": {
            "type": "object",
            "required": ["code"],
            "properties": {
              "code": {
                "type": "string",
                "description": "Stable error token such as unauthenticated or invalid_request."
              },
              "message": {
                "type": "string",
                "description": "Human-readable explanation."
              }
            },
            "additionalProperties": false,
            "description": "Machine-readable failure."
          }
        },
        "additionalProperties": false,
        "description": "Error body returned by the API. The request id is in the x-request-id header.",
        "title": "ApiError"
      },
      "MembershipList": {
        "type": "object",
        "required": ["items"],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MembershipView"
            },
            "description": "Membership rows."
          }
        },
        "additionalProperties": false,
        "description": "A list of memberships.",
        "title": "MembershipList",
        "examples": [
          {
            "items": [
              {
                "id": "memA1b2C3d4E5",
                "workspaceId": "wspQ7WsH2Np5L",
                "userId": "usrB2c3D4e5F6",
                "displayName": "Ada Lovelace",
                "email": "ada@example.com",
                "role": "admin",
                "status": "active",
                "joinedAt": "2026-09-14T18:00:00.000Z",
                "revision": 1
              }
            ]
          }
        ]
      },
      "MembershipView": {
        "type": "object",
        "required": [
          "id",
          "workspaceId",
          "userId",
          "displayName",
          "email",
          "role",
          "status",
          "joinedAt",
          "revision"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The membership id."
          },
          "workspaceId": {
            "type": "string",
            "description": "The workspace id."
          },
          "userId": {
            "type": "string",
            "description": "The member's user id."
          },
          "displayName": {
            "type": "string",
            "description": "The member's display name."
          },
          "email": {
            "type": "string",
            "description": "The member's email."
          },
          "role": {
            "type": "string",
            "enum": ["viewer", "editor", "admin"],
            "description": "The member's workspace role.",
            "title": "Role"
          },
          "status": {
            "type": "string",
            "enum": ["active", "retained", "left", "removed"],
            "description": "Membership state."
          },
          "joinedAt": {
            "type": "string",
            "description": "When the member joined, in UTC."
          },
          "revision": {
            "type": "number",
            "description": "Monotonic membership revision."
          }
        },
        "additionalProperties": false,
        "description": "One workspace membership.",
        "title": "MembershipView",
        "examples": [
          {
            "id": "memA1b2C3d4E5",
            "workspaceId": "wspQ7WsH2Np5L",
            "userId": "usrB2c3D4e5F6",
            "displayName": "Ada Lovelace",
            "email": "ada@example.com",
            "role": "admin",
            "status": "active",
            "joinedAt": "2026-09-14T18:00:00.000Z",
            "revision": 1
          }
        ]
      },
      "UpdateMemberRequest": {
        "type": "object",
        "required": ["role"],
        "properties": {
          "role": {
            "type": "string",
            "enum": ["viewer", "editor", "admin"],
            "description": "New role for the member.",
            "title": "Role"
          }
        },
        "additionalProperties": false,
        "description": "Role change for a member.",
        "title": "UpdateMemberRequest",
        "examples": [
          {
            "role": "editor"
          }
        ]
      },
      "ApiKeyList": {
        "type": "object",
        "required": ["items"],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApiKeyView"
            },
            "description": "API key rows without secrets."
          }
        },
        "additionalProperties": false,
        "description": "A list of API keys.",
        "title": "ApiKeyList",
        "examples": [
          {
            "items": [
              {
                "id": "keyE5f6G7h8I9",
                "workspaceId": "wspQ7WsH2Np5L",
                "name": "Local CLI",
                "accessKeyId": "GSK0123456789ABCDE",
                "ownerKind": "user",
                "ownerId": "usrB2c3D4e5F6",
                "role": "viewer",
                "createdAt": "2026-09-14T18:00:00.000Z",
                "lastUsedAt": null,
                "expiresAt": null,
                "revokedAt": null,
                "revision": 1
              }
            ]
          }
        ]
      },
      "ApiKeyView": {
        "type": "object",
        "required": [
          "id",
          "workspaceId",
          "name",
          "accessKeyId",
          "ownerKind",
          "ownerId",
          "role",
          "createdAt",
          "lastUsedAt",
          "expiresAt",
          "revokedAt",
          "revision"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The API key id."
          },
          "workspaceId": {
            "type": "string",
            "description": "The workspace id."
          },
          "name": {
            "type": "string",
            "description": "Display name."
          },
          "accessKeyId": {
            "type": "string",
            "description": "Public access-key id. It starts with GSK."
          },
          "ownerKind": {
            "type": "string",
            "enum": ["user", "service_account"],
            "description": "Whether a person or a service account owns the key."
          },
          "ownerId": {
            "type": "string",
            "description": "User id or service account id of the owner."
          },
          "role": {
            "type": "string",
            "enum": ["viewer", "editor", "admin"],
            "description": "Role granted by this key.",
            "title": "Role"
          },
          "createdAt": {
            "type": "string",
            "description": "When the key was created, in UTC."
          },
          "lastUsedAt": {
            "anyOf": [
              {
                "type": "string",
                "description": "When the key was last used, or null."
              },
              {
                "type": "null"
              }
            ],
            "description": "When the key was last used, or null."
          },
          "expiresAt": {
            "anyOf": [
              {
                "type": "string",
                "description": "When the key expires, or null if it does not expire."
              },
              {
                "type": "null"
              }
            ],
            "description": "When the key expires, or null if it does not expire."
          },
          "revokedAt": {
            "anyOf": [
              {
                "type": "string",
                "description": "When the key was revoked, or null."
              },
              {
                "type": "null"
              }
            ],
            "description": "When the key was revoked, or null."
          },
          "revision": {
            "type": "number",
            "description": "Monotonic API key revision."
          }
        },
        "additionalProperties": false,
        "description": "One API key. The secret is never included.",
        "title": "ApiKeyView",
        "examples": [
          {
            "id": "keyE5f6G7h8I9",
            "workspaceId": "wspQ7WsH2Np5L",
            "name": "Local CLI",
            "accessKeyId": "GSK0123456789ABCDE",
            "ownerKind": "user",
            "ownerId": "usrB2c3D4e5F6",
            "role": "viewer",
            "createdAt": "2026-09-14T18:00:00.000Z",
            "lastUsedAt": null,
            "expiresAt": null,
            "revokedAt": null,
            "revision": 1
          }
        ]
      },
      "InvitationList": {
        "type": "object",
        "required": ["items"],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InvitationView"
            },
            "description": "Invitation rows."
          }
        },
        "additionalProperties": false,
        "description": "A list of invitations.",
        "title": "InvitationList",
        "examples": [
          {
            "items": [
              {
                "id": "invC3d4E5f6G7",
                "workspaceId": "wspQ7WsH2Np5L",
                "email": "grace@example.com",
                "role": "editor",
                "state": "pending",
                "delivery": "queued",
                "expiresAt": "2026-09-21T18:00:00.000Z",
                "revision": 1
              }
            ]
          }
        ]
      },
      "InvitationView": {
        "type": "object",
        "required": [
          "id",
          "workspaceId",
          "email",
          "role",
          "state",
          "delivery",
          "expiresAt",
          "revision"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The invitation id."
          },
          "workspaceId": {
            "type": "string",
            "description": "The workspace id."
          },
          "email": {
            "type": "string",
            "description": "The invited email."
          },
          "role": {
            "type": "string",
            "enum": ["viewer", "editor", "admin"],
            "description": "Role the person receives if they accept.",
            "title": "Role"
          },
          "state": {
            "type": "string",
            "enum": ["pending", "accepted", "revoked", "expired"],
            "description": "Invitation lifecycle state."
          },
          "delivery": {
            "type": "string",
            "enum": ["queued", "sent", "failed"],
            "description": "Email delivery state."
          },
          "expiresAt": {
            "type": "string",
            "description": "When the invitation expires, in UTC."
          },
          "revision": {
            "type": "number",
            "description": "Monotonic invitation revision."
          }
        },
        "additionalProperties": false,
        "description": "One workspace invitation.",
        "title": "InvitationView",
        "examples": [
          {
            "id": "invC3d4E5f6G7",
            "workspaceId": "wspQ7WsH2Np5L",
            "email": "grace@example.com",
            "role": "editor",
            "state": "pending",
            "delivery": "queued",
            "expiresAt": "2026-09-21T18:00:00.000Z",
            "revision": 1
          }
        ]
      },
      "CreateInvitationsRequest": {
        "type": "object",
        "required": ["emails", "role"],
        "properties": {
          "emails": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Email addresses to invite. Send 1 to 50 addresses."
          },
          "role": {
            "type": "string",
            "enum": ["viewer", "editor", "admin"],
            "description": "Role granted when the person accepts.",
            "title": "Role"
          }
        },
        "additionalProperties": false,
        "description": "Batch invite payload.",
        "title": "CreateInvitationsRequest",
        "examples": [
          {
            "emails": ["grace@example.com"],
            "role": "editor"
          }
        ]
      },
      "InvitationBatchItem": {
        "type": "object",
        "required": ["email", "outcome", "invitation"],
        "properties": {
          "email": {
            "type": "string",
            "description": "The submitted email."
          },
          "outcome": {
            "type": "string",
            "enum": ["created", "resent", "already_member", "pending_other_role"],
            "description": "What Spark did for this address."
          },
          "invitation": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/InvitationView"
              },
              {
                "type": "null"
              }
            ],
            "description": "The invitation when one was created or updated. Null when the address is already a member."
          }
        },
        "additionalProperties": false,
        "description": "Invite result for one email.",
        "title": "InvitationBatchItem"
      },
      "UpdateInvitationRequest": {
        "type": "object",
        "required": ["role"],
        "properties": {
          "role": {
            "type": "string",
            "enum": ["viewer", "editor", "admin"],
            "description": "New role for the pending invitation.",
            "title": "Role"
          }
        },
        "additionalProperties": false,
        "description": "Role change for a pending invitation.",
        "title": "UpdateInvitationRequest",
        "examples": [
          {
            "role": "viewer"
          }
        ]
      },
      "ServiceAccountList": {
        "type": "object",
        "required": ["items"],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ServiceAccountView"
            },
            "description": "Service account rows."
          }
        },
        "additionalProperties": false,
        "description": "A list of service accounts.",
        "title": "ServiceAccountList",
        "examples": [
          {
            "items": [
              {
                "id": "sacD4e5F6g7H8",
                "workspaceId": "wspQ7WsH2Np5L",
                "name": "CI runner",
                "description": "Deploys from GitHub Actions.",
                "role": "viewer",
                "status": "active",
                "createdBy": "usrB2c3D4e5F6",
                "createdByName": "Ada Lovelace",
                "createdAt": "2026-09-14T18:00:00.000Z",
                "keyCount": 0,
                "revision": 1
              }
            ]
          }
        ]
      },
      "ServiceAccountView": {
        "type": "object",
        "required": [
          "id",
          "workspaceId",
          "name",
          "description",
          "role",
          "status",
          "createdBy",
          "createdByName",
          "createdAt",
          "keyCount",
          "revision"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The service account id."
          },
          "workspaceId": {
            "type": "string",
            "description": "The workspace id."
          },
          "name": {
            "type": "string",
            "description": "Display name."
          },
          "description": {
            "type": "string",
            "description": "Optional notes."
          },
          "role": {
            "type": "string",
            "enum": ["viewer", "editor", "admin"],
            "description": "Workspace role for keys this account owns.",
            "title": "Role"
          },
          "status": {
            "type": "string",
            "enum": ["active", "deleted"],
            "description": "Service account state."
          },
          "createdBy": {
            "type": "string",
            "description": "User id of the creator."
          },
          "createdByName": {
            "type": "string",
            "description": "Display name of the creator."
          },
          "createdAt": {
            "type": "string",
            "description": "When the account was created, in UTC."
          },
          "keyCount": {
            "type": "number",
            "description": "Number of active keys on this account."
          },
          "revision": {
            "type": "number",
            "description": "Monotonic service-account revision."
          }
        },
        "additionalProperties": false,
        "description": "One service account.",
        "title": "ServiceAccountView",
        "examples": [
          {
            "id": "sacD4e5F6g7H8",
            "workspaceId": "wspQ7WsH2Np5L",
            "name": "CI runner",
            "description": "Deploys from GitHub Actions.",
            "role": "viewer",
            "status": "active",
            "createdBy": "usrB2c3D4e5F6",
            "createdByName": "Ada Lovelace",
            "createdAt": "2026-09-14T18:00:00.000Z",
            "keyCount": 0,
            "revision": 1
          }
        ]
      },
      "CreateServiceAccountRequest": {
        "type": "object",
        "required": ["name"],
        "properties": {
          "name": {
            "type": "string",
            "description": "Display name."
          },
          "description": {
            "type": "string",
            "description": "Optional notes."
          },
          "role": {
            "type": "string",
            "enum": ["viewer", "editor", "admin"],
            "description": "Workspace role for keys this account owns. Defaults to viewer.",
            "title": "Role"
          }
        },
        "additionalProperties": false,
        "description": "Create payload for a service account.",
        "title": "CreateServiceAccountRequest",
        "examples": [
          {
            "name": "CI runner",
            "description": "Deploys from GitHub Actions.",
            "role": "viewer"
          }
        ]
      },
      "UpdateServiceAccountRequest": {
        "type": "object",
        "required": [],
        "properties": {
          "name": {
            "type": "string",
            "description": "Display name."
          },
          "description": {
            "type": "string",
            "description": "Optional notes."
          },
          "role": {
            "type": "string",
            "enum": ["viewer", "editor", "admin"],
            "description": "New workspace role for keys this account owns.",
            "title": "Role"
          }
        },
        "additionalProperties": false,
        "description": "Fields to change on a service account. Omit a field to leave it unchanged.",
        "title": "UpdateServiceAccountRequest",
        "examples": [
          {
            "name": "Nightly CI"
          }
        ]
      },
      "CreateApiKeyRequest": {
        "type": "object",
        "required": ["name"],
        "properties": {
          "name": {
            "type": "string",
            "description": "Display name."
          },
          "role": {
            "type": "string",
            "enum": ["viewer", "editor", "admin"],
            "description": "Role for the new key. A key cannot exceed the owner's role.",
            "title": "Role"
          },
          "expiresAt": {
            "type": "string",
            "description": "Optional expiry in UTC. The time must be in the future."
          },
          "owner": {
            "type": "object",
            "required": ["kind", "serviceAccountId"],
            "properties": {
              "kind": {
                "type": "string",
                "enum": ["service_account"],
                "description": "Must be service_account."
              },
              "serviceAccountId": {
                "type": "string",
                "description": "The service account that will own the key."
              }
            },
            "additionalProperties": false,
            "description": "Service-account owner. Omit this object for a personal key.",
            "title": "ApiKeyOwner"
          }
        },
        "additionalProperties": false,
        "description": "Create payload for an API key. Omit owner to create a personal key.",
        "title": "CreateApiKeyRequest",
        "examples": [
          {
            "name": "Local CLI",
            "role": "viewer"
          }
        ]
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "description": "Send Authorization: Bearer gsk_{accessKeyId}.{secret}. Store the full token in SPARK_API_KEY. A key belongs to one workspace. Its role is viewer, editor, or admin.",
        "type": "http",
        "scheme": "bearer"
      }
    }
  },
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Workspaces",
      "description": "Workspace access probes."
    },
    {
      "name": "Members",
      "description": "Workspace membership and member API keys."
    },
    {
      "name": "Invitations",
      "description": "Pending workspace invitations."
    },
    {
      "name": "Service accounts",
      "description": "Machine identities that own API keys."
    },
    {
      "name": "API keys",
      "description": "Personal and service-account API keys."
    }
  ],
  "servers": [
    {
      "url": "https://api.spark.graphon.ai"
    }
  ]
}
