Yappy REST API
Base URL: **https://yappy.biz/api/v1**
Read endpoints are public and need no credentials. Responses are JSON (application/json; charset=utf-8) and errors are RFC 9457 problem documents (application/problem+json). Every response carries an API-Version header.
The complete contract is [/openapi.json](https://yappy.biz/openapi.json) — OpenAPI 3.1, with an operationId, a description, and a typed response schema on every operation, which is what makes it usable as an LLM function-calling toolset without hand-writing wrappers.
Discovery
curl -s https://yappy.biz/api/v1
Returns the endpoint index, the current API version date, the rate-limit policy, and links to the spec, the MCP server, and the auth metadata.
Endpoints
| Method | Path | What it returns |
|---|---|---|
| GET | /api/v1 | Service index |
| GET | /api/v1/releases | Release history, newest first, paginated |
| GET | /api/v1/releases/latest | The current release, from the live appcast |
| GET | /api/v1/releases/{version} | One release by version string |
| GET | /api/v1/docs | Documentation index, paginated |
| GET | /api/v1/docs/{slug} | One documentation page, as markdown |
| GET | /api/v1/faq | Frequently asked questions, paginated |
| GET | /api/v1/pricing | Plans and backend costs |
| GET | /api/v1/features | Product capabilities |
| GET | /api/v1/requirements | System requirements |
| GET | /api/v1/compatibility | Whether a given Mac can run Yappy |
| GET | /api/v1/search | Full-text search over docs and FAQ |
| POST | /api/v1/batch | Up to 20 GET operations in one round trip |
| POST | /api/v1/exports | Start an export job (202) |
| GET | /api/v1/exports/{job_id} | Poll an export job |
Pagination
List endpoints are cursor-paginated. Pass limit (1–100, default 20) and cursor:
curl -s "https://yappy.biz/api/v1/releases?limit=2"
{
"object": "list",
"data": [ { "object": "release", "version": "0.4.19" } ],
"pagination": {
"limit": 2,
"has_more": true,
"next_cursor": "cmVsZWFzZXM6Mg"
}
}
next_cursor is opaque — pass it back verbatim as cursor. When has_more is false, next_cursor is null. A Link header with rel="next" carries the same URL for clients that prefer RFC 8288.
Versioning and deprecation
The major version is in the path (/api/v1). Additive changes — new fields, new endpoints, new enum members — ship inside v1 without notice, so parse leniently and ignore fields you do not know.
Breaking changes get a new major version. When a version is scheduled for removal, every response from it carries:
Deprecation: true
Sunset: Wed, 01 Jul 2026 00:00:00 GMT
Link: <https://yappy.biz/developers/rest-api>; rel="deprecation"
with at least 180 days between the first Deprecation header and the Sunset date. v1 is current and carries neither.
The dated API-Version response header (for example 2026-08-25) tells you which build of v1 answered.
Batch
One round trip, up to 20 read operations:
curl -sX POST https://yappy.biz/api/v1/batch \
-H 'content-type: application/json' \
-H 'Idempotency-Key: 0f4c2b1a-batch-1' \
-d '{"operations":[
{"id":"rel","method":"GET","path":"/releases/latest"},
{"id":"faq","method":"GET","path":"/faq?limit=2"}
]}'
Each result carries the id you supplied, a status, and a body. One failing operation does not fail the batch — you get its problem document in that entry's body and the rest still succeed.
Async jobs
Exports are modelled as jobs so a slow one never blocks a request:
curl -isX POST https://yappy.biz/api/v1/exports \
-H 'content-type: application/json' \
-H 'Idempotency-Key: docs-export-1' \
-d '{"resource":"docs","format":"markdown"}'
HTTP/2 202
Location: https://yappy.biz/api/v1/exports/ZG9jczptYXJrZG93bg
Retry-After: 1
{ "object": "job", "id": "ZG9jczptYXJrZG93bg", "status": "queued",
"resource": "docs", "poll_url": "https://yappy.biz/api/v1/exports/ZG9jczptYXJrZG93bg" }
Poll poll_url until status is completed, then read result.url. Statuses are queued, running, completed, failed.
Idempotency
Send an Idempotency-Key header on any POST. The key is echoed back on the response and, for exports, determines the job id — so retrying a request that timed out returns the same job rather than starting a second one.
Yappy's write operations are pure functions of their request body, so a replay can never double-charge or duplicate a record. The header exists so your retry logic does not have to know that.
Conditional requests
Every GET returns a strong ETag. Send it back as If-None-Match and you get a 304 Not Modified with no body, which is the cheapest way to poll for a new release.
Rate limits and errors
See rate limits and errors.