Documentation
What's what
Before anything else — here's how the pieces fit together.
Cards are the individual question-and-answer pairs. Every card has a front (the question or prompt) and a back (the answer).
Decks are collections of cards on a single topic — like "PSYC 1011 Midterm" or "Organic Chemistry: Reactions." You study a deck, share a deck, and manage cards inside a deck.
Courses are Dal course pages, like BIOL 1010 or STAT 1060. Each course page shows all the public decks Dal students have contributed for that course. You don't own a course — it's a shared community space. Anyone can add their deck to a course, and the community helps keep the cards accurate.
Collections are your own private folders. If you want to group your personal decks together (e.g. "Fall semester" or "Finals prep"), you can put them in a collection. Collections are just for your own organization — they're not visible to anyone else.
Three ways to create a deck
1. Generate with AI — right inside the app
Go to New deck and pick the Generate with AI tab. Paste in your lecture notes, slides, or any study material and the app will turn it into a full deck instantly. This is the fastest option for most people — no copying prompts, no uploading files.
2. Use any AI outside the app, then import
If you'd rather use ChatGPT, Claude, Gemini, or any other AI on your own, use the prompt template below. Copy it, replace [TOPIC] with your subject, and paste it into any AI. It will output a JSON file in exactly the right format. Then go to New deck → Import JSON and drop the file in (or paste the JSON directly).
This is useful when you want more control over the prompt, or when you already have a long document open in another AI tool.
Your task is to output a JSON data file — nothing else. Do not build an app, do not write HTML or JavaScript, do not create a UI. Just produce a JSON object containing flashcard data about [TOPIC].
Output it as a downloadable deck.json file if your interface supports it, otherwise wrap it in a ```json code block. No explanation before or after.
{
"name": "string — the deck title",
"description": "string — one sentence description",
"coverImage": "string (optional) — a relevant Unsplash image URL",
"cards": [
{
"front": {
"title": "string — the question or concept (required)",
"description": "string (optional) — extra context on the front"
},
"back": {
"title": "string — the answer (required)",
"description": "string (optional) — explanation or detail",
"image": "string (optional) — a relevant Unsplash image URL for this card"
}
}
]
}
Rules:
- Output the JSON data only — no code, no apps, no HTML, no JavaScript
- front.title and back.title are required for every card
- Use clear, concise language
- Aim for 10–20 cards
- For image fields, use real Unsplash URLs in the format:
https://images.unsplash.com/photo-[ID]?w=800&q=80
Pick images that genuinely match the card content
- If [TOPIC] has not been replaced with a real topic, stop and ask the user what topic they want3. Use the API directly
If you're a developer, running scripts, or building tools, you can create decks programmatically via the REST API. Generate an API key in Settings → API Keys and POST directly to /api/decks. The rest of this page documents everything the API can do.
Authentication
All API endpoints are authenticated with Bearer API keys. Generate a key in Settings under API Keys, then pass it as an Authorization header on every request.
Authorization: Bearer YOUR_API_KEY
Keys are scoped to your account. All write operations (create, update, delete) require a valid key. Some read operations (fetching public decks and course collections) work without authentication.
Decks
List your decks
/api/decksAPI key requiredReturns all decks owned by your account, sorted by most recently updated.
{
"decks": [
{
"id": "cm1abc123",
"title": "Cell Biology",
"description": "Key concepts from BIOL 2030",
"visibility": "PRIVATE",
"coverImage": null,
"cardCount": 24,
"collectionIds": ["cm1coll456"],
"createdAt": "2024-09-01T12:00:00Z",
"updatedAt": "2024-09-15T08:30:00Z"
}
]
}Error codes
401Missing or invalid API keyCreate a deck
/api/decksAPI key requiredCreates a new deck with cards in a single request. External image URLs in coverImage and back.image are mirrored to storage automatically.
Request body fields
namestringrequireddescriptionstringoptionalvisibilityenumoptionalcoverImagestring URLoptionalcards[].front.titlestringrequiredcards[].front.descriptionstringoptionalcards[].back.titlestringrequiredcards[].back.descriptionstringoptionalcards[].back.imagestring URLoptional{
"name": "Solar System",
"description": "Key facts about the planets.",
"visibility": "PUBLIC",
"coverImage": "https://images.unsplash.com/photo-111?w=1200&q=80",
"cards": [
{
"front": { "title": "How many planets are in the solar system?" },
"back": {
"title": "8",
"description": "Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune."
}
},
{
"front": { "title": "What is the largest planet?" },
"back": { "title": "Jupiter" }
}
]
}{
"id": "cm1abc123",
"title": "Solar System",
"cardCount": 2,
"visibility": "PUBLIC",
"editUrl": "https://flashcardbrowser.com/decks/cm1abc123/edit"
}curl -X POST https://flashcardbrowser.com/api/decks \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Solar System",
"visibility": "PRIVATE",
"cards": [
{
"front": { "title": "How many planets are in the solar system?" },
"back": { "title": "8" }
}
]
}'const res = await fetch("https://flashcardbrowser.com/api/decks", {
method: "POST",
headers: {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "Solar System",
visibility: "PRIVATE",
cards: [
{
front: { title: "How many planets are in the solar system?" },
back: { title: "8" },
},
],
}),
});
const deck = await res.json();
// { id, title, cardCount, visibility, editUrl }Error codes
400Invalid JSON body401Missing or invalid API key422Missing required field — see error message for detailsGet a deck
/api/decks/:idAPI key optionalReturns a deck and its full card list. Public decks are accessible without authentication. Private decks require the owner's API key.
{
"id": "cm1abc123",
"title": "Solar System",
"description": "Key facts about the planets.",
"visibility": "PUBLIC",
"coverImage": "https://...",
"cardCount": 2,
"ownerName": "Alice",
"collectionIds": [],
"createdAt": "2024-09-01T12:00:00Z",
"updatedAt": "2024-09-15T08:30:00Z",
"cards": [
{ "id": "cm1card1", "question": "How many planets...", "answer": "8", "imageUrl": null, "position": 0 },
{ "id": "cm1card2", "question": "What is the largest planet?", "answer": "Jupiter", "imageUrl": null, "position": 1 }
]
}Note on card format: Cards in this response use question/answer fields. This differs from the front/back structure used when creating a deck — see the format note in the Cards section.
Error codes
401Deck is private — provide the owner's API key404Deck not foundUpdate a deck
/api/decks/:idAPI key requiredUpdate one or more metadata fields on a deck you own. All body fields are optional — send only what you want to change.
Request body fields
titlestringoptionaldescriptionstringoptionalvisibilityenumoptionalcoverImagestringoptional{
"title": "Updated Title",
"description": "Updated description.",
"visibility": "PUBLIC",
"coverImage": null
}{
"id": "cm1abc123",
"title": "Updated Title",
"description": "Updated description.",
"visibility": "PUBLIC",
"coverImage": null,
"updatedAt": "2024-09-20T10:00:00Z"
}Error codes
401Missing or invalid API key403Deck belongs to a different user404Deck not found422No valid fields to updateDelete a deck
/api/decks/:idAPI key requiredPermanently deletes a deck and all its cards. This cannot be undone.
Returns 204 No Content on success.
Error codes
401Missing or invalid API key403Deck belongs to a different user404Deck not foundExport a deck
/api/decks/:id/exportAPI key optionalDownloads a deck as a .json file in the same format accepted by Import JSON. Useful for backing up a deck, sharing it, or re-importing it elsewhere. Public decks are accessible without authentication; private decks require the owner's API key.
The response is sent as a file download (Content-Disposition: attachment) with a filename derived from the deck title.
{
"name": "Solar System",
"description": "Key facts about the planets.",
"coverImage": "https://...",
"cards": [
{
"id": "cm1card1",
"front": { "title": "How many planets are in the solar system?" },
"back": { "title": "8" }
},
{
"id": "cm1card2",
"front": { "title": "What is the largest planet?" },
"back": { "title": "Jupiter" }
}
]
}Error codes
401Deck is private — provide the owner's API key404Deck not foundCards
Format note: When creating a deck (POST /api/decks), cards use a front/back structure. When reading or writing individual cards, they use question/answer directly.
| Context | Shape |
|---------|-------|
| POST /api/decks — bulk create | { front: { title, description? }, back: { title, description?, image? } } |
| POST /api/decks/:id/cards — add one | { question, answer, imageUrl? } |
| GET /api/decks/:id — returned cards | { id, question, answer, imageUrl, position } |
List cards
/api/decks/:id/cardsAPI key optionalLists all visible cards in a deck. Same auth rules as Get a deck: public decks need no auth, private decks require the owner's key. Hidden cards (flagged by the community) are excluded.
{
"cards": [
{ "id": "cm1card1", "question": "How many planets...", "answer": "8", "imageUrl": null, "position": 0, "createdAt": "...", "updatedAt": "..." },
{ "id": "cm1card2", "question": "Largest planet?", "answer": "Jupiter", "imageUrl": null, "position": 1, "createdAt": "...", "updatedAt": "..." }
]
}Error codes
401Deck is private — provide the owner's API key404Deck not foundAdd a card
/api/decks/:id/cardsAPI key requiredAdds a single card to a deck you own. If position is omitted the card is appended after the last existing card.
Request body fields
questionstringrequiredanswerstringrequiredimageUrlstringoptionalpositionnumberoptional{
"question": "What is the speed of light?",
"answer": "299,792,458 m/s (approximately 3 × 10⁸ m/s)",
"imageUrl": null
}{
"id": "cm1card99",
"question": "What is the speed of light?",
"answer": "299,792,458 m/s (approximately 3 × 10⁸ m/s)",
"imageUrl": null,
"position": 2,
"createdAt": "2024-09-20T10:00:00Z"
}Error codes
401Missing or invalid API key403Deck belongs to a different user404Deck not found422Missing required field: question or answerUpdate a card
/api/decks/:id/cards/:cardIdAPI key requiredUpdates a card's question, answer, or image. All fields are optional — send only what you want to change.
Request body fields
questionstringoptionalanswerstringoptionalimageUrlstringoptional{
"question": "What is the approximate speed of light?",
"answer": "3 × 10⁸ m/s"
}{
"id": "cm1card99",
"question": "What is the approximate speed of light?",
"answer": "3 × 10⁸ m/s",
"imageUrl": null,
"position": 2,
"updatedAt": "2024-09-21T09:00:00Z"
}Error codes
401Missing or invalid API key403Deck belongs to a different user404Deck or card not found422No valid fields to updateDelete a card
/api/decks/:id/cards/:cardIdAPI key requiredPermanently deletes a card. Returns 204 No Content on success.
Error codes
401Missing or invalid API key403Deck belongs to a different user404Deck or card not foundCollections
Collections are groups of decks. There are two kinds:
- Personal collections — created by you, visible only to your account.
courseCodeisnull. - Course collections — admin-managed groups linked to a Dal course code (e.g.
"INFO 2390"). Publicly readable by anyone.
A deck can belong to at most one personal collection and any number of course collections simultaneously.
List collections
/api/collectionsAPI key requiredReturns your personal collections (excluding course collections).
{
"collections": [
{
"id": "cm1coll1",
"name": "My Notes",
"courseCode": null,
"deckCount": 3,
"createdAt": "2024-08-01T00:00:00Z",
"updatedAt": "2024-09-01T00:00:00Z"
}
]
}To list all course collections globally, add ?type=course:
/api/collections?type=courseAPI key required{
"collections": [
{
"id": "cm1course1",
"name": "Introduction to Data Science",
"courseCode": "INFO 2390",
"deckCount": 5,
"createdAt": "2024-08-01T00:00:00Z",
"updatedAt": "2024-09-01T00:00:00Z"
}
]
}Error codes
401Missing or invalid API keyCreate a collection
/api/collectionsAPI key requiredCreates a new personal collection. To bootstrap a course collection for a Dal course that doesn't exist yet, include courseCode — this creates the collection and adds an empty community deck automatically.
Request body fields
namestringrequiredcourseCodestringoptionalPersonal collection
{ "name": "BIOL 2030 – Cell Biology" }{
"id": "cm1coll1",
"name": "BIOL 2030 – Cell Biology",
"courseCode": null,
"deckCount": 0,
"createdAt": "2024-09-01T12:00:00Z",
"updatedAt": "2024-09-01T12:00:00Z"
}Course collection
{
"name": "Cell Biology",
"courseCode": "BIOL 2030"
}{
"id": "cm1course2",
"name": "Cell Biology",
"courseCode": "BIOL 2030",
"deckCount": 1,
"createdAt": "2024-09-01T12:00:00Z",
"updatedAt": "2024-09-01T12:00:00Z"
}Course collections are community-owned — any verified Dal student can create one, but only admins can rename or delete them. You can create at most 3 course collections per 24 hours.
Error codes
401Missing or invalid API key409A collection for that course code already exists — see id in response422Missing required field: name429Rate limit exceeded — max 3 course collections per 24 hoursGet a collection
/api/collections/:idAPI key optionalReturns a collection and its full deck list. Course collections are publicly readable — no auth needed. Personal collections require the owner's API key.
{
"id": "cm1coll1",
"name": "My Notes",
"courseCode": null,
"createdAt": "2024-08-01T00:00:00Z",
"updatedAt": "2024-09-01T00:00:00Z",
"decks": [
{
"id": "cm1abc123",
"title": "Cell Biology",
"description": "Key concepts from BIOL 2030",
"visibility": "PRIVATE",
"coverImage": null,
"cardCount": 24,
"ownerName": "Alice",
"addedAt": "2024-09-01T12:00:00Z"
}
]
}Error codes
403Personal collection — provide the owner's API key404Collection not foundRename a collection
/api/collections/:idAPI key requiredRequest body fields
namestringrequired{ "name": "New Name" }{
"id": "cm1coll1",
"name": "New Name",
"courseCode": null,
"updatedAt": "2024-09-20T10:00:00Z"
}Error codes
401Missing or invalid API key403Collection belongs to a different user, or is a course collection (admin only)404Collection not found422Missing required field: nameDelete a collection
/api/collections/:idAPI key requiredDeletes the collection. Decks inside are not deleted — they are simply unlinked. Returns 204 No Content on success. Course collections can only be deleted by admins.
Error codes
401Missing or invalid API key403Collection belongs to a different user, or is a course collection (admin only)404Collection not foundAdd deck to collection
/api/collections/:id/decks/:deckIdAPI key requiredAdds a deck to a collection. Both the collection and the deck must belong to your account. Idempotent — adding a deck already in the collection is a no-op.
If the deck is already in another personal collection it is moved automatically. Course collection memberships are never affected.
{ "collectionId": "cm1coll1", "deckId": "cm1abc123" }Error codes
401Missing or invalid API key403Collection or deck belongs to a different user404Collection or deck not foundRemove deck from collection
/api/collections/:id/decks/:deckIdAPI key requiredRemoves a deck from a collection. The deck itself is not deleted. Returns 204 No Content on success.
Error codes
401Missing or invalid API key403Collection belongs to a different user404Deck is not in this collectionStatus codes
All endpoints follow standard HTTP conventions.
Status codes
200Success201Created204Success — no body returned400Invalid JSON body401Missing or invalid API key403Forbidden — resource belongs to a different user404Resource not found422Validation error — check the error field in the response body for details5xxServer error — wait a moment and retry