{
  "openapi": "3.0.0",
  "info": {
    "title": "art-swipe-api",
    "version": "0.0.1",
    "description": "apps",
    "contact": {
      "name": "Lemerick",
      "email": "emerick.lafortune@footovision.com"
    }
  },
  "paths": {
    "/admin/artists/{id}/instagram/scrape": {
      "post": {
        "x-controller-name": "AdminInstagramScrapeController",
        "x-operation-name": "scrapeArtist",
        "tags": [
          "AdminInstagramScrapeController"
        ],
        "responses": {
          "202": {
            "description": "Instagram scrape workflow enqueued",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "workflowId",
                    "scrapingRunId",
                    "jobId"
                  ],
                  "properties": {
                    "workflowId": {
                      "type": "string"
                    },
                    "scrapingRunId": {
                      "type": "string"
                    },
                    "jobId": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "handle": {
                    "type": "string",
                    "description": "Override du handle stocké (ex. \"@alma_rivest\" ou \"alma_rivest\")"
                  },
                  "resultsLimit": {
                    "type": "number",
                    "minimum": 1,
                    "maximum": 200,
                    "description": "Nombre max de posts (défaut 30)"
                  }
                }
              }
            }
          },
          "x-parameter-index": 1
        },
        "operationId": "AdminInstagramScrapeController.scrapeArtist"
      }
    },
    "/admin/artists/{id}/media": {
      "get": {
        "x-controller-name": "AdminMediaController",
        "x-operation-name": "listArtistMedia",
        "tags": [
          "AdminMediaController"
        ],
        "responses": {
          "200": {
            "description": "List of media for an artist, optionally filtered by status",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items",
                    "total"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    },
                    "total": {
                      "type": "number"
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "number"
            }
          }
        ],
        "operationId": "AdminMediaController.listArtistMedia"
      }
    },
    "/admin/artists/{id}": {
      "get": {
        "x-controller-name": "AdminBoardController",
        "x-operation-name": "getArtist",
        "tags": [
          "AdminBoardController"
        ],
        "responses": {
          "200": {
            "description": "Artist drill-down (admin)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "operationId": "AdminBoardController.getArtist"
      }
    },
    "/admin/artists": {
      "post": {
        "x-controller-name": "AdminBoardController",
        "x-operation-name": "createArtist",
        "tags": [
          "AdminBoardController"
        ],
        "responses": {
          "200": {
            "description": "Create a new artist (admin)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "slug": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AdminArtistCreateBody"
              }
            }
          }
        },
        "operationId": "AdminBoardController.createArtist"
      },
      "get": {
        "x-controller-name": "AdminBoardController",
        "x-operation-name": "listArtists",
        "tags": [
          "AdminBoardController"
        ],
        "responses": {
          "200": {
            "description": "Paginated list of artists (admin)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "total": {
                      "type": "number"
                    },
                    "items": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "filter",
            "in": "query",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Artist.Filter"
                }
              }
            }
          }
        ],
        "operationId": "AdminBoardController.listArtists"
      }
    },
    "/admin/artworks": {
      "get": {
        "x-controller-name": "AdminBoardController",
        "x-operation-name": "listArtworks",
        "tags": [
          "AdminBoardController"
        ],
        "responses": {
          "200": {
            "description": "Paginated list of original artworks (admin)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "total": {
                      "type": "number"
                    },
                    "items": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "filter",
            "in": "query",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Artwork.Filter"
                }
              }
            }
          }
        ],
        "operationId": "AdminBoardController.listArtworks"
      }
    },
    "/admin/fal/credits": {
      "get": {
        "x-controller-name": "AdminBoardController",
        "x-operation-name": "getFalCredits",
        "tags": [
          "AdminBoardController"
        ],
        "responses": {
          "200": {
            "description": "Solde de crédits du compte fal.ai (admin)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdminFalCreditsResponse"
                }
              }
            }
          }
        },
        "operationId": "AdminBoardController.getFalCredits"
      }
    },
    "/admin/jobs/{id}/retry": {
      "post": {
        "x-controller-name": "AdminWorkflowController",
        "x-operation-name": "retryJob",
        "tags": [
          "AdminWorkflowController"
        ],
        "responses": {
          "200": {
            "description": "Retry a failed/dead_letter job",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "jobId": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "operationId": "AdminWorkflowController.retryJob"
      }
    },
    "/admin/media/{id}/approve": {
      "post": {
        "x-controller-name": "AdminMediaController",
        "x-operation-name": "approveMedia",
        "tags": [
          "AdminMediaController"
        ],
        "responses": {
          "200": {
            "description": "Mark a media as approved (does not create an artwork)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "mediaId": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "operationId": "AdminMediaController.approveMedia"
      }
    },
    "/admin/media/{id}/create-artwork": {
      "post": {
        "x-controller-name": "AdminMediaController",
        "x-operation-name": "createArtworkFromMedia",
        "tags": [
          "AdminMediaController"
        ],
        "responses": {
          "200": {
            "description": "Create an artwork row from this media",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "mediaId": {
                      "type": "string"
                    },
                    "artworkId": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "operationId": "AdminMediaController.createArtworkFromMedia"
      }
    },
    "/admin/media/{id}/reject": {
      "post": {
        "x-controller-name": "AdminMediaController",
        "x-operation-name": "rejectMedia",
        "tags": [
          "AdminMediaController"
        ],
        "responses": {
          "200": {
            "description": "Mark a media as rejected — kept in DB for dedup history",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "mediaId": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "operationId": "AdminMediaController.rejectMedia"
      }
    },
    "/admin/payouts/pending": {
      "get": {
        "x-controller-name": "AdminPayoutController",
        "x-operation-name": "listPendingPayouts",
        "tags": [
          "AdminPayoutController"
        ],
        "responses": {
          "200": {
            "description": "Artistes ayant un solde Wave positif non encore viré",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AdminPendingPayoutItem"
                  }
                }
              }
            }
          }
        },
        "operationId": "AdminPayoutController.listPendingPayouts"
      }
    },
    "/admin/payouts": {
      "post": {
        "x-controller-name": "AdminPayoutController",
        "x-operation-name": "recordPayout",
        "tags": [
          "AdminPayoutController"
        ],
        "responses": {
          "201": {
            "description": "Virement Wave enregistré",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ArtistPayout"
                }
              }
            }
          }
        },
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AdminRecordPayoutBody"
              }
            }
          }
        },
        "operationId": "AdminPayoutController.recordPayout"
      },
      "get": {
        "x-controller-name": "AdminPayoutController",
        "x-operation-name": "listPayouts",
        "tags": [
          "AdminPayoutController"
        ],
        "responses": {
          "200": {
            "description": "Historique des virements Wave (filtre optionnel ?artistId=)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ArtistPayout"
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "artistId",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "operationId": "AdminPayoutController.listPayouts"
      }
    },
    "/admin/s3/diag": {
      "get": {
        "x-controller-name": "AdminS3DiagController",
        "x-operation-name": "diag",
        "tags": [
          "AdminS3DiagController"
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "description": "S3 configuration and connectivity diagnostic"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "live",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "operationId": "AdminS3DiagController.diag"
      }
    },
    "/admin/scraping/instagram-profile": {
      "post": {
        "x-controller-name": "AdminScrapingController",
        "x-operation-name": "scrapeInstagramProfile",
        "tags": [
          "AdminScrapingController"
        ],
        "responses": {
          "200": {
            "description": "Instagram profile scrape result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "source",
                    "url",
                    "runId",
                    "fetchedAt",
                    "itemsCount"
                  ],
                  "properties": {
                    "source": {
                      "type": "string"
                    },
                    "url": {
                      "type": "string"
                    },
                    "runId": {
                      "type": "string"
                    },
                    "fetchedAt": {
                      "type": "string"
                    },
                    "itemsCount": {
                      "type": "number"
                    },
                    "profile": {
                      "type": "object"
                    },
                    "posts": {
                      "type": "array"
                    },
                    "relatedProfiles": {
                      "type": "array"
                    }
                  }
                }
              }
            }
          }
        },
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "input"
                ],
                "properties": {
                  "input": {
                    "type": "string",
                    "description": "Handle Instagram (ex. \"@alma_rivest\"), nom court ou URL complète"
                  },
                  "resultsLimit": {
                    "type": "number",
                    "description": "Nombre max de posts (défaut 30, plafond ~200)"
                  }
                }
              }
            }
          }
        },
        "operationId": "AdminScrapingController.scrapeInstagramProfile"
      }
    },
    "/admin/scraping/run": {
      "post": {
        "x-controller-name": "AdminScrapingController",
        "x-operation-name": "startRun",
        "tags": [
          "AdminScrapingController"
        ],
        "responses": {
          "200": {
            "description": "Scraping run started",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "runId",
                    "scrapingRunId"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "runId": {
                      "type": "string",
                      "description": "Apify actor run ID"
                    },
                    "scrapingRunId": {
                      "type": "string",
                      "description": "Internal scraping_run row ID (UUID)"
                    }
                  }
                }
              }
            }
          }
        },
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "handles"
                ],
                "properties": {
                  "handles": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "minItems": 1,
                    "description": "Instagram handles to scrape (@ prefix optional)"
                  },
                  "hashtags": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Hashtags to scrape (# prefix optional)"
                  },
                  "postsLimit": {
                    "type": "number",
                    "minimum": 1,
                    "maximum": 500,
                    "description": "Max posts per handle/hashtag (default: 30)"
                  }
                }
              }
            }
          },
          "required": true
        },
        "operationId": "AdminScrapingController.startRun"
      }
    },
    "/admin/scraping/runs/{id}": {
      "get": {
        "x-controller-name": "AdminScrapingController",
        "x-operation-name": "getRun",
        "tags": [
          "AdminScrapingController"
        ],
        "responses": {
          "200": {
            "description": "Scraping run detail",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "actorId": {
                      "type": "string"
                    },
                    "inputJson": {
                      "type": "object"
                    },
                    "status": {
                      "type": "string"
                    },
                    "startedAt": {
                      "type": "string"
                    },
                    "endedAt": {
                      "type": "string"
                    },
                    "artworksInserted": {
                      "type": "number"
                    },
                    "artistsInserted": {
                      "type": "number"
                    },
                    "artistsSkipped": {
                      "type": "number"
                    },
                    "error": {
                      "type": "string"
                    },
                    "createdAt": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "operationId": "AdminScrapingController.getRun"
      }
    },
    "/admin/scraping/runs": {
      "get": {
        "x-controller-name": "AdminScrapingController",
        "x-operation-name": "listRuns",
        "tags": [
          "AdminScrapingController"
        ],
        "responses": {
          "200": {
            "description": "List of scraping runs (most recent first)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "actorId": {
                        "type": "string"
                      },
                      "status": {
                        "type": "string"
                      },
                      "startedAt": {
                        "type": "string"
                      },
                      "endedAt": {
                        "type": "string"
                      },
                      "artworksInserted": {
                        "type": "number"
                      },
                      "artistsInserted": {
                        "type": "number"
                      },
                      "artistsSkipped": {
                        "type": "number"
                      },
                      "error": {
                        "type": "string"
                      },
                      "createdAt": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "operationId": "AdminScrapingController.listRuns"
      }
    },
    "/admin/users/{id}/credits": {
      "post": {
        "x-controller-name": "AdminBoardController",
        "x-operation-name": "grantCredits",
        "tags": [
          "AdminBoardController"
        ],
        "responses": {
          "200": {
            "description": "Grant credits to a user (admin only)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdminGrantCreditsResponse"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AdminGrantCreditsBody"
              }
            }
          },
          "x-parameter-index": 1
        },
        "operationId": "AdminBoardController.grantCredits"
      }
    },
    "/admin/users/{id}": {
      "get": {
        "x-controller-name": "AdminBoardController",
        "x-operation-name": "getUser",
        "tags": [
          "AdminBoardController"
        ],
        "responses": {
          "200": {
            "description": "User drill-down (admin)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "operationId": "AdminBoardController.getUser"
      }
    },
    "/admin/users": {
      "get": {
        "x-controller-name": "AdminBoardController",
        "x-operation-name": "listUsers",
        "tags": [
          "AdminBoardController"
        ],
        "responses": {
          "200": {
            "description": "Paginated list of users (admin)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "total": {
                      "type": "number"
                    },
                    "items": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "has_playlists",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "dir",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "number"
            }
          }
        ],
        "operationId": "AdminBoardController.listUsers"
      }
    },
    "/admin/workflows/{id}/cancel": {
      "post": {
        "x-controller-name": "AdminWorkflowController",
        "x-operation-name": "cancelWorkflow",
        "tags": [
          "AdminWorkflowController"
        ],
        "responses": {
          "200": {
            "description": "Cancel workflow and pending jobs",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "operationId": "AdminWorkflowController.cancelWorkflow"
      }
    },
    "/admin/workflows/{id}": {
      "get": {
        "x-controller-name": "AdminWorkflowController",
        "x-operation-name": "getWorkflow",
        "tags": [
          "AdminWorkflowController"
        ],
        "responses": {
          "200": {
            "description": "Workflow with its jobs",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "operationId": "AdminWorkflowController.getWorkflow"
      }
    },
    "/admin/workflows": {
      "get": {
        "x-controller-name": "AdminWorkflowController",
        "x-operation-name": "listWorkflows",
        "tags": [
          "AdminWorkflowController"
        ],
        "responses": {
          "200": {
            "description": "List recent workflows",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "operationId": "AdminWorkflowController.listWorkflows"
      }
    },
    "/animate/{id}": {
      "get": {
        "x-controller-name": "AnimationController",
        "x-operation-name": "getJobStatus",
        "tags": [
          "AnimationController"
        ],
        "responses": {
          "200": {
            "description": "Get animation job status",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AnimationJobResponse"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "operationId": "AnimationController.getJobStatus"
      }
    },
    "/animate": {
      "post": {
        "x-controller-name": "AnimationController",
        "x-operation-name": "animate",
        "tags": [
          "AnimationController"
        ],
        "responses": {
          "200": {
            "description": "Animation job queued (open policy) or reuse found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AnimateResponse"
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AnimateRequestBody"
              }
            }
          }
        },
        "operationId": "AnimationController.animate"
      }
    },
    "/animation-models": {
      "get": {
        "x-controller-name": "AnimationModelController",
        "x-operation-name": "listAnimationModels",
        "tags": [
          "AnimationModelController"
        ],
        "responses": {
          "200": {
            "description": "List of active animation models ordered by display_order",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "slug": {
                        "type": "string"
                      },
                      "provider": {
                        "type": "string",
                        "enum": [
                          "fal"
                        ]
                      },
                      "modelId": {
                        "type": "string"
                      },
                      "styleLabel": {
                        "type": "string"
                      },
                      "description": {
                        "type": "string",
                        "nullable": true
                      },
                      "costCredits": {
                        "type": "number"
                      },
                      "durationS": {
                        "type": "number"
                      },
                      "capabilities": {
                        "type": "object",
                        "nullable": true
                      },
                      "active": {
                        "type": "boolean"
                      },
                      "isDefault": {
                        "type": "boolean"
                      },
                      "displayOrder": {
                        "type": "number"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "operationId": "AnimationModelController.listAnimationModels"
      }
    },
    "/artists/me/playlists": {
      "post": {
        "x-controller-name": "PlaylistController",
        "x-operation-name": "createMyArtistPlaylist",
        "tags": [
          "PlaylistController"
        ],
        "responses": {
          "201": {
            "description": "Created artist-owned playlist",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePlaylistBody"
              }
            }
          }
        },
        "operationId": "PlaylistController.createMyArtistPlaylist"
      },
      "get": {
        "x-controller-name": "PlaylistController",
        "x-operation-name": "listMyArtistPlaylists",
        "tags": [
          "PlaylistController"
        ],
        "responses": {
          "200": {
            "description": "List artist-owned playlists of the current authenticated artist",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "operationId": "PlaylistController.listMyArtistPlaylists"
      }
    },
    "/artists/{artistId}/artworks": {
      "get": {
        "x-controller-name": "ArtistController",
        "x-operation-name": "findArtworksByArtist",
        "tags": [
          "ArtistController"
        ],
        "responses": {
          "200": {
            "description": "Array of Artwork views for an artist (image/audio URLs resolved)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ArtworkView"
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "artistId",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "operationId": "ArtistController.findArtworksByArtist"
      }
    },
    "/artists/{idOrSlug}/claim": {
      "post": {
        "x-controller-name": "ArtistController",
        "x-operation-name": "claimArtist",
        "tags": [
          "ArtistController"
        ],
        "responses": {
          "200": {
            "description": "Claim artist profile with Instagram OAuth",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "status": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    },
                    "instagramHandle": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "idOrSlug",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "instagramCode",
                  "state"
                ],
                "properties": {
                  "instagramCode": {
                    "type": "string"
                  },
                  "state": {
                    "type": "string"
                  }
                }
              }
            }
          },
          "x-parameter-index": 1
        },
        "operationId": "ArtistController.claimArtist"
      }
    },
    "/artists/{idOrSlug}/claim-intent": {
      "post": {
        "x-controller-name": "ArtistController",
        "x-operation-name": "claimIntent",
        "tags": [
          "ArtistController"
        ],
        "responses": {
          "200": {
            "description": "Initiates Instagram OAuth claim flow. Returns a signed state and authorization URL.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "authorizationUrl": {
                      "type": "string"
                    },
                    "state": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "idOrSlug",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "operationId": "ArtistController.claimIntent"
      }
    },
    "/artists/{idOrSlug}/claim-status": {
      "get": {
        "x-controller-name": "ArtistController",
        "x-operation-name": "getClaimStatus",
        "tags": [
          "ArtistController"
        ],
        "responses": {
          "200": {
            "description": "Get claim status for artist",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string"
                    },
                    "instagramHandle": {
                      "type": "string"
                    },
                    "claimedAt": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "idOrSlug",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "operationId": "ArtistController.getClaimStatus"
      }
    },
    "/artists/{idOrSlug}/connect-onboarding": {
      "post": {
        "x-controller-name": "ArtistConnectController",
        "x-operation-name": "createConnectOnboarding",
        "tags": [
          "ArtistConnectController"
        ],
        "responses": {
          "200": {
            "description": "Stripe Connect onboarding URL",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConnectOnboardingResponse"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "idOrSlug",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "name": "x-request-id",
            "in": "header",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "origin",
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "operationId": "ArtistConnectController.createConnectOnboarding"
      }
    },
    "/artists/{idOrSlug}/connect-status": {
      "get": {
        "x-controller-name": "ArtistConnectController",
        "x-operation-name": "getConnectStatus",
        "tags": [
          "ArtistConnectController"
        ],
        "responses": {
          "200": {
            "description": "Stripe Connect account status",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "connected": {
                      "type": "boolean"
                    },
                    "chargesEnabled": {
                      "type": "boolean"
                    },
                    "payoutsEnabled": {
                      "type": "boolean"
                    },
                    "detailsSubmitted": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "idOrSlug",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "name": "x-request-id",
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "operationId": "ArtistConnectController.getConnectStatus"
      }
    },
    "/artists/{idOrSlug}/matches": {
      "get": {
        "x-controller-name": "ArtistController",
        "x-operation-name": "findMatches",
        "tags": [
          "ArtistController"
        ],
        "responses": {
          "200": {
            "description": "Find matching artists using embeddings",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "mode": {
                      "type": "string"
                    },
                    "results": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "artistId": {
                            "type": "string"
                          },
                          "slug": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          },
                          "city": {
                            "type": "string"
                          },
                          "avatarUrl": {
                            "type": "string"
                          },
                          "bio": {
                            "type": "string"
                          },
                          "similarity": {
                            "type": "number"
                          },
                          "reasons": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "idOrSlug",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "name": "mode",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "visualWeight",
            "in": "query",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "textWeight",
            "in": "query",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "x-request-id",
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "operationId": "ArtistController.findMatches"
      }
    },
    "/artists/{idOrSlug}/payout-balance": {
      "get": {
        "x-controller-name": "ArtistPayoutController",
        "x-operation-name": "getPayoutBalance",
        "tags": [
          "ArtistPayoutController"
        ],
        "responses": {
          "200": {
            "description": "Solde Wave de l'artiste (owner ou admin)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "grossCents": {
                      "type": "number"
                    },
                    "feeCents": {
                      "type": "number"
                    },
                    "netCents": {
                      "type": "number"
                    },
                    "paidCents": {
                      "type": "number"
                    },
                    "owedCents": {
                      "type": "number"
                    },
                    "currency": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "idOrSlug",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "operationId": "ArtistPayoutController.getPayoutBalance"
      }
    },
    "/artists/{idOrSlug}/payout-info": {
      "get": {
        "x-controller-name": "ArtistPayoutController",
        "x-operation-name": "listPayoutInfo",
        "tags": [
          "ArtistPayoutController"
        ],
        "responses": {
          "200": {
            "description": "Liste des méthodes de payout de l'artiste (owner ou admin)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ArtistPayoutInfo"
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "idOrSlug",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "operationId": "ArtistPayoutController.listPayoutInfo"
      }
    },
    "/artists/{idOrSlug}/payout-settings": {
      "patch": {
        "x-controller-name": "ArtistPayoutController",
        "x-operation-name": "upsertWavePayoutSettings",
        "tags": [
          "ArtistPayoutController"
        ],
        "responses": {
          "200": {
            "description": "Méthodes de payout Wave de l'artiste après upsert",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ArtistPayoutInfo"
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "idOrSlug",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WavePayoutSettingsBody"
              }
            }
          },
          "x-parameter-index": 1
        },
        "operationId": "ArtistPayoutController.upsertWavePayoutSettings"
      }
    },
    "/artists/{idOrSlug}/payouts": {
      "get": {
        "x-controller-name": "ArtistPayoutController",
        "x-operation-name": "listPayouts",
        "tags": [
          "ArtistPayoutController"
        ],
        "responses": {
          "200": {
            "description": "Historique des virements (Wave + Stripe) de l'artiste (owner ou admin)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ArtistPayout"
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "idOrSlug",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "operationId": "ArtistPayoutController.listPayouts"
      }
    },
    "/artists/{idOrSlug}/recompute-embeddings": {
      "post": {
        "x-controller-name": "ArtistController",
        "x-operation-name": "recomputeEmbeddings",
        "tags": [
          "ArtistController"
        ],
        "responses": {
          "200": {
            "description": "Recompute artist embeddings from artworks",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "artworksCount": {
                      "type": "number"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "idOrSlug",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "operationId": "ArtistController.recomputeEmbeddings"
      }
    },
    "/artists/{idOrSlug}/reject": {
      "post": {
        "x-controller-name": "ArtistController",
        "x-operation-name": "rejectArtist",
        "tags": [
          "ArtistController"
        ],
        "responses": {
          "200": {
            "description": "Reject artist profile claim (admin only)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "idOrSlug",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "reason": {
                    "type": "string"
                  }
                }
              }
            }
          },
          "x-parameter-index": 1
        },
        "operationId": "ArtistController.rejectArtist"
      }
    },
    "/artists/{idOrSlug}/verify": {
      "post": {
        "x-controller-name": "ArtistController",
        "x-operation-name": "verifyArtist",
        "tags": [
          "ArtistController"
        ],
        "responses": {
          "200": {
            "description": "Verify artist profile claim (admin only)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "idOrSlug",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "operationId": "ArtistController.verifyArtist"
      }
    },
    "/artists/{idOrSlug}": {
      "patch": {
        "x-controller-name": "ArtistController",
        "x-operation-name": "update",
        "tags": [
          "ArtistController"
        ],
        "responses": {
          "200": {
            "description": "Updated Artist",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Artist"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "idOrSlug",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ArtistPatchBody"
              }
            }
          },
          "x-parameter-index": 1
        },
        "operationId": "ArtistController.update"
      },
      "get": {
        "x-controller-name": "ArtistController",
        "x-operation-name": "findByIdOrSlug",
        "tags": [
          "ArtistController"
        ],
        "responses": {
          "200": {
            "description": "Artist model instance",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Artist"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "idOrSlug",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "operationId": "ArtistController.findByIdOrSlug"
      }
    },
    "/artists": {
      "get": {
        "x-controller-name": "ArtistController",
        "x-operation-name": "findAll",
        "tags": [
          "ArtistController"
        ],
        "responses": {
          "200": {
            "description": "Array of Artist model instances",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Artist"
                  }
                }
              }
            }
          }
        },
        "operationId": "ArtistController.findAll"
      }
    },
    "/artworks/artist/{artistId}": {
      "get": {
        "x-controller-name": "ArtworkController",
        "x-operation-name": "findByArtistId",
        "tags": [
          "ArtworkController"
        ],
        "responses": {
          "200": {
            "description": "Array of Artwork views for an artist",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ArtworkView"
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "artistId",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "operationId": "ArtworkController.findByArtistId"
      }
    },
    "/artworks/{id}/animations": {
      "get": {
        "x-controller-name": "ArtworkController",
        "x-operation-name": "getAnimations",
        "tags": [
          "ArtworkController"
        ],
        "responses": {
          "200": {
            "description": "List of succeeded animation jobs for an artwork",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ArtworkAnimationItem"
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "operationId": "ArtworkController.getAnimations"
      }
    },
    "/artworks/{id}/audio": {
      "get": {
        "x-controller-name": "ArtworkController",
        "x-operation-name": "serveAudio",
        "tags": [
          "ArtworkController"
        ],
        "responses": {
          "302": {
            "description": "Found",
            "content": {
              "application/json": {
                "schema": {
                  "description": "Redirect to audio URL"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "description": "Artwork or audio not found"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "operationId": "ArtworkController.serveAudio"
      }
    },
    "/artworks/{id}/image": {
      "get": {
        "x-controller-name": "ArtworkController",
        "x-operation-name": "serveImage",
        "tags": [
          "ArtworkController"
        ],
        "responses": {
          "302": {
            "description": "Found",
            "content": {
              "application/json": {
                "schema": {
                  "description": "Redirect to image URL"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "description": "Artwork not found"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "operationId": "ArtworkController.serveImage"
      }
    },
    "/artworks/{id}/qr": {
      "get": {
        "x-controller-name": "ArtworkController",
        "x-operation-name": "generateQrCode",
        "tags": [
          "ArtworkController"
        ],
        "responses": {
          "200": {
            "description": "PNG QR code pointing to the public artwork page",
            "content": {
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "operationId": "ArtworkController.generateQrCode"
      }
    },
    "/artworks/{id}": {
      "patch": {
        "x-controller-name": "ArtworkController",
        "x-operation-name": "updateById",
        "tags": [
          "ArtworkController"
        ],
        "responses": {
          "200": {
            "description": "Updated Artwork view",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ArtworkView"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ArtworkUpdateBody"
              }
            }
          },
          "x-parameter-index": 1
        },
        "operationId": "ArtworkController.updateById"
      },
      "get": {
        "x-controller-name": "ArtworkController",
        "x-operation-name": "findById",
        "tags": [
          "ArtworkController"
        ],
        "responses": {
          "200": {
            "description": "Artwork view (image/audio URLs resolved)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ArtworkView"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "operationId": "ArtworkController.findById"
      },
      "delete": {
        "x-controller-name": "ArtworkController",
        "x-operation-name": "deleteById",
        "tags": [
          "ArtworkController"
        ],
        "responses": {
          "204": {
            "description": "No Content",
            "content": {
              "application/json": {
                "schema": {
                  "description": "Artwork deleted"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "operationId": "ArtworkController.deleteById"
      }
    },
    "/artworks": {
      "post": {
        "x-controller-name": "ArtworkController",
        "x-operation-name": "create",
        "tags": [
          "ArtworkController"
        ],
        "responses": {
          "200": {
            "description": "Created Artwork view",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ArtworkView"
                }
              }
            }
          }
        },
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ArtworkCreateBody"
              }
            }
          }
        },
        "operationId": "ArtworkController.create"
      },
      "get": {
        "x-controller-name": "ArtworkController",
        "x-operation-name": "findAll",
        "tags": [
          "ArtworkController"
        ],
        "responses": {
          "200": {
            "description": "Array of Artwork views (image/audio URLs resolved)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ArtworkView"
                  }
                }
              }
            }
          }
        },
        "operationId": "ArtworkController.findAll"
      }
    },
    "/auth/wa/send-otp": {
      "post": {
        "x-controller-name": "WhatsappAuthController",
        "x-operation-name": "sendOtp",
        "tags": [
          "WhatsappAuthController"
        ],
        "responses": {
          "200": {
            "description": "Envoi du code OTP via WhatsApp Cloud API",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WaSendOtpResponse"
                }
              }
            }
          }
        },
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WaSendOtpRequest"
              }
            }
          }
        },
        "operationId": "WhatsappAuthController.sendOtp"
      }
    },
    "/auth/wa/verify-otp": {
      "post": {
        "x-controller-name": "WhatsappAuthController",
        "x-operation-name": "verifyOtp",
        "tags": [
          "WhatsappAuthController"
        ],
        "responses": {
          "200": {
            "description": "Vérification OTP + retour du custom token Firebase",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WaVerifyOtpResponse"
                }
              }
            }
          }
        },
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WaVerifyOtpRequest"
              }
            }
          }
        },
        "operationId": "WhatsappAuthController.verifyOtp"
      }
    },
    "/credits/purchase": {
      "post": {
        "x-controller-name": "CreditsController",
        "x-operation-name": "createPurchaseSession",
        "tags": [
          "CreditsController"
        ],
        "responses": {
          "200": {
            "description": "Created payment checkout session for credits purchase",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreditsPurchaseResponse"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "x-country",
            "in": "header",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "origin",
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreditsPurchaseBody"
              }
            }
          }
        },
        "operationId": "CreditsController.createPurchaseSession"
      }
    },
    "/credits/session/{sessionId}": {
      "get": {
        "x-controller-name": "CreditsController",
        "x-operation-name": "getSession",
        "tags": [
          "CreditsController"
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "description": "Get Stripe checkout session details"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "sessionId",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "operationId": "CreditsController.getSession"
      }
    },
    "/credits": {
      "get": {
        "x-controller-name": "CreditsController",
        "x-operation-name": "getCredits",
        "tags": [
          "CreditsController"
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "description": "Get user credits balance and recent transactions"
                }
              }
            }
          }
        },
        "operationId": "CreditsController.getCredits"
      }
    },
    "/donations/artist/{artistId}": {
      "get": {
        "x-controller-name": "DonationController",
        "x-operation-name": "findByArtist",
        "tags": [
          "DonationController"
        ],
        "responses": {
          "200": {
            "description": "Donations for an artist (owner/admin only, includes donor)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/DonationWithRelations"
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "artistId",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "operationId": "DonationController.findByArtist"
      }
    },
    "/donations/mine": {
      "get": {
        "x-controller-name": "DonationController",
        "x-operation-name": "findMine",
        "tags": [
          "DonationController"
        ],
        "responses": {
          "200": {
            "description": "Donations made by the current user",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Donation"
                  }
                }
              }
            }
          }
        },
        "operationId": "DonationController.findMine"
      }
    },
    "/donations": {
      "post": {
        "x-controller-name": "DonationController",
        "x-operation-name": "create",
        "tags": [
          "DonationController"
        ],
        "responses": {
          "200": {
            "description": "Created donation (pending) + Checkout URL",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DonationCreateResponse"
                }
              }
            }
          }
        },
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DonationCreateBody"
              }
            }
          }
        },
        "operationId": "DonationController.create"
      }
    },
    "/fal/webhooks": {
      "post": {
        "x-controller-name": "FalWebhooksController",
        "x-operation-name": "receive",
        "tags": [
          "FalWebhooksController"
        ],
        "responses": {
          "200": {
            "description": "fal.ai webhook callback — finalize the matching job",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "jobId": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "secret",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "operationId": "FalWebhooksController.receive"
      }
    },
    "/me/animations": {
      "get": {
        "x-controller-name": "ArtworkController",
        "x-operation-name": "findMyAnimations",
        "tags": [
          "ArtworkController"
        ],
        "responses": {
          "200": {
            "description": "Animations générées par l’utilisateur courant",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/MyAnimationView"
                  }
                }
              }
            }
          }
        },
        "operationId": "ArtworkController.findMyAnimations"
      }
    },
    "/me/playlists/{id}/artworks/{artworkId}": {
      "delete": {
        "x-controller-name": "PlaylistController",
        "x-operation-name": "removeArtwork",
        "tags": [
          "PlaylistController"
        ],
        "responses": {
          "200": {
            "description": "Artwork removed",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "name": "artworkId",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "operationId": "PlaylistController.removeArtwork"
      }
    },
    "/me/playlists/{id}/artworks": {
      "post": {
        "x-controller-name": "PlaylistController",
        "x-operation-name": "addArtwork",
        "tags": [
          "PlaylistController"
        ],
        "responses": {
          "200": {
            "description": "Artwork added (or already present)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddArtworkBody"
              }
            }
          },
          "x-parameter-index": 1
        },
        "operationId": "PlaylistController.addArtwork"
      }
    },
    "/me/playlists/{id}/reorder": {
      "patch": {
        "x-controller-name": "PlaylistController",
        "x-operation-name": "reorder",
        "tags": [
          "PlaylistController"
        ],
        "responses": {
          "200": {
            "description": "Reordered",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReorderBody"
              }
            }
          },
          "x-parameter-index": 1
        },
        "operationId": "PlaylistController.reorder"
      }
    },
    "/me/playlists/{id}": {
      "patch": {
        "x-controller-name": "PlaylistController",
        "x-operation-name": "updatePlaylist",
        "tags": [
          "PlaylistController"
        ],
        "responses": {
          "200": {
            "description": "Updated playlist",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdatePlaylistBody"
              }
            }
          },
          "x-parameter-index": 1
        },
        "operationId": "PlaylistController.updatePlaylist"
      },
      "delete": {
        "x-controller-name": "PlaylistController",
        "x-operation-name": "deletePlaylist",
        "tags": [
          "PlaylistController"
        ],
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "operationId": "PlaylistController.deletePlaylist"
      }
    },
    "/me/playlists": {
      "post": {
        "x-controller-name": "PlaylistController",
        "x-operation-name": "createPlaylist",
        "tags": [
          "PlaylistController"
        ],
        "responses": {
          "201": {
            "description": "Created playlist",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePlaylistBody"
              }
            }
          }
        },
        "operationId": "PlaylistController.createPlaylist"
      },
      "get": {
        "x-controller-name": "PlaylistController",
        "x-operation-name": "listMyPlaylists",
        "tags": [
          "PlaylistController"
        ],
        "responses": {
          "200": {
            "description": "List playlists of the authenticated user",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "operationId": "PlaylistController.listMyPlaylists"
      }
    },
    "/media/{id}/image": {
      "get": {
        "x-controller-name": "MediaController",
        "x-operation-name": "getMediaImage",
        "tags": [
          "MediaController"
        ],
        "responses": {
          "200": {
            "description": "Return value of MediaController.getMediaImage"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "operationId": "MediaController.getMediaImage"
      }
    },
    "/payment-intents/by-ref/{providerRef}": {
      "get": {
        "x-controller-name": "PaymentIntentController",
        "x-operation-name": "getByRef",
        "tags": [
          "PaymentIntentController"
        ],
        "responses": {
          "200": {
            "description": "Payment intent status (public, capability-token access)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "kind": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string"
                    },
                    "amountCents": {
                      "type": "number"
                    },
                    "currency": {
                      "type": "string"
                    },
                    "metadata": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "providerRef",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "operationId": "PaymentIntentController.getByRef"
      }
    },
    "/ping": {
      "get": {
        "x-controller-name": "PingController",
        "x-operation-name": "ping",
        "tags": [
          "PingController"
        ],
        "responses": {
          "200": {
            "description": "Ping Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PingResponse"
                }
              }
            }
          }
        },
        "operationId": "PingController.ping"
      }
    },
    "/playlists/{id}": {
      "get": {
        "x-controller-name": "PlaylistController",
        "x-operation-name": "getPlaylist",
        "tags": [
          "PlaylistController"
        ],
        "responses": {
          "200": {
            "description": "Public playlist with items",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "operationId": "PlaylistController.getPlaylist"
      }
    },
    "/stats/artists/{slug}": {
      "get": {
        "x-controller-name": "StatsController",
        "x-operation-name": "artistStats",
        "tags": [
          "StatsController"
        ],
        "responses": {
          "200": {
            "description": "Aggregated statistics for an artist",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ArtistStats"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "operationId": "StatsController.artistStats"
      }
    },
    "/stats/artworks/{id}": {
      "get": {
        "x-controller-name": "StatsController",
        "x-operation-name": "artworkStats",
        "tags": [
          "StatsController"
        ],
        "responses": {
          "200": {
            "description": "Viewing statistics for a single artwork",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ArtworkStats"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "operationId": "StatsController.artworkStats"
      }
    },
    "/stats/vernissage": {
      "get": {
        "x-controller-name": "StatsController",
        "x-operation-name": "vernissage",
        "tags": [
          "StatsController"
        ],
        "responses": {
          "200": {
            "description": "Aggregated vernissage statistics",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VernissageStats"
                }
              }
            }
          }
        },
        "operationId": "StatsController.vernissage"
      }
    },
    "/uploads/file": {
      "post": {
        "x-controller-name": "UploadController",
        "x-operation-name": "uploadFile",
        "tags": [
          "UploadController"
        ],
        "responses": {
          "200": {
            "description": "Uploaded media row",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Media"
                }
              }
            }
          }
        },
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "x-parser": "stream",
              "schema": {
                "type": "object"
              }
            }
          },
          "description": "multipart/form-data avec un champ `kind` et un fichier",
          "required": true
        },
        "operationId": "UploadController.uploadFile"
      }
    },
    "/uploads/presigned": {
      "post": {
        "x-controller-name": "UploadController",
        "x-operation-name": "createPresignedUpload",
        "tags": [
          "UploadController"
        ],
        "responses": {
          "200": {
            "description": "Presigned S3 upload URL",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PresignedUploadResponse"
                }
              }
            }
          }
        },
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PresignedUploadBody"
              }
            }
          }
        },
        "operationId": "UploadController.createPresignedUpload"
      }
    },
    "/user/become-artist": {
      "post": {
        "x-controller-name": "UserController",
        "x-operation-name": "becomeArtist",
        "tags": [
          "UserController"
        ],
        "responses": {
          "200": {
            "description": "Crée un nouveau profil artiste from scratch et rattache le user — pas de revendication d'un artiste existant. Retourne un nouveau JWT.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          }
        },
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BecomeArtistBody"
              }
            }
          }
        },
        "operationId": "UserController.becomeArtist"
      }
    },
    "/user/claim-artist": {
      "post": {
        "x-controller-name": "UserController",
        "x-operation-name": "claimArtist",
        "tags": [
          "UserController"
        ],
        "responses": {
          "200": {
            "description": "User linked to artist — returns new JWT with updated role",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          }
        },
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ClaimArtistBody"
              }
            }
          }
        },
        "operationId": "UserController.claimArtist"
      }
    },
    "/user/login": {
      "post": {
        "x-controller-name": "UserController",
        "x-operation-name": "login",
        "tags": [
          "UserController"
        ],
        "responses": {
          "200": {
            "description": "JWT token + user",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          }
        },
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LoginRequest"
              }
            }
          }
        },
        "operationId": "UserController.login"
      }
    },
    "/user/me": {
      "get": {
        "x-controller-name": "UserController",
        "x-operation-name": "me",
        "tags": [
          "UserController"
        ],
        "responses": {
          "200": {
            "description": "Current authenticated user",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicUser"
                }
              }
            }
          }
        },
        "operationId": "UserController.me"
      }
    },
    "/user/onboarding": {
      "post": {
        "x-controller-name": "UserController",
        "x-operation-name": "onboarding",
        "tags": [
          "UserController"
        ],
        "responses": {
          "200": {
            "description": "Profil utilisateur initialisé (prénom, nom, date naissance, email)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicUser"
                }
              }
            }
          }
        },
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OnboardingBody"
              }
            }
          }
        },
        "operationId": "UserController.onboarding"
      }
    },
    "/user/register": {
      "post": {
        "x-controller-name": "UserController",
        "x-operation-name": "register",
        "tags": [
          "UserController"
        ],
        "responses": {
          "200": {
            "description": "Registered user + JWT",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          }
        },
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RegisterRequest"
              }
            }
          }
        },
        "operationId": "UserController.register"
      }
    },
    "/users/{userId}/playlists": {
      "get": {
        "x-controller-name": "PlaylistController",
        "x-operation-name": "listUserPlaylists",
        "tags": [
          "PlaylistController"
        ],
        "responses": {
          "200": {
            "description": "Public playlists of a user (own user sees all)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "userId",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "operationId": "PlaylistController.listUserPlaylists"
      }
    },
    "/view-events/batch": {
      "post": {
        "x-controller-name": "ViewEventController",
        "x-operation-name": "batch",
        "tags": [
          "ViewEventController"
        ],
        "responses": {
          "200": {
            "description": "Number of view events inserted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ViewEventBatchResponse"
                }
              }
            }
          }
        },
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ViewEventBatchBody"
              }
            }
          }
        },
        "operationId": "ViewEventController.batch"
      }
    },
    "/webhooks/apify": {
      "post": {
        "x-controller-name": "ApifyWebhookController",
        "x-operation-name": "handleApifyWebhook",
        "tags": [
          "ApifyWebhookController"
        ],
        "responses": {
          "200": {
            "description": "Webhook received and processed",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "received": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          }
        },
        "requestBody": {
          "content": {
            "application/json": {
              "x-parser": "raw",
              "schema": {
                "$ref": "#/components/schemas/Buffer"
              }
            }
          },
          "description": "Raw Apify webhook payload. Parsé en Buffer (x-parser: raw) pour vérifier la signature HMAC-SHA256 sur les bytes exacts du corps de la requête. Le JSON est ensuite parsé à la main ci-dessous. Pas de schema => aucune validation AJV sur le Buffer. Cf. PaymentWebhooksController pour le motif.",
          "required": true
        },
        "operationId": "ApifyWebhookController.handleApifyWebhook"
      }
    },
    "/webhooks/stripe": {
      "post": {
        "x-controller-name": "PaymentWebhooksController",
        "x-operation-name": "handleStripe",
        "tags": [
          "PaymentWebhooksController"
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "description": "Unified Stripe webhook (donations + credits)"
                }
              }
            }
          }
        },
        "requestBody": {
          "content": {
            "application/json": {
              "x-parser": "raw",
              "schema": {
                "$ref": "#/components/schemas/Buffer"
              }
            }
          },
          "description": "Raw Stripe webhook payload. Parsé en Buffer (x-parser: raw) pour que la signature HMAC soit vérifiée sur les bytes EXACTS signés par Stripe — un objet JSON re-sérialisé ne matcherait jamais (ordre des clés).",
          "required": true
        },
        "operationId": "PaymentWebhooksController.handleStripe"
      }
    },
    "/webhooks/wave": {
      "post": {
        "x-controller-name": "PaymentWebhooksController",
        "x-operation-name": "handleWave",
        "tags": [
          "PaymentWebhooksController"
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "description": "Unified Wave webhook (donations + credits)"
                }
              }
            }
          }
        },
        "requestBody": {
          "content": {
            "application/json": {
              "x-parser": "raw",
              "schema": {
                "$ref": "#/components/schemas/Buffer"
              }
            }
          },
          "description": "Raw Wave webhook payload. Parsé en Buffer (x-parser: raw) pour vérifier la signature HMAC sur les bytes exacts. Voir handleStripe pour le détail.",
          "required": true
        },
        "operationId": "PaymentWebhooksController.handleWave"
      }
    }
  },
  "servers": [
    {
      "url": "https://api.morphart.app"
    }
  ],
  "components": {
    "schemas": {
      "WaSendOtpResponse": {
        "title": "WaSendOtpResponse",
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": false
      },
      "WaSendOtpRequest": {
        "title": "WaSendOtpRequest",
        "type": "object",
        "properties": {
          "phone": {
            "type": "string"
          }
        },
        "required": [
          "phone"
        ],
        "additionalProperties": false
      },
      "WaVerifyOtpResponse": {
        "title": "WaVerifyOtpResponse",
        "type": "object",
        "properties": {
          "customToken": {
            "type": "string"
          }
        },
        "required": [
          "customToken"
        ],
        "additionalProperties": false
      },
      "WaVerifyOtpRequest": {
        "title": "WaVerifyOtpRequest",
        "type": "object",
        "properties": {
          "phone": {
            "type": "string"
          },
          "code": {
            "type": "string"
          }
        },
        "required": [
          "phone",
          "code"
        ],
        "additionalProperties": false
      },
      "ViewEventBatchResponse": {
        "title": "ViewEventBatchResponse",
        "type": "object",
        "properties": {
          "inserted": {
            "type": "number"
          }
        },
        "required": [
          "inserted"
        ],
        "additionalProperties": false
      },
      "ViewEventInput": {
        "title": "ViewEventInput",
        "type": "object",
        "properties": {
          "artworkId": {
            "type": "string"
          },
          "durationMs": {
            "type": "number"
          },
          "recordedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "artworkId",
          "durationMs",
          "recordedAt"
        ],
        "additionalProperties": false
      },
      "ViewEventBatchBody": {
        "title": "ViewEventBatchBody",
        "type": "object",
        "properties": {
          "anonymousId": {
            "type": "string"
          },
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ViewEventInput"
            }
          }
        },
        "required": [
          "events"
        ],
        "additionalProperties": false
      },
      "PublicUser": {
        "title": "PublicUser",
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "displayName": {
            "type": "string"
          },
          "firstName": {
            "type": "string"
          },
          "lastName": {
            "type": "string"
          },
          "birthDate": {
            "type": "string"
          },
          "onboardedAt": {
            "type": "string"
          },
          "role": {
            "type": "string"
          },
          "artistId": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "role"
        ],
        "additionalProperties": false
      },
      "AuthResponse": {
        "title": "AuthResponse",
        "type": "object",
        "properties": {
          "token": {
            "type": "string"
          },
          "user": {
            "$ref": "#/components/schemas/PublicUser"
          }
        },
        "required": [
          "token",
          "user"
        ],
        "additionalProperties": false
      },
      "RegisterRequest": {
        "title": "RegisterRequest",
        "type": "object",
        "properties": {
          "email": {
            "type": "string"
          },
          "password": {
            "type": "string"
          },
          "displayName": {
            "type": "string"
          }
        },
        "required": [
          "email",
          "password"
        ],
        "additionalProperties": false
      },
      "LoginRequest": {
        "title": "LoginRequest",
        "type": "object",
        "properties": {
          "email": {
            "type": "string"
          },
          "password": {
            "type": "string"
          }
        },
        "required": [
          "email",
          "password"
        ],
        "additionalProperties": false
      },
      "ClaimArtistBody": {
        "title": "ClaimArtistBody",
        "type": "object",
        "properties": {
          "artistSlug": {
            "type": "string"
          }
        },
        "required": [
          "artistSlug"
        ],
        "additionalProperties": false
      },
      "BecomeArtistBody": {
        "title": "BecomeArtistBody",
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "role": {
            "type": "string"
          },
          "city": {
            "type": "string"
          },
          "bio": {
            "type": "string"
          }
        },
        "required": [
          "name"
        ],
        "additionalProperties": false
      },
      "OnboardingBody": {
        "title": "OnboardingBody",
        "type": "object",
        "properties": {
          "firstName": {
            "type": "string"
          },
          "lastName": {
            "type": "string"
          },
          "birthDate": {
            "type": "string"
          }
        },
        "required": [
          "firstName",
          "lastName",
          "birthDate"
        ],
        "additionalProperties": false
      },
      "PresignedUploadResponse": {
        "title": "PresignedUploadResponse",
        "type": "object",
        "properties": {
          "uploadUrl": {
            "type": "string"
          },
          "s3Key": {
            "type": "string"
          },
          "imageUrl": {
            "type": "string"
          },
          "contentType": {
            "type": "string"
          },
          "expiresIn": {
            "type": "number"
          },
          "acl": {
            "type": "string"
          }
        },
        "required": [
          "uploadUrl",
          "s3Key",
          "imageUrl",
          "contentType",
          "expiresIn"
        ],
        "additionalProperties": false
      },
      "PresignedUploadBody": {
        "title": "PresignedUploadBody",
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "artwork",
              "audio",
              "profile"
            ]
          },
          "contentType": {
            "type": "string"
          }
        },
        "required": [
          "kind",
          "contentType"
        ],
        "additionalProperties": false
      },
      "Media": {
        "title": "Media",
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "artistId": {
            "type": "string"
          },
          "scrapingRunId": {
            "type": "string"
          },
          "source": {
            "type": "string",
            "enum": [
              "scrape",
              "upload"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "approved",
              "rejected"
            ]
          },
          "url": {
            "type": "string"
          },
          "s3Key": {
            "type": "string"
          },
          "mimeType": {
            "type": "string"
          },
          "widthPx": {
            "type": "number"
          },
          "heightPx": {
            "type": "number"
          },
          "bytesSize": {
            "type": "number"
          },
          "altText": {
            "type": "string"
          },
          "igShortcode": {
            "type": "string"
          },
          "igPostUrl": {
            "type": "string"
          },
          "igPostId": {
            "type": "string"
          },
          "igImageIndex": {
            "type": "number"
          },
          "igCaption": {
            "type": "string"
          },
          "igLikesCount": {
            "type": "number"
          },
          "igTimestamp": {
            "type": "string",
            "format": "date-time"
          },
          "metadata": {
            "type": "object"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "approvedAt": {
            "type": "string",
            "format": "date-time"
          },
          "rejectedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "source",
          "status"
        ],
        "additionalProperties": false
      },
      "TopArtwork": {
        "title": "TopArtwork",
        "type": "object",
        "properties": {
          "artworkId": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "totalMs": {
            "type": "number"
          },
          "viewerCount": {
            "type": "number"
          }
        },
        "required": [
          "artworkId",
          "title",
          "totalMs",
          "viewerCount"
        ],
        "additionalProperties": false
      },
      "VernissageStats": {
        "title": "VernissageStats",
        "type": "object",
        "properties": {
          "totalViewMs": {
            "type": "number"
          },
          "uniqueVisitors": {
            "type": "number"
          },
          "totalArtworks": {
            "type": "number"
          },
          "totalArtists": {
            "type": "number"
          },
          "totalDonationsCents": {
            "type": "number"
          },
          "donationCount": {
            "type": "number"
          },
          "topArtworks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TopArtwork"
            }
          }
        },
        "required": [
          "totalViewMs",
          "uniqueVisitors",
          "totalArtworks",
          "totalArtists",
          "totalDonationsCents",
          "donationCount",
          "topArtworks"
        ],
        "additionalProperties": false
      },
      "ArtworkStats": {
        "title": "ArtworkStats",
        "type": "object",
        "properties": {
          "artworkId": {
            "type": "string"
          },
          "totalMs": {
            "type": "number"
          },
          "viewerCount": {
            "type": "number"
          },
          "avgMsPerViewer": {
            "type": "number"
          }
        },
        "required": [
          "artworkId",
          "totalMs",
          "viewerCount",
          "avgMsPerViewer"
        ],
        "additionalProperties": false
      },
      "ArtistStats": {
        "title": "ArtistStats",
        "type": "object",
        "properties": {
          "artistSlug": {
            "type": "string"
          },
          "artistId": {
            "type": "string"
          },
          "totalMs": {
            "type": "number"
          },
          "artworkCount": {
            "type": "number"
          },
          "totalDonationsCents": {
            "type": "number"
          },
          "donationCount": {
            "type": "number"
          }
        },
        "required": [
          "artistSlug",
          "artistId",
          "totalMs",
          "artworkCount",
          "totalDonationsCents",
          "donationCount"
        ],
        "additionalProperties": false
      },
      "CreatePlaylistBody": {
        "title": "CreatePlaylistBody",
        "type": "object",
        "properties": {
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "visibility": {
            "type": "string",
            "enum": [
              "public",
              "private"
            ]
          },
          "spotifyPlaylistUrl": {
            "type": "string",
            "format": "uri",
            "maxLength": 500
          }
        },
        "required": [
          "title"
        ],
        "additionalProperties": false
      },
      "UpdatePlaylistBody": {
        "title": "UpdatePlaylistBody",
        "type": "object",
        "properties": {
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "visibility": {
            "type": "string",
            "enum": [
              "public",
              "private"
            ]
          },
          "coverArtworkId": {
            "type": "string"
          },
          "spotifyPlaylistUrl": {
            "type": "string",
            "format": "uri",
            "maxLength": 500
          }
        },
        "additionalProperties": false
      },
      "AddArtworkBody": {
        "title": "AddArtworkBody",
        "type": "object",
        "properties": {
          "artworkId": {
            "type": "string"
          },
          "position": {
            "type": "number"
          }
        },
        "required": [
          "artworkId"
        ],
        "additionalProperties": false
      },
      "ReorderBody": {
        "title": "ReorderBody",
        "type": "object",
        "properties": {
          "artworkIds": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "artworkIds"
        ],
        "additionalProperties": false
      },
      "Buffer": {},
      "Donation": {
        "title": "Donation",
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "userId": {
            "type": "string"
          },
          "anonymousId": {
            "type": "string"
          },
          "artistId": {
            "type": "string"
          },
          "amountCents": {
            "type": "number"
          },
          "currency": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "succeeded",
              "failed",
              "refunded"
            ]
          },
          "provider": {
            "type": "string"
          },
          "paymentProvider": {
            "type": "string",
            "enum": [
              "stripe",
              "wave",
              "mock"
            ]
          },
          "providerRef": {
            "type": "string"
          },
          "intent": {
            "type": "string",
            "enum": [
              "support",
              "animation"
            ]
          },
          "artworkId": {
            "type": "string"
          },
          "paymentIntentId": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "artistId",
          "amountCents"
        ],
        "additionalProperties": false
      },
      "DonationCreateResponse": {
        "title": "DonationCreateResponse",
        "type": "object",
        "properties": {
          "checkoutUrl": {
            "type": "string"
          },
          "sessionId": {
            "type": "string"
          },
          "intentId": {
            "type": "string"
          },
          "donation": {
            "$ref": "#/components/schemas/Donation"
          }
        },
        "required": [
          "checkoutUrl"
        ],
        "additionalProperties": false
      },
      "DonationCreateBody": {
        "title": "DonationCreateBody",
        "type": "object",
        "properties": {
          "artistId": {
            "type": "string"
          },
          "amountCents": {
            "type": "number"
          },
          "currency": {
            "type": "string"
          },
          "anonymousId": {
            "type": "string"
          },
          "paymentProvider": {
            "type": "string",
            "enum": [
              "stripe",
              "wave",
              "mock"
            ]
          },
          "intent": {
            "type": "string",
            "enum": [
              "support",
              "animation"
            ]
          },
          "artworkId": {
            "type": "string"
          }
        },
        "required": [
          "artistId",
          "amountCents"
        ],
        "additionalProperties": false
      },
      "User": {
        "title": "User",
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "passwordHash": {
            "type": "string"
          },
          "phone": {
            "type": "string"
          },
          "firebaseUid": {
            "type": "string"
          },
          "displayName": {
            "type": "string"
          },
          "firstName": {
            "type": "string"
          },
          "lastName": {
            "type": "string"
          },
          "birthDate": {
            "type": "string",
            "format": "date-time"
          },
          "onboardedAt": {
            "type": "string",
            "format": "date-time"
          },
          "role": {
            "type": "string",
            "enum": [
              "visitor",
              "artist",
              "admin"
            ]
          },
          "artistId": {
            "type": "string"
          },
          "creditsBalance": {
            "type": "number"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "description": "{\"indexInfo\":{\"email\":{\"unique\":true}}}",
        "required": [
          "role",
          "creditsBalance"
        ],
        "additionalProperties": false
      },
      "DonationWithRelations": {
        "title": "DonationWithRelations",
        "type": "object",
        "description": "(tsType: DonationWithRelations, schemaOptions: { includeRelations: true })",
        "properties": {
          "id": {
            "type": "string"
          },
          "userId": {
            "type": "string"
          },
          "anonymousId": {
            "type": "string"
          },
          "artistId": {
            "type": "string"
          },
          "amountCents": {
            "type": "number"
          },
          "currency": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "succeeded",
              "failed",
              "refunded"
            ]
          },
          "provider": {
            "type": "string"
          },
          "paymentProvider": {
            "type": "string",
            "enum": [
              "stripe",
              "wave",
              "mock"
            ]
          },
          "providerRef": {
            "type": "string"
          },
          "intent": {
            "type": "string",
            "enum": [
              "support",
              "animation"
            ]
          },
          "artworkId": {
            "type": "string"
          },
          "paymentIntentId": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "donor": {
            "$ref": "#/components/schemas/User"
          },
          "foreignKey": {}
        },
        "required": [
          "artistId",
          "amountCents"
        ],
        "additionalProperties": false,
        "x-typescript-type": "DonationWithRelations"
      },
      "CreditsPurchaseResponse": {
        "title": "CreditsPurchaseResponse",
        "type": "object",
        "properties": {
          "checkoutUrl": {
            "type": "string"
          }
        },
        "required": [
          "checkoutUrl"
        ],
        "additionalProperties": false
      },
      "CreditsPurchaseBody": {
        "title": "CreditsPurchaseBody",
        "type": "object",
        "properties": {
          "packId": {
            "type": "string"
          },
          "paymentProvider": {
            "type": "string",
            "enum": [
              "stripe",
              "wave",
              "mock"
            ]
          }
        },
        "required": [
          "packId"
        ],
        "additionalProperties": false
      },
      "ArtworkView": {
        "title": "ArtworkView",
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "artistId": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "year": {
            "type": "number"
          },
          "medium": {
            "type": "string"
          },
          "dimensions": {
            "type": "string"
          },
          "price": {
            "type": "number"
          },
          "currency": {
            "type": "string"
          },
          "imageUrl": {
            "type": "string"
          },
          "audioUrl": {
            "type": "string"
          },
          "displayOrder": {
            "type": "number"
          },
          "provider": {
            "type": "string"
          },
          "sourceUrl": {
            "type": "string"
          },
          "spotifyTrackUrl": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "isAnimated": {
            "type": "boolean"
          },
          "kind": {
            "type": "string"
          },
          "parentArtworkId": {
            "type": "string"
          },
          "generatedByUserId": {
            "type": "string"
          },
          "generationModelSlug": {
            "type": "string"
          },
          "videoUrl": {
            "type": "string"
          },
          "mediaId": {
            "type": "string"
          },
          "audioMediaId": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "artistId",
          "title"
        ],
        "additionalProperties": false
      },
      "ArtworkAnimationItem": {
        "title": "ArtworkAnimationItem",
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "modelSlug": {
            "type": "string"
          },
          "modelStyleLabel": {
            "type": "string"
          },
          "modelDescription": {
            "type": "string"
          },
          "videoUrl": {
            "type": "string"
          },
          "durationS": {
            "type": "number"
          },
          "posterImageUrl": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "modelSlug",
          "modelStyleLabel",
          "videoUrl"
        ],
        "additionalProperties": false
      },
      "MyAnimationView": {
        "title": "MyAnimationView",
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "parentArtworkId": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "modelSlug": {
            "type": "string"
          },
          "modelStyleLabel": {
            "type": "string"
          },
          "videoUrl": {
            "type": "string"
          },
          "posterImageUrl": {
            "type": "string"
          },
          "durationS": {
            "type": "number"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "title",
          "videoUrl"
        ],
        "additionalProperties": false
      },
      "ArtworkCreateBody": {
        "title": "ArtworkCreateBody",
        "type": "object",
        "properties": {
          "title": {
            "type": "string"
          },
          "imageUrl": {
            "type": "string"
          },
          "mediaId": {
            "type": "string"
          },
          "audioMediaId": {
            "type": "string"
          },
          "year": {
            "type": "number"
          },
          "medium": {
            "type": "string"
          },
          "dimensions": {
            "type": "string"
          },
          "price": {
            "type": "number"
          },
          "currency": {
            "type": "string"
          },
          "provider": {
            "type": "string",
            "enum": [
              "local",
              "s3",
              "external",
              "instagram"
            ]
          },
          "sourceUrl": {
            "type": "string"
          },
          "spotifyTrackUrl": {
            "type": "string"
          },
          "displayOrder": {
            "type": "number"
          },
          "audioUrl": {
            "type": "string"
          },
          "description": {
            "type": "string"
          }
        },
        "required": [
          "title"
        ],
        "additionalProperties": false
      },
      "ArtworkUpdateBody": {
        "title": "ArtworkUpdateBody",
        "type": "object",
        "properties": {
          "title": {
            "type": "string"
          },
          "year": {
            "type": "number"
          },
          "medium": {
            "type": "string"
          },
          "dimensions": {
            "type": "string"
          },
          "price": {
            "type": "number"
          },
          "currency": {
            "type": "string"
          },
          "imageUrl": {
            "type": "string"
          },
          "mediaId": {
            "type": "string"
          },
          "audioMediaId": {
            "type": "string"
          },
          "provider": {
            "type": "string",
            "enum": [
              "local",
              "s3",
              "external",
              "instagram"
            ]
          },
          "sourceUrl": {
            "type": "string"
          },
          "spotifyTrackUrl": {
            "type": "string"
          },
          "displayOrder": {
            "type": "number"
          },
          "audioUrl": {
            "type": "string"
          },
          "description": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "Artist": {
        "title": "Artist",
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "role": {
            "type": "string"
          },
          "city": {
            "type": "string"
          },
          "bio": {
            "type": "string"
          },
          "coverUrl": {
            "type": "string"
          },
          "avatarUrl": {
            "type": "string"
          },
          "donationUrl": {
            "type": "string"
          },
          "visualEmbedding": {
            "type": "string"
          },
          "textEmbedding": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "claimStatus": {
            "type": "string",
            "enum": [
              "unverified",
              "claimed",
              "verified",
              "rejected"
            ]
          },
          "instagramHandle": {
            "type": "string"
          },
          "instagramUserId": {
            "type": "string"
          },
          "claimedByUserId": {
            "type": "string"
          },
          "claimedAt": {
            "type": "string",
            "format": "date-time"
          },
          "scrapedAt": {
            "type": "string",
            "format": "date-time"
          },
          "rejectionReason": {
            "type": "string"
          },
          "scrapeSource": {
            "type": "string"
          },
          "animationPolicy": {
            "type": "string",
            "enum": [
              "open",
              "closed"
            ]
          }
        },
        "description": "{\"indexInfo\":{\"slug\":{\"unique\":true}}}",
        "required": [
          "slug",
          "name"
        ],
        "additionalProperties": false
      },
      "ArtistPatchBody": {
        "title": "ArtistPatchBody",
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "role": {
            "type": "string"
          },
          "city": {
            "type": "string"
          },
          "bio": {
            "type": "string"
          },
          "coverUrl": {
            "type": "string"
          },
          "avatarUrl": {
            "type": "string"
          },
          "donationUrl": {
            "type": "string"
          },
          "animationPolicy": {
            "type": "string",
            "enum": [
              "open",
              "closed"
            ]
          }
        },
        "additionalProperties": false
      },
      "ArtistPayoutInfo": {
        "title": "ArtistPayoutInfo",
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "artistId": {
            "type": "string"
          },
          "method": {
            "type": "string",
            "enum": [
              "wave",
              "stripe"
            ]
          },
          "label": {
            "type": "string"
          },
          "isDefault": {
            "type": "boolean"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "pending",
              "disabled"
            ]
          },
          "phone": {
            "type": "string"
          },
          "accountHolderName": {
            "type": "string"
          },
          "country": {
            "type": "string"
          },
          "stripeAccountId": {
            "type": "string"
          },
          "stripeAccountStatus": {
            "type": "string"
          },
          "stripeOnboardingComplete": {
            "type": "boolean"
          },
          "verifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "artistId",
          "method",
          "isDefault",
          "status"
        ],
        "additionalProperties": false
      },
      "WavePayoutSettingsBody": {
        "title": "WavePayoutSettingsBody",
        "type": "object",
        "properties": {
          "method": {
            "type": "string",
            "enum": [
              "wave"
            ]
          },
          "phone": {
            "type": "string",
            "minLength": 5,
            "maxLength": 30
          },
          "accountHolderName": {
            "type": "string",
            "maxLength": 120
          },
          "country": {
            "type": "string",
            "maxLength": 2
          },
          "label": {
            "type": "string",
            "maxLength": 60
          },
          "isDefault": {
            "type": "boolean"
          }
        },
        "required": [
          "method",
          "phone"
        ],
        "additionalProperties": false
      },
      "ArtistPayout": {
        "title": "ArtistPayout",
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "artistId": {
            "type": "string"
          },
          "payoutInfoId": {
            "type": "string"
          },
          "provider": {
            "type": "string",
            "enum": [
              "wave",
              "stripe"
            ]
          },
          "amountCents": {
            "type": "number"
          },
          "currency": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "in_transit",
              "paid",
              "failed"
            ]
          },
          "providerRef": {
            "type": "string"
          },
          "source": {
            "type": "string",
            "enum": [
              "manual",
              "webhook"
            ]
          },
          "note": {
            "type": "string"
          },
          "recordedByUserId": {
            "type": "string"
          },
          "paidAt": {
            "type": "string",
            "format": "date-time"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "artistId",
          "provider",
          "amountCents",
          "currency",
          "status",
          "source"
        ],
        "additionalProperties": false
      },
      "ConnectOnboardingResponse": {
        "title": "ConnectOnboardingResponse",
        "type": "object",
        "properties": {
          "onboardingUrl": {
            "type": "string"
          },
          "accountId": {
            "type": "string"
          },
          "alreadyOnboarded": {
            "type": "boolean"
          }
        },
        "required": [
          "onboardingUrl"
        ],
        "additionalProperties": false
      },
      "AnimateResponse": {
        "title": "AnimateResponse",
        "type": "object",
        "properties": {
          "jobId": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "reused": {
            "type": "boolean"
          },
          "videoUrl": {
            "type": "string"
          }
        },
        "required": [
          "jobId",
          "status"
        ],
        "additionalProperties": false
      },
      "AnimateRequestBody": {
        "title": "AnimateRequestBody",
        "type": "object",
        "properties": {
          "artworkId": {
            "type": "string"
          },
          "modelSlug": {
            "type": "string"
          },
          "prompt": {
            "type": "string",
            "maxLength": 1000
          },
          "durationS": {
            "type": "number",
            "minimum": 5,
            "maximum": 15
          }
        },
        "required": [
          "artworkId"
        ],
        "additionalProperties": false
      },
      "AnimationJobResponse": {
        "title": "AnimationJobResponse",
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "artworkId": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "resultUrl": {
            "type": "string"
          },
          "errorMessage": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "status"
        ],
        "additionalProperties": false
      },
      "AdminPendingPayoutItem": {
        "title": "AdminPendingPayoutItem",
        "type": "object",
        "properties": {
          "artistId": {
            "type": "string"
          },
          "artistName": {
            "type": "string"
          },
          "phone": {
            "type": "string"
          },
          "accountHolderName": {
            "type": "string"
          },
          "country": {
            "type": "string"
          },
          "owedCents": {
            "type": "number"
          },
          "grossCents": {
            "type": "number"
          },
          "paidCents": {
            "type": "number"
          },
          "currency": {
            "type": "string"
          }
        },
        "required": [
          "artistId",
          "artistName",
          "owedCents",
          "grossCents",
          "paidCents",
          "currency"
        ],
        "additionalProperties": false
      },
      "AdminRecordPayoutBody": {
        "title": "AdminRecordPayoutBody",
        "type": "object",
        "properties": {
          "artistId": {
            "type": "string"
          },
          "amountCents": {
            "type": "number",
            "minimum": 1
          },
          "currency": {
            "type": "string"
          },
          "providerRef": {
            "type": "string",
            "minLength": 1
          },
          "note": {
            "type": "string"
          }
        },
        "required": [
          "artistId",
          "amountCents",
          "providerRef"
        ],
        "additionalProperties": false
      },
      "AdminFalCreditsResponse": {
        "title": "AdminFalCreditsResponse",
        "type": "object",
        "properties": {
          "configured": {
            "type": "boolean"
          },
          "username": {
            "type": "string"
          },
          "currentBalance": {
            "type": "number"
          },
          "currency": {
            "type": "string"
          }
        },
        "required": [
          "configured"
        ],
        "additionalProperties": false
      },
      "AdminArtistCreateBody": {
        "title": "AdminArtistCreateBody",
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "role": {
            "type": "string"
          },
          "city": {
            "type": "string"
          },
          "bio": {
            "type": "string"
          },
          "coverUrl": {
            "type": "string"
          },
          "avatarUrl": {
            "type": "string"
          }
        },
        "required": [
          "name"
        ],
        "additionalProperties": false
      },
      "AdminGrantCreditsResponse": {
        "title": "AdminGrantCreditsResponse",
        "type": "object",
        "properties": {
          "transactionId": {
            "type": "string"
          },
          "newBalance": {
            "type": "number"
          }
        },
        "required": [
          "transactionId",
          "newBalance"
        ],
        "additionalProperties": false
      },
      "AdminGrantCreditsBody": {
        "title": "AdminGrantCreditsBody",
        "type": "object",
        "properties": {
          "amount": {
            "type": "number",
            "minimum": 1,
            "maximum": 100000
          },
          "note": {
            "type": "string",
            "maxLength": 500
          }
        },
        "required": [
          "amount"
        ],
        "additionalProperties": false
      },
      "Artist.Filter": {
        "type": "object",
        "title": "Artist.Filter",
        "properties": {
          "offset": {
            "type": "integer",
            "minimum": 0
          },
          "limit": {
            "type": "integer",
            "minimum": 1,
            "example": 100
          },
          "skip": {
            "type": "integer",
            "minimum": 0
          },
          "order": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            ]
          },
          "where": {
            "title": "Artist.WhereFilter",
            "type": "object",
            "additionalProperties": true
          },
          "fields": {
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "boolean"
                  },
                  "slug": {
                    "type": "boolean"
                  },
                  "name": {
                    "type": "boolean"
                  },
                  "role": {
                    "type": "boolean"
                  },
                  "city": {
                    "type": "boolean"
                  },
                  "bio": {
                    "type": "boolean"
                  },
                  "coverUrl": {
                    "type": "boolean"
                  },
                  "avatarUrl": {
                    "type": "boolean"
                  },
                  "donationUrl": {
                    "type": "boolean"
                  },
                  "visualEmbedding": {
                    "type": "boolean"
                  },
                  "textEmbedding": {
                    "type": "boolean"
                  },
                  "createdAt": {
                    "type": "boolean"
                  },
                  "claimStatus": {
                    "type": "boolean"
                  },
                  "instagramHandle": {
                    "type": "boolean"
                  },
                  "instagramUserId": {
                    "type": "boolean"
                  },
                  "claimedByUserId": {
                    "type": "boolean"
                  },
                  "claimedAt": {
                    "type": "boolean"
                  },
                  "scrapedAt": {
                    "type": "boolean"
                  },
                  "rejectionReason": {
                    "type": "boolean"
                  },
                  "scrapeSource": {
                    "type": "boolean"
                  },
                  "animationPolicy": {
                    "type": "boolean"
                  }
                },
                "additionalProperties": false
              },
              {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "id",
                    "slug",
                    "name",
                    "role",
                    "city",
                    "bio",
                    "coverUrl",
                    "avatarUrl",
                    "donationUrl",
                    "visualEmbedding",
                    "textEmbedding",
                    "createdAt",
                    "claimStatus",
                    "instagramHandle",
                    "instagramUserId",
                    "claimedByUserId",
                    "claimedAt",
                    "scrapedAt",
                    "rejectionReason",
                    "scrapeSource",
                    "animationPolicy"
                  ],
                  "example": "id"
                },
                "uniqueItems": true
              }
            ],
            "title": "Artist.Fields"
          }
        },
        "additionalProperties": false,
        "x-typescript-type": "@loopback/repository#Filter<Artist>"
      },
      "Artwork.ScopeFilter": {
        "type": "object",
        "properties": {
          "offset": {
            "type": "integer",
            "minimum": 0
          },
          "limit": {
            "type": "integer",
            "minimum": 1,
            "example": 100
          },
          "skip": {
            "type": "integer",
            "minimum": 0
          },
          "order": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            ]
          },
          "where": {
            "type": "object",
            "additionalProperties": true
          },
          "fields": {
            "oneOf": [
              {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "uniqueItems": true
              }
            ]
          },
          "include": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {},
              "additionalProperties": true
            }
          }
        },
        "additionalProperties": false,
        "title": "Artwork.ScopeFilter"
      },
      "Artwork.IncludeFilter.Items": {
        "title": "Artwork.IncludeFilter.Items",
        "type": "object",
        "properties": {
          "relation": {
            "type": "string",
            "enum": [
              "imageMedia",
              "audioMedia",
              "videoMedia",
              "animations"
            ]
          },
          "scope": {
            "$ref": "#/components/schemas/Artwork.ScopeFilter"
          }
        }
      },
      "Artwork.Filter": {
        "type": "object",
        "title": "Artwork.Filter",
        "properties": {
          "offset": {
            "type": "integer",
            "minimum": 0
          },
          "limit": {
            "type": "integer",
            "minimum": 1,
            "example": 100
          },
          "skip": {
            "type": "integer",
            "minimum": 0
          },
          "order": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            ]
          },
          "where": {
            "title": "Artwork.WhereFilter",
            "type": "object",
            "additionalProperties": true
          },
          "fields": {
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "boolean"
                  },
                  "artistId": {
                    "type": "boolean"
                  },
                  "title": {
                    "type": "boolean"
                  },
                  "year": {
                    "type": "boolean"
                  },
                  "medium": {
                    "type": "boolean"
                  },
                  "dimensions": {
                    "type": "boolean"
                  },
                  "price": {
                    "type": "boolean"
                  },
                  "currency": {
                    "type": "boolean"
                  },
                  "displayOrder": {
                    "type": "boolean"
                  },
                  "provider": {
                    "type": "boolean"
                  },
                  "sourceUrl": {
                    "type": "boolean"
                  },
                  "spotifyTrackUrl": {
                    "type": "boolean"
                  },
                  "embedding": {
                    "type": "boolean"
                  },
                  "createdAt": {
                    "type": "boolean"
                  },
                  "dirty": {
                    "type": "boolean"
                  },
                  "isAnimated": {
                    "type": "boolean"
                  },
                  "parentArtworkId": {
                    "type": "boolean"
                  },
                  "kind": {
                    "type": "boolean"
                  },
                  "generatedByUserId": {
                    "type": "boolean"
                  },
                  "generationModelSlug": {
                    "type": "boolean"
                  },
                  "videoUrl": {
                    "type": "boolean"
                  },
                  "s3VideoKey": {
                    "type": "boolean"
                  },
                  "generationJobId": {
                    "type": "boolean"
                  },
                  "mediaId": {
                    "type": "boolean"
                  },
                  "audioMediaId": {
                    "type": "boolean"
                  },
                  "videoMediaId": {
                    "type": "boolean"
                  },
                  "description": {
                    "type": "boolean"
                  }
                },
                "additionalProperties": false
              },
              {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "id",
                    "artistId",
                    "title",
                    "year",
                    "medium",
                    "dimensions",
                    "price",
                    "currency",
                    "displayOrder",
                    "provider",
                    "sourceUrl",
                    "spotifyTrackUrl",
                    "embedding",
                    "createdAt",
                    "dirty",
                    "isAnimated",
                    "parentArtworkId",
                    "kind",
                    "generatedByUserId",
                    "generationModelSlug",
                    "videoUrl",
                    "s3VideoKey",
                    "generationJobId",
                    "mediaId",
                    "audioMediaId",
                    "videoMediaId",
                    "description"
                  ],
                  "example": "id"
                },
                "uniqueItems": true
              }
            ],
            "title": "Artwork.Fields"
          },
          "include": {
            "title": "Artwork.IncludeFilter",
            "type": "array",
            "items": {
              "anyOf": [
                {
                  "$ref": "#/components/schemas/Artwork.IncludeFilter.Items"
                },
                {
                  "type": "string"
                }
              ]
            }
          }
        },
        "additionalProperties": false,
        "x-typescript-type": "@loopback/repository#Filter<Artwork>"
      },
      "PingResponse": {
        "type": "object",
        "title": "PingResponse",
        "properties": {
          "greeting": {
            "type": "string"
          },
          "date": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "headers": {
            "type": "object",
            "properties": {
              "Content-Type": {
                "type": "string"
              }
            },
            "additionalProperties": true
          }
        }
      }
    }
  }
}