Contents
Getting Started
Getting Started Authentication Your First RequestAccount API
Overview Balance & Spend My Pricing Account Info Current KeyRED (Xiaohongshu) Data
Overview Note APIs User APIs Search APIs Product APIs Topic APIs Creator InsightsDandelion (PGY) Data
Overview Creator Fundamentals Note Case Studies Creator Discovery Note Level Content Square Keyword AnalysisReference
Response Format Error Codes Billing Self-hostingAPI Documentation
Get started with Rnote API — from sign-up to your first request.
Base URL (each API family has its own prefix)
https://rnote.dev/api/v2/crawlerhttps://rnote.dev/api/v2/pgySame 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 playgroundWhich 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.
- · Hand-written docs with parameter notes and sample values
- · One-click request snippets in several languages
- · Requests can be saved and shared with teammates
- · Generated live from the running service, so it cannot drift from the real API
- · Full field types, accepted values and response schemas
- · Hit
Authorizeonce with yourX-API-Keyand the browser remembers it
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 Create an account and verify your email
- 2 Sign in to the admin panel and create an API key under "API Keys"
- 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.
curl 'https://rnote.dev/api/v1/account/balance' \
-H 'X-API-Key: sk-5bc4****************************e175'
Balance & Spend
/balance
Account balance, lifetime deposits and lifetime spend
balance · total_deposited · total_charged · overdraft_limit. Amounts are 6-decimal strings — do not parse as floats.
My Pricing
/pricing
Price list, including the unit price you are actually charged
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
/me
Current account: role, email verification, reseller discount, enterprise billing mode, rate limits
a***@gmail.com.
Current Key
/key
Metadata for the key used on this request: label, status, rate limit, scopes
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
/note/image
Fetch an image note's detail — content, image list, author info, engagement metrics and more.
note_id (required)
/note/video
Fetch a video note's detail — playback URL, cover image, author info and more.
note_id (required)
/note/comments
Fetch a note's comments, with pagination and multiple sort options.
note_id (required) · cursor · index · sort_strategy (default / latest_v2 / like_count)
$.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).
/note/sub_comments
Fetch second-level comments (replies) on a note, with cursor pagination.
note_id (required) · comment_id (required) · cursor · index · num
User APIs
/user/info
Fetch a user's profile — nickname, avatar, bio, follower count and more.
user_id (required)
/user/posted
Fetch the notes a user has posted, with cursor pagination.
user_id (required) · cursor · num
/user/faved
Fetch the notes a user has collected, with cursor pagination.
user_id (required) · cursor · num
Search APIs
/search/notes
Search notes, with sorting and filtering.
keyword (required) · page · sort (general / time_descending / popularity_descending) · note_type (0=all / 1=video / 2=image)
/search/recommend
Search suggestions: pass a keyword and get RedNote's autocomplete / related search terms — for search-box completion and related-term recommendations
keyword (required)
/search/users
Search users.
keyword (required) · page
/search/images
Search images.
keyword (required) · page
/search/products
Search products.
keyword (required) · page · sort_by · source
/search/groups
Search group chats.
keyword (required) · page
Product APIs
/product/detail
Fetch product detail.
product_id (required)
/product/review/overview
Fetch a product's review summary.
product_id (required)
/product/reviews
Fetch a product's reviews, with cursor pagination.
product_id (required) · cursor · sort_type
/product/recommendations
Fetch related-product recommendations.
product_id (required) · cursor
Topic APIs
/topic/info
Fetch topic detail.
topic_id (required)
/topic/feed
Fetch notes under a topic, with cursor pagination.
topic_id (required) · cursor · sort_by
Creator Insights
/creator/inspiration/feed
Fetch recommended creator inspirations.
cursor · num
/creator/hot/inspiration/feed
Fetch trending creator inspirations.
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.
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.
/blogger/detailCreator profile: nickname, RedNote ID, region, tags, follower count, image/video collaboration rates
user_id (required)/blogger/data-summaryOverview: cost/quote estimates (CPM, CPUV, cost per read), content format mix, monthly follower growth
user_id (required) · business/blogger/fans-summaryFollower overview: total followers, share of active/engaged/paying followers, and peer percentile
user_id (required)/blogger/fans-profileAudience breakdown: age, gender, region, interests, device distribution — for audience matching
user_id (required)/blogger/fans-historyFollower growth history: net gain over a window, growth rate, daily follower counts
user_id (required) · increase_type · date_type/blogger/core-dataCore metrics: daily trend (dailyData) plus period totals (sumData) — impressions, reads, engagement, CPM, CPE
user_id (required) · business · note_type · date_type · advertise_switch/blogger/notes-rateNote performance: median impressions/reads/engagement, engagement rate, completion rate, 100-like and 1k-like ratios, peer percentile
user_id (required) · business · note_type · date_type · advertise_switchNote Case Studies
A creator's published notes. The two endpoints return different field structures — do not mix them.
/blogger/notesNote details (paginated): reads, likes, saves, video flag, sponsored flag. Native KOL endpoint — returns an empty list for cross-region creators
user_id (required) · page_number · page_size · note_type · order_type · advertise_switch · feature_tag · content_tag · is_third_platform/blogger/notes_v2Note case studies v2: covers cross-region creators. Use this when the endpoint above returns empty; the response shape differs
user_id (required) · page_number · page_size (1-8) · note_type · order_typeCreator Discovery
Find candidate creators across the platform, rather than looking up a known ID.
/blogger/listCreator search: structured filters plus sorting, paginated. Filters are passed as grouped objects — blogger, fans, note, coop, live, flags
page_num · page_size · brand_user_id · keyword · search_type · column · sort · goal · blogger · fans · note · coop · live · flags/blogger/filter-optionsAll available filter options (enum dictionary). Use it to build the filters for /blogger/list dynamically instead of hardcoding enum values
/blogger/similarSimilar creators: given one creator, return others with comparable style and audience — useful for scaling a shortlist
user_id (required) · page_num · page_size (1-4)/live-blogger/listLive-commerce creator directory: filter by category, buyer persona, e-commerce conversion strength, live performance
page_num · page_size (1-20) · seed · nick_name · category · buyer · ecom · live · fans · flagsNote Level
Commercial data for a known note ID.
/note/detailNote details: body text, image/video media, impressions, reads, likes, saves, comments
note_id (required)/note/commentsFeatured comments: the comment list from the note's "featured comments" block
note_id (required)/note/componentsNote components: products, forms, and other components attached to the note
note_id (required)Content Square
Cross-creator trending leaderboards — for topic research and spotting winners.
/content/squareContent 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
biz_type (required) · page_num · page_size (1-34) · search_word · order_by · date_range · category · industry · note_type · content_type · theme · placement and moreKeyword Analysis
Search demand and audience for a term — for topic selection and targeting.
/keyword/statKeyword overview: search index plus the audience profile and creator mix behind that term
search_word (required)/keyword/dailyDaily search index for a keyword: a time series, so you can read trends and seasonal spikes
search_word (required)/keyword/relatedRelated keywords: expand one term into adjacent search terms for topic ideation
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.