{"endpoints":[{"path":"/ping","method":"GET","auth":"none","response":"{\"ok\":true,\"api\":\"v1\",\"time\":1786734577051}","scope":null,"about":"Connectivity check. Use it to prove you can reach the API before debugging credentials.","fields":[],"example":"curl https://gestic.org/api/v1/ping"},{"path":"/tokens","method":"POST","auth":"password, or a signed-in Gestic browser session","response":"{\"token\":\"gst_70e5cc0e8519...\",\"label\":\"CardTrader sync\",\n \"scopes\":[\"lists:read\",\"collection:read\"],\n \"note\":\"Copy this now: it is stored hashed and cannot be shown again.\"}","scope":null,"about":"Creates an API key. This is the only response that ever contains the secret: it is stored hashed and cannot be shown again. A key cannot create another key -- that needs your password or your browser session, so a leaked key cannot promote itself.","fields":[{"name":"login","about":"Your Gestic e-mail. Omit when calling from a signed-in browser session.","type":"string","required":false},{"name":"password","about":"The SHA-256 hex of your password, the same as the login endpoint expects. Never the plaintext.","type":"string","required":false},{"name":"label","about":"What this key is for (\"CardTrader sync\"). Shown in your settings so an unused or leaked key can be identified.","type":"string","required":false},{"name":"scopes","about":"Defaults to [\"collection:read\"]. Valid: collection:read, collection:write, lists:read, lists:write, offers:write.","type":"array of string","required":false},{"name":"expiresInDays","about":"Optional expiry. Omit for a key that does not expire.","type":"integer","required":false}],"example":"curl -X POST https://gestic.org/api/v1/tokens \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"login\":\"you@example.com\",\"password\":\"<sha256 hex>\",\n       \"label\":\"CardTrader sync\",\"scopes\":[\"collection:read\",\"lists:read\"]}'"},{"path":"/me","method":"GET","auth":"token or session","response":"{\"ok\":true,\"userId\":1719,\"login\":\"you@example.com\",\n \"authenticatedBy\":\"token\",\"tokenId\":1,\n \"scopes\":[\"lists:read\",\"collection:read\"],\"rateLimitPerMinute\":60}","scope":null,"about":"Confirms a key works and reports what it may do. This is the call to make first when something is not working.","fields":[],"example":"curl -H 'Authorization: Bearer gst_...' https://gestic.org/api/v1/me"},{"path":"/tokens","method":"GET","auth":"token or session","response":"{\"tokens\":[{\"id\":1,\"label\":\"CardTrader sync\",\"prefix\":\"gst_70e5cc0e\",\n   \"scopes\":[\"collection:read\"],\"created\":\"2026-08-14T10:52:11Z\",\n   \"lastUsed\":\"2026-08-14T10:53:02Z\",\"calls\":3,\n   \"expires\":null,\"revoked\":false,\"revokedAt\":null}]}","scope":null,"about":"Your keys. Secrets are never returned -- only the first 12 characters, so you can tell them apart.","fields":[],"example":"curl -H 'Authorization: Bearer gst_...' https://gestic.org/api/v1/tokens"},{"path":"/tokens/{id}","method":"DELETE","auth":"token or session","response":"{\"revoked\":1}","scope":null,"about":"Revokes a key immediately. Irreversible; issue a new one instead of un-revoking.","fields":[{"name":"id","about":"The id from GET /tokens. It must be one of your own keys.","type":"integer (in the path)","required":true}],"example":"curl -X DELETE -H 'Authorization: Bearer gst_...' https://gestic.org/api/v1/tokens/1"}],"rateLimit":{"headers":["X-RateLimit-Limit","X-RateLimit-Remaining","X-RateLimit-Reset","Retry-After"],"exceeded":"429 with {\"error\":\"rate_limited\"}","token":"60 requests per minute"},"versioning":"Breaking changes get /api/v2. Fields may be added to v1 responses, so parse defensively and ignore what you do not know.","timestamps":"ISO-8601 in UTC (2026-08-14T10:52:11Z), or null. Safe for new Date().","api":"Gestic API","scopes":["collection:read","collection:write","lists:read","lists:write","offers:write"],"planned":["GET /lists -- your lists, so a script can find the one it should work on","GET /lists/{id}/cards -- what is in a list","POST /lists/{id}/cards -- add copies","DELETE /lists/{id}/cards -- remove copies (by versionid, or by card+finish+condition)"],"version":"v1","errors":{"404 unknown_endpoint":"No such path in v1","401 no_credential":"No Authorization header and no session","403 forbidden_scope":"The key lacks the scope this endpoint needs","shape":"{\"error\":\"code\",\"message\":\"...\"} -- branch on the code, not the text","401 invalid_token":"The token is unknown, revoked or expired","429 rate_limited":"Too many requests this minute","403 cross_site":"A cookie-authenticated write that did not come from gestic.org","400 bad_scopes":"A scope in the request is not one we define","503 unavailable":"Temporarily unable to serve; retry"},"base":"https://gestic.org/api/v1","authentication":{"session":"A signed-in gestic.org browser session also authenticates GET requests; cookie-authenticated writes must be same-origin.","header":"Authorization: Bearer gst_<64 hex>","createKey":"POST /tokens with your login and the SHA-256 hex of your password"}}