API Reference
Overview
This page documents the current external AI-agent contract for Flashcards.
If your client speaks MCP, the MCP connector is the simplest way to connect and wraps this same data surface. This page documents the HTTP discovery and SQL contract used by CLI agents.
Start from the canonical discovery entrypoint:
GET https://api.flashcards-open-source-app.com/v1/
The same discovery payload is also available at GET /v1/agent, but /v1/ is the primary public entrypoint.
The discovery response tells an agent how to:
- start email OTP login
- exchange the OTP for a long-lived API key
- load account context
- create or select a workspace
- continue through the published SQL surface
Published Specs
Primary spec URLs for the external agent surface:
https://api.flashcards-open-source-app.com/v1/agent/openapi.jsonhttps://api.flashcards-open-source-app.com/v1/agent/swagger.json
Equivalent root aliases also exist:
https://api.flashcards-open-source-app.com/v1/openapi.jsonhttps://api.flashcards-open-source-app.com/v1/swagger.json
Authentication Bootstrap
OTP bootstrap runs on the auth service:
POST https://auth.flashcards-open-source-app.com/api/agent/send-codePOST https://auth.flashcards-open-source-app.com/api/agent/verify-code
The flow is:
- Call
GET /v1/. - Send the user's email to
send-code. - Read
otpSessionTokenfrom the response. - Ask the user for the latest 8-digit email code.
- Call
verify-codewithcode,otpSessionToken, andlabel. - Persist the returned API key outside chat memory.
Recommended environment variable:
export FLASHCARDS_OPEN_SOURCE_API_KEY="fca_ABCDEFGH_0123456789ABCDEFGHJKMNPQRS"
Authenticated requests use:
Authorization: ApiKey <key>
Example bootstrap sequence:
curl https://api.flashcards-open-source-app.com/v1/
curl -X POST https://auth.flashcards-open-source-app.com/api/agent/send-code \
-H "Content-Type: application/json" \
-d '{"email":"you@example.com"}'
curl -X POST https://auth.flashcards-open-source-app.com/api/agent/verify-code \
-H "Content-Type: application/json" \
-d '{
"code":"12345678",
"otpSessionToken":"...",
"label":"Codex on MacBook"
}'
Post-Login Agent Surface
After verification, the current agent surface is:
GET /v1/agent/meGET /v1/agent/workspacesPOST /v1/agent/workspacesPOST /v1/agent/workspaces/{workspaceId}/selectPOST /v1/agent/sql/query(read-only)POST /v1/agent/sql/execute(write)
Typical bootstrap looks like this:
GET /v1/agent/meGET /v1/agent/workspaces?limit=100- If needed,
POST /v1/agent/workspaceswith{"name":"Personal"} - If needed,
POST /v1/agent/workspaces/{workspaceId}/select - Use
POST /v1/agent/sql/queryfor reads andPOST /v1/agent/sql/executefor writes
The workspace selection is explicit per API key connection. Agents should follow the returned instructions text and docs.openapiUrl field from each envelope instead of guessing the next step.
SQL Surface
POST /v1/agent/sql/query is the strictly read-only surface (SHOW TABLES, DESCRIBE, SELECT) and POST /v1/agent/sql/execute is the write surface (INSERT, UPDATE, DELETE); a single call must be all reads or all writes.
It is intentionally limited and is not full PostgreSQL. These docs cover only the supported dialect, not a PostgreSQL compatibility reference.
No read path repairs data, recalculates scheduling, or changes card state. Use
POST /v1/agent/sql/execute for every write.
Current statement families:
SHOW TABLESDESCRIBE <resource>SELECTINSERTUPDATEDELETE
Published logical resources currently include:
workspacecardsdecksreview_events
Notes:
LIMITdefaults to100and is capped at100- use
ORDER BYwhen you need stable pagination - use
SHOW TABLESorDESCRIBE cardsfor schema discovery - the external agent contract is workspace-scoped after selection
Example request:
curl -X POST https://api.flashcards-open-source-app.com/v1/agent/sql/query \
-H "Content-Type: application/json" \
-H "Authorization: ApiKey $FLASHCARDS_OPEN_SOURCE_API_KEY" \
-d '{"sql":"SHOW TABLES"}'
Example card query:
curl -X POST https://api.flashcards-open-source-app.com/v1/agent/sql/query \
-H "Content-Type: application/json" \
-H "Authorization: ApiKey $FLASHCARDS_OPEN_SOURCE_API_KEY" \
-d '{
"sql":"SELECT card_id, front_text, back_text, tags FROM cards ORDER BY updated_at DESC LIMIT 20 OFFSET 0"
}'
Example mutation:
curl -X POST https://api.flashcards-open-source-app.com/v1/agent/sql/execute \
-H "Content-Type: application/json" \
-H "Authorization: ApiKey $FLASHCARDS_OPEN_SOURCE_API_KEY" \
-d '{
"sql":"UPDATE cards SET back_text = '\''Updated answer'\'' WHERE card_id = '\''50b5b928-7f04-4cc8-878d-6cd0e8b98474'\''"
}'
A remote MCP server is also available at https://mcp.flashcards-open-source-app.com/mcp using OAuth 2.1 (Dynamic Client Registration + PKCE). It exposes the same split as two tools, sql_query (strictly read-only) and sql_execute (write), plus strictly read-only list_workspaces.
Safety And Scope
The SQL surface is a contained, parser-enforced dialect rather than raw PostgreSQL. The guardrails are:
- Closed statement allowlist: only
SHOW TABLES,DESCRIBE,SHOW COLUMNS, andSELECTfor reads, andINSERT,UPDATE, andDELETEfor writes. Anything else is rejected at parse time. - Limited resources: statements can only touch the
workspace,cards,decks, andreview_eventsresources. - Per-workspace scoping: every statement is scoped to your selected workspace, with no cross-tenant access.
- Caps: up to
100rows per statement, up to50statements per batch, and a result cap of roughly12ktokens. Mutation batches apply atomically. - Read/write split:
sql_queryandlist_workspacesare strictly read-only (readOnlyHint) and never repair data, recalculate scheduling, or change card state.sql_executeis the only write tool and performs writes (destructiveHint); a single call must be all reads or all writes.
Human And Sync APIs
Flashcards also includes separate APIs for human clients and offline-first sync, but they are not the main contract for external agents:
- browser flows use shared-domain cookies plus CSRF protection
- offline-first clients use implemented sync routes under
/v1/workspaces/{workspaceId}/sync/pushand/v1/workspaces/{workspaceId}/sync/pull - sync routes are intentionally outside the external agent OpenAPI surface