Card records
A card belongs to a deck and stores values for that deck's fields. It may also name tags. New hand-authored cards can omit their own IDs. Ordinary packages include that deck; cards-only imports use the selected destination's template instead.
Location and basic example
Put one card object per physical line in any content/cards/*.jsonl file, such as content/cards/notes.jsonl or content/cards/chapter-1.jsonl. Filenames are arbitrary; files must be directly inside that canonical directory. Omit the collection when there are no cards.
These two complete JSONL records use the basic Tokyo deck. The second also requires the tag-beginner record and your own files at media/cat.png and media/example.wav:
{"deckId":"deck-tokyo","values":{"field-front":{"type":"text","value":"Sumimasen"},"field-back":{"type":"text","value":"Excuse me"}}}
{"id":"card-konichiwa","deckId":"deck-tokyo","createdAt":"2026-01-01T00:00:00Z","updatedAt":"2026-01-01T00:00:00Z","tagIds":["tag-beginner"],"values":{"field-front":{"type":"text","value":"Konnichiwa"},"field-back":{"type":"text","value":"Hello"},"field-image":{"type":"image","mediaPath":"media/cat.png"},"field-audio":{"type":"audio","mediaPath":"media/example.wav"}}}
The first card intentionally omits id, timestamps, tagIds, and values for the media fields. It imports as a new card with no tags and empty media fields. The second card keeps explicit dates for backup-style preservation.
Cards-only example for Add Card
When using a selected deck's Add Card import, omit deck files and omit every card's deckId. This line assumes the selected deck already has text fields with IDs field-front and field-back:
{"values":{"field-front":{"type":"text","value":"Hello"},"field-back":{"type":"text","value":"Bonjour"}}}
Keep the destination field IDs and types from the downloaded starter. Duplicate this anonymous line for another new card; no ID editing is needed. Tags and media remain optional, but referenced tags must still be in this archive. Only cards, tags, and media are supported. A full archive with deck shards still uses the ordinary examples above. See the cards-only contract for the starter-file workflow and validation requirements.
Full example
Copy the runnable content/cards/00000.jsonl, or read its expanded records below. Each object occupies one physical line in the file; the formatting here is for reading.
Use these records with both full decks, the linked package tags, and the image/audio files. The inherited records omit display overrides; the override records include every applicable settings property. Chinese and Japanese can retain content-specific pronunciation corrections while inheriting display settings. The linked card file also includes card-read-line, used by the initial-learning schedule.
Language card inheriting its template
{
"id": "card-station",
"deckId": "deck-japanese-travel",
"createdAt": "2026-03-01T09:00:00.000000Z",
"updatedAt": "2026-03-02T09:00:00.000000Z",
"tagIds": [
"tag-beginner",
"tag-travel"
],
"values": {
"field-ja-word": {
"type": "japanese",
"value": "駅",
"useTemplateSettings": true,
"settings": {
"furiganaOverrides": [
{
"sourceIndex": 0,
"expectedKanji": "駅",
"rubyOverride": "えき"
}
],
"romajiOverride": "eki",
"pitchOverridePattern": [
"H",
"L"
]
}
},
"field-ja-meaning": {
"type": "text",
"value": "station",
"useTemplateSettings": true
},
"field-ja-audio": {
"type": "audio",
"mediaPath": "media/pronunciation.wav",
"useTemplateSettings": true
},
"field-ja-photo": {
"type": "image",
"mediaPath": "media/station.png",
"useTemplateSettings": true
},
"field-ja-speak": {
"type": "tts",
"useTemplateSettings": true
},
"field-zh-word": {
"type": "chinese",
"value": "站",
"useTemplateSettings": true,
"settings": {
"pinyinOverrides": [
{
"tokenIndex": 0,
"pinyin": "zhan4"
}
]
}
},
"field-ja-map": {
"type": "image_occlusion",
"mediaPath": "media/station.png",
"occlusionRects": [
{
"x": 0.1,
"y": 0.2,
"width": 0.3,
"height": 0.25
},
{
"x": 0.6,
"y": 0.1,
"width": 0.2,
"height": 0.3
}
],
"useTemplateSettings": true
}
}
}
Language card with complete overrides
{
"id": "card-ticket",
"deckId": "deck-japanese-travel",
"createdAt": "2026-03-01T09:00:00.000000Z",
"updatedAt": "2026-03-02T09:00:00.000000Z",
"tagIds": [
"tag-travel"
],
"values": {
"field-ja-word": {
"type": "japanese",
"value": "切符",
"useTemplateSettings": false,
"generalSettings": {
"isHidden": false
},
"settings": {
"showPitchAccent": true,
"showFurigana": true,
"showRomaji": true,
"annotationSetting": "hint",
"furiganaOverrides": [
{
"sourceIndex": 0,
"expectedKanji": "切符",
"rubyOverride": "きっぷ"
}
],
"romajiOverride": "kippu",
"romajiType": "ascii",
"pitchOverridePattern": [
"L",
"H",
"H"
]
}
},
"field-ja-meaning": {
"type": "text",
"value": "ticket",
"useTemplateSettings": false,
"generalSettings": {
"isHidden": false
},
"settings": {}
},
"field-ja-audio": {
"type": "audio",
"mediaPath": "media/pronunciation.wav",
"useTemplateSettings": false,
"generalSettings": {
"isHidden": false
},
"settings": {
"autoplay": true
}
},
"field-ja-photo": {
"type": "image",
"mediaPath": "media/station.png",
"useTemplateSettings": false,
"generalSettings": {
"isHidden": true
},
"settings": {}
},
"field-ja-speak": {
"type": "tts",
"value": "切符",
"useTemplateSettings": false,
"generalSettings": {
"isHidden": false
},
"settings": {
"autoplay": true,
"sourceType": "manual",
"contentSourceId": "",
"locale": "ja-JP"
}
},
"field-zh-word": {
"type": "chinese",
"value": "票",
"useTemplateSettings": false,
"generalSettings": {
"isHidden": false
},
"settings": {
"chineseType": "simplified",
"showPinyin": true,
"annotationSetting": "hint",
"pinyinOverrides": [
{
"tokenIndex": 0,
"pinyin": "piao4"
}
]
}
},
"field-ja-map": {
"type": "image_occlusion",
"mediaPath": "media/station.png",
"occlusionRects": [
{
"x": 0.1,
"y": 0.2,
"width": 0.3,
"height": 0.25
},
{
"x": 0.6,
"y": 0.1,
"width": 0.2,
"height": 0.3
}
],
"useTemplateSettings": false,
"generalSettings": {
"isHidden": false
},
"settings": {}
}
}
}
Programming card inheriting its template
{
"id": "card-list-literal",
"deckId": "deck-dart-fundamentals",
"createdAt": "2026-03-01T09:00:00.000000Z",
"updatedAt": "2026-03-02T09:00:00.000000Z",
"tagIds": [
"tag-beginner",
"tag-programming"
],
"values": {
"field-dart-prompt": {
"type": "text",
"value": "Growable list literal",
"useTemplateSettings": true
},
"field-dart-code": {
"type": "code",
"value": "final items = <String>[];",
"useTemplateSettings": true
},
"field-dart-cloze": {
"type": "cloze",
"value": "Dart has null safety.",
"clozeRanges": [
{
"start": 9,
"end": 13
}
],
"useTemplateSettings": true
},
"field-dart-notes": {
"type": "rich_text",
"value": [
{
"insert": "List literal",
"attributes": {
"bold": true
}
},
{
"insert": " creates a growable list.\n"
}
],
"useTemplateSettings": true
},
"field-dart-formula": {
"type": "tex",
"value": "\\sum_{i=1}^{n} i = \\frac{n(n+1)}{2}",
"useTemplateSettings": true
}
}
}
Programming card with complete overrides
{
"id": "card-null-safety",
"deckId": "deck-dart-fundamentals",
"createdAt": "2026-03-01T09:00:00.000000Z",
"updatedAt": "2026-03-02T09:00:00.000000Z",
"tagIds": [
"tag-programming"
],
"values": {
"field-dart-prompt": {
"type": "text",
"value": "Null safety",
"useTemplateSettings": false,
"generalSettings": {
"isHidden": false
},
"settings": {}
},
"field-dart-code": {
"type": "code",
"value": "String? name;",
"useTemplateSettings": false,
"generalSettings": {
"isHidden": false
},
"settings": {
"selectedLanguage": "dart",
"showLineNumbers": true,
"wrapLines": true,
"forceDarkMode": true,
"showLanguageHeader": true,
"fitToContent": false,
"minLines": 3,
"maxLines": 12
}
},
"field-dart-cloze": {
"type": "cloze",
"value": "Dart has null safety.",
"clozeRanges": [
{
"start": 9,
"end": 13
}
],
"useTemplateSettings": false,
"generalSettings": {
"isHidden": false
},
"settings": {}
},
"field-dart-notes": {
"type": "rich_text",
"value": [
{
"insert": "Nullable",
"attributes": {
"bold": true
}
},
{
"insert": " types use the ? suffix.\n"
}
],
"useTemplateSettings": false,
"generalSettings": {
"isHidden": false
},
"settings": {}
},
"field-dart-formula": {
"type": "tex",
"value": "\\sum_{i=1}^{n} i = \\frac{n(n+1)}{2}",
"useTemplateSettings": false,
"generalSettings": {
"isHidden": false
},
"settings": {
"autoSize": false
}
}
}
}
Record properties
Extra record and nested value properties are ignored. Duplicate JSON keys remain invalid, and entries in values must still name actual deck field IDs. Optional timestamps have no generated default; see timestamp syntax.
Card identity
Readable IDs such as card-konichiwa are allowed and must be unique across all card files. Field IDs remain required even when a card omits its own id. Ordinary cards also require deckId; scoped cards-only records must omit it.
Only an omitted id requests a generated identity. "id":null, "id":"", or a non-string ID is invalid. The reader assigns a temporary source identity. It is not an ID to copy into another record's references.
That temporary identity does not enable later updates. Cards with omitted IDs always become new records, even with override-existing import. To update an existing card, keep its persisted ID from an app export. Ordinary imports remap source IDs to destination IDs.
Cards referenced by schedules or normal review history must supply explicit IDs. Do not attempt to reconstruct a generated identity for those references. Generated source-identity metadata is not an extra JSON property.
Values and settings
Each key in values is a field ID, not its display name. The value must be an object containing type, and that type must match the deck definition. There are 11 exact wire strings: text, rich_text, image, cloze, tts, audio, image_occlusion, chinese, japanese, code, and tex.
Do not put nested values, settings, Delta arrays, or masks inside a serialized JSON string. Strings containing line breaks use escaped \n, so the whole card remains one physical JSONL line.
Each field value inherits its template's settings by default. Set useTemplateSettings:false to provide card-specific general/type settings. While inheriting, only Chinese pronunciation corrections and Japanese furigana/romaji/pitch corrections are allowed. The complete field reference documents every setting, default, null behavior, and override rule.
- In ordinary packages,
deckId must resolve to a deck in the same package. Cards-only files omit it and use the selected destination deck's template.
- Every key in
values must resolve to a field defined by that deck, or by the supplied destination in cards-only mode. Unknown field IDs and mismatched types fail validation; omitting unused fields is valid.
- Every
tagIds entry must resolve to a tag. Omit tagIds or use [] when the tags collection is absent.
- A media value points directly at an exact media path, such as
media/cat.png. No asset ID, hash, MIME declaration, or size declaration is needed in a card.
- If the media directory or referenced file is missing, import retains the card/field/settings with an empty media value and reports missing media. Missing image-occlusion media also clears its rectangles. Unsafe paths and present but corrupt or oversized media still fail.
- Schedules/history can refer to an explicitly identified card. Content-only imports do not require schedules or review history.
Additional examples
This card uses the one-field deck-cloze shown in the deck examples. It hides Tokyo and Japan using sorted UTF-16 offsets. This is a complete JSONL record:
{"id":"card-geography","deckId":"deck-cloze","createdAt":"2026-01-01T00:00:00Z","updatedAt":"2026-01-01T00:00:00Z","values":{"field-sentence":{"type":"cloze","value":"Tokyo is in Japan.","clozeRanges":[{"start":0,"end":5},{"start":12,"end":17}]}}}
This complete record uses the Tokyo deck and changes audio autoplay for this card only. Other fields stay empty:
{"id":"card-audio-practice","deckId":"deck-tokyo","createdAt":"2026-01-01T00:00:00Z","updatedAt":"2026-01-01T00:00:00Z","values":{"field-audio":{"type":"audio","mediaPath":"media/example.wav","useTemplateSettings":false,"settings":{"autoplay":true}}}}
For an intentionally blank card, an empty values map is valid. Its deck still needs a valid template:
Schemas: ordinary card record, field values, general settings, and type settings. The ordinary card schema requires deckId and does not describe cards-only records; those require validation against the selected destination template. Cross-record relationships and type-specific constraints are also checked by the reader.