Public Content API
Find and download public content for your application
Public Content API
Browse public cards, lorebooks, presets, personas, prompt guides, regex scripts, and series. Download supported content in portable formats without an SDK, account, API key, or RoleCall installation.
Base URL: https://plotlightstudios.com
Access: read-only, guest permissions. Requests do not use inference tokens.
Start here
Search any supported content type through one endpoint:
curl --fail-with-body --get \
'https://plotlightstudios.com/api/v1/content' \
--data-urlencode 'type=cards' \
--data-urlencode 'q=wizard' \
--data-urlencode 'limit=10'
Download a returned item by its UUID:
curl --fail-with-body \
'https://plotlightstudios.com/api/v1/content/cards/CARD_UUID?format=json' \
-o character.json
Replace CARD_UUID with an actual result. Every result includes ready-to-use downloads links. Resolve relative links against the base URL.
const downloadUrl = new URL(item.downloads.json, 'https://plotlightstudios.com');
Routes
| Route | Purpose |
|---|---|
/api/v1/content?type=cards | Search a content pool |
/api/v1/content/{type} | The same search, with type in the path |
/api/v1/content/{type}/{id} | Download its default portable format |
/api/v1/content/{type}/{id}?format=... | Choose a download format |
/api/v1/content/{type}/{id}/download | Equivalent explicit download route |
/api/v1/content/tags | Paginated native tag catalog |
All routes support GET, HEAD, and CORS OPTIONS. Unsupported methods return 405. IDs must be UUIDs. Existing character and lorebook URLs remain supported.
Content types
type | What you get | Download formats |
|---|---|---|
cards or characters | Published, exportable character cards | json, json3, backyard, png, png3 |
lorebooks | Published lorebooks | st |
presets | Published preset editions from their public listing | legacy, nemo-wiki |
personas | Published personas | json |
guides | Published, visible prompt guides | st, json |
regex or regex-scripts | Published regex scripts | st |
series | Published collection metadata | No portable download |
The first format listed is the default. type defaults to characters. Art galleries and image-generation records are excluded. Series exports currently require the signed-in application; the public API does not offer the ZIP bundle.
Native tag filtering
Clients can recreate discovery's category picker using the actual tag catalog. Each tag includes its id, slug, name, category, subcategory, description, and content applicability flags.
curl --fail-with-body \
'https://plotlightstudios.com/api/v1/content/tags?type=cards&category=genre&limit=100'
Tag catalog arguments:
| Argument | Meaning |
|---|---|
type | cards, characters, personas, presets, or lorebooks; omit for all applicable types |
category | Exact native category identifier, such as genre or species |
include_after_dark | true includes adult tag labels; default false. This does not grant access to adult content |
limit | 1-100; default 100 |
offset | 0-10000; default 0 |
Use the returned slugs verbatim. Slugs are not reliably derived from display names. The tag endpoint uses the same data and pagination envelope as content search.
Include and exclude together
tags requires all selected tags. exclude_tags rejects content carrying any excluded tag. Both accept up to 10 comma-separated slugs, each at most 50 characters, across native categories.
const url = new URL('/api/v1/content', 'https://plotlightstudios.com');
url.searchParams.set('type', 'cards');
url.searchParams.set('tags', selectedTags.map(tag => tag.slug).join(','));
url.searchParams.set('exclude_tags', excludedTags.map(tag => tag.slug).join(','));
url.searchParams.set('sort', 'popular');
url.searchParams.set('limit', '20');
const response = await fetch(url, { credentials: 'omit' });
if (!response.ok) throw new Error(`Search failed: ${response.status}`);
const page = await response.json();
Omit empty tag lists. Unknown included slugs return no matches; unknown excluded slugs exclude nothing. Selecting and excluding the same tag produces no matches.
Guides and regex scripts currently have no native tag assignments, so their catalogs reject tags and exclude_tags. Their search modes still work. Series supports included tags; its current discovery owner does not support tag exclusions, so that argument is rejected for series.
Search arguments
Common arguments:
| Argument | Default | Meaning |
|---|---|---|
q | Omitted | Search text, up to 200 characters |
mode | names | Field to search; supported values depend on content type below |
tags | Omitted | Require all selected native tag slugs |
exclude_tags | Omitted | Exclude any selected native tag slug, where supported |
sort | recent | recent, popular, rating; uses native discovery's ordering |
limit | 30 | Integer 1-100 |
offset | 0 | Integer 0-10000 |
Search modes:
| Content | Supported mode values |
|---|---|
| Cards | names, creators, tags, fandoms, genres |
| Lorebooks | names, creators, genres, types |
| Presets | names, creators, styles, models |
| Personas, regex, series | names, creators |
| Guides | names, genres (category), types (guide type) |
Additional native filters:
| Argument | Content | Meaning |
|---|---|---|
min_rating | Cards | Minimum rating, 0-5; decimals allowed |
has_vn | Cards | true or 1 requires visual-novel data |
min_roses | Lorebooks, presets | Minimum native download/rose count |
min_favorites | Lorebooks, presets, personas, regex, series | Minimum favorite count |
has_compendium | Lorebooks | true or 1 requires compendium data |
model_families | Presets | Up to 10 comma-separated native model-family identifiers, each at most 20 characters |
min_prompts | Presets | Minimum prompt count, integer 0-1000 |
min_forks | Presets | Minimum fork count |
Count minimums are integers from 0 to 1000000. Boolean feature filters also accept false or 0 to remove that requirement; they do not mean 'only items without the feature'.
Combine arguments freely within a content type:
curl --fail-with-body --get \
'https://plotlightstudios.com/api/v1/content/presets' \
--data-urlencode 'q=roleplay' \
--data-urlencode 'mode=names' \
--data-urlencode 'min_prompts=5' \
--data-urlencode 'min_favorites=10' \
--data-urlencode 'sort=popular'
Unknown arguments, repeated arguments, unsupported modes, filters for another content type, and invalid values return 400. Parameters are case-sensitive. This prevents a typo from silently broadening your search.
Results and pagination
{
"data": [
{
"id": "11111111-1111-4111-8111-111111111111",
"type": "characters",
"name": "Forest Mage",
"description": "A mage who guards an ancient forest.",
"image_url": null,
"updated_at": null,
"creator": { "name": "Example Creator", "username": "example" },
"tags": [],
"detail_url": "/discovery/characters/11111111-1111-4111-8111-111111111111",
"downloads": {
"json": "/api/v1/content/characters/11111111-1111-4111-8111-111111111111/download?format=json"
}
}
],
"pagination": { "limit": 20, "offset": 0, "has_more": false, "next_offset": null }
}
This is illustrative data. Actual download maps include every supported format. Aliases return the canonical type (cards returns characters). Descriptions, preview images, timestamps, and creator fields may be null or absent. Public tag fields include id, name, slug, and category.
Preserve filters and limit when requesting pagination.next_offset. Stop when it is null, not when data is empty. Native discovery can remove items after fetching a page, leaving short pages even when more results exist. At offset 10000 there may be more matches but no further page is offered. Results are live, not a database snapshot; totals are not supplied.
Portable files
Downloads return the file itself with a suggested filename in Content-Disposition. They do not return a search envelope. format is the only download argument.
- Cards:
jsonis Character Card V2;json3is V3.pngembeds V2 metadata in the portrait;png3embeds V3 plus V2 compatibility metadata.backyardis Backyard/Faraday JSON. Permitted export-enabled lorebooks are merged intocharacter_book. - Lorebooks:
stis SillyTavern worldbook JSON. - Presets:
legacyandnemo-wikiuse the existing SillyTavern-compatible serializers. Supported prompts, sampler settings, and portable regex rules are included. - Personas:
jsoncontains character-style persona fields, without RoleCall runtime extensions. - Guides:
standjsoncontain a SillyTavern prompt list with one guide. - Regex:
stcontains SillyTavern regex rules: one object for a single rule, an array for multiple rules. Treat regex and replacement text as untrusted data in your importer.
RoleCall-only trackers, props, loadouts, private dependencies, and account settings are not portable API payloads. A download is not a complete artwork archive. Preview URLs are image references; PNG cards include the main portrait. V3 cards may include supported sprite references that need separate fetching.
Check HTTP status before saving a response so an error JSON is not saved as a content file.
Browser and extension access
CORS permits public reads. Send credentials: 'omit'; no Authorization header is needed. Login cookies never widen public API permissions. Use a returned download URL rather than constructing one when possible.
const response = await fetch(
new URL(item.downloads.png, 'https://plotlightstudios.com'),
{ credentials: 'omit' },
);
if (!response.ok) throw new Error(`Download failed: ${response.status}`);
const file = await response.blob();
There is no private-library connection or write API. Native guest visibility rules apply, including After Dark restrictions. Listing adult tag labels does not change content access.
Errors and responsible use
| Status | Meaning |
|---|---|
| 400 | Invalid query, format, or UUID |
| 401 / 403 | Content cannot be exported to this audience |
| 404 | Unknown resource, missing content, or unavailable download |
| 429 | Rate limited; slow down |
| 500 / 503 | Temporary server or dependency failure |
Errors have an error message. Downloads recheck current publication and access rules; a previous search result does not guarantee later availability. Responses are not cached by shared CDNs.
Use Retry-After when supplied and respect exposed X-RateLimit-* headers. Rate limits are enforced independently by the search and export owners. Debounce searches, avoid parallel bulk downloads, and back off on 429. Public availability does not grant permission to republish creators' work; preserve attribution and honor withdrawals.