Store API
The public HTTP endpoints of the Chataway store at chataway.co — catalog, app details, bundles and assets, signatures and revocations, publishing and review status.
Base URL: https://chataway.co. Responses are JSON unless noted. Public endpoints need no authentication and allow cross-origin requests.
Most developers only need the CLI, which wraps the publishing endpoints. These are here for tooling, CI, and anyone who wants to show their listing on their own site.
#Catalog
#GET /api/apps/catalog
Listed apps with a published version.
| Query | |
|---|---|
q | Search text (name, description, publisher). |
category | One of the categories. |
{
"apps": [
{
"appId": "com.example.acme-assets",
"name": "Acme Assets",
"tagline": "Upload images and audio from your chats to your Acme library.",
"description": "Upload images and audio from your chats to your Acme library.",
"categories": ["media", "games"],
"publisher": { "slug": "acme", "name": "Acme Inc.", "verified": true, "website": "https://example.com" },
"version": "1.2.0",
"publishedAt": "2026-09-30T10:12:00.000Z",
"iconUrl": "https://chataway.co/api/apps/com.example.acme-assets/versions/1.2.0/files/assets/icon.png",
"markUrl": "https://chataway.co/api/apps/com.example.acme-assets/versions/1.2.0/files/assets/mark.svg",
"accent": "#2F7BF6",
"screenshots": ["https://chataway.co/api/apps/…/files/assets/s1.png"],
"permissions": ["Receive images and audio you choose to upload to Acme"],
"grants": ["files:receive", "host:media"],
"domains": ["apps.example.com", "cdn.example.com"],
"accounts": [{ "id": "acme", "label": "Acme", "scopes": ["openid", "asset:write"], "required": true }],
"tools": [{ "id": "upload_decals", "name": "Upload decals", "description": "…" }],
"installs": 1204,
"rating": { "average": 4.6, "count": 38 },
"homepage": "https://example.com/chataway",
"support": "mailto:help@example.com",
"size": 214318
}
]
}The tagline is the first sentence of your description (≤ 100 characters). Cached for 30 seconds.
#GET /api/apps/:appId
One app: everything in the catalog entry, plus versions (published versions, newest first) and readme (your README.md).
{
"appId": "com.example.acme-assets",
"…": "…",
"readme": "# Acme Assets\n…",
"versions": [
{
"version": "1.2.0",
"publishedAt": "2026-09-30T10:12:00.000Z",
"changelog": "## 1.2.0\n- Audio uploads",
"sha256": "9c1f…",
"size": 214318,
"signature": "base64…",
"keyId": "k1",
"grants": ["files:receive", "host:media"],
"domains": ["apps.example.com", "cdn.example.com"],
"accounts": ["acme", "acme:openid", "acme:asset:write"],
"bundleUrl": "https://chataway.co/api/apps/com.example.acme-assets/versions/1.2.0/bundle"
}
]
}#GET /api/apps/:appId/versions/:version/bundle
The signed .chataway-app zip. Headers:
| Header | |
|---|---|
X-Chataway-Sha256 | SHA-256 of the zip (hex). |
X-Chataway-Signature | Ed25519 signature (base64) over the signed facts. |
X-Chataway-Key-Id | Which store key signed it. |
X-Chataway-Published-At | Publication time (part of the signed facts). |
#GET /api/apps/:appId/versions/:version/files/*path
One file out of a published bundle — your icon, mark and screenshots. Served with a restrictive CSP (an SVG can't run script) and cached for a day. Use these URLs to show your listing art on your own site.
#GET /api/apps/:appId/reviews
Ratings and reviews for an app.
#Signatures and revocations
#GET /api/apps/public-key
{ "keyId": "k1", "publicKeyPem": "-----BEGIN PUBLIC KEY-----\n…" }Chataway pins this key. Every published version is signed with Ed25519 over the canonical JSON (sorted keys, no whitespace) of:
{ "accounts": ["acme", "acme:asset:write", "acme:openid"], "appId": "com.example.acme-assets",
"domains": ["apps.example.com", "cdn.example.com"], "grants": ["files:receive", "host:media"],
"publishedAt": "2026-09-30T10:12:00.000Z", "sha256": "9c1f…", "version": "1.2.0" }domains includes your mcpUrl host; lists are sorted, domains lowercased. The desktop installer refuses bundles whose hash, signature or signed facts don't match the manifest inside.
#GET /api/apps/revocations
The yanked versions, signed the same way. Every Mac checks it hourly and at startup, and disables listed versions.
{
"entries": [{ "appId": "com.example.acme-assets", "version": "1.1.0", "reason": "Uploads went to the wrong account", "at": "2026-09-29T08:00:00.000Z" }],
"signedAt": "2026-09-30T10:00:00.000Z",
"signature": "base64…"
}#Publishing
These need a developer token (Authorization: Bearer cwd_…) from chataway login or the developer dashboard.
#POST /api/apps/publish
The request body is the bundle zip (Content-Type: application/zip; up to 25 MiB). At most 20 uploads per 10 minutes.
curl -X POST https://chataway.co/api/apps/publish \
-H "Authorization: Bearer $CHATAWAY_TOKEN" \
-H "Content-Type: application/zip" \
--data-binary @dist/com.example.acme-assets-1.2.0.chataway-app201 response:
{
"appId": "com.example.acme-assets",
"version": "1.2.0",
"status": "in_review",
"reasons": ["permissions-widened"],
"issues": [],
"permissionDiff": { "grantsAdded": [], "domainsAdded": ["cdn.example.com"], "accountsAdded": [], "fileParamsAdded": [], "requiresAdded": [], "widens": true, "…": "…" },
"reviewUrl": "https://chataway.co/dashboard/developer/apps/com.example.acme-assets"
}status is published when the version was auto-approved, in_review when it waits for a person. reasons says why: first-version, permissions-widened, publisher-unverified, flagged:<code>.
Errors:
| Status | code | |
|---|---|---|
| 400 | empty_body | No bundle in the body. |
| 400 | invalid_bundle | Not a readable zip (with issues). |
| 401 | unauthorized | Missing or invalid developer token. |
| 403 | not_a_member | You're not a member of the manifest's publisher. |
| 403 | publisher_suspended, app_suspended | |
| 404 | unknown_publisher | Create the publisher in the developer dashboard first. |
| 409 | id_taken | The app id belongs to another publisher. |
| 409 | version_not_greater | version must be greater than every version you've uploaded (with latest). |
| 413 | Over 25 MiB. | |
| 422 | validation_failed | The store checks failed; see issues. |
| 429 | Too many uploads; slow down. |
#GET /api/apps/:appId/versions/:version/status
{ "appId": "com.example.acme-assets", "version": "1.2.0", "status": "rejected", "issues": [], "notes": "The confirm card doesn't say uploads are public." }Statuses: submitted → checking → in_review → approved / rejected → published → yanked. See Publishing.
#Device sign-in
What chataway login uses:
POST /api/developer/device/start | → { deviceCode, userCode, verifyUrl, interval, expiresIn }. Codes live 10 minutes. |
POST /api/developer/device/poll { deviceCode } | → { token } once approved, { pending: true } before, 403 access_denied if denied in the browser, 410 expired when the code expired. Poll every interval seconds. |
#Connected-account relay
Used by Chataway, not by your app — listed so you know what your OAuth server talks to:
GET /apps/oauth/callback?state&code | The redirect URI you register. Parks the code for 5 minutes and shows "You can close this tab". |
GET /api/apps/oauth/result?state= | The Mac collects the code, once. |
See Connected accounts.