Skip to main content

Notebooks with the API

Create notebooks, organize sections, and write pages with every block type the editor supports - including videos, sentences, multiple choice, images and PDFs.

By YalangoUpdated October 12, 2026

Reading needs a key with the notebooks:read scope. Every change needs notebooks:write.

A notebook holds sections, and each section holds pages. A page is a list of blocks.

Create a notebook

curl -X POST https://yalango.com/api/v1/notebooks \
  -H "Authorization: Bearer yal_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"name": "Spanish grammar", "target_ISO_639-1": "es", "source_ISO_639-1": "en"}'

name (up to 200 characters) and target_ISO_639-1 are required. Notebooks created through the API are private and start empty. PATCH /v1/notebooks/{notebookDocId} changes name and description.

Read the outline

GET /v1/notebooks/{notebookDocId} returns the sections in order, and the page titles in each:

{
  "notebook": {
    "doc_id": "Nb7xK2pQ9mL4vR8tW1zY",
    "name": "Spanish grammar",
    "is_course": false,
    "sections": [
      {
        "section_doc_id": "Sc1aB2cD3eF4gH5iJ6kL",
        "name": "Verbs",
        "pages": [{ "page_doc_id": "Pg9zY8xW7vU6tS5rQ4pO", "title": "Ser and estar" }]
      }
    ]
  }
}

Manage sections

PATCH /v1/notebooks/{notebookDocId}/sections takes any combination of these, checks all of them, and then applies them together:

curl -X PATCH https://yalango.com/api/v1/notebooks/Nb7xK2pQ9mL4vR8tW1zY/sections \
  -H "Authorization: Bearer yal_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "add": ["Pronouns"],
    "rename": [{ "section_doc_id": "Sc1aB2cD3eF4gH5iJ6kL", "name": "Verbs and tenses" }]
  }'
  • add - new section names. They are placed after the existing sections.
  • rename - section ids and their new names.
  • delete - section ids to remove. Every page in the section is deleted too, and this cannot be undone.
  • order - every remaining section id, in the new order.
  • page_order - for each section you want to reorder, its id and every page id in the new order.

Write a page

Create a page at the end of a section with POST /v1/notebooks/{notebookDocId}/pages:

curl -X POST https://yalango.com/api/v1/notebooks/Nb7xK2pQ9mL4vR8tW1zY/pages \
  -H "Authorization: Bearer yal_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "section_doc_id": "Sc1aB2cD3eF4gH5iJ6kL",
    "title": "Ser and estar",
    "blocks": [
      { "type": "heading_1", "content": "When to use ser" },
      { "type": "markdown", "content": "Use **ser** for identity and origin." },
      { "type": "deck", "ref_doc_id": "8sKd92mfPqR1xLvBn4Tz", "block_title": "Practice", "study_settings": { "game": "cloze", "exercise_count": 15, "play_mode": "source_first" } },
      { "type": "video", "content": "https://www.youtube.com/watch?v=dQw4w9WgXcQ" },
      { "type": "sentence", "sentence": "Soy estudiante.", "translation": "I am a student." },
      { "type": "multiple_choice", "block_title": "Check yourself", "questions": [
        { "question": "Which verb expresses identity?", "options": ["ser", "estar", "tener"], "correct_index": 0, "explanation": "Use ser for identity." }
      ] }
    ]
  }'

These block types can be written through the API:

TypeFields
markdowncontent - Markdown text
heading_1, heading_2, heading_3content - the heading text
deck, tableref_doc_id - one of your own decks or tables. Optional block_title, block_description and study_settings
textref_doc_id - one of your own texts. Optional block_title and block_description
videocontent - a YouTube URL (youtube.com/watch?v=..., youtu.be/..., or an 11-character id). Optional title and description
sentencesentence (required) and translation (may be empty). Pronunciation is generated automatically. Optional title and description
multiple_choicequestions (required on create) - array of { question, options (2-6), correct_index, explanation? }. Self-contained; not tracked. Optional title and description
pdfref_doc_id of a PDF from GET /v1/pdfs or POST /v1/pdfs/uploads. Premium. Optional title and description
imagecontent - the JSON string from POST /v1/notebooks/{notebookDocId}/images. Optional credits, title and description. Premium.

Study settings

On deck and table blocks, study_settings presets the Study tab. When game is set, the reader lands on that game's intro screen. Sending an object replaces the stored presets; null clears them; omitting the field keeps what is stored.

FieldNotes
gameflashcards, quiz, write, mix, memory, hangman; decks also allow hanzi, audio, cloze. Tables cannot use audio, cloze or hanzi.
exercise_countOne of 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, or "all".
play_modetarget_first, source_first or mix. On tables, target is the question column.
question_column_id / answer_column_idTable only. column_id values from get_table. Must both be set and must differ.

The name shown on a deck, table, text or PDF block is filled in from the item itself. Linking to an item that is not yours returns 403.

Images and PDFs

Image and PDF blocks need Yalango Premium. Without it the API returns 403 premium_required.

Upload an image (jpeg, png, gif or webp, at most 5 MB) with POST /v1/notebooks/{notebookDocId}/images. Pass file_name, content_type and data_base64 (the file bytes, base64-encoded). The response content string goes straight onto an image block.

Upload a PDF (at most 20 MB) with POST /v1/pdfs/uploads. Pass name, file_name, target_ISO_639-1 and data_base64. A small file fits in one call. Larger ones are split into up to 4 chunks: send chunk_index 0 first (omit upload_id), then the rest with the returned upload_id until complete is true. The response pdf.doc_id is the ref_doc_id for a pdf block.

GET /v1/pdfs lists PDFs already in the library so you can embed one without uploading it again.

These two upload routes accept bodies up to 8 MB. Every other route stays at 256 KB.

Edit a page

Read the page first with GET /v1/notebooks/{notebookDocId}/pages/{pageDocId}. Every block has an id.

Then send PATCH with the complete list of blocks in the order you want:

{
  "blocks": [
    { "id": "c1d2e3f4-..." },
    { "id": "a9b8c7d6-...", "content": "Use **ser** for identity, origin and time." },
    { "type": "markdown", "content": "A new paragraph at the end." }
  ]
}
  • { "id" } on its own keeps that block exactly as it is.
  • An id with fields edits that block.
  • A block without an id is added as a new block.
  • A block you leave out is removed. Dropping an image block deletes its file from storage.

A page can have up to 300 blocks and a title of up to 300 characters. Pages cannot move between sections.

Delete

  • DELETE /v1/notebooks/{notebookDocId}/pages/{pageDocId} deletes one page and its uploaded images.
  • DELETE /v1/notebooks/{notebookDocId} deletes the whole notebook with all of its sections, pages and images.

Neither can be undone.

Published courses

A notebook published as a language course can be read but not changed through the API. Any change returns 409 notebook_is_course.

Limits

The free plan allows 10 notebooks. Going over returns 402 quota_exceeded. A notebook can have up to 200 sections and 1,000 pages. Yalango Premium removes the notebook limit.

Was this article helpful?
0

Comments

Sign in to join the conversation.