Sylvia API Documentation v3.4.0
Version history and migration notes: see the Changelog.
Overview
Sylvia is a Reddit data API. It returns structured JSON for public Reddit
data: posts, comments, subreddits, users, search, and live streams.
You do not need a Reddit account or OAuth credentials. You need a Sylvia API
key.
You get:
- Full comment trees, resolved recursively
- Multiple output shapes: raw JSON, Reddit-compatible, minimal, NDJSON, CSV,
and your own custom templates - One key for both REST and MCP
Use cases
| Use case | Endpoints | Formats |
|---|---|---|
| AI training datasets | listings, search, live | ndjson, csv, minimal |
| Brand and market monitoring | domain, search, comments/live | default, custom |
| Research and social listening | subreddit about, user about | reddit, minimal |
| Reddit client replacement | all reads | |
| Data pipelines | any listing | csv, ndjson |
Quickstart
Path to your first request
- Go to https://sylvia-api.com and sign up.
- Create an API key in the dashboard. The key starts with
syl_. It is shown
once. Save it. - Send a request:
curl -H "X-API-KEY: syl_8a1f..." \
"https://api.sylvia-api.com/v1/reddit/r/AskReddit/hot?limit=10"
Python:
import requests
API = "https://api.sylvia-api.com/v1/reddit"
HEADERS = {"X-API-KEY": "syl_8a1f..."}
r = requests.get(f"{API}/r/Python/top",
headers=HEADERS,
params={"limit": 50, "t": "week", "format": "minimal"})
data = r.json() # {"success": true, "data": {...}, "request_id": "..."}
posts = data["data"]["posts"]
Node.js:
const res = await fetch(
"https://api.sylvia-api.com/v1/reddit/u/spez/about",
{ headers: { "X-API-KEY": "syl_8a1f..." } }
);
const body = await res.json();
Billing note: adding credits is crypto-only. See Billing.
Authentication
All data endpoints require an API key in the X-API-KEY header:
curl -H "X-API-KEY: syl_8a1f..." \
"https://api.sylvia-api.com/v1/reddit/r/all/top?limit=25"
Keys
- Create keys in the dashboard at https://sylvia-api.com.
- A key can have an optional
expirydate and abudget(USD cap). - The key is shown once at creation. Save it.
Two credentials
Sylvia has two distinct credentials, and they are not interchangeable:
| Credential | Prefix | Used for |
|---|---|---|
| API key | syl_ |
Data endpoints (/v1/reddit/*, /mcp) |
| Account token | SV_ |
Account management (keys, profile, payments) |
The account token is issued at signup. It authenticates the dashboard and
account-level operations. It is not a data key. You cannot query Reddit
data with it.
Credential separation
Sending the wrong credential returns 401 with a message telling you which
one to use:
| You send | Data endpoint | Account endpoint |
|---|---|---|
X-API-KEY: syl_... |
✅ | ❌ 401 |
Authorization: Bearer SV_... |
❌ 401 |
✅ |
Data endpoints reject a Bearer token with This endpoint requires an X-API-KEY, not a Bearer account token. Account endpoints reject an API key
with This endpoint requires your account token (SV_), not an API key.
Account management endpoints
Base: https://api.sylvia-api.com. All require the account token in the
Authorization: Bearer SV_... header (or x-sylvia-auth: SV_...).
| Endpoint | Method | Description |
|---|---|---|
/auth/me |
GET | Account profile (email, tier, balance, status) |
/keys |
GET | List API keys (masked prefixes: full secrets never returned) |
/keys |
POST | Create a key (full key shown once in the response) |
/keys/{id} |
DELETE | Revoke a key |
/createPayment |
POST | Create a crypto deposit payment link |
/auth/recent-requests |
GET | Recent request history |
/auth/usage-history |
GET | Per-day usage analytics |
/auth/formats |
GET | List formats and which are available on your tier |
/auth/default-format |
POST | Set the account's default format |
/templates |
GET / POST | List or create custom templates |
/templates/{name} |
DELETE | Delete a custom template |
curl -H "Authorization: Bearer SV_..." "https://api.sylvia-api.com/auth/me"
/createPayment accepts { "amount": 10, "orderId": "..." }. The coin is
chosen on our payment processor's checkout page, so no payCurrency is
needed. It is rate-limited to 20 links per hour per account.
Core Concepts
Base URL
| Surface | URL |
|---|---|
| API | https://api.sylvia-api.com/v1/reddit |
| Website and dashboard | https://sylvia-api.com |
| MCP endpoint | https://api.sylvia-api.com/mcp |
Response envelope
Every successful response uses this shape:
{
"success": true,
"data": {
"posts": [ ... ],
"after": "t3_abc123"
},
"request_id": "3f2b1c9a-..."
}
message: optional human string on some endpointserror: present only on failure
Pagination
Listing endpoints return an after cursor. Pass it to the next request:
curl -H "X-API-KEY: syl_..." \
"https://api.sylvia-api.com/v1/reddit/r/Python/hot?limit=100"
# -> data.after = "t3_xyz..."
curl -H "X-API-KEY: syl_..." \
"https://api.sylvia-api.com/v1/reddit/r/Python/hot?limit=100&after=t3_xyz..."
after: forward cursorbefore: backward cursorafter: null: end of data
Limits above 100
Requests above limit=100 are split into pages of 100, chained by cursor,
and merged. Each page uses one rate-limit token. Billing is one charge per
request. The header X-Chunked-Items shows the merged count.
Note: for
limitabove 100, treat the merged count as best-effort. For an
exact count, page with cursors.
Rate limits
Rate limits are enforced per API key with a sliding window. Response headers:
| Header | Meaning |
|---|---|
X-RateLimit-Tier |
free, strela, svetka, or enterprise |
X-RateLimit-Limit |
requests per second for the tier |
X-RateLimit-Remaining |
remaining in the window |
X-RateLimit-Reset |
epoch ms when the window resets |
Retry-After |
seconds, present on 429 |
429 response:
{
"success": false,
"error": "Rate limit exceeded",
"tier": "free",
"retry_after_seconds": 5,
"upgrade_url": "https://sylvia-api.com/#pricing"
}
Tier limits:
| Tier | Requests per minute | Burst |
|---|---|---|
| Free | 480 | 15 |
| Strela | 1,200 | 40 |
| Svetka | 2,400 | 80 |
| Enterprise | 3,600 | 100 |
Pricing & Tiers
| Item | Price |
|---|---|
| Standard request | $0.0005 per successful request |
| Live stream | $0.05 per request |
| Search | $0.05 per request |
You are charged for requests that complete successfully. Requests rejected
for auth failure, rate limit, or service error are not charged.
Tiers are set by trailing-30-day deposits:
| Tier | Condition (30d) | Formats | Templates |
|---|---|---|---|
| Free | default | default, reddit, markdown, custom | 1 |
| Strela | $50+ | + minimal, csv | 5 |
| Svetka | $200+ | + ndjson | unlimited |
| Enterprise | $500+ | all | unlimited |
- Free tier starts with $0.50 credit (~1,000 standard requests).
Billing
Adding credits is crypto-only. Sylvia does not accept credit cards,
PayPal, or bank transfer. Payments go through our crypto payment processor.
You can pay with a wide range of currencies. Common ones include:
| Currency | Networks |
|---|---|
| USDT | Polygon, TRON, Solana, Ethereum |
| USDC | Ethereum, Solana, Polygon |
| BTC | Bitcoin |
| ETH | Ethereum |
| BNB | BSC |
| XRP | Ripple |
| LTC | Litecoin |
| SOL | Solana |
| DOGE | Dogecoin |
| ADA | Cardano |
- The full list of available coins appears on the checkout page. It is larger
than the table above and may change. - The coin is chosen at checkout. The API and dashboard do not send a currency.
- Each deposit invoice carries a $1.00 service fee.
- A network fee (varies by coin) is added by the payment provider at checkout.
Response Formats
Control the response shape with the format= parameter on any data endpoint.
1. Default (raw)
Omit format for the raw envelope:
{
"success": true,
"data": {
"posts": [{
"id": "1vd3wrd",
"title": "What's a skill that looks easy but is actually hard?",
"author": "someone",
"selftext": "...",
"score": 48210,
"num_comments": 9321,
"created_utc": 1754132400,
"subreddit": "AskReddit",
"permalink": "/r/AskReddit/comments/1vd3wrd/...",
"url": "https://reddit.com/r/AskReddit/comments/1vd3wrd/...",
"upvote_ratio": 0.91,
"over_18": false
}],
"after": "t3_1vd3wrd"
},
"request_id": "uuid-v4"
}
All tiers.
2. Reddit-compatible
format=reddit wraps output in the Reddit Listing envelope. It is a drop-in
replacement for PRAW and Reddit-API clients:
{
"kind": "Listing",
"data": {
"children": [
{ "kind": "t3", "data": { "id": "1vd3wrd", "title": "...", ... } }
],
"after": null,
"before": null,
"dist": 25
}
}
- Comments have
kind: "t1", posts havekind: "t3". - All tiers.
3. Minimal (Strela+)
format=minimal extracts only core fields. Payloads are about 60% smaller:
[
{
"id": "1vd3wrd",
"title": "What's a skill that looks easy but is actually hard?",
"text": "selftext or body",
"author": "someone",
"created_utc": 1754132400,
"score": 48210,
"subreddit": "AskReddit",
"permalink": "/r/AskReddit/comments/1vd3wrd/...",
"num_comments": 9321,
"url": "https://reddit.com/..."
}
]
Fields: id, title, text, author, created_utc, score, subreddit, permalink, num_comments, url. The text field uses selftext, then body.
- Strela+. Free tier gets 403
FEATURE_LOCKED.
4. NDJSON (Svetka+)
format=ndjson: one JSON object per line:
{"id":"1vd3wrd","title":"...","score":48210,...}
{"id":"1vd3ws9","title":"...","score":1041,...}
Good for streaming and bulk pipelines.
- Svetka+. Free and Strela get 403
FEATURE_LOCKED.
5. CSV (Strela+)
format=csv: a flat table with headers:
id,title,author,subreddit,score,num_comments,created_utc,permalink,url,selftext,body
1vd3wrd,"What's a skill...",someone,AskReddit,48210,9321,1754132400,/r/AskReddit/...,https://reddit.com/...,,,
Fields: id, title, author, subreddit, score, num_comments, created_utc, permalink, url, selftext, body. Values with commas, quotes, or newlines are
quoted. Import into Excel, Google Sheets, or pandas.
- Strela+. Free tier gets 403
FEATURE_LOCKED.
6. Markdown
format=markdown renders each post or comment as a self-contained markdown
document: YAML frontmatter, an H1 title, and the body as prose. Documents are
joined with --- separators: the same shape as markdown collections and
static-site frontmatter, so it drops straight into RAG, document-ingestion,
and AI-training pipelines.
---
id: "1vd3wrd"
title: "What's a skill that looks easy but is actually hard?"
author: "someone"
created_utc: 1754132400
score: 48210
subreddit: "AskReddit"
permalink: "/r/AskReddit/comments/1vd3wrd/..."
num_comments: 9321
url: "https://reddit.com/..."
---
# What's a skill that looks easy but is actually hard?
Full body text of the post…
---
---
id: "1vd3ws9"
title: "Another post"
author: "someone_else"
created_utc: 1754132500
---
# Another post
Another body…
- Frontmatter uses the minimal field set:
id, title, author, created_utc, score, subreddit, permalink, num_comments, url. - Posts get an H1 title; comments render their
bodyas prose. include_comments=trueinlines nested comments under their parent, quoted
by depth. Defaults tofalseto keep payloads small.- Intended for RAG pipelines, LLM context, document ingestion, and AI training
datasets. - All tiers.
7. Custom templates
format=custom(name) applies a user-defined schema. See
Custom Templates. Available on all tiers.
Unknown format:
400 Unknown format: X. Use 'reddit', 'minimal', 'ndjson', 'csv', 'markdown', or 'custom(name)'.
Custom Templates
Custom templates define your own response shape. Pick the fields you want,
rename them, nest them, or set fixed values. Create templates in the
dashboard under Response Templates. Apply them with format=custom(name).
Template schema
A template maps output field names to source paths or literal values:
{
"name": "myTemplate",
"schema": {
"id": "$.id",
"title": "$.title",
"link": "$.permalink",
"score": "$.score",
"source": "reddit"
}
}
Values that start with $ are paths into the source item. Other values pass
through as literals.
Path syntax
$.field: a top-level field$.a.b.c: a nested field- The path applies to each item after the envelope is unwrapped
- A missing field becomes
null - A path that hits an array maps across the items
Common paths: id, title, selftext, body, author, created_utc,
score, subreddit, permalink, num_comments, url, upvote_ratio,
over_18, removed_by_category.
Examples
Example 1: a tweet-style export:
{
"name": "tweets",
"schema": {
"id": "$.id",
"text": "$.selftext",
"author": "$.author",
"date": "$.created_utc",
"score": "$.score"
}
}
curl -H "X-API-KEY: syl_..." \
"https://api.sylvia-api.com/v1/reddit/r/Python/hot?limit=5&format=custom(tweets)"
[
{ "id": "1vd3wrd", "text": "...", "author": "someone", "date": 1754132400, "score": 48210 }
]
Example 2: a nested structure:
{
"name": "nested",
"schema": {
"meta": { "id": "$.id", "sub": "$.subreddit" },
"content": { "title": "$.title", "body": "$.selftext" }
}
}
Example 3: fixed values for provenance:
{
"name": "enriched",
"schema": {
"id": "$.id",
"source": "reddit",
"collected_at": "$.created_utc"
}
}
Behavior:
- A single-item response (for example
/about) returns one object. - A listing returns an array of objects.
- Use
$.bodyfor comments and$.selftextfor posts.
Limits and lifecycle
| Tier | Max templates |
|---|---|
| Free | 1 |
| Strela | 5 |
| Svetka / Enterprise | unlimited |
- Templates are scoped to your account.
- If a paid tier lapses,
custom()returns 403TIER_EXPIRED. Templates are
removed after 24 hours locked unless you top up. - A missing template returns 404
Template 'X' not found.
Variations
You can shape any endpoint output along four axes. Combine them freely.
Sort
| Sort | Endpoint | Meaning |
|---|---|---|
| hot | /r/{sub}/hot |
Default feed order |
| new | /r/{sub}/new |
Newest first |
| top | /r/{sub}/top |
Highest score |
| rising | /r/{sub}/rising |
Trending up |
| controversial | /r/{sub}/controversial |
Highest controversy |
Applies to r/all and domain listings too.
Time window
t= filters top and controversial:
| Value | Window |
|---|---|
hour |
Last hour |
day |
Today |
week |
This week |
month |
This month |
year |
This year |
all |
All time |
curl -H "X-API-KEY: syl_..." \
"https://api.sylvia-api.com/v1/reddit/r/Python/top?t=week&limit=50"
Format
Every data endpoint accepts a format= parameter. See
Response Formats for the full reference: that section is
the single source of truth for formats and their tier requirements.
Listing
Subreddit endpoints vary by the last path segment:
| Variation | Returns |
|---|---|
/r/{sub}/about |
Metadata: name, members, description, is_private, over18, icon_img, created_utc |
/r/{sub}/about/rules |
Rules list |
/r/{sub}/sticky |
Sticky posts |
/r/{sub}/wiki/pages |
Wiki page list |
/r/{sub}/wiki/{page} |
Wiki page content |
/r/{sub}/comments/live |
Live comment stream ($0.05) |
API Reference: Data Endpoints
Base: https://api.sylvia-api.com/v1/reddit. All require X-API-KEY.
Subreddits
| Endpoint | Description |
|---|---|
GET /r/{sub}/about |
Subreddit metadata |
GET /r/{sub}/about/rules |
Rules list |
GET /r/{sub}/{sort} |
Posts: hot, new, top, rising, controversial |
GET /r/{sub}/comments/live |
Live comment stream ($0.05) |
GET /r/{sub}/sticky |
Sticky posts |
GET /r/{sub}/wiki/pages |
Wiki page list |
GET /r/{sub}/wiki/{page} |
Wiki page content |
GET /r/{sub}/about
curl -H "X-API-KEY: syl_..." "https://api.sylvia-api.com/v1/reddit/r/rust/about"
{ "data": { "name": "rust", "members": 418274, "is_private": false, "over18": false, "created_utc": 1291325238 } }
GET /r/{sub}/about/rules
curl -H "X-API-KEY: syl_..." "https://api.sylvia-api.com/v1/reddit/r/rust/about/rules"
{ "data": { "rules": [{ "description": "Strive to treat others with respect.", "priority": 1 }] } }
GET /r/{sub}/{sort}
curl -H "X-API-KEY: syl_..." "https://api.sylvia-api.com/v1/reddit/r/rust/top?t=week&limit=10"
{ "data": { "after": "t3_1vn95fs", "posts": [{ "title": "A Bluetooth keyboard and mouse emulator", "score": 48210, "subreddit": "rust" }] } }
GET /r/{sub}/comments/live
curl -H "X-API-KEY: syl_..." "https://api.sylvia-api.com/v1/reddit/r/rust/comments/live?limit=10"
{ "data": { "after": "t1_p3z8fnl", "comments": [{ "body": "Great writeup.", "author": "someone", "subreddit": "rust" }] } }
GET /r/{sub}/sticky
curl -H "X-API-KEY: syl_..." "https://api.sylvia-api.com/v1/reddit/r/rust/sticky"
{ "data": [{ "data": { "children": [{ "data": { "title": "Weekly questions thread", "stickied": true } }] } }] }
GET /r/{sub}/wiki/pages
curl -H "X-API-KEY: syl_..." "https://api.sylvia-api.com/v1/reddit/r/rust/wiki/pages"
{ "data": { "data": ["config/description", "config/sidebar", "rules"] } }
GET /r/{sub}/wiki/{page}
curl -H "X-API-KEY: syl_..." "https://api.sylvia-api.com/v1/reddit/r/rust/wiki/config/description"
{ "data": { "content": "A place for all things Rust…", "revision_date": 1720000000 } }
Users
| Endpoint | Description |
|---|---|
GET /u/{username}/about |
Profile metadata: karma, age, icon |
GET /u/{username}/submitted |
User's posts |
GET /u/{username}/comments |
User's comments |
GET /u/{username}/overview |
Posts and comments combined |
GET /u/{username}/about
curl -H "X-API-KEY: syl_..." "https://api.sylvia-api.com/v1/reddit/u/spez/about"
{ "data": { "name": "spez", "comment_karma": 756480, "created_utc": 1118030400, "is_employee": true } }
GET /u/{username}/submitted
curl -H "X-API-KEY: syl_..." "https://api.sylvia-api.com/v1/reddit/u/spez/submitted?limit=10"
{ "data": { "after": "t3_1tvsa59", "items": [{ "title": "…", "subreddit": "announcements", "created_utc": 1785945836 }] } }
GET /u/{username}/comments
curl -H "X-API-KEY: syl_..." "https://api.sylvia-api.com/v1/reddit/u/spez/comments?limit=10"
{ "data": { "after": "t1_p1w9j2v", "items": [{ "body": "That was the thinking.", "subreddit": "announcements" }] } }
GET /u/{username}/overview
curl -H "X-API-KEY: syl_..." "https://api.sylvia-api.com/v1/reddit/u/spez/overview?limit=10"
{ "data": { "after": "t1_p1w9j2v", "items": [{ "kind": "t1", "body": "…" }, { "kind": "t3", "title": "…" }] } }
Posts and comments
| Endpoint | Description |
|---|---|
GET /submission?url={reddit_url} |
A post by URL |
GET /comment?url={reddit_url} |
A comment by URL |
GET /submission/{post_id}/full |
A full thread, comments resolved recursively |
GET /duplicates/{submission_id} |
Crosspost duplicates |
GET /domain/{domain}/{sort} |
Posts that link to a domain |
GET /morechildren?link_id=&children= |
Expand comment IDs |
GET /by_id?names=t3_abc,t3_def |
Fetch by fullnames (max 100) |
GET /submission
curl -H "X-API-KEY: syl_..." \
"https://api.sylvia-api.com/v1/reddit/submission?url=https://www.reddit.com/r/rust/comments/1vd3wrd/"
{ "data": { "id": "1vd3wrd", "title": "…", "author": "FriendlytoNature", "num_comments": 6769 } }
GET /comment
curl -H "X-API-KEY: syl_..." \
"https://api.sylvia-api.com/v1/reddit/comment?url=https://www.reddit.com/r/rust/comments/1vd3wrd/comment/xyz/"
{ "data": { "id": "xyz", "body": "…", "author": "mellowmonk", "score": 1 } }
GET /submission/{post_id}/full
curl -H "X-API-KEY: syl_..." "https://api.sylvia-api.com/v1/reddit/submission/1vd3wrd/full"
{ "data": { "thread": [{ "data": { "children": [{ "kind": "t1", "data": { "body": "…", "replies": { "data": { "children": [] } } } }] } }] } }
GET /duplicates/{submission_id}
curl -H "X-API-KEY: syl_..." "https://api.sylvia-api.com/v1/reddit/duplicates/1vd3wrd"
{ "data": { "after": null, "posts": [{ "id": "…", "title": "…", "subreddit": "rust" }] } }
GET /domain/{domain}/{sort}
curl -H "X-API-KEY: syl_..." "https://api.sylvia-api.com/v1/reddit/domain/github.com/hot?limit=10"
{ "data": { "after": "t3_1vplh09", "posts": [{ "title": "…", "domain": "github.com", "subreddit": "programming" }] } }
GET /morechildren
curl -H "X-API-KEY: syl_..." \
"https://api.sylvia-api.com/v1/reddit/morechildren?link_id=t3_1vd3wrd&children=t1_abc,t1_def"
{ "data": { "json": { "data": { "things": [{ "kind": "t1", "data": { "body": "…" } }] } } } }
GET /by_id
curl -H "X-API-KEY: syl_..." "https://api.sylvia-api.com/v1/reddit/by_id?names=t3_1vd3wrd,t3_1vplh09"
{ "data": { "data": { "children": [{ "kind": "t3", "data": { "id": "1vd3wrd", "title": "…" } }] } } }
Search and discovery
| Endpoint | Description |
|---|---|
GET /search?q= |
Global search ($0.05) |
GET /subreddits/{category} |
popular, default, new, premium |
GET /subreddits/search?q= |
Search subreddits by name or description |
GET /subreddit_autocomplete?q= |
Autocomplete subreddit names |
GET /r/all/{sort} |
r/all feed |
GET /comments/live |
Global comment stream ($0.05) |
GET /search
curl -H "X-API-KEY: syl_..." "https://api.sylvia-api.com/v1/reddit/search?q=rust&limit=10"
{ "data": { "after": "t3_1vpp3dq", "results": [{ "title": "…", "subreddit": "playrust", "score": 42 }] } }
GET /subreddits/{category}
curl -H "X-API-KEY: syl_..." "https://api.sylvia-api.com/v1/reddit/subreddits/popular?limit=10"
{ "data": { "after": "t5_2w844", "subreddits": [{ "name": "AskReddit", "subscribers": 46000000 }] } }
GET /subreddits/search
curl -H "X-API-KEY: syl_..." "https://api.sylvia-api.com/v1/reddit/subreddits/search?q=rust"
{ "data": { "subreddits": [{ "name": "rust", "subscribers": 418274 }] } }
GET /subreddit_autocomplete
curl -H "X-API-KEY: syl_..." "https://api.sylvia-api.com/v1/reddit/subreddit_autocomplete?q=ru"
{ "data": { "subreddits": [{ "name": "rust", "numSubscribers": 418274 }] } }
GET /r/all/{sort}
curl -H "X-API-KEY: syl_..." "https://api.sylvia-api.com/v1/reddit/r/all/hot?limit=10"
{ "data": { "after": "t3_1vpkut8", "posts": [{ "title": "…", "subreddit": "…", "score": 12000 }] } }
GET /comments/live
curl -H "X-API-KEY: syl_..." "https://api.sylvia-api.com/v1/reddit/comments/live?limit=10"
{ "data": { "after": "t1_…", "comments": [{ "body": "…", "author": "…", "subreddit": "…" }] } }
Search parameters:
| Param | Type | Notes |
|---|---|---|
q |
string | required |
sort |
string | new (default) or relevance |
limit |
int | 1–100 |
after / before |
string | pagination cursors |
subreddit |
string | scope to a subreddit |
include_over_18 |
bool | include NSFW |
type |
string | posts or comments |
Error Handling
| HTTP | Meaning |
|---|---|
| 200 | Success |
| 400 | Bad request, invalid params, unknown format |
| 401 | Missing API key |
| 402 | Insufficient credits or budget |
| 403 | Invalid key, forbidden endpoint, feature locked |
| 404 | Not found, unknown route, template not found |
| 429 | Rate limited, includes Retry-After |
| 502 | All engines failed |
| 503 | Service unavailable |
Gateway error body:
{
"error": {
"message": "Invalid or inactive API Key",
"status": 403,
"code": "FORBIDDEN",
"timestamp": "ISO-8601",
"path": "/v1/reddit/r/AskReddit/about"
}
}
Error codes:
| Code | Meaning |
|---|---|
FORBIDDEN |
Bad key, forbidden endpoint |
FEATURE_LOCKED |
Format or template above tier limit |
TIER_EXPIRED |
Templates locked after tier lapse |
NOT_FOUND |
Unknown route |
RATE_LIMITED |
429 |
Retry: on 429, respect Retry-After. On 502 or 503, retry with exponential
backoff. On 4xx, fix the request. Do not retry blindly.
Model Context Protocol (MCP)
Sylvia exposes a Model Context Protocol server so LLM agents (Claude, ChatGPT,
Cursor, Windsurf, etc.) can call the same data layer as the REST API. Two ways
to run it: hosted (no install) or self-hosted (local process).
The MCP server exposes three tool groups:
Read tools (23): the Reddit data reads, mirroring the REST data endpoints:
subreddit_about, subreddit_posts, subreddit_rules, subreddit_sticky,
subreddit_wiki, subreddit_wiki_pages, subreddits, subreddits_search,
subreddit_autocomplete, user_about, user_posts, user_comments,
user_overview, submission, comment, thread, search, search_advanced,
comments_live, subreddit_comments_live, domain, duplicates, by_id.
Account tools (7): account management, mirroring the account REST
endpoints: account_me, list_keys, create_key, delete_key,
create_payment, recent_requests, usage_history.
Format & template tools (5): manage formats and custom templates:
list_formats, set_default_format, list_templates, create_template,
delete_template.
Auth: read tools use the X-API-KEY header (your syl_ key). Account and
format/template tools use your account token (SV_): send it as an
x-sylvia-auth header alongside the API key. The account/format tools are
gated by the same tier logic as the REST API (e.g. create_template obeys
your tier's template limit, set_default_format rejects formats above your
tier with 403 FEATURE_LOCKED).
Hosted MCP
Point your agent at the managed endpoint: no npm install, no local process.
Send both credentials so read and account tools work:
{
"mcpServers": {
"sylvia": {
"url": "https://api.sylvia-api.com/mcp",
"headers": {
"X-API-KEY": "syl_your_key",
"x-sylvia-auth": "SV_your_account_token"
}
}
}
}
The hosted server returns format=markdown by default for read tools (the
natural shape for LLM context). Pass a format argument to any read tool to
override (e.g. format: "csv", format: "reddit").
Self-hosted MCP
Run the server locally with the npm package:
npx @sylvia-api/reddit-mcp --api-key syl_your_key
Register it with your agent as a stdio server:
{
"mcpServers": {
"sylvia": {
"command": "npx",
"args": ["@sylvia-api/reddit-mcp", "--api-key", "syl_your_key"]
}
}
}
Note: the self-hosted server defaults to raw JSON (not markdown) and does
not enable the account/format tools unless you pass an account token. Whether
to align its defaults with the hosted server is an open question: flagged,
not assumed.
Hosted vs self-hosted
| Hosted MCP | Self-hosted MCP | |
|---|---|---|
| Where it runs | Sylvia's infrastructure | Your machine |
| Setup | Add a URL + headers to agent config | npx @sylvia-api/reddit-mcp --api-key … |
| Default format | markdown |
raw JSON |
| Account/format tools | Enabled (with account token) | Requires account token via --account-token |
| Updates | Automatic | npm update -g or re-run npx |
| Data layer | Same as REST | Same as REST |
Example tool call
An agent asked for the top posts in r/rust:
{
"name": "subreddit_posts",
"arguments": { "subreddit": "rust", "sort": "top", "limit": 5 }
}
The hosted server returns markdown by default (raw JSON on free/strela):
{
"content": [
{
"type": "text",
"text": "---\nid: \"1vd3wrd\"\ntitle: \"A Bluetooth keyboard and mouse emulator\"\nscore: 48210\nsubreddit: \"rust\"\n---\n\n# A Bluetooth keyboard and mouse emulator\n\n…"
}
]
}
SDKs
Official SDKs wrap the REST API. They mirror the endpoints in
API Reference; install one to get typed
clients and helpers instead of hand-writing HTTP.
| Language | Package | Install | Registry |
|---|---|---|---|
| Python | sylvia-api |
pip install sylvia-api |
PyPI |
| JavaScript / TypeScript | @sylvia-api/reddit-mcp |
npm install @sylvia-api/reddit-mcp |
npm |
| Rust | sylvia-api |
cargo add sylvia-api |
crates.io |
# Python
pip install sylvia-api
# JavaScript / TypeScript
npm install @sylvia-api/reddit-mcp
# Rust
cargo add sylvia-api
- The JavaScript package ships full TypeScript types and doubles as the
self-hosted MCP server: see Self-hosted MCP. - Sources and examples live under the
c1nn3rGitHub account.
SDK Examples
Python: page through all results
import requests
API = "https://api.sylvia-api.com/v1/reddit"
H = {"X-API-KEY": "syl_..."}
def fetch_all(path, limit=100, **params):
"""Follow after-cursors until the end."""
items, after = [], None
while True:
p = {"limit": limit, **params}
if after:
p["after"] = after
r = requests.get(f"{API}{path}", headers=H, params=p).json()
batch = r["data"].get("posts") or r["data"].get("items") or []
items += batch
after = r["data"].get("after")
if not after:
break
return items
posts = fetch_all("/r/AskReddit/top", t="week")
Python: CSV into pandas
import pandas as pd
import requests
r = requests.get(f"{API}/r/Python/hot", headers=H,
params={"limit": 100, "format": "csv"})
df = pd.read_csv(pd.io.common.StringIO(r.text))
Node.js: typed fetch
async function reddit(path, params = {}) {
const url = new URL(`https://api.sylvia-api.com/v1/reddit${path}`);
Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, v));
const res = await fetch(url, { headers: { "X-API-KEY": process.env.SYLVIA_KEY } });
if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`);
return res.json();
}
const data = await reddit("/u/spez/submitted", { limit: 50, format: "minimal" });
Best Practices
- Use
format=minimalorcustom()for production reads (see
Response Formats). Payloads are smaller, which means
lower latency. - Use
aftercursors, not page numbers. Cursors stay stable under
concurrent writes. - Cap
limitat 100 for deterministic results. For more, loop cursors. - Batch with
by_id(up to 100 fullnames) instead of many single fetches.
One request is one charge. - On 429, respect
Retry-After. On 502 or 503, use exponential backoff. - Watch
X-RateLimit-Remainingand slow down before it reaches zero. - Save keys at creation. They are shown once.
- For AI datasets: use ndjson, loop cursors, and add provenance fields with
custom(). - For PRAW migrations:
format=redditreturns the Listing envelope. Point
your PRAW parser at the JSON. - For agents: use the MCP endpoint. It has 23 read tools plus account and
format management: see Model Context Protocol (MCP).
FAQ
Do I need OAuth or a Reddit account?
No. You only need a Sylvia API key.
What counts as a billable request?
A request that completes successfully. Auth failures, rate limits, and
service errors are free.
Why is search $0.05 and a listing $0.0005?
Search and live streams cost more to serve. Everything else is standard.
How do custom templates work on single-item endpoints?
A single-item response returns one object. A listing returns an array. The
schema applies per item.
Can I share templates across accounts?
No. Templates are scoped to your account.
What happens when a paid tier expires?
Formats lock to the free set. custom() returns 403 TIER_EXPIRED.
Templates are removed after 24 hours locked unless you top up.
Do you store my data?
Sylvia fetches Reddit data on demand and returns it. Request history is
in-memory and visible only to the key owner.
Documentation maintained at sylvia-api.com/docs (v3.4.0).