# List user's AI Studios for GTM GET /api/v1/gtm/studios/ Returns AI Studios (Publications) owned by the authenticated user within the current workspace, with GTM metadata. Shows which studios are eligible for GTM features and their current quota usage. Results are filtered by the active workspace. Reference: https://docs.aisquare.studio/api-reference/ai-square-studio-api/gtm-studio/gtm-studios-list ## OpenAPI Specification ```yaml openapi: 3.1.0 info: title: AISquare Studio API version: 1.0.0 paths: /api/v1/gtm/studios/: get: operationId: gtm-studios-list summary: List user's AI Studios for GTM description: >- Returns AI Studios (Publications) owned by the authenticated user within the current workspace, with GTM metadata. Shows which studios are eligible for GTM features and their current quota usage. Results are filtered by the active workspace. tags: - subpackage_gtmStudio parameters: - name: page in: query description: A page number within the paginated result set. required: false schema: type: integer - name: page_size in: query description: Number of results to return per page. required: false schema: type: integer responses: '200': description: List of user's AI Studios with GTM metadata content: application/json: schema: $ref: '#/components/schemas/PaginatedStudioListList' '401': description: Authentication required content: application/json: schema: description: Any type components: schemas: UserSimple: type: object properties: id: type: integer username: type: string description: >- Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only. email: type: string format: email full_name: type: string first_time_login: type: boolean description: Check if this is the user's first login. theme: type: - string - 'null' is_superuser: type: boolean description: >- Designates that this user has all permissions without explicitly assigning them. is_staff: type: boolean description: Designates whether the user can log into this admin site. is_active: type: boolean description: >- Designates whether this user should be treated as active. Unselect this instead of deleting accounts. is_verified: type: boolean profile_picture: type: string format: uri description: |- Convert ImageFieldFile to URL string for JSON serialization. Args: obj: The model instance being serialized (typically IAMUser) Returns: str | None: The URL of the profile picture, or None if not available required: - id - username - email - first_time_login - profile_picture description: >- Mixin to handle profile_picture serialization for WebSocket compatibility. This mixin adds a SerializerMethodField for profile_picture that converts ImageFieldFile objects to URL strings, making them JSON serializable for WebSocket consumers. The mixin intelligently handles profile pictures from IAMUserDetail by: 1. Accessing the related `details` queryset on the IAMUser model 2. Extracting the ImageFieldFile from the first detail record 3. Converting it to a URL string for JSON serialization Usage: ```python class MyUserSerializer(ProfilePictureMixin, serializers.ModelSerializer): class Meta: model = User fields = ['id', 'username', 'profile_picture', ...] ``` Note: - This mixin expects the model to have a `details` related manager - The related detail should have a `profile_picture` ImageField - Returns None if no profile picture is found or an error occurs title: UserSimple GlobalVisibilityEnum: type: string enum: - public - private - team - org description: |- * `public` - Public * `private` - Private * `team` - Team * `org` - Organization title: GlobalVisibilityEnum StudioList: type: object properties: id: type: string format: uuid name: type: string custom_url: type: string description: type: string logo: type: - string - 'null' format: uri cover_image: type: - string - 'null' format: uri owner: $ref: '#/components/schemas/UserSimple' visibility: $ref: '#/components/schemas/GlobalVisibilityEnum' allow_bookings: type: boolean created_at: type: string format: date-time updated_at: type: string format: date-time gtm_meta: type: - object - 'null' additionalProperties: description: Any type description: |- Get real quota data from OutreachCampaign tracking. Auto-creates StudioMeta if it doesn't exist (lazy initialization). experiences_by_type: type: object additionalProperties: type: integer description: |- Get count of published experiences by type for this publication. Uses centralized ExperienceCountingService for consistency. Only counts experiences with is_draft=False and primary_deployed_resource_id set. Output Sample: { "AI_EXPERT": 5, "AI_NOTE": 10, "QUEST": 3, "PODCAST": 2 } followers_count: type: integer description: |- Get the follower count for the studio's owner. Returns the total number of users following the publication owner. subscribers_count: type: integer description: Get the total number of subscribers for this publication. required: - id - name - custom_url - owner - created_at - updated_at - gtm_meta - experiences_by_type - followers_count - subscribers_count description: Serializer for listing user's AI Studios with GTM metadata title: StudioList PaginatedStudioListList: type: object properties: count: type: integer next: type: - string - 'null' format: uri previous: type: - string - 'null' format: uri results: type: array items: $ref: '#/components/schemas/StudioList' required: - count - results title: PaginatedStudioListList ``` ## SDK Code Examples ```python import requests url = "https://api.example.com/api/v1/gtm/studios/" payload = {} headers = {"Content-Type": "application/json"} response = requests.get(url, json=payload, headers=headers) print(response.json()) ``` ```javascript const url = 'https://api.example.com/api/v1/gtm/studios/'; const options = {method: 'GET', headers: {'Content-Type': 'application/json'}, body: '{}'}; try { const response = await fetch(url, options); const data = await response.json(); console.log(data); } catch (error) { console.error(error); } ``` ```go package main import ( "fmt" "strings" "net/http" "io" ) func main() { url := "https://api.example.com/api/v1/gtm/studios/" payload := strings.NewReader("{}") req, _ := http.NewRequest("GET", url, payload) req.Header.Add("Content-Type", "application/json") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := io.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) } ``` ```ruby require 'uri' require 'net/http' url = URI("https://api.example.com/api/v1/gtm/studios/") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true request = Net::HTTP::Get.new(url) request["Content-Type"] = 'application/json' request.body = "{}" response = http.request(request) puts response.read_body ``` ```java import com.mashape.unirest.http.HttpResponse; import com.mashape.unirest.http.Unirest; HttpResponse response = Unirest.get("https://api.example.com/api/v1/gtm/studios/") .header("Content-Type", "application/json") .body("{}") .asString(); ``` ```php request('GET', 'https://api.example.com/api/v1/gtm/studios/', [ 'body' => '{}', 'headers' => [ 'Content-Type' => 'application/json', ], ]); echo $response->getBody(); ``` ```csharp using RestSharp; var client = new RestClient("https://api.example.com/api/v1/gtm/studios/"); var request = new RestRequest(Method.GET); request.AddHeader("Content-Type", "application/json"); request.AddParameter("application/json", "{}", ParameterType.RequestBody); IRestResponse response = client.Execute(request); ``` ```swift import Foundation let headers = ["Content-Type": "application/json"] let parameters = [] as [String : Any] let postData = JSONSerialization.data(withJSONObject: parameters, options: []) let request = NSMutableURLRequest(url: NSURL(string: "https://api.example.com/api/v1/gtm/studios/")! as URL, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0) request.httpMethod = "GET" request.allHTTPHeaderFields = headers request.httpBody = postData as Data let session = URLSession.shared let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in if (error != nil) { print(error as Any) } else { let httpResponse = response as? HTTPURLResponse print(httpResponse) } }) dataTask.resume() ```