{
  "openapi": "3.1.0",
  "info": {
    "title": "Viral Outliers Agent API",
    "version": "1.0.0",
    "description": "Search viral outlier posts, pull profile stats, generate transcripts and crawl social profiles on demand. Prepaid credit billing with a hard stop at zero. Human docs: https://viraloutliers.com/docs"
  },
  "servers": [
    {
      "url": "https://viraloutliers.com"
    }
  ],
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key (so_live_…) from Settings → API Keys, as \"Authorization: Bearer so_live_…\" or the x-api-key header."
      }
    }
  },
  "paths": {
    "/api/v1/search/content": {
      "post": {
        "operationId": "search_outliers",
        "summary": "Search Viral Outlier Posts",
        "description": "Search a continuously-crawled database of social media posts ranked by outlier score: how strongly a post overperforms the account's own baseline. Filter by platform, keyword, content type, views, follower count, engagement rate and time window; sort by outlier score, views or recency. Returns post metadata, stats and thumbnails. Use this to find proven viral formats in any niche before creating content. Results may include deleted posts (deleted_at set) and posts from deactivated profiles (profile is_active=false), these are kept for their thumbnails and format ideas, with stats frozen at deletion; filter on deleted_at / is_active if you only want live content.\n\nCost: 1 credit(s) per call.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "402": {
            "description": "Insufficient credits"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "query": {
                    "type": "string",
                    "description": "Keyword search over captions/titles."
                  },
                  "platforms": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "\"tiktok\" | \"instagram\" | \"youtube\"."
                  },
                  "contentTypes": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Platform content types (e.g. reel, short, slideshow)."
                  },
                  "minOutlierScore": {
                    "type": "number",
                    "description": "Only posts overperforming their account baseline by at least this factor."
                  },
                  "minViews": {
                    "type": "number",
                    "description": "Minimum view count."
                  },
                  "maxFollowers": {
                    "type": "number",
                    "description": "Cap account size, find small accounts with huge posts."
                  },
                  "timeFrame": {
                    "type": "string",
                    "description": "\"one_week\" | \"one_month\" | … | \"all_time\"."
                  },
                  "sortBy": {
                    "type": "string",
                    "description": "Sort key, e.g. outlier score or views."
                  },
                  "page": {
                    "type": "number",
                    "description": "Page number, 1-based."
                  },
                  "pageSize": {
                    "type": "number",
                    "description": "Results per page, clamped to 1–100."
                  }
                },
                "required": []
              }
            }
          }
        }
      }
    },
    "/api/v1/search/profiles": {
      "post": {
        "operationId": "search_profiles",
        "summary": "Search Social Media Profiles",
        "description": "Search tracked social media profiles by handle or name, filtered by platform. Returns profile metadata, follower counts and average performance stats. Use it to resolve a handle to a profile id before fetching stats or posts, or to discover creators in the database. Results may include deactivated profiles (is_active=false), e.g. an account that was renamed or went private, retained with frozen stats; filter on is_active if you only want live accounts. Note a creator who changed handles can appear as two rows (old deactivated + new active).\n\nCost: 1 credit(s) per call.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "402": {
            "description": "Insufficient credits"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "query": {
                    "type": "string",
                    "description": "Handle or name fragment."
                  },
                  "platforms": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "\"tiktok\" | \"instagram\" | \"youtube\"."
                  },
                  "page": {
                    "type": "number",
                    "description": "Page number, 1-based."
                  },
                  "pageSize": {
                    "type": "number",
                    "description": "Results per page, clamped to 1–100."
                  }
                },
                "required": []
              }
            }
          }
        }
      }
    },
    "/api/v1/posts/{postId}": {
      "get": {
        "operationId": "get_post",
        "summary": "Get Post Details",
        "description": "Fetch a single post by id: views, likes, comments, engagement rate, outlier scores for seven time windows, thumbnail and the owning profile. When a transcript or visual analysis already exists it is included at no extra cost. Request new ones via request_transcript. Use after search_outliers to deep-dive a result.\n\nCost: 1 credit(s) per call.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "postId",
            "in": "path",
            "required": true,
            "description": "Internal post id from search results.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "includeTranscript",
            "in": "query",
            "required": false,
            "description": "Attach the cached transcript when one exists (default true).",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "includeVisualAnalysis",
            "in": "query",
            "required": false,
            "description": "Attach cached scene/visual analysis when it exists (default true).",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "402": {
            "description": "Insufficient credits"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v1/profiles/{profileId}": {
      "get": {
        "operationId": "get_profile",
        "summary": "Get Profile Stats",
        "description": "Fetch one tracked profile by id: follower count, bio, average views/likes/engagement across time windows, and recent tracked posts. The averages are the baseline outlier scores are computed against. Use search_profiles first to resolve a handle to an id.\n\nCost: 1 credit(s) per call.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "profileId",
            "in": "path",
            "required": true,
            "description": "Profile id from search_profiles or search results.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "402": {
            "description": "Insufficient credits"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v1/transcriptions": {
      "post": {
        "operationId": "request_transcript",
        "summary": "Transcribe a Post",
        "description": "Queues AI transcription for a post (spoken audio; slideshows use on-screen text extraction). Accepts a public post URL or an internal post id. Asynchronous: returns a job reference to poll with get_job_status; once complete the transcript is attached to get_post responses. Credits are charged on queueing and automatically refunded if the job fails.\n\nCost: 10 credit(s) per call. Asynchronous: poll GET /api/v1/jobs/{jobRef}.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "402": {
            "description": "Insufficient credits"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "Public post URL (e.g. a TikTok/Reel/Short link). The easy path when you have a link."
                  },
                  "postId": {
                    "type": "string",
                    "description": "Internal post id (from search results). Provide this or url."
                  }
                },
                "required": []
              }
            }
          }
        }
      }
    },
    "/api/v1/crawls": {
      "post": {
        "operationId": "crawl_profile",
        "summary": "Crawl a New Profile",
        "description": "Submits a public profile for crawling: profile metadata plus its recent posts, stats and thumbnails, after which it stays tracked and appears in searches. Asynchronous. Returns a job reference for get_job_status. If the profile is already tracked, this returns immediately without charging a full crawl. Credits are refunded automatically when a crawl fails.\n\nCost: 40 credit(s) per call. Asynchronous: poll GET /api/v1/jobs/{jobRef}.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "402": {
            "description": "Insufficient credits"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "platform": {
                    "type": "string",
                    "description": "\"tiktok\" | \"instagram\" | \"youtube\"."
                  },
                  "handle": {
                    "type": "string",
                    "description": "Public handle, without @."
                  }
                },
                "required": [
                  "platform",
                  "handle"
                ]
              }
            }
          }
        }
      }
    },
    "/api/v1/jobs/{jobRef}": {
      "get": {
        "operationId": "get_job_status",
        "summary": "Check Job Status",
        "description": "Returns the status of an asynchronous job started by crawl_profile or request_transcript: pending, processing, completed or failed. Free to call: polling must never cost credits. Poll every 10–30 seconds; jobs typically complete within a few minutes.\n\nCost: free.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "jobRef",
            "in": "path",
            "required": true,
            "description": "Job reference returned by an async skill.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "402": {
            "description": "Insufficient credits"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v1/credits": {
      "get": {
        "operationId": "get_credit_balance",
        "summary": "Check Credit Balance",
        "description": "Returns the current API credit balance for the authenticated account. Free to call. Agents should check the balance before starting large batch jobs and surface \"insufficient_credits\" errors to the user with a link to top up.\n\nCost: free.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "402": {
            "description": "Insufficient credits"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v1/profiles/compare": {
      "post": {
        "operationId": "compare_profiles",
        "summary": "Compare Profiles Head-to-Head",
        "description": "Compares 2–5 tracked profiles (by profile id or platform+handle) and returns each one's stats (follower count, average views/likes across time windows, engagement rate) plus a computed ranking flagging the top performer by followers and by engagement. Pure lookup, fast. Unresolved profiles come back in a notFound list rather than failing the call.\n\nCost: 2 credit(s) per call.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "402": {
            "description": "Insufficient credits"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "profileIds": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Profile ids to compare (from search)."
                  },
                  "handles": {
                    "type": "string",
                    "description": "Handle pairs to resolve, e.g. [{\"platform\":\"tiktok\",\"handle\":\"x\"}]. 2–5 profiles total across both fields."
                  }
                },
                "required": []
              }
            }
          }
        }
      }
    },
    "/api/v1/trends": {
      "post": {
        "operationId": "niche_trends",
        "summary": "What's Trending in a Niche",
        "description": "Returns the top overperforming posts in a niche over a recent window (default one week), plus a breakdown of which content types are driving the trend and which creators are represented. Filter by keyword and platform. Great as the first call in a content-research loop: see what's hot, then deep-dive or remix the winners.\n\nCost: 2 credit(s) per call.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "402": {
            "description": "Insufficient credits"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "query": {
                    "type": "string",
                    "description": "Niche keyword over captions/titles/handles."
                  },
                  "platforms": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "\"tiktok\" | \"instagram\" | \"youtube\"."
                  },
                  "timeFrame": {
                    "type": "string",
                    "description": "\"one_week\" (default) up to \"all_time\"."
                  },
                  "limit": {
                    "type": "number",
                    "description": "Top posts to return, clamped 1–50 (default 20)."
                  }
                },
                "required": []
              }
            }
          }
        }
      }
    },
    "/api/v1/posts/resolve": {
      "post": {
        "operationId": "resolve_post_url",
        "summary": "Resolve a Post URL",
        "description": "Takes a public post URL (TikTok video/photo, Instagram post/reel, YouTube video/short) and resolves it to the tracked post: the entry point when your input is a link. found:true returns the postId for get_post, request_transcript, download_post_media and remix_post. found:false tells you whether the whole profile is untracked (call crawl_profile) or just this post. TikTok/Instagram short links (vm.tiktok.com, /share/) must be expanded to the canonical URL first.\n\nCost: 1 credit(s) per call.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "402": {
            "description": "Insufficient credits"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "Public post URL (canonical form, not a short link)."
                  }
                },
                "required": [
                  "url"
                ]
              }
            }
          }
        }
      }
    },
    "/api/v1/posts/media": {
      "post": {
        "operationId": "download_post_media",
        "summary": "Download Post Media",
        "description": "Returns direct media URLs for a tracked post, the video file, or slideshow images with positions. Accepts a public post URL or an internal post id. When media is not stored yet it queues an on-demand fetch and returns a jobRef to poll (typically ready within ~90 seconds); call again once complete. Platform CDN URLs can expire, so download promptly. YouTube currently returns the thumbnail image. You are responsible for using downloaded media in line with the platforms' terms and applicable law.\n\nCost: 3 credit(s) per call. Asynchronous: poll GET /api/v1/jobs/{jobRef}.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "402": {
            "description": "Insufficient credits"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "Public post URL. The easy path when you have a link."
                  },
                  "postId": {
                    "type": "string",
                    "description": "Internal post id. Provide this or url."
                  }
                },
                "required": []
              }
            }
          }
        }
      }
    },
    "/api/v1/remixes": {
      "post": {
        "operationId": "remix_post",
        "summary": "Remix a Post to Your Niche",
        "description": "Takes a post (pass a public post URL or an internal post id) plus a target niche/brand description, and produces an adapted content idea: rewritten title and description, segment-by-segment script, and an execution checklist, the proven format transplanted into your niche. Asynchronous (~1–3 minutes): returns a jobRef; poll get_remix_result until its \"remix\" field is populated (it returns status + result together). For video posts the remix now auto-generates the transcript and visual analysis first, so quality no longer depends on you transcribing beforehand (it just takes a little longer). Credits are refunded automatically if the remix fails.\n\nCost: 20 credit(s) per call. Asynchronous: poll GET /api/v1/jobs/{jobRef}.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "402": {
            "description": "Insufficient credits"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "Public post URL. The easy path when a user hands you a link they saw."
                  },
                  "postId": {
                    "type": "string",
                    "description": "Internal post id (from search results). Provide this or url."
                  },
                  "targetNiche": {
                    "type": "string",
                    "description": "Your niche/brand/audience, 5–500 chars (e.g. \"B2B SaaS founders selling analytics tools\")."
                  },
                  "tone": {
                    "type": "string",
                    "description": "Preferred tone of voice for the adaptation."
                  }
                },
                "required": [
                  "targetNiche"
                ]
              }
            }
          }
        }
      }
    },
    "/api/v1/remixes/{jobRef}": {
      "get": {
        "operationId": "get_remix_result",
        "summary": "Fetch a Finished Remix",
        "description": "Returns the finished remix for a remix_post job: adapted title, description, script segments and checklist. Free to call. Poll get_job_status until the job reports completed, then fetch here. The result is also viewable in the web app under Content Ideas.\n\nCost: free.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "jobRef",
            "in": "path",
            "required": true,
            "description": "The pipeline jobRef returned by remix_post (URL-encode it).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "402": {
            "description": "Insufficient credits"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v1/credits/topup": {
      "post": {
        "operationId": "create_topup_link",
        "summary": "Create a Credit Top-Up Link",
        "description": "Creates a Stripe Checkout link for a credit pack, so when the balance runs out mid-task you can hand the account owner a one-click payment link instead of instructions. Credits land within seconds of payment. Free to call (5 links/hour); links are valid for 24 hours. Packs: see the pricing table in the docs.\n\nCost: free.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "402": {
            "description": "Insufficient credits"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "packId": {
                    "type": "string",
                    "description": "One of: pack_s, pack_m, pack_l."
                  }
                },
                "required": [
                  "packId"
                ]
              }
            }
          }
        }
      }
    },
    "/api/v1/feedback": {
      "post": {
        "operationId": "report_issue",
        "summary": "Report an Issue",
        "description": "Report a problem with any skill: an error you keep hitting, data that looks wrong or stale, or something you needed that the API could not do. Free: never spend credits on telling us something is broken. Include what you called, what you expected and what happened. Set wantsUpdate to true to get an email on your account address when the issue is resolved. Reports go straight to the team.\n\nCost: free.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "402": {
            "description": "Insufficient credits"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "message": {
                    "type": "string",
                    "description": "What you called, what you expected, what happened (10–2000 chars)."
                  },
                  "skill": {
                    "type": "string",
                    "description": "Which skill the issue is about, when known."
                  },
                  "wantsUpdate": {
                    "type": "boolean",
                    "description": "true = email the account address when resolved."
                  }
                },
                "required": [
                  "message"
                ]
              }
            }
          }
        }
      }
    },
    "/api/v1/trending": {
      "get": {
        "operationId": "get_trending_outliers",
        "summary": "Trending Viral Outliers (Free)",
        "description": "Returns the current top trending outlier posts across TikTok, Instagram and YouTube, deduplicated to one per creator. Free and unauthenticated (rate-limited per IP; cached ~2 hours). A taste of the database. For filtered search, transcripts and on-demand crawling, create an API key.\n\nCost: free.",
        "security": [],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "402": {
            "description": "Insufficient credits"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v1/tracking": {
      "post": {
        "operationId": "track_profile",
        "summary": "Monitor a Profile",
        "description": "Starts monitoring a profile so it is automatically re-crawled at a cadence you choose (daily, every_3_days or weekly), keeping its posts and stats fresh without you polling crawl_profile. Identify the profile by profileId, platform+handle, or a public profile/post URL. Managing monitoring is free; each scheduled refresh crawl costs credits (10 per refresh) and monitoring pauses itself if your balance runs out, then resumes when you top up. The profile must already be in the database; crawl_profile it first if it is not. Calling again on an already-monitored profile just updates the cadence. Pull the new posts with get_tracked_updates.\n\nCost: free.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "402": {
            "description": "Insufficient credits"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "profileId": {
                    "type": "string",
                    "description": "Internal profile id from search results."
                  },
                  "platform": {
                    "type": "string",
                    "description": "\"tiktok\" | \"instagram\" | \"youtube\" (pair with handle)."
                  },
                  "handle": {
                    "type": "string",
                    "description": "Public handle, without @ (pair with platform)."
                  },
                  "url": {
                    "type": "string",
                    "description": "Public profile or post URL identifying the profile."
                  },
                  "frequency": {
                    "type": "string",
                    "description": "\"daily\" | \"every_3_days\" | \"weekly\" (default weekly)."
                  }
                },
                "required": []
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "untrack_profile",
        "summary": "Stop Monitoring a Profile",
        "description": "Stops monitoring a profile: no further scheduled refresh crawls are charged for it. Free to call. Pass the internal profileId (from list_tracked_profiles or search results). The profile and its already-crawled posts stay in the database and searchable; only the recurring refresh stops. Returns not_found if the profile is not currently being monitored.\n\nCost: free.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "profileId",
            "in": "query",
            "required": true,
            "description": "Internal profile id to stop monitoring (query ?profileId= or JSON body).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "402": {
            "description": "Insufficient credits"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      },
      "get": {
        "operationId": "list_tracked_profiles",
        "summary": "List Monitored Profiles",
        "description": "Returns every profile you are currently monitoring, with its handle, platform, follower count, refresh cadence, next scheduled crawl time, when it was last checked for updates, and any paused reason (e.g. paused for insufficient credits). Free to call. Use it to audit what is being refreshed and what it is costing, or to grab a profileId for untrack_profile.\n\nCost: free.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "402": {
            "description": "Insufficient credits"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/api/v1/tracking/updates": {
      "get": {
        "operationId": "get_tracked_updates",
        "summary": "Get New Posts From Monitored Profiles",
        "description": "Returns the posts newly discovered (first stored by our crawler) since your last check, across all the profiles you are monitoring. Free to call. Each call advances a per-profile cursor, so a subsequent call only returns posts crawled after it (a feed, not a re-scan). New posts arrive when a profile's scheduled refresh crawl runs, on the cadence set by track_profile. Results are the same flattened post shape as search_outliers (stats, thumbnail, handle). Total posts are capped (limit 1–100, default 50).\n\nCost: free.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Max posts to return, clamped 1–100 (default 50).",
            "schema": {
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "402": {
            "description": "Insufficient credits"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    }
  }
}