Developers
Public, machine-readable interfaces to the Denpasoft catalog.
Overview
The Denpasoft public API is a free, read-only set of HTTP endpoints serving the published catalog directly from the edge. No API keys, no authentication, no per-user state: every documented endpoint returns the same data to every caller. Use it to build search tools, catalog browsers, feed readers, or link previews.
A machine-readable description of the JSON endpoints is published at /openapi.json (OpenAPI 3.1).
Stability policy
Endpoints documented on this page follow a stable-contract rule:
- Publicly documented means identity-free (the response never depends on who is asking) and edge-terminated (served from our edge, not proxied per-request to a backend).
- Changes are additive only: new optional fields may appear in responses at any time; existing fields will not change meaning or type.
- Breaking changes get a new path. Existing paths keep their contract.
Anything not documented on this page — including other paths under /api/ — is internal and may change or disappear without notice.
Do not build against it.
Conventions
- All endpoints are
GET. -
Errors are JSON:
{ "code": string, "message": string }. -
Rate-limited requests return
429. -
Most product-list responses share one envelope:
{ "results": SearchHit[] }. The paginated catalog listing (/api/public/v1/catalog/list) is the exception — it returns{ products, total, totalPages }. -
The product page for a hit is
https://denpasoft.com/product/{slug}.
A SearchHit is a product card object:
{
"databaseId": 123, // number — stable product id
"slug": "example-title", // string — /product/{slug}
"name": "Example Title", // string
"imageUrl": "https://…", // string | null — cover image
"regularPrice": "24.99", // string | null
"salePrice": "19.99", // string | null
"onSale": false // boolean
} New optional fields may be added to SearchHit over time (additive-only policy); ignore fields you do not recognize.
Endpoints
GET /api/search
Instant text search over the published catalog. Example: https://denpasoft.com/api/search?q=clover&limit=8
| Parameter | Description |
|---|---|
q |
Search text. Queries shorter than 2 characters return an empty result list (still
200).
|
limit | Optional. Maximum hits to return: 1–12, default 8. Out-of-range values are clamped, not rejected. |
-
The parameter set is closed: any query parameter other than
qandlimitreturns400. -
Response:
{ "results": SearchHit[] }. A query with no matches returns an empty list, not an error. -
Errors:
400(unknown parameter),429(rate limited). - Caching:
no-store— do not cache responses.
GET /api/catalog/by-ids
Hydrate a list of product ids into SearchHit objects. Example: https://denpasoft.com/api/catalog/by-ids?ids=101,102,103
| Parameter | Description |
|---|---|
ids |
Required. Comma-separated positive integers. Duplicates are removed (first occurrence
wins; input order is preserved in the response). At most 20 ids are used — extras are
silently ignored. If no valid id survives parsing (missing, empty, or wholly
malformed), the request is rejected with 400.
|
-
The parameter set is closed: only
idsis accepted; any other parameter returns400. -
Response:
{ "results": SearchHit[] }. Ids that do not resolve to a published product are dropped silently; surviving hits keep the input order. -
Errors:
400,429. - Caching:
no-store.
GET /api/public/v1/catalog/list
Page through the published catalog — everything, newest, on sale, featured, or filtered by
category, brand, or developer. This is the stable third-party catalog listing. Example: https://denpasoft.com/api/public/v1/catalog/list?scope=new&page=1&per_page=24
| Parameter | Description |
|---|---|
scope |
Optional. One of all, new, sale, featured, category, brand, or developer. An unsupported value — or a scope whose
required slug is missing — yields an empty page (still 200).
|
category |
Category slug. Required when scope=category.
|
publisher |
Brand/publisher slug. Required when scope=brand, or
pass it on any scope as a cross-axis filter.
|
developer |
Developer slug. Required when scope=developer, or pass
it on any scope as a cross-axis filter.
|
page | Optional. 1-based page number; out-of-range or non-numeric values fall back to 1. |
per_page | Optional. Page size, clamped to 1–48 (default 24). |
-
The parameter set is closed: any query parameter other than
scope,category,publisher,developer,page, andper_pagereturns400. -
Response is the paginated envelope (not the shared
resultsone):{ "products": SearchHit[], "total": number, "totalPages": number }. -
Fail-open: an unavailable or incomplete catalog mirror returns
200 { "products": [], "total": 0, "totalPages": 0 }— treat an empty page as "no results", not an error. -
Errors:
400(unknown parameter),429(rate limited). - Caching:
no-store.
GET /api/recommend
Similar titles by example: pass a seed of product ids you like and get back catalog picks in
the same vein. Example: https://denpasoft.com/api/recommend?ids=101,102
| Parameter | Description |
|---|---|
ids |
Required. Comma-separated positive integers — the seed titles. Same parsing rules as by-ids, but capped at 10 seed ids. Missing or wholly
invalid → 400.
|
-
Response:
{ "results": SearchHit[] }with up to 8 picks. Seed titles are excluded from the results. -
Fail-open: when no picks are available, the response is
200 { "results": [] }— treat an empty list as "no suggestions", not an error. -
Errors:
400,429. - Caching:
no-store.
GET /api/oembed
oEmbed 1.0 provider (link type) for the storefront's embeddable
pages — public user profiles and product pages. Embeddable pages advertise this endpoint via a <link rel="alternate" type="application/json+oembed">
discovery tag. Example: https://denpasoft.com/api/oembed?url=https://denpasoft.com/profile/{publicId}&format=json
| Parameter | Description |
|---|---|
url |
Required. Absolute URL of the page to embed. Must be on the same host as the request;
a missing or unparseable value returns 400.
|
format |
Optional. Only json is supported; any other value returns
501.
|
-
Response: an oEmbed 1.0
linkpayload —version,type,title,provider_name,provider_url, plus optionalauthor_name,author_url, andthumbnail_url. -
A URL that is not embeddable — wrong host, unknown page, a private profile, or an
unindexed product — returns the same
404in every case. -
thumbnail_urlis intentionally a blurred preview image. - Caching:
no-store.
Feeds
Catalog and news feeds for readers, aggregators, and bulk consumers:
| Path | Format | Contents |
|---|---|---|
/feed/ | RSS 2.0 | Site news (latest 20 posts). |
/feed/new-releases | RSS 2.0 | Newest catalog releases. |
/feed/new-releases.json | JSON | Newest releases, JSON product envelope. |
/feed/products.json | JSON | Published-catalog product snapshot. |
/feed/products.csv | CSV | Same data as products.json, one row per product. |
/feed/sales.json | JSON | Titles currently on sale. |
/feed/theme/{term}/feed/brand/{term}/feed/developer/{term} | RSS 2.0 | Per-theme / per-brand / per-developer release feeds. |
The JSON feeds share one envelope: { "schemaVersion", "feed", "count", "products": [...] },
where each product carries id, slug, canonical URL, name, image, prices, and taxonomy terms. schemaVersion only changes on breaking revisions; new optional fields may appear within a version. JSON feeds
are CORS-enabled (Access-Control-Allow-Origin: *).
Feeds are publicly cacheable (Cache-Control: public, max-age=1800, s-maxage=3600) — honor these headers and poll no more than the cache lifetime. Degraded responses use a
short retry TTL.
Discovery surfaces
-
/sitemap-index.xml — sitemap index linking the per-section sub-sitemaps
(products, categories, brands, developers, news, and more).
/robots.txt — crawl policy and sitemap pointer. -
/opensearch.xml — OpenSearch description for browser search integration.
-
Catalog pages embed
schema.org JSON-LD structured data.
Fair use
-
All endpoints are rate-limited per IP. Sustained excess traffic receives
429responses — back off and retry later. - Cache responses wherever the headers allow it; prefer the bulk feeds over hammering the per-request endpoints.
-
Identify your client with a descriptive
User-Agent(project name plus a contact URL or email). - Security issues: see /.well-known/security.txt.
Data licensing
Parts of the catalog's tag/metadata vocabulary (e.g. the themeTags fields in the JSON feeds) contain information from VNDB, made
available under the Open Database License (ODbL) v1.0
with contents under the DbCL v1.0. JSON envelopes carry a machine-readable license stanza with the attribution notice.
If you redistribute that tag data, preserve the attribution and see /policy/data-licenses/ for scope and full terms. Everything else in the catalog (products, prices, descriptions, images) is not openly licensed.