API Documentation

Get started with Rnote API — from sign-up to your first request.

Base URL (each API family has its own prefix)

RED (Xiaohongshu) data APIs: https://rnote.dev/api/v2/crawler
Dandelion (PGY) creator data APIs: https://rnote.dev/api/v2/pgy

Same host, different path prefixes. Crawler endpoints are mostly GET; Dandelion endpoints are POST with a JSON body. The full interactive reference is available via Swagger UI.

Online API playground

We provide an Apifox-based online playground — enter your API key and test every endpoint right in the browser, no code required.

Open the playground

Which one should I use?

Both send real requests from your browser, both use your own API Key, and both are billed as normal calls. What differs is where the documentation comes from.

Online Playground Apifox
  • · Hand-written docs with parameter notes and sample values
  • · One-click request snippets in several languages
  • · Requests can be saved and shared with teammates
docs.rnote.dev
Swagger UI generated from OpenAPI
  • · Generated live from the running service, so it cannot drift from the real API
  • · Full field types, accepted values and response schemas
  • · Hit Authorize once with your X-API-Key and the browser remembers it
Open Swagger UI

Recommendation: start in the Online Playground — it explains the most and you can copy working code straight out of it. Once you are wiring things up, if the docs and an actual response disagree, or you need to confirm whether a parameter is really supported in production, trust Swagger UI: it is generated from the service that is actually running, so nothing can go un-synced.

Before you start

  1. 1 Create an account and verify your email
  2. 2 Sign in to the admin panel and create an API key under "API Keys"
  3. 3 Top up your balance on the Billing page (only successful requests are charged)

Authentication

All API requests authenticate by passing your API key in the X-API-Key header.

# Pass your API key in an HTTP header
curl -X 'GET' \
  'https://rnote.dev/api/v2/crawler/note/image?note_id=697c0eee000000000a03c308' \
  -H 'accept: application/json' \
  -H 'X-API-Key: sk-5bc4****************************e175'

Your First Request

Example — fetching an image note's detail:

curl -X 'GET' \
  'https://rnote.dev/api/v2/crawler/note/image?note_id=697c0eee000000000a03c308' \
  -H 'accept: application/json' \
  -H 'X-API-Key: sk-5bc4****************************e175'
import requests

API_KEY = "sk-5bc4****************************e175"
BASE_URL = "https://rnote.dev/api/v2/crawler"

response = requests.get(
    f"{BASE_URL}/note/image",
    params={"note_id": "697c0eee000000000a03c308"},
    headers={
        "X-API-Key": API_KEY,
        "accept": "application/json",
    },
)

data = response.json()
print(data)
const API_KEY = "sk-5bc4****************************e175";
const BASE_URL = "https://rnote.dev/api/v2/crawler";

const res = await fetch(
  `${BASE_URL}/note/image?note_id=697c0eee000000000a03c308`,
  {
    headers: {
      "X-API-Key": API_KEY,
      "accept": "application/json",
    },
  }
);

const data = await res.json();
console.log(data);

Account API

https://rnote.dev/api/v1/account

Read your own account data with the same API Key — no dashboard login. Handy for cost tracking and low-balance alerts inside your scripts.

Always free: never billed, and callable even at zero balance.

Read-only GETs that return only your own data. For safety this group cannot create, modify or delete API Keys, and never returns any key in plaintext — so a leaked key cannot escalate into account takeover.

Rate limit 30/min. If your key has a scope restriction, add /api/v1/account to it.

Example: check balance
curl 'https://rnote.dev/api/v1/account/balance' \
  -H 'X-API-Key: sk-5bc4****************************e175'

Balance & Spend

GET /balance

Account balance, lifetime deposits and lifetime spend

Returns balance · total_deposited · total_charged · overdraft_limit. Amounts are 6-decimal strings — do not parse as floats.

My Pricing

GET /pricing

Price list, including the unit price you are actually charged

Each item carries effective_price (list price) and your_price (what you actually pay). Resellers see the discounted price; enterprise accounts see their contract price (then enterprise_pricing is true and discount_rate is 0, since enterprise pricing does not stack the reseller discount). The public /api/public/pricing has list prices only.

Account Info

GET /me

Current account: role, email verification, reseller discount, enterprise billing mode, rate limits

Email is masked as a***@gmail.com.

Current Key

GET /key

Metadata for the key used on this request: label, status, rate limit, scopes

Never returns the plaintext key, and never lists your other keys.

RED (Xiaohongshu) Data APIs

https://rnote.dev/api/v2/crawler

Public on-platform content: notes, users, search, products, topics and creator inspiration. Mostly GET requests with query-string parameters.

Note APIs

GET /note/image

Fetch an image note's detail — content, image list, author info, engagement metrics and more.

Parameters: note_id (required)
GET /note/video

Fetch a video note's detail — playback URL, cover image, author info and more.

Parameters: note_id (required)
GET /note/comments

Fetch a note's comments, with pagination and multiple sort options.

Parameters: note_id (required) · cursor · index · sort_strategy (default / latest_v2 / like_count)
Paging: $.data.cursor in the response is a JSON string {"cursor":"...","index":3,"pageArea":"ALL"}. Either split it into cursor / index / pageArea, or pass the whole string as cursor — the server unwraps it (values inside the JSON win).
GET /note/sub_comments

Fetch second-level comments (replies) on a note, with cursor pagination.

Parameters: note_id (required) · comment_id (required) · cursor · index · num

User APIs

GET /user/info

Fetch a user's profile — nickname, avatar, bio, follower count and more.

Parameters: user_id (required)
GET /user/posted

Fetch the notes a user has posted, with cursor pagination.

Parameters: user_id (required) · cursor · num
GET /user/faved

Fetch the notes a user has collected, with cursor pagination.

Parameters: user_id (required) · cursor · num

Search APIs

GET /search/notes

Search notes, with sorting and filtering.

Parameters: keyword (required) · page · sort (general / time_descending / popularity_descending) · note_type (0=all / 1=video / 2=image)
GET /search/recommend

Search suggestions: pass a keyword and get RedNote's autocomplete / related search terms — for search-box completion and related-term recommendations

Params: keyword (required)
GET /search/users

Search users.

Parameters: keyword (required) · page
GET /search/images

Search images.

Parameters: keyword (required) · page
GET /search/products

Search products.

Parameters: keyword (required) · page · sort_by · source
GET /search/groups

Search group chats.

Parameters: keyword (required) · page

Product APIs

GET /product/detail

Fetch product detail.

Parameters: product_id (required)
GET /product/review/overview

Fetch a product's review summary.

Parameters: product_id (required)
GET /product/reviews

Fetch a product's reviews, with cursor pagination.

Parameters: product_id (required) · cursor · sort_type
GET /product/recommendations

Fetch related-product recommendations.

Parameters: product_id (required) · cursor

Topic APIs

POST /topic/info

Fetch topic detail.

Body: topic_id (required)
GET /topic/feed

Fetch notes under a topic, with cursor pagination.

Parameters: topic_id (required) · cursor · sort_by

Creator Insights

GET /creator/inspiration/feed

Fetch recommended creator inspirations.

Parameters: cursor · num
GET /creator/hot/inspiration/feed

Fetch trending creator inspirations.

Parameters: cursor · num

Dandelion (PGY) Data APIs

https://rnote.dev/api/v2/pgy

Commercial data from Dandelion (蒲公英), RedNote's official creator-collaboration platform: creator discovery and rate cards, audience breakdowns, note conversion metrics, trending leaderboards, and keyword search demand — the data behind influencer buying and competitive analysis.

All endpoints are POST with a JSON body. Same X-API-Key authentication, pay-per-call pricing, and charge-on-success behaviour. Creator and note IDs are 24-character RedNote IDs.

page_size is capped at the value Dandelion's own web UI uses (it varies per endpoint and is noted below); passing a larger number does not return more rows.

Example: creator note conversion metrics
curl -X 'POST' \
  'https://rnote.dev/api/v2/pgy/blogger/notes-rate' \
  -H 'X-API-Key: sk-5bc4****************************e175' \
  -H 'Content-Type: application/json' \
  -d '{"user_id": "5c668b3e0000000012021605", "note_type": 3, "date_type": 1}'

Creator Fundamentals

Commercial profile and audience data for a known creator ID.

POST/blogger/detail

Creator profile: nickname, RedNote ID, region, tags, follower count, image/video collaboration rates

Params: user_id (required)
POST/blogger/data-summary

Overview: cost/quote estimates (CPM, CPUV, cost per read), content format mix, monthly follower growth

Params: user_id (required) · business
POST/blogger/fans-summary

Follower overview: total followers, share of active/engaged/paying followers, and peer percentile

Params: user_id (required)
POST/blogger/fans-profile

Audience breakdown: age, gender, region, interests, device distribution — for audience matching

Params: user_id (required)
POST/blogger/fans-history

Follower growth history: net gain over a window, growth rate, daily follower counts

Params: user_id (required) · increase_type · date_type
POST/blogger/core-data

Core metrics: daily trend (dailyData) plus period totals (sumData) — impressions, reads, engagement, CPM, CPE

Params: user_id (required) · business · note_type · date_type · advertise_switch
POST/blogger/notes-rate

Note performance: median impressions/reads/engagement, engagement rate, completion rate, 100-like and 1k-like ratios, peer percentile

Params: user_id (required) · business · note_type · date_type · advertise_switch

Note Case Studies

A creator's published notes. The two endpoints return different field structures — do not mix them.

POST/blogger/notes

Note details (paginated): reads, likes, saves, video flag, sponsored flag. Native KOL endpoint — returns an empty list for cross-region creators

Params: user_id (required) · page_number · page_size · note_type · order_type · advertise_switch · feature_tag · content_tag · is_third_platform
POST/blogger/notes_v2

Note case studies v2: covers cross-region creators. Use this when the endpoint above returns empty; the response shape differs

Params: user_id (required) · page_number · page_size (1-8) · note_type · order_type

Creator Discovery

Find candidate creators across the platform, rather than looking up a known ID.

POST/blogger/list

Creator search: structured filters plus sorting, paginated. Filters are passed as grouped objects — blogger, fans, note, coop, live, flags

Params: page_num · page_size · brand_user_id · keyword · search_type · column · sort · goal · blogger · fans · note · coop · live · flags
POST/blogger/filter-options

All available filter options (enum dictionary). Use it to build the filters for /blogger/list dynamically instead of hardcoding enum values

Params: No parameters
POST/blogger/similar

Similar creators: given one creator, return others with comparable style and audience — useful for scaling a shortlist

Params: user_id (required) · page_num · page_size (1-4)
POST/live-blogger/list

Live-commerce creator directory: filter by category, buyer persona, e-commerce conversion strength, live performance

Params: page_num · page_size (1-20) · seed · nick_name · category · buyer · ecom · live · fans · flags

Note Level

Commercial data for a known note ID.

POST/note/detail

Note details: body text, image/video media, impressions, reads, likes, saves, comments

Params: note_id (required)
POST/note/comments

Featured comments: the comment list from the note's "featured comments" block

Params: note_id (required)
POST/note/components

Note components: products, forms, and other components attached to the note

Params: note_id (required)

Content Square

Cross-creator trending leaderboards — for topic research and spotting winners.

POST/content/square

Content square: 8 leaderboards (trending, product seeding, e-commerce ads, PGY collaborations, lead generation, e-commerce trending, direct seeding, app promotion) with multi-dimensional filters. Each board holds 100 entries

Params: biz_type (required) · page_num · page_size (1-34) · search_word · order_by · date_range · category · industry · note_type · content_type · theme · placement and more

Keyword Analysis

Search demand and audience for a term — for topic selection and targeting.

POST/keyword/stat

Keyword overview: search index plus the audience profile and creator mix behind that term

Params: search_word (required)
POST/keyword/daily

Daily search index for a keyword: a time series, so you can read trends and seasonal spikes

Params: search_word (required)
POST/keyword/related

Related keywords: expand one term into adjacent search terms for topic ideation

Params: search_word (required)

Enum values (note_type, order_type, date_type, biz_type) and full response fields are documented in the Swagger UI.

Response Format

All data endpoints (/api/v2/crawler/*, /api/v2/pgy/*) use a consistent JSON envelope:

Successful response

{
  "success": true,
  "data": { /* Business data, shape varies by endpoint */ },
  "billed": true,
  "debug_id": "a1b2c3d4",
  "debug_info": "..."   /* diagnostic info — include it when reporting an issue */
}

Failure response

{
  "success": false,
  "data": null,
  "error": "Rate limited, please retry later",
  "retry_after": 5.0,
  "billed": false,
  "debug_id": "a1b2c3d4",
  "debug_info": "..."   /* diagnostic info — include it when reporting an issue */
}

Field reference

Field Type Description
success bool Business success flag (matches HTTP status semantics)
data object | null Business data; null on failure
error string | null Generic error message; null on success
retry_after float | null Suggested wait seconds on rate-limit / temporary unavailability; mirrors the HTTP Retry-After header
billed bool Whether this request was billed (only successful requests are billed; any failure is free)
debug_id string | null 8-character random correlation code; include it when reporting an issue so we can locate this request
debug_info string | null Diagnostic info; include it when reporting an issue (no need to decode it)

About debug_id and debug_info

When reporting an issue, including the debug_id (short code) or debug_info from the response helps us locate the request much faster. You don't need to decode them — just send them to us as-is.

Error Codes

Middleware layer (auth / rate-limit / billing)

These statuses are returned before the request reaches business logic, regardless of endpoint.

HTTP status Meaning How to handle
401 Missing or invalid API key Check the X-API-Key header
402 Insufficient balance Top up your balance in the admin panel
403 Not authorized for this endpoint Check your API key's scopes
429 Per-user / per-IP rate limit exceeded Reduce your request rate and retry later

Business layer (data endpoints)

Data endpoints use standard 4xx/5xx HTTP status codes on failure, plus a Retry-After header where relevant. Check both the HTTP status and body.success.

HTTP status Trigger How to handle
400 Invalid request parameter Fix the parameter (do not retry)
404 Endpoint does not exist Check the URL path
429 Too many requests Wait the duration in the Retry-After header, then retry
500 Internal server error Retry later; if it persists, contact support with the debug_id
502 Data source temporarily refused or unavailable Retry later (changing parameters usually doesn't help)
503 Service temporarily busy Wait the duration in the Retry-After header, then retry
504 Request pipeline timeout Retry later

Client error-handling example

Recommended pattern — check both HTTP status and body.success, and include debug_id in your error logs:

import requests

resp = requests.get(
    "https://rnote.dev/api/v2/crawler/user/info",
    headers={"X-API-Key": "sk-..."},
    params={"user_id": "..."},
    timeout=20,
)
body = resp.json()

# Double-check: HTTP status first, body.success fallback
if resp.status_code >= 400 or not body.get("success"):
    error = body.get("error", "Unknown error")
    debug_id = body.get("debug_id", "n/a")
    retry_after = body.get("retry_after")
    print(f"Request failed [{debug_id}]: {error}", end="")
    if retry_after:
        print(f" (retry in {retry_after}s)")
    # Include debug_id when contacting support
else:
    data = body["data"]
    # Process business data ...

Billing

Per-request billing

Only successful (HTTP 2xx) requests are billed; failed requests are free. Each endpoint is priced independently.

Insufficient balance

When your balance can't cover a request, the API returns HTTP 402 and the request is not executed.

Transaction records

Every charge is viewable on the Billing page of the admin panel — time, endpoint, amount and more.

Self-hosting

Every endpoint on this page is served by the hosted API and billed per call. If your volumes are high, or the data cannot pass through a third party, you can instead buy the server-side source code and run it on your own machines.

What you get

Three server-side codebases — RedNote app, RedNote web and Dandelion (PGY) — with request signing, device registration, automatic captcha solving, plus automation for sign-up and login, publishing, comments and DMs and bulk account management, against both the mainland and overseas apps. Containerised, and you can compile it yourself.

How it differs from the hosted API

The hosted API works out of the box and bills only successful calls, with devices and proxies handled for you. Self-hosting is a one-off purchase with no per-call metering, but accounts, proxies and operations are yours to run.

Scope of use

The source code is provided as study material, for protocol analysis and algorithm research. No accounts or platform data are included.