> ## Documentation Index
> Fetch the complete documentation index at: https://aisa.one/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# PGY note blogger square

> PGY note blogger square

PGY note blogger square

**Pricing** — base \$0.029 per successful call (provider cost × 1.45; final charge scales by your plan multiplier). Charged only when the upstream response body `code` is `200`.

<Note>
  Response structure is not yet fully documented — **refer to the actual API response**.
</Note>

## Example

```bash theme={null}
curl -X POST "https://api.aisa.one/apis/v1/tikhub/xiaohongshu/pgy/get_blogger_list" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'  # see request schema below
```


## OpenAPI

````yaml openapi/tikhub-en.json POST /tikhub/xiaohongshu/pgy/get_blogger_list
openapi: 3.0.0
info:
  title: TikHub API
  description: >-
    Multi-platform social media data via TikHub — Douyin, TikTok, Bilibili,
    Kuaishou, Weibo, Xiaohongshu, Zhihu, and commercial
    (Xingtu/Huahuo/Billboard) endpoints.
  version: 1.0.0
servers:
  - url: https://api.aisa.one/apis/v1
security:
  - bearerAuth: []
paths:
  /tikhub/xiaohongshu/pgy/get_blogger_list:
    post:
      tags:
        - TikHub - Xiaohongshu
      summary: PGY note blogger square
      description: PGY note blogger square
      operationId: post_tikhub_xiaohongshu_pgy_get_blogger_list
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BloggerListReq'
        required: true
      responses:
        '200':
          description: >-
            Successful response. Response structure varies; refer to the actual
            API response.
components:
  schemas:
    BloggerListReq:
      properties:
        page_num:
          type: integer
          maximum: 250
          minimum: 1
          title: Page Num
          description: Page, 1-250
          default: 1
          example: 1
        page_size:
          type: integer
          maximum: 20
          minimum: 1
          title: Page Size
          description: 'Page size, 1-20 (web fixed at 20; recommended: keep at 20)'
          default: 20
          example: 20
        keyword:
          type: string
          maxLength: 50
          title: Keyword
          description: Keyword; empty=filter only, no search
          default: ''
          example: Coffee
        search_type:
          type: integer
          enum:
            - 0
            - 1
          title: Search Type
          description: 1=search bloggers by note keyword (default), 0=search by nickname
          default: 1
          example: 1
        column:
          type: string
          enum:
            - comprehensiverank
            - fansCount
            - price
            - clickNum
            - mEngagementNum
            - accumCommonImpMedinNum30d
            - accumPicCommonImpMedinNum30d
            - accumVideoCommonImpMedinNum30d
            - pictureClickMidNum
            - videoClickMidNum
            - pictureInterMidNum
            - videoInterMidNum
            - thousandLikePercent30
            - pictureThousandLikePercent30
            - videoThousandLikePercent30
            - hundredLikePercent30
            - pictureHundredLikePercent30
            - videoHundredLikePercent30
            - videoFinishRate
            - accumCoopImpMedinNum30d
            - readMidCoop30
            - interMidCoop30
            - mCpuvNum30d
            - picturePrice
            - videoPrice
            - pictureReadCost
            - videoReadCost
            - inviteReply48hNumRatio
            - fans30GrowthRate
            - fansActiveIn28dLv
            - fansEngageNum30dLv
            - kliveCnt30d
            - avgLiveViewerNum
            - avgAgmv90d
          title: Column
          description: Sort column, 34 options, see endpoint docs
          default: comprehensiverank
          example: comprehensiverank
        sort:
          type: string
          enum:
            - desc
            - asc
          title: Sort
          description: 'Sort direction: desc/asc'
          default: desc
          example: desc
        brand_user_id:
          title: Brand User Id
          description: Brand/advertiser user ID, optional
          example: 5dcfa5370000000001006030
          nullable: true
          type: string
        similar_user_id:
          title: Similar User Id
          description: >-
            Find similar bloggers; unlike /get_blogger_similar it can be
            combined with all filters below
          example: 5c668b3e0000000012021605
          nullable: true
          type: string
        similar_word:
          title: Similar Word
          description: Nickname echo for similar_user_id; does not affect results
          nullable: true
          type: string
          maxLength: 64
        goal:
          $ref: '#/components/schemas/GoalFilter'
          description: Cooperation goal filters
          nullable: true
        blogger:
          $ref: '#/components/schemas/BloggerAttrFilter'
          description: Blogger attribute filters
          nullable: true
        fans:
          $ref: '#/components/schemas/FansFilter'
          description: Fans profile filters
          nullable: true
        note:
          $ref: '#/components/schemas/NoteFilter'
          description: Organic note metric filters
          nullable: true
        coop:
          $ref: '#/components/schemas/CoopFilter'
          description: Sponsored note metric filters
          nullable: true
        live:
          $ref: >-
            #/components/schemas/crawlers__xiaohongshu__pgy__pgy_filters__LiveFilter
          description: Live metric filters
          nullable: true
        flags:
          $ref: >-
            #/components/schemas/crawlers__xiaohongshu__pgy__pgy_filters__FlagFilter
          description: Boolean flag filters
          nullable: true
      additionalProperties: false
      type: object
      title: BloggerListReq
    GoalFilter:
      properties:
        market_target:
          title: Market Target
          description: >-
            Marketing objective: on the web UI this is a three-level selector
            (objective -> metric -> measurement method); pass the final leaf
            code: `estimateAllCpm` Awareness/Impression Performance/Cost,
            `mAccumImpNum` Awareness/Impression Performance/Scale, `readCost`
            Awareness/Read Performance/Cost, `mValidRawReadFeedNum`
            Awareness/Read Performance/Scale, `estimateEngageCost`
            Consideration/Engagement Performance/Cost, `mEngagementNum90d`
            Consideration/Engagement Performance/Scale, `estimateCpuv`
            Conversion/Overflow Store-Visit Performance/Cost, `mCpuvNum`
            Conversion/Overflow Store-Visit Performance/Scale
          example: mAccumImpNum
          nullable: true
          type: string
          enum:
            - estimateAllCpm
            - mAccumImpNum
            - readCost
            - mValidRawReadFeedNum
            - estimateEngageCost
            - mEngagementNum90d
            - estimateCpuv
            - mCpuvNum
      additionalProperties: false
      type: object
      title: GoalFilter
      description: >-
        Cooperation goal: match bloggers by marketing objective (Exposure /
        Seeding / Conversion).


        To filter bloggers by audience segment, use
        `BloggerAttrFilter.audience20` (top-20 audiences).
    BloggerAttrFilter:
      properties:
        content_tag:
          title: Content Tag
          description: >-
            Creator category: use the category name. There are 28 level-1
            categories: Beauty / Skincare / Personal Care / Parenting / Fashion
            / Food / Home Decor / Film & TV & Entertainment News / Sports &
            Fitness / Pets / Culture & Art / Hobbies / Daily Life / Education /
            Workplace / Relationships / Photography / Gaming / Tech & Digital /
            Travel / Music / Comedy / Health & Wellness / Automotive / Wedding /
            Business & Finance / Stock Footage / Other. Level-2 names may also
            be used; **both levels can be mixed in the same array**, and
            multiple values are OR-ed. To select an entire category, use its
            level-1 name — **do not expand it to all level-2 names** (some
            creators are tagged at level-1 only; expanding will miss them). **If
            all categories are acceptable, omit this field entirely** — there is
            no category named "All", and passing one will silently return 0
            results. Incorrect names also return 0 results without an error;
            always copy names verbatim from the contentTags dictionary. Note:
            this is a separate classification from "industry" (coop.industry).
          example:
            - Beauty
            - Facial Care
            - Facial Cleanser
          nullable: true
          items:
            type: string
            maxLength: 64
          type: array
          maxItems: 30
        personal_tags:
          title: Personal Tags
          description: >-
            Creator persona: use the `tagName` (bare name) from personalTagsV2
            in `/get_blogger_filter_options`. This is a three-level tree (family
            identity / professional identity / background -> group -> leaf).
            **Any level can be filled in, and levels can be mixed**; multiple
            values are OR-ed. To select an entire group, use the group name — no
            need to enumerate every leaf (e.g. level-1 `Professional
            Identity`=91 results, level-2 `Internet`=8, leaf `Mom`=31).
          example:
            - Mother
          nullable: true
          items:
            type: string
            maxLength: 64
          type: array
          maxItems: 30
        feature_tags:
          title: Feature Tags
          description: >-
            Specialty content: use the bare name from featureTags in
            `/get_blogger_filter_options`. **Level-1 (format / style / lifestyle
            / skin type & tone / skincare) and level-2 (e.g. vlog / Korean
            style) can both be used and mixed**; multiple values are OR-ed.
            Selecting a level-1 name includes the entire group (e.g. level-1
            `Format`=183 results, level-2 `vlog`=136).
          example:
            - vlog
          nullable: true
          items:
            type: string
            maxLength: 64
          type: array
          maxItems: 30
        content_theme:
          title: Content Theme
          description: >-
            Content theme: use the **level-1 label** from contentTheme in
            `/blogger/filter-options` (e.g. Automotive / General). Note: only
            level-1 is supported; using a sub-item label or ID returns no
            results.
          example:
            - Automotive Features
          nullable: true
          items:
            type: string
            maxLength: 64
          type: array
          maxItems: 30
        audience20:
          title: Audience20
          description: >-
            "Top-20 Audience Segments": **do not use bare flat names**. For
            level-1, provide just the name (e.g. `Outdoor Leisure`, = the entire
            segment); **for level-2, write `"level1 level1-level2"`** (e.g.
            `"Outdoor Leisure Outdoor Leisure-Extreme Challengers"`) — the
            level-1 name must appear twice. **Using the level-2 label directly
            from the dictionary (e.g. `Extreme Challengers`) silently returns 0
            results**. Level-1 and composite level-2 values can be mixed in the
            same array; multiple values are OR-ed. Full list available from
            `/get_blogger_filter_options` under audience20 (19 level-1 / 121
            level-2 segments).
          example:
            - Free Travel
            - Outdoor Freedom - Extreme Challengers
          nullable: true
          items:
            type: string
            maxLength: 64
          type: array
          maxItems: 30
        industry_crowd:
          title: Industry Crowd
          description: >-
            Industry-specific audience profile: use the **deepest leaf value**
            from automotiveIndustryTag in `/blogger/filter-options` (numeric
            string ID, e.g. 15795914; 1,600+ available). Using a label or
            intermediate-level ID returns no results.
          example:
            - '15795914'
          nullable: true
          items:
            type: string
            maxLength: 64
          type: array
          maxItems: 30
        consumer_behavior:
          title: Consumer Behavior
          description: >-
            Estimated consumer behavior: **must use the full space-separated
            path including the root node** (e.g. `"Content Behavior Estimate
            Automotive"`); the path can stop at any depth. See
            **consumerBehavior** in `/get_blogger_filter_options` (5-level
            tree). WARNING: Using a bare leaf name causes no error and returns
            no 0 results — instead the filter is silently ignored and the full
            unfiltered result set is returned. Only the full path form actually
            filters (e.g. `["Content Behavior Estimate Automotive"]` returns 54
            results). When using this filter, compare totals with and without it
            to confirm the filter is taking effect. Note: this field is rolled
            out per account; if the dictionary returns null, the current account
            does not have access.
          example:
            - 'Content behavior estimate: Automotive'
          nullable: true
          items:
            type: string
            maxLength: 64
          type: array
          maxItems: 30
        note_scene:
          title: Note Scene
          description: >-
            Note category: use the **full space-separated path** (Category
            Level1 Level2 Level3), e.g. "Automotive Rational-Decision
            Car-Selection-Guide Policy". The path can stop at any depth (deeper
            = narrower). **Using only the last segment (e.g.
            "Car-Selection-Guide") returns 0 results.** See **contentScenes** in
            `/get_blogger_filter_options` (e.g. `["Automotive"]`=75,
            `["Automotive Rational-Decision"]`=23, 4-level path=1,
            `["Car-Selection-Guide"]`=0).
          example:
            - 'Automotive: Rational Decision-Making, Car Selection Guide, Policy'
          nullable: true
          items:
            type: string
            maxLength: 64
          type: array
          maxItems: 30
        gender:
          title: Gender
          description: 'Gender: Male / Female'
          example: Female
          nullable: true
          type: string
          enum:
            - Male
            - Female
        location:
          title: Location
          description: >-
            Creator location: plain place names work at any level
            (province/city/district), and multiple values are OR-ed (e.g.
            ["Shanghai"], ["Hangzhou"], ["Shangcheng District"]). Full path
            format (e.g. "China Zhejiang Hangzhou") is also accepted and will be
            converted automatically. See **areas** in
            /get_blogger_filter_options for available place names (down to
            district level).
          example:
            - Shanghai
          nullable: true
          items:
            type: string
            maxLength: 64
          type: array
          maxItems: 30
        signed:
          title: Signed
          description: >-
            Contract status: -1=no filter, 0=individual creator, 1=agency-signed
            creator
          example: 0
          nullable: true
          type: integer
          enum:
            - -1
            - 0
            - 1
      additionalProperties: false
      type: object
      title: BloggerAttrFilter
      description: >-
        Blogger attributes: category, persona, content specialty, audience
        profile, gender, region, contract status, etc.


        For hierarchical options (category / persona / content specialty /
        content theme / top-20 audiences / industry profile / estimated consumer
        behavior), first call `/api/v2/pgy/blogger/filter-options` to get the
        values — each field description specifies which level to use.
    FansFilter:
      properties:
        count:
          $ref: '#/components/schemas/RangeFilter'
          description: Follower count range
          nullable: true
        age:
          title: Age
          description: >-
            Audience age distribution: 0=no filter, 1=under 18, 2=18-24,
            3=25-34, 4=35-44, 5=over 44 (high proportion)
          example: 3
          nullable: true
          type: integer
          enum:
            - 0
            - 1
            - 2
            - 3
            - 4
            - 5
        gender:
          title: Gender
          description: >-
            Audience gender: 0=no filter, 1=predominantly male, 2=predominantly
            female
          example: 2
          nullable: true
          type: integer
          enum:
            - 0
            - 1
            - 2
        marital_status:
          title: Marital Status
          description: 'Relationship status: -1=no filter, 0=single/unmarried, 1=married'
          nullable: true
          type: integer
          enum:
            - -1
            - 0
            - 1
        consumption_level:
          title: Consumption Level
          description: 'Consumption level: -1=no filter, 0=low, 1=medium, 2=high'
          nullable: true
          type: integer
          enum:
            - -1
            - 0
            - 1
            - 2
        child_age:
          title: Child Age
          description: >-
            Parenting stage: 0=trying to conceive, 2=0-6 months, 3=7-12 months,
            4=1-3 years, 5=4-6 years, 6=7-12 years, 7=early pregnancy, 8=late
            pregnancy
          nullable: true
          items:
            type: integer
            enum:
              - 0
              - 2
              - 3
              - 4
              - 5
              - 6
              - 7
              - 8
          type: array
          maxItems: 30
        device_price:
          title: Device Price
          description: Phone price tier, e.g. 3000-3999 / 8000+
          example:
            - 3000-3999
          nullable: true
          items:
            type: string
            enum:
              - 0-999
              - 1000-1999
              - 2000-2999
              - 3000-3999
              - 4000-4999
              - 5000-5999
              - 6000-6999
              - 7000-7999
              - 8000+
          type: array
          maxItems: 30
        device_brand:
          title: Device Brand
          description: Phone brand
          example:
            - Apple
          nullable: true
          items:
            type: string
            enum:
              - Apple
              - Huawei
              - OPPO
              - VIVO
              - Honor
              - Xiaomi
              - OnePlus
              - Meizu
              - ZTE
              - Autocomplete
          type: array
          maxItems: 30
        location:
          title: Location
          description: >-
            Audience location: plain place names work (e.g. ["Shanghai"],
            ["Hangzhou"]) and the full path will be filled in automatically.
            Full path format (e.g. "China Zhejiang Hangzhou") is also accepted.
            Note: this tree only goes down to city level (no district). See
            **fansAreas** in /get_blogger_filter_options for available values.
          example:
            - Shanghai
          nullable: true
          items:
            type: string
            maxLength: 64
          type: array
          maxItems: 30
      additionalProperties: false
      type: object
      title: FansFilter
      description: >-
        Audience profile — the "Audience Profile" section of the web page
        (follower count / age / gender / region / relationship status / spending
        / parenting & baby / mobile device).
    NoteFilter:
      properties:
        imp_median:
          $ref: '#/components/schemas/RangeFilter'
          description: Median impressions
          nullable: true
        read_median:
          $ref: '#/components/schemas/RangeFilter'
          description: Median reads
          nullable: true
        inter_median:
          $ref: '#/components/schemas/RangeFilter'
          description: Median engagement count
          nullable: true
        thousand_like_percent:
          $ref: '#/components/schemas/PercentRange'
          description: >-
            1,000-like note ratio: fill 0-100 percent points (20 means 20%, not
            0.2)
          nullable: true
        note_type:
          title: Note Type
          description: >-
            Note type: 0=no filter, 1=primarily image+text notes, 2=primarily
            video notes
          example: 2
          nullable: true
          type: integer
          enum:
            - 0
            - 1
            - 2
      additionalProperties: false
      type: object
      title: NoteFilter
      description: >-
        Organic note data — the 'Daily Notes' section on the web page (organic
        traffic performance over the last 30 days).
    CoopFilter:
      properties:
        pic_price:
          $ref: '#/components/schemas/RangeFilter'
          description: Cooperation quote — fixed price for image+text notes (RMB)
          nullable: true
        video_price:
          $ref: '#/components/schemas/RangeFilter'
          description: Cooperation quote — fixed price for video notes (RMB)
          nullable: true
        order_count:
          $ref: '#/components/schemas/RangeFilter'
          description: >-
            Open orders (accepted but not yet completed), NOT lifetime
            collaboration count. This reflects current in-progress orders; do
            not use this field to find experienced creators.
          nullable: true
        reply_48h_ratio:
          $ref: '#/components/schemas/PercentRange'
          description: >-
            Cooperation credit — 48h invitation reply rate: fill 0-100 percent
            points (80 means 80%)
          nullable: true
        industry:
          title: Industry
          description: Recent collaboration industries
          example: Beauty & Personal Care
          nullable: true
          type: string
          enum:
            - No filter
            - Beauty & Personal Care
            - Food & Beverages
            - Parenting & Baby
            - Consumer Electronics & Appliances
            - Daily necessities
            - Clothing and accessories
            - Internet
            - Lifestyle Services
            - Home & Building Materials
            - Automotive
        brand_ids:
          title: Brand Ids
          description: 'Recent collaboration brands: list of brand userIds'
          nullable: true
          items:
            type: string
            maxLength: 64
          type: array
          maxItems: 20
        exclude_brands:
          title: Exclude Brands
          description: >-
            Used with brand_ids: true=exclude bloggers who have cooperated with
            these brands
          nullable: true
          type: boolean
        imp_median:
          $ref: '#/components/schemas/RangeFilter'
          description: Reach scale — median impressions (collaboration notes)
          nullable: true
        read_median:
          $ref: '#/components/schemas/RangeFilter'
          description: Reach scale — median reads (collaboration notes)
          nullable: true
        inter_median:
          $ref: '#/components/schemas/RangeFilter'
          description: Reach scale — median engagement count (collaboration notes)
          nullable: true
        cpuv:
          $ref: '#/components/schemas/RangeFilter'
          description: >-
            Reach scale — median store-visit UV count (not cost): median
            store-visit UV count for cross-domain collaboration notes in the
            last 30 days. **This is a visit count, not a monetary amount** (web
            tiers: 500-1000 / 1000-2000 / 2000-5000 / 5000-10000 / 10000+). To
            filter by cost per store visit, use estimate_cpuv instead.
          nullable: true
        pic_cpm:
          $ref: '#/components/schemas/RangeFilter'
          description: Estimated CPM — image+text notes
          nullable: true
        video_cpm:
          $ref: '#/components/schemas/RangeFilter'
          description: Estimated CPM — video notes
          nullable: true
        pic_read_price:
          $ref: '#/components/schemas/RangeFilter'
          description: Estimated cost per read — image+text notes
          nullable: true
        video_read_price:
          $ref: '#/components/schemas/RangeFilter'
          description: Estimated cost per read — video notes
          nullable: true
        pic_engage_cost:
          $ref: '#/components/schemas/RangeFilter'
          description: Estimated cost per engagement — image+text notes
          nullable: true
        video_engage_cost:
          $ref: '#/components/schemas/RangeFilter'
          description: Estimated cost per engagement — video notes
          nullable: true
        estimate_cpuv:
          $ref: '#/components/schemas/RangeFilter'
          description: Overflow store-visit cost per visit
          nullable: true
      additionalProperties: false
      type: object
      title: CoopFilter
      description: >-
        Sponsored notes — the "Sponsored Notes" section on the web page
        (cooperation performance + data performance).
    crawlers__xiaohongshu__pgy__pgy_filters__LiveFilter:
      properties:
        live_count:
          $ref: '#/components/schemas/RangeFilter'
          description: Number of live streams in the last 30 days
          nullable: true
        avg_viewer:
          $ref: '#/components/schemas/RangeFilter'
          description: >-
            Average viewers per live stream over the last 90 days (live_count
            uses a 30-day window instead).
          nullable: true
        avg_gmv:
          $ref: '#/components/schemas/RangeFilter'
          description: >-
            Average GMV per live stream over the last 90 days (live_count uses a
            30-day window instead).
          nullable: true
      additionalProperties: false
      type: object
      title: LiveFilter
      description: Live data — the "Live Data" section of the web page.
    crawlers__xiaohongshu__pgy__pgy_filters__FlagFilter:
      properties:
        is_star:
          title: Is Star
          description: Celebrity
          nullable: true
          type: boolean
        new_high_quality:
          title: New High Quality
          description: Rising creator
          nullable: true
          type: boolean
        high_quality:
          title: High Quality
          description: Quality creator
          nullable: true
          type: boolean
        note_and_live:
          title: Note And Live
          description: Both notes and live streams available for collaboration
          nullable: true
          type: boolean
        filter_intention:
          title: Filter Intention
          description: Intended industry match
          nullable: true
          type: boolean
        activity_codes:
          title: Activity Codes
          description: >-
            Trending activity: use the `code` value for each item in the
            activities list from `/blogger/filter-options`
          nullable: true
          items:
            type: string
            maxLength: 64
          type: array
          maxItems: 30
        exclude_low_active:
          title: Exclude Low Active
          description: Exclude low-activity creators
          nullable: true
          type: boolean
        exclude_fans_down:
          title: Exclude Fans Down
          description: Exclude creators with declining followers
          nullable: true
          type: boolean
        exclude_cooperated:
          title: Exclude Cooperated
          description: Exclude previously collaborated creators
          nullable: true
          type: boolean
        exclude_invited:
          title: Exclude Invited
          description: Exclude already-invited creators
          nullable: true
          type: boolean
        industry_first:
          title: Industry First
          description: >-
            Industry-recommended creators — level-1 industry name (e.g. Beauty &
            Personal Care); the platform will recommend creators specializing in
            that industry
          example: Beauty & Personal Care
          nullable: true
          type: string
          maxLength: 64
        industry_second:
          title: Industry Second
          description: >-
            Industry-recommended creators — level-2 industry name (used together
            with industry_first; values from taxonomy2Tags in industryTags in
            `/blogger/filter-options`)
          nullable: true
          type: string
          maxLength: 64
      additionalProperties: false
      type: object
      title: FlagFilter
      description: >-
        Boolean flags — controls the "Platform Recommendations" (featured
        bloggers / trending campaigns) and "Standard Exclusions" (one-click
        exclude) sections on the web page.
    RangeFilter:
      properties:
        min:
          title: Min
          description: Minimum value (inclusive)
          example: 10000
          nullable: true
          type: number
          maximum: 1000000000000
          minimum: 0
        max:
          title: Max
          description: Maximum value (inclusive); omit for no upper limit
          example: 50000
          nullable: true
          type: number
          maximum: 1000000000000
          minimum: 0
      additionalProperties: false
      type: object
      title: RangeFilter
      description: >-
        Numeric range corresponding to the custom input box in the web filter.


        - Either bound may be omitted: omitting `min` defaults to 0, omitting
        `max` means no upper limit

        - At least one bound must be provided, otherwise 422
    PercentRange:
      properties:
        min:
          title: Min
          description: Minimum value (inclusive), percentile 0-100
          example: 20
          nullable: true
          type: number
          maximum: 100
          minimum: 0
        max:
          title: Max
          description: Maximum value (inclusive), percentile 0-100
          example: 80
          nullable: true
          type: number
          maximum: 100
          minimum: 0
      additionalProperties: false
      type: object
      title: PercentRange
      description: >-
        Percentage range: enter a value between 0 and 100 as a percentile, e.g.
        `40` means 40% (**not 0.4**).


        This convention follows the PGY web interface: the tier for
        notes-per-thousand-likes is written as `{"40% and above": [40, null]}`
        or `{"below 10%": [null, 10]}` — the value sent upstream is simply 40 or
        10.


        **What is and is not validated — stated clearly to avoid confusion**:

        * Caught: values with the wrong order of magnitude — entering 200 or
        9500 (as if using parts-per-ten-thousand or raw counts) will return a
        422 error, whereas the generic RangeFilter allows up to 1e12 and
        previously passed such values through.

        * **Not caught: values that are too small** — entering 0.4 is still
        valid because 0.4% is a legitimate value; the type system cannot
        distinguish "meant 40% but wrote 0.4" from "genuinely filtering for
        0.4%". This ambiguity can only be resolved through field documentation.
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: AIsa API key. Get yours at https://aisa.one

````