Skip to content
Developer API

Build activities from your own system

One POST per activity type. Send your content as JSON, get back an activity in your Puzzel.org account and a URL you can hand to players or drop into an iframe.

Base URL
https://puzzel.org/api/public/v1
Auth
Key + email in the body
Endpoints
38 activity types
Quota
10 activities a day

Your first request

Nothing to install and no handshake: post a JSON body with your key, your email and your content. The response carries the new activity's key and the URL it plays at.

POST crossword
curl -X POST https://puzzel.org/api/public/v1/crossword \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "Crossword",
  "language": "en",
  "items": [
    {
      "answer": "BANANA",
      "description": "A long yellow fruit",
      "type": "text"
    },
    {
      "answer": "CHERRY",
      "description": "A small red stone fruit",
      "type": "text"
    },
    {
      "answer": "MELON",
      "description": "Big, green outside, sweet inside",
      "type": "text"
    }
  ]
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/crossword/embed?p=-Nq8sample_activity_key",
  "message": "Crossword created successfully"
}

Every example on this page is a complete, runnable request. Swap in your own key and content and it works as-is.

Authentication

There are no headers and no bearer token. Both credentials travel in the JSON body of every request, and the key is only accepted for the account that email belongs to.

FieldTypeWhat it does
account_api_key
required
string
stringYour account's API key. It goes in the body, not in a header.
email
required
string
stringThe address your Puzzel.org account signs in with. The key is only valid together with it.

Your key sits on the account section of your dashboard, behind Show.

Sign in

API keys are handed out when a subscription starts, so a free account does not have one yet.

See the plans

Treat the key like a password. It creates and overwrites activities in your account, so keep it server-side and out of anything a browser can read.

The request body

Every endpoint takes the same five fields. What differs is the content field underneath them: most take an array of items, a few take one sentence or one image, and sudoku takes nothing at all.

FieldTypeWhat it does
account_api_key
required
string
stringYour account's API key. It goes in the body, not in a header.
email
required
string
stringThe address your Puzzel.org account signs in with. The key is only valid together with it.
title
optional
string
stringThe name the activity gets in your dashboard. Leave it out and the endpoint uses its own fallback name.
language
optional
string
stringOnly decides the locale in the URL you get back — it does not translate anything you send. Word search also reads it to switch its filler letters to Arabic when it is "ar".
Default: "en"
activity_key
optional
string
stringLeave it out to create a new activity. Pass the key of one you already own and that activity is rebuilt instead.

settings is an object of per-endpoint options. Which ones an endpoint reads is listed with it below; anything else you put there is ignored.

What comes back

A successful call answers 200 with the new activity's key and the URL it plays at. Anything else answers with success set to false and a single error string.

Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/crossword/embed?p=-Nq8sample_activity_key",
  "message": "Crossword created successfully"
}
Failure
{
  "success": false,
  "error": "Invalid Email or API Key"
}

The url you get back is the embed view. Swap embed for play to open it full-page, or for build to open it in the builder — the key after p= stays the same.

Creating vs. updating

Send activity_key and the activity behind it is rebuilt in place: its content is replaced, its name and version stamp are refreshed, and the key itself stays the same — so links and embeds you already shared keep working. Results, folder placement and every setting the endpoint does not write itself are left as they were.

activity_key
{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "activity_key": "-Nq8sample_activity_key",
  "title": "Fruit crossword, week 2",
  "items": [
    {
      "answer": "BANANA",
      "description": "A long yellow fruit",
      "type": "text"
    },
    {
      "answer": "CHERRY",
      "description": "A small red stone fruit",
      "type": "text"
    },
    {
      "answer": "MELON",
      "description": "Big, green outside, sweet inside",
      "type": "text"
    }
  ]
}
  • title is applied on every update, its default included — leave it out and the activity is renamed to that endpoint's fallback name.
  • The setting blocks an endpoint writes itself are rewritten from scratch, so an update also resets those to the values you send, or to the endpoint's defaults.
  • You can only update activities your own account owns. Someone else's key answers 403.
  • An update costs the same as a create: one call off today's quota.

Rate limit

10
10 activities per account per day

Every successful call counts, creates and updates alike. Go over and the next request answers 429 until the counter is cleared.

The counter is wiped once a day by a scheduled job, not on a rolling 24-hour window.

Errors

Errors always arrive as JSON with the same two fields, never as an HTML page. The error string is written to be read by a person — it names the field or the limit that failed.

StatusWhat it means
400
Bad Request
Something in the body is missing, malformed or out of range. The message names the field.
401
Unauthorized
The email is unknown, or the key does not belong to that account.
403
Forbidden
The activity_key you sent belongs to a different account.
429
Too Many Requests
Today's quota is used up. It clears once a day.
500
Server Error
The generator could not build a puzzle from what you sent — usually too few words, or words that cannot be fitted together.

Endpoints

One path per activity type, all POST, all under the same base URL. Each one lists the content it needs, the settings it reads and a request you can run.

Words & letters

Crossword puzzle

Interlocks your answers into a grid and numbers the clues for you.

#
POST /api/public/v1/crossword 2 to 80 in items
Content

An array of words. Each entry pairs the answer with the clue that points at it.

Falls back to the name “Crossword API”

Worth knowing
  • Answers shorter than two characters are dropped before the grid is built, and at least two have to survive that.
  • Answers are upper-cased and the generator gets twenty attempts to fit them. If it cannot place a single word the call answers 500.
Settings it reads
FieldTypeWhat it does
hidden_solution
optional in settings
string
stringAn optional bonus word. Its letters are marked in cells of the finished grid, for players to collect once the crossword is solved, so every letter of it has to appear in the answers.
Example request
POST crossword
curl -X POST https://puzzel.org/api/public/v1/crossword \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "Crossword",
  "language": "en",
  "items": [
    {
      "answer": "BANANA",
      "description": "A long yellow fruit",
      "type": "text"
    },
    {
      "answer": "CHERRY",
      "description": "A small red stone fruit",
      "type": "text"
    },
    {
      "answer": "MELON",
      "description": "Big, green outside, sweet inside",
      "type": "text"
    }
  ]
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/crossword/embed?p=-Nq8sample_activity_key",
  "message": "Crossword created successfully"
}

Word search

Hides your words in a letter grid, in the directions and the shape you choose.

#
POST /api/public/v1/wordseeker 2 to 40 in items
Content

An array of words. The clue text becomes the word list players work from.

Falls back to the name “Wordseeker API”

Worth knowing
  • Answers under two characters are dropped, and every answer is upper-cased before it goes into the grid.
  • The grid is padded with Latin letters unless language is "ar", which switches the filler to Arabic.
Settings it reads
FieldTypeWhat it does
hidden_solution
optional in settings
string
stringThe leftover letters spell this out. Setting it also tells the generator to fit the solution first rather than pack in as many words as it can.
directions
optional in settings
string[]
string[]Which ways a word may run. Leave it out and words run east, south-east and south only.
One of westeastnorthsouthnorthwestnortheastsouthwestsoutheast
Default: ["east", "southeast", "south"]
template
optional in settings
string
stringCuts the grid into a shape instead of leaving it square.
One of squarecirclecrossdiamondpyramidsmileystarcross_plus
Example request
POST wordseeker
curl -X POST https://puzzel.org/api/public/v1/wordseeker \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "Wordseeker",
  "language": "en",
  "items": [
    {
      "answer": "BANANA",
      "description": "A long yellow fruit",
      "type": "text"
    },
    {
      "answer": "CHERRY",
      "description": "A small red stone fruit",
      "type": "text"
    },
    {
      "answer": "MELON",
      "description": "Big, green outside, sweet inside",
      "type": "text"
    }
  ],
  "settings": {
    "hidden_solution": "FRUIT",
    "directions": [
      "east",
      "south",
      "southeast"
    ],
    "template": "square"
  }
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/wordseeker/embed?p=-Nq8sample_activity_key",
  "message": "Wordseeker created successfully"
}

Acrostic

Stacks your answers so one column spells a hidden word.

#
POST /api/public/v1/acrostic 1 to 40 in items
Content

An array of words. Between them they have to supply every letter of the hidden word.

Falls back to the name “Acrostic API”

Worth knowing
  • If the answers cannot supply the letters the solution needs, the call answers 500 rather than saving a half-built grid.
  • The generator reorders your answers to make the column work, so the order you send is not the order players see.
Settings it reads
FieldTypeWhat it does
hidden_solution
required in settings
string
stringThe word the highlighted column spells out. This endpoint will not run without it.
Example request
POST acrostic
curl -X POST https://puzzel.org/api/public/v1/acrostic \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "Acrostic",
  "language": "en",
  "items": [
    {
      "answer": "PEACH",
      "description": "Fuzzy skin, sweet flesh",
      "type": "text"
    },
    {
      "answer": "BANANA",
      "description": "A long yellow fruit",
      "type": "text"
    },
    {
      "answer": "CHERRY",
      "description": "A small red stone fruit",
      "type": "text"
    },
    {
      "answer": "MELON",
      "description": "Big, green outside, sweet inside",
      "type": "text"
    }
  ],
  "settings": {
    "hidden_solution": "PLUM"
  }
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/acrostic/embed?p=-Nq8sample_activity_key",
  "message": "Acrostic created successfully"
}

Word scramble

api_e_word_scramble

#
POST /api/public/v1/word-scramble 1 to 40 in items
Content

api_c_word_scramble

Falls back to the name “Word Scramble API”

Worth knowing
  • Activities made through the API always have the shuffle-the-order setting on, so the order you send is not the order players get.
Settings it reads
FieldTypeWhat it does
hidden_solution
optional in settings
string
stringAn optional bonus word players enter once the rest is solved.
Example request
POST word-scramble
curl -X POST https://puzzel.org/api/public/v1/word-scramble \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "Word Scramble",
  "language": "en",
  "items": [
    {
      "answer": "BANANA",
      "description": "A long yellow fruit",
      "type": "text"
    },
    {
      "answer": "CHERRY",
      "description": "A small red stone fruit",
      "type": "text"
    },
    {
      "answer": "MELON",
      "description": "Big, green outside, sweet inside",
      "type": "text"
    }
  ],
  "settings": {
    "hidden_solution": "FRUIT"
  }
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/word-scramble/embed?p=-Nq8sample_activity_key",
  "message": "Word Scramble created successfully"
}

Hangman

Turns your words or phrases into guess-the-letter rounds.

#
POST /api/public/v1/hangman 1 to 50 in items
Content

An array of words or short phrases. The clue is the hint players see.

Falls back to the name “Hangman API”

Example request
POST hangman
curl -X POST https://puzzel.org/api/public/v1/hangman \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "Hangman",
  "language": "en",
  "items": [
    {
      "answer": "BANANA",
      "description": "A long yellow fruit",
      "type": "text"
    }
  ]
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/hangman/embed?p=-Nq8sample_activity_key",
  "message": "Hangman created successfully"
}

Wordle

Makes a guess-the-word game out of every word you send.

#
POST /api/public/v1/wordle 1 to 50 in items
Content

An array of words. Players get one round per word.

Falls back to the name “Wordle API”

Worth knowing
  • Made with the check-that-guesses-are-real-words setting on. Switch it off in the builder if your words are names or invented.
Example request
POST wordle
curl -X POST https://puzzel.org/api/public/v1/wordle \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "Wordle",
  "language": "en",
  "items": [
    {
      "answer": "MELON",
      "description": "Sweet and green",
      "type": "text"
    },
    {
      "answer": "PEACH",
      "description": "Fuzzy and orange",
      "type": "text"
    }
  ]
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/wordle/embed?p=-Nq8sample_activity_key",
  "message": "Wordle created successfully"
}

Typing practice

api_e_typing_practice

#
POST /api/public/v1/typing-practice 1 to 50 in items
Content

api_c_typing_practice

Falls back to the name “Typing Practice API”

Example request
POST typing-practice
curl -X POST https://puzzel.org/api/public/v1/typing-practice \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "Typing Practice",
  "language": "en",
  "items": [
    {
      "answer": "The quick brown fox jumps over the lazy dog",
      "description": "Every letter of the alphabet",
      "type": "text"
    },
    {
      "answer": "Pack my box with five dozen liquor jugs",
      "description": "Another pangram",
      "type": "text"
    }
  ]
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/typing-practice/embed?p=-Nq8sample_activity_key",
  "message": "Typing Practice created successfully"
}

Wheel of fortune

api_e_wheel_of_fortune

#
POST /api/public/v1/wheel-of-fortune 1 to 50 in items
Content

api_c_wheel_of_fortune

Falls back to the name “Wheel of Fortune API”

Worth knowing
  • Made with “show the outcome in the wheel only”, so the result is read off the wheel rather than announced beside it.
Example request
POST wheel-of-fortune
curl -X POST https://puzzel.org/api/public/v1/wheel-of-fortune \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "Wheel of Fortune",
  "language": "en",
  "items": [
    {
      "answer": "Read a page aloud",
      "description": "Segment 1",
      "type": "text"
    },
    {
      "answer": "Name three fruits",
      "description": "Segment 2",
      "type": "text"
    },
    {
      "answer": "Spell it backwards",
      "description": "Segment 3",
      "type": "text"
    }
  ]
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/wheel-of-fortune/embed?p=-Nq8sample_activity_key",
  "message": "Wheel of Fortune created successfully"
}

Arrowword

An arrow crossword: the clues sit inside the grid, each with an arrow to its answer.

#
POST /api/public/v1/arrowword 2 to 80 in items
Content

An array of words. Each entry pairs the answer with a clue short enough to fit in one cell.

Falls back to the name “Arrowword API”

Settings it reads
FieldTypeWhat it does
hidden_solution
optional in settings
string
stringAn optional bonus word. Its letters are marked in cells of the finished grid, so every letter of it has to appear in the answers.
Example request
POST arrowword
curl -X POST https://puzzel.org/api/public/v1/arrowword \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "Arrowword",
  "language": "en",
  "items": [
    {
      "answer": "Stockholm",
      "description": "Capital of Sweden",
      "type": "text"
    },
    {
      "answer": "Oslo",
      "description": "Capital of Norway",
      "type": "text"
    },
    {
      "answer": "Helsinki",
      "description": "Capital of Finland",
      "type": "text"
    }
  ],
  "settings": {
    "hidden_solution": "North"
  }
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/arrowword/embed?p=-Nq8sample_activity_key",
  "message": "Arrowword created successfully"
}

Strands

A grid in which every letter belongs to a themed word, with one word that names the theme running from edge to edge.

#
POST /api/public/v1/strands 2 to 24 in items
Content

An array of theme words. Together with the spangram their letters have to fill a board exactly.

Falls back to the name “Strands API”

Worth knowing
  • The letters of all words and the spangram together have to come to exactly 30, 35, 36, 40, 42, 45, 48, 49, 50, 54, 56, 60, 63, 64, 70, 72 or 80. Any other count answers 400 and says how many letters to add or remove.
Settings it reads
FieldTypeWhat it does
theme
optional in settings
string
stringThe riddle shown above the grid. Left out, players see the title.
spangram
optional in settings
string
stringThe word or phrase that names the theme and crosses the board from one edge to the other.
Example request
POST strands
curl -X POST https://puzzel.org/api/public/v1/strands \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "Strands",
  "language": "en",
  "items": [
    {
      "answer": "whisk",
      "type": "text"
    },
    {
      "answer": "ladle",
      "type": "text"
    },
    {
      "answer": "spatula",
      "type": "text"
    },
    {
      "answer": "grater",
      "type": "text"
    },
    {
      "answer": "peeler",
      "type": "text"
    },
    {
      "answer": "skillet",
      "type": "text"
    }
  ],
  "settings": {
    "theme": "What the cook reaches for",
    "spangram": "Kitchen tools"
  }
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/strands/embed?p=-Nq8sample_activity_key",
  "message": "Strands created successfully"
}

Name them all

api_e_name_them_all

#
POST /api/public/v1/name-them-all 1 to 250 in items
Content

api_c_name_them_all

Falls back to the name “Name Them All API”

Worth knowing
  • An entry is an object with an answer, and optionally aliases (other spellings that count), a description (the hint) and a group. Capitals, accents and punctuation are ignored when a name is checked.
Settings it reads
FieldTypeWhat it does
list_match_mode
optional in settings
string
stringWhether a name counts the moment it is typed, or only on Enter.
One of while_typingon_enter
Default: "while_typing"
list_slot_hint
optional in settings
string
stringWhat an empty slot gives away: nothing, the length of the name, its first letter, or the hint you wrote.
One of nonelengthfirst_letterhint
Default: "none"
list_arrange
optional in settings
string
stringOne column per group, or one list.
One of groupsone_list
Default: "groups"
list_allow_give_up
optional in settings
boolean
booleanShows a give-up button that ends the run and reveals what was missed.
Default: false
Example request
POST name-them-all
curl -X POST https://puzzel.org/api/public/v1/name-them-all \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "Name Them All",
  "language": "en",
  "items": [
    {
      "answer": "United Kingdom",
      "aliases": [
        "UK",
        "Great Britain",
        "Britain"
      ],
      "group": "Islands"
    },
    {
      "answer": "Ireland",
      "aliases": [
        "Éire"
      ],
      "group": "Islands"
    },
    {
      "answer": "Côte d'Azur's neighbour Monaco",
      "aliases": [
        "Monaco"
      ],
      "description": "The smallest one",
      "group": "Mainland"
    }
  ],
  "settings": {
    "list_slot_hint": "first_letter",
    "list_match_mode": "on_enter",
    "list_allow_give_up": true
  }
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/name-them-all/embed?p=-Nq8sample_activity_key",
  "message": "Name them all list created successfully"
}
Cards & pairs

Memory

Face-down cards to turn over and match in pairs.

#
POST /api/public/v1/memory 2 to 30 in items
Content

An array of pairs. Each pair holds the two cards that belong together.

Falls back to the name “Memory Game API”

Worth knowing
  • A card is an object with a type and a value. Use "text" for words, or "image", "audio", "youtube" or "link" with a URL in value, and add alt for a description.
Example request
POST memory
curl -X POST https://puzzel.org/api/public/v1/memory \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "Memory Game",
  "language": "en",
  "items": [
    {
      "cards": [
        {
          "type": "text",
          "value": "Apple"
        },
        {
          "type": "text",
          "value": "A red fruit"
        }
      ]
    },
    {
      "cards": [
        {
          "type": "text",
          "value": "Banana"
        },
        {
          "type": "text",
          "value": "A yellow fruit"
        }
      ]
    }
  ]
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/memory/embed?p=-Nq8sample_activity_key",
  "message": "Memory game created successfully"
}

Match them up

api_e_matching_pairs

#
POST /api/public/v1/matching-pairs 2 to 30 in items
Content

api_c_matching_pairs

Falls back to the name “Matching Game API”

Worth knowing
  • A card is an object with a type and a value. Use "text" for words, or "image", "audio", "youtube" or "link" with a URL in value, and add alt for a description.
Example request
POST matching-pairs
curl -X POST https://puzzel.org/api/public/v1/matching-pairs \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "Matching Game",
  "language": "en",
  "items": [
    {
      "cards": [
        {
          "type": "text",
          "value": "Apple"
        },
        {
          "type": "text",
          "value": "A red fruit"
        }
      ]
    },
    {
      "cards": [
        {
          "type": "text",
          "value": "Banana"
        },
        {
          "type": "text",
          "value": "A yellow fruit"
        }
      ]
    }
  ]
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/matching-pairs/embed?p=-Nq8sample_activity_key",
  "message": "Matching pairs game created successfully"
}

Flash cards

api_e_flash_cards

#
POST /api/public/v1/flash-cards 1 to 150 in items
Content

api_c_flash_cards

Falls back to the name “Flash Cards API”

Worth knowing
  • The endpoint stores as many cards as you send, so send exactly two per entry — front, then back.
  • A card is an object with a type and a value. Use "text" for words, or "image", "audio", "youtube" or "link" with a URL in value, and add alt for a description.
Example request
POST flash-cards
curl -X POST https://puzzel.org/api/public/v1/flash-cards \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "Flash Cards",
  "language": "en",
  "items": [
    {
      "cards": [
        {
          "type": "text",
          "value": "Apple"
        },
        {
          "type": "text",
          "value": "A red fruit"
        }
      ]
    },
    {
      "cards": [
        {
          "type": "text",
          "value": "Banana"
        },
        {
          "type": "text",
          "value": "A yellow fruit"
        }
      ]
    }
  ]
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/flash-cards/embed?p=-Nq8sample_activity_key",
  "message": "Flash Cards created successfully"
}

Categorize

Cards to sort into the bucket they belong in.

#
POST /api/public/v1/categorize At least 2 in items · at most 60 cards in all
Content

An array of categories, each with a name and the cards that belong in it.

Falls back to the name “Categorize Game API”

Worth knowing
  • A category sent without a name is saved as “Untitled Category”, so always send one.
  • A card is an object with a type and a value. Use "text" for words, or "image", "audio", "youtube" or "link" with a URL in value, and add alt for a description.
Example request
POST categorize
curl -X POST https://puzzel.org/api/public/v1/categorize \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "Categorize Game",
  "language": "en",
  "items": [
    {
      "name": "Red fruits",
      "cards": [
        {
          "type": "text",
          "value": "Strawberry"
        },
        {
          "type": "text",
          "value": "Cherry"
        }
      ]
    },
    {
      "name": "Yellow fruits",
      "cards": [
        {
          "type": "text",
          "value": "Banana"
        },
        {
          "type": "text",
          "value": "Lemon"
        }
      ]
    }
  ]
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/categorize/embed?p=-Nq8sample_activity_key",
  "message": "Categorize game created successfully"
}

Reorder

A sequence players have to put back in order.

#
POST /api/public/v1/reorder At least 1 in items · at most 60 cards in all
Content

An array of sequences. Each holds its cards in the correct order.

Falls back to the name “Reorder Game API”

Worth knowing
  • The order you send is stored as the correct order — number one first.
  • A card is an object with a type and a value. Use "text" for words, or "image", "audio", "youtube" or "link" with a URL in value, and add alt for a description.
Example request
POST reorder
curl -X POST https://puzzel.org/api/public/v1/reorder \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "Reorder Game",
  "language": "en",
  "items": [
    {
      "name": "From seed to fruit",
      "cards": [
        {
          "type": "text",
          "value": "Plant the seed"
        },
        {
          "type": "text",
          "value": "Water it"
        },
        {
          "type": "text",
          "value": "Watch it grow"
        },
        {
          "type": "text",
          "value": "Pick the fruit"
        }
      ]
    }
  ]
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/reorder/embed?p=-Nq8sample_activity_key",
  "message": "Reorder game created successfully"
}

Bingo

A class bingo the host calls live: every player gets a card drawn from your items.

#
POST /api/public/v1/bingo Takes no items
Content

An array of items the cards are drawn from. Send clearly more than one card has squares, so that cards differ.

Falls back to the name “Bingo API”

Worth knowing
  • An item is an object with a value, and optionally a type ("text", "image" or "audio" with a URL in value), a description (the clue the host reads out in clues mode) and alt.
Settings it reads
FieldTypeWhat it does
mode
optional in settings
string
stringWhat fills the squares: your items, your items called by their clue, or plain numbers (which need no items).
One of itemscluesnumbers
Default: "items"
rows
optional in settings
number
numberRows on each card, 2 to 5.
Default: 3
columns
optional in settings
number
numberColumns on each card, 2 to 5.
Default: 3
highest_number
optional in settings
number
numberIn numbers mode, cards are filled from 1 up to this number, 100 at most. A plan feature: without a plan it stays 50.
Default: 50
Example request
POST bingo
curl -X POST https://puzzel.org/api/public/v1/bingo \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "Bingo",
  "language": "en",
  "items": [
    {
      "type": "text",
      "value": "Paris",
      "description": "The capital of France"
    },
    {
      "type": "text",
      "value": "Berlin",
      "description": "The capital of Germany"
    },
    {
      "type": "text",
      "value": "Madrid",
      "description": "The capital of Spain"
    }
  ],
  "settings": {
    "mode": "clues",
    "rows": 3,
    "columns": 4,
    "highest_number": 75
  }
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/bingo/embed?p=-Nq8sample_activity_key",
  "message": "Bingo created successfully"
}

I have, who has

api_e_i_have_who_has

#
POST /api/public/v1/i-have-who-has 3 to 40 in items
Content

api_c_i_have_who_has

Falls back to the name “I Have, Who Has API”

Worth knowing
  • No question and no answer may appear twice: a pupil holding the answer could not tell which question it belongs to.
Settings it reads
FieldTypeWhat it does
chain_shape
optional in settings
string
stringA loop closes on itself, so any card can start; a line opens on a Start card and ends on an End card.
One of loopline
Default: "loop"
Example request
POST i-have-who-has
curl -X POST https://puzzel.org/api/public/v1/i-have-who-has \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "I Have, Who Has",
  "language": "en",
  "items": [
    {
      "cards": [
        {
          "type": "text",
          "value": "3 × 4"
        },
        {
          "type": "text",
          "value": "12"
        }
      ]
    },
    {
      "cards": [
        {
          "type": "text",
          "value": "6 × 7"
        },
        {
          "type": "text",
          "value": "42"
        }
      ]
    },
    {
      "cards": [
        {
          "type": "text",
          "value": "9 × 9"
        },
        {
          "type": "text",
          "value": "81"
        }
      ]
    }
  ],
  "settings": {
    "chain_shape": "line"
  }
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/i-have-who-has/embed?p=-Nq8sample_activity_key",
  "message": "I have, who has created successfully"
}

Keypad

A code lock: a pad of keys, some of which together are the code.

#
POST /api/public/v1/keypad 1 to 30 in items
Content

An array of keys. The keys in the code carry their place in it.

Falls back to the name “Keypad API”

Worth knowing
  • A key is an object with a value, and optionally a type ("text", "image" or "audio" with a URL in value), alt, and code_position: its place in the code, 1 first. A key can be in the code once, and at least one key has to be.
Settings it reads
FieldTypeWhat it does
instructions
optional in settings
string
stringThe question or riddle the code answers, shown with the pad.
force_solution_in_correct_order
optional in settings
boolean
booleanThe keys have to be pressed in order. Off, any order of the right keys opens the lock.
Default: false
randomize_order
optional in settings
boolean
booleanEach player gets the keys in a shuffled arrangement.
Default: true
Example request
POST keypad
curl -X POST https://puzzel.org/api/public/v1/keypad \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "Keypad",
  "language": "en",
  "items": [
    {
      "type": "text",
      "value": "4"
    },
    {
      "type": "text",
      "value": "7",
      "code_position": 2
    },
    {
      "type": "text",
      "value": "9"
    },
    {
      "type": "text",
      "value": "2",
      "code_position": 1
    }
  ],
  "settings": {
    "instructions": "Press the prime numbers, smallest first.",
    "force_solution_in_correct_order": true,
    "randomize_order": false
  }
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/keypad/embed?p=-Nq8sample_activity_key",
  "message": "Keypad created successfully"
}

Quartets

The card game: players ask each other for cards to collect sets of four.

#
POST /api/public/v1/quartets 2 to 16 in items
Content

An array of sets. Each has a name and exactly four cards.

Falls back to the name “Quartets API”

Worth knowing
  • A card is a name, or an object with a name and a description (the fact shown on it). No card name may appear twice in the game: players ask for cards by name.
Settings it reads
FieldTypeWhat it does
type
optional in settings
string
stringA plain game, or a learning game in which every card shows a fact. Left out, it is learn when any card has a description.
One of normallearn
Example request
POST quartets
curl -X POST https://puzzel.org/api/public/v1/quartets \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "Quartets",
  "language": "en",
  "items": [
    {
      "name": "Birds",
      "cards": [
        {
          "name": "Owl",
          "description": "Hunts at night and turns its head three quarters of the way round."
        },
        {
          "name": "Robin",
          "description": "Sings through the winter."
        },
        {
          "name": "Woodpecker",
          "description": "Drums on trees up to twenty times a second."
        },
        {
          "name": "Jay",
          "description": "Buries thousands of acorns each autumn."
        }
      ]
    },
    {
      "name": "Mammals",
      "cards": [
        {
          "name": "Hedgehog",
          "description": "Carries about five thousand spines."
        },
        {
          "name": "Fox",
          "description": "Hears a mouse under the snow."
        },
        {
          "name": "Badger",
          "description": "Lives in a sett with its clan."
        },
        {
          "name": "Otter",
          "description": "Sleeps holding hands so it does not drift off."
        }
      ]
    }
  ],
  "settings": {
    "type": "learn"
  }
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/quartets/embed?p=-Nq8sample_activity_key",
  "message": "Quartets game created successfully"
}
Questions & answers

Quiz

Multiple-choice and open questions, scored as players go.

#
POST /api/public/v1/quiz 1 to 100 in items
Content

An array of questions. Multiple-choice questions carry their answers; open questions carry the answer you accept.

Falls back to the name “Quiz API”

Worth knowing
  • question_type is "multiple_choice", where the right option carries isCorrect true; "true_false", the same with exactly two options, true first and false second; or "open_answer", which uses correct_answer instead. Left out, it is treated as multiple choice.
  • The quiz endpoint passes settings straight through as activity setting blocks, so it is not a place for loose options — adjust the quiz in the builder afterwards.
Example request
POST quiz
curl -X POST https://puzzel.org/api/public/v1/quiz \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "Quiz",
  "language": "en",
  "items": [
    {
      "question_type": "multiple_choice",
      "description": "Which fruit is yellow?",
      "answers": [
        {
          "type": "text",
          "description": "Banana",
          "isCorrect": true
        },
        {
          "type": "text",
          "description": "Cherry",
          "isCorrect": false
        }
      ]
    },
    {
      "question_type": "open_answer",
      "description": "What colour is a lemon?",
      "correct_answer": "Yellow",
      "explanation": "Lemons ripen from green to yellow."
    }
  ]
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/quiz/embed?p=-Nq8sample_activity_key",
  "message": "Quiz created successfully"
}

Board game

api_e_board_game

#
POST /api/public/v1/board-game 1 to 100 in items
Content

api_c_board_game

Falls back to the name “Board Game API”

Worth knowing
  • question_type is "multiple_choice", where the right option carries isCorrect true; "true_false", the same with exactly two options, true first and false second; or "open_answer", which uses correct_answer instead. Left out, it is treated as multiple choice.
Settings it reads
FieldTypeWhat it does
number_of_tiles
optional in settings
number
numberHow many tiles the board has. Between 10 and 75.
Default: 30
game_mode
optional in settings
string
stringWhether players race to the finish or collect items along the way.
One of race_to_finishcollect_items
Default: "race_to_finish"
Example request
POST board-game
curl -X POST https://puzzel.org/api/public/v1/board-game \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "Board Game",
  "language": "en",
  "items": [
    {
      "question_type": "multiple_choice",
      "description": "Which fruit is yellow?",
      "answers": [
        {
          "type": "text",
          "description": "Banana",
          "isCorrect": true
        },
        {
          "type": "text",
          "description": "Cherry",
          "isCorrect": false
        }
      ]
    },
    {
      "question_type": "open_answer",
      "description": "What colour is a lemon?",
      "correct_answer": "Yellow",
      "explanation": "Lemons ripen from green to yellow."
    }
  ],
  "settings": {
    "number_of_tiles": 30,
    "game_mode": "race_to_finish"
  }
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/board-game/embed?p=-Nq8sample_activity_key",
  "message": "Board Game created successfully"
}

Maze

A maze to walk through: every question is a hall, and its answers are the doors.

#
POST /api/public/v1/maze At least 1 in items
Content

An array of multiple-choice or true-false questions, exactly the shape the quiz endpoint takes. Open questions are refused: a door needs an answer written on it.

Falls back to the name “Maze API”

Settings it reads
FieldTypeWhat it does
maze_width
optional in settings
string
stringHow the halls are laid out: one column, a square, or wider.
One of narrownormalwide
Default: "normal"
maze_corridors
optional in settings
string
stringHow much maze lies between two questions.
One of shortnormallong
Default: "normal"
maze_fog
optional in settings
string
stringShow the whole maze, or only what the player has been next to.
One of offnear
Default: "off"
maze_wrong_door_pause
optional in settings
string
stringHow long the doors stay shut after a wrong one.
One of noneshortlong
Default: "short"
maze_walk_there
optional in settings
boolean
booleanOffers a button that walks the token to the next hall.
Default: false
maze_seed
optional in settings
string
stringThe seed the maze is generated from. The same seed and questions give the same maze; left out, a new one is drawn.
Example request
POST maze
curl -X POST https://puzzel.org/api/public/v1/maze \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "Maze",
  "language": "en",
  "items": [
    {
      "question_type": "multiple_choice",
      "description": "What is it called when water vapour turns back into liquid droplets?",
      "answers": [
        {
          "type": "text",
          "description": "Evaporation",
          "isCorrect": false
        },
        {
          "type": "text",
          "description": "Condensation",
          "isCorrect": true
        },
        {
          "type": "text",
          "description": "Transpiration",
          "isCorrect": false
        }
      ],
      "explanation": "Cooling vapour condenses into the droplets that make clouds."
    },
    {
      "question_type": "true_false",
      "description": "Most of the water on Earth is fresh water.",
      "answers": [
        {
          "type": "text",
          "description": "True",
          "isCorrect": false
        },
        {
          "type": "text",
          "description": "False",
          "isCorrect": true
        }
      ]
    }
  ],
  "settings": {
    "maze_width": "wide",
    "maze_corridors": "short",
    "maze_seed": "water123",
    "maze_fog": "near"
  }
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/maze/embed?p=-Nq8sample_activity_key",
  "message": "Maze created successfully"
}

Jeopardy

A game-show board: categories across the top, clues underneath that are worth more the further down they sit.

#
POST /api/public/v1/jeopardy At least 2 in items
Content

An array of categories, left to right. Each has a name and its clues from the top row down.

Falls back to the name “Jeopardy API”

Worth knowing
  • A clue is a question as the quiz endpoint takes it, open_answer unless it says otherwise, with correct_answer and optionally aliases. It may also carry value (its own worth) and daily_double. null leaves a cell empty.
Settings it reads
FieldTypeWhat it does
jeopardy_buzzer_mode
optional in settings
string
stringWho plays how: the host runs it from the console, players buzz from their phones, or each player works the board alone.
One of hostphonessolo
Default: "host"
jeopardy_contestants
optional in settings
string
stringWhether the console speaks of teams or of players.
One of teamsplayers
Default: "teams"
jeopardy_value_step
optional in settings
number
numberWhat a row is worth: a clue is worth this times its row number. From 50 to 500, in steps of 50.
Default: 100
jeopardy_answer_time
optional in settings
number
numberSeconds to answer once a clue is open, up to 300. 0 is no clock.
Default: 20
jeopardy_wrong_answer_costs
optional in settings
boolean
booleanA wrong answer takes the clue's value off the score.
Default: false
jeopardy_reveal_on_timeout
optional in settings
boolean
booleanThe board shows the answer itself when the clock runs out.
Default: false
jeopardy_require_question_form
optional in settings
boolean
booleanReminds players to answer in the form of a question.
Default: false
Example request
POST jeopardy
curl -X POST https://puzzel.org/api/public/v1/jeopardy \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "Jeopardy",
  "language": "en",
  "items": [
    {
      "name": "Planets",
      "questions": [
        {
          "question_type": "open_answer",
          "description": "The planet closest to the Sun.",
          "correct_answer": "Mercury"
        },
        {
          "question_type": "open_answer",
          "description": "It is known as the red planet.",
          "correct_answer": "Mars",
          "explanation": "Iron oxide in its soil gives it the colour."
        },
        {
          "question_type": "multiple_choice",
          "description": "This planet has the most confirmed moons.",
          "answers": [
            {
              "description": "Jupiter",
              "isCorrect": false
            },
            {
              "description": "Saturn",
              "isCorrect": true
            },
            {
              "description": "Neptune",
              "isCorrect": false
            }
          ],
          "daily_double": true
        }
      ]
    },
    {
      "name": "Moons",
      "questions": [
        {
          "question_type": "open_answer",
          "description": "The only world besides Earth that people have walked on.",
          "correct_answer": "The Moon",
          "aliases": [
            "Luna"
          ]
        },
        null,
        {
          "question_type": "name_them_all",
          "description": "Name the four Galilean satellites.",
          "answers": [
            {
              "description": "Io"
            },
            {
              "description": "Europa"
            },
            {
              "description": "Ganymede",
              "aliases": [
                "Ganymedes"
              ]
            },
            {
              "description": "Callisto"
            }
          ],
          "required_count": 3,
          "value": 500
        }
      ]
    }
  ],
  "settings": {
    "jeopardy_buzzer_mode": "solo",
    "jeopardy_value_step": 200,
    "jeopardy_wrong_answer_costs": true
  }
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/jeopardy/embed?p=-Nq8sample_activity_key",
  "message": "Jeopardy board created successfully"
}

Interactive video

api_e_interactive_video

#
POST /api/public/v1/interactive-video 1 to 50 in items
Content

api_c_interactive_video

Falls back to the name “Interactive Video API”

Worth knowing
  • A popup is an object with time (seconds, or "1:23"), kind ("question" unless it says "note", "think" or "chapter") and description. A question is a question as the quiz endpoint takes it, and may carry rewind_to: where a wrong answer replays from.
Settings it reads
FieldTypeWhat it does
video_url
required in settings
string
stringThe video: a YouTube, Vimeo or Bunny Stream page, or a direct link to an mp4, webm or mov file.
video_duration
optional in settings
number
numberThe length of the video in seconds. When given, a popup past the end is refused.
Example request
POST interactive-video
curl -X POST https://puzzel.org/api/public/v1/interactive-video \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "Interactive Video",
  "language": "en",
  "items": [
    {
      "time": 5,
      "kind": "chapter",
      "description": "Evaporation"
    },
    {
      "time": 42.5,
      "kind": "question",
      "question_type": "multiple_choice",
      "description": "What turns liquid water into vapour?",
      "answers": [
        {
          "type": "text",
          "description": "Heat from the sun",
          "isCorrect": true
        },
        {
          "type": "text",
          "description": "Wind from the north",
          "isCorrect": false
        },
        {
          "type": "text",
          "description": "Salt in the sea",
          "isCorrect": false
        }
      ],
      "explanation": "The sun warms the surface and the water evaporates.",
      "rewind_to": 20
    }
  ],
  "settings": {
    "video_url": "https://www.youtube.com/watch?v=al-do-HGuIk",
    "video_duration": 180,
    "video_allow_skipping": true
  }
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/interactive-video/embed?p=-Nq8sample_activity_key",
  "message": "Interactive video created successfully"
}
Sentences & numbers

Cryptogram

Turns a sentence into a code to crack, one character at a time.

#
POST /api/public/v1/cryptogram Takes no items
Content

One sentence, in the sentence field. This endpoint takes no items.

Falls back to the name “Cryptogram API”

Worth knowing
  • Anything you send in items is ignored — the puzzle is built from the sentence alone.
Settings it reads
FieldTypeWhat it does
sentence
required
string
stringThe sentence to encrypt. Players decode it character by character.
helpers
optional in settings
string
stringWhich characters are given away for free as a way in: none, the most common ones, the vowels, or the ones you list yourself.
One of nonemost_commonvowelscustom
Default: "none"
character_list
optional in settings
string
stringThe alphabet the cipher is built from. Left empty, the encryption picks its own.
extra_letters
optional in settings
string
stringThe characters given away when helpers is "custom". Ignored for the other helper modes.
hide_unused_characters
optional in settings
boolean
booleanLeaves characters the sentence never uses out of the key.
Default: false
Example request
POST cryptogram
curl -X POST https://puzzel.org/api/public/v1/cryptogram \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "Cryptogram",
  "language": "en",
  "sentence": "An apple a day keeps the doctor away",
  "settings": {
    "helpers": "vowels",
    "hide_unused_characters": false
  }
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/cryptogram/embed?p=-Nq8sample_activity_key",
  "message": "Cryptogram created successfully"
}

Calculation

Hides a sentence behind sums — solve the sum, reveal the letter.

#
POST /api/public/v1/calculation Takes no items
Content

One sentence, in the sentence field. This endpoint takes no items.

Falls back to the name “Calculation Game API”

Worth knowing
  • If the constraints are too tight to encode the sentence, the call answers 400 asking you to loosen them rather than saving a partial puzzle.
Settings it reads
FieldTypeWhat it does
sentence
required
string
stringThe sentence players uncover by solving the sums.
difficulty_level
optional in settings
number
numberThe highest answer a sum is allowed to have.
One of 20501001000
Default: "100"
operators
optional in settings
string[]
string[]Which operations may appear. x is multiply, : is divide.
One of +-x:
Default: ["+", "-", "x", ":"]
max_operations
optional in settings
number
numberHow many operations one sum may chain together.
One of 123
Default: 1
number_difficulty
optional in settings
number
numberCaps the individual numbers inside a sum. Anywhere from 5 to 1000.
Default: 100
Example request
POST calculation
curl -X POST https://puzzel.org/api/public/v1/calculation \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "Calculation Game",
  "language": "en",
  "sentence": "Fruit salad for everyone",
  "settings": {
    "difficulty_level": "100",
    "operators": [
      "+",
      "-",
      "x",
      ":"
    ],
    "max_operations": 1,
    "number_difficulty": 100
  }
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/calculation/embed?p=-Nq8sample_activity_key",
  "message": "Calculation game created successfully"
}

Sudoku

Generates a solved grid, then takes numbers back out.

#
POST /api/public/v1/sudoku Takes no items
Content

Nothing. The whole puzzle comes out of its two settings.

Falls back to the name “Sudoku API”

Worth knowing
  • Send no items and no sentence — size and difficulty are the entire input.
  • The builder only offers the difficulty for 2x3, 3x3 and 3x4. The API applies it to every size, 2x2 and 4x4 included.
Settings it reads
FieldTypeWhat it does
size
optional in settings
string
stringThe size of one block, written as rows by columns — 3x3 gives the classic 9x9 grid. The endpoint only checks that it parses as two numbers, so stay with the sizes the builder offers.
One of 2x22x33x33x44x4
Default: "3x3"
difficulty_level
optional in settings
string
stringHow many numbers are left on the board to start from.
One of easynormalhard
Default: "normal"
Example request
POST sudoku
curl -X POST https://puzzel.org/api/public/v1/sudoku \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "Sudoku",
  "language": "en",
  "settings": {
    "size": "3x3",
    "difficulty_level": "normal"
  }
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/sudoku/embed?p=-Nq8sample_activity_key",
  "message": "Sudoku created successfully"
}

Fallen phrase

api_e_fallen_phrase

#
POST /api/public/v1/fallen-phrase Takes no items
Content

api_c_fallen_phrase

Falls back to the name “Fallen Phrase API”

Settings it reads
FieldTypeWhat it does
sentence
required
string
stringThe phrase to hide: a quote, a proverb, a key sentence. At most 120 letters and digits.
columns
optional in settings
number
numberHow wide the board is, from 8 to 18. Narrower stacks more letters in each column and is harder.
Default: 14
helpers
optional in settings
string
stringWhich letters stay in the grid as a way in: none, the most common ones, the vowels, or the ones you list yourself.
One of nonemost_commonvowelscustom
Default: "none"
extra_letters
optional in settings
string
stringThe letters given away when helpers is "custom".
Example request
POST fallen-phrase
curl -X POST https://puzzel.org/api/public/v1/fallen-phrase \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "Fallen Phrase",
  "language": "en",
  "sentence": "Don't count your chickens before they hatch.",
  "settings": {
    "columns": 12,
    "helpers": "custom",
    "extra_letters": "ky"
  }
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/fallen-phrase/embed?p=-Nq8sample_activity_key",
  "message": "Fallen phrase created successfully"
}

Times tables

api_e_times_tables

#
POST /api/public/v1/times-tables Takes no items
Content

api_c_times_tables

Falls back to the name “Times Tables API”

Settings it reads
FieldTypeWhat it does
tables
optional in settings
number[]
number[]The tables to practise. Left out, it is 1 to 10; an 11 or 12 makes the grid 12 by 12.
One of 123456789101112
order
optional in settings
string
stringWhether the rows and columns run in order or shuffled.
One of ascendingshuffled
Default: "ascending"
picture
optional in settings
string
stringThe picture right answers paint.
One of sailboatheartrockettreecatfishflowerhouse
Default: "sailboat"
players_choose_tables
optional in settings
boolean
booleanLets each player pick which of the tables to practise.
Default: false
fill_same_sums
optional in settings
boolean
booleanOne right answer fills every square with the same sum.
Default: true
Example request
POST times-tables
curl -X POST https://puzzel.org/api/public/v1/times-tables \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "Times Tables",
  "language": "en",
  "settings": {
    "tables": [
      7,
      3,
      4
    ],
    "order": "shuffled",
    "seed": "k3x9q2ab",
    "picture": "rocket",
    "players_choose_tables": true,
    "fill_same_sums": false
  }
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/times-tables/embed?p=-Nq8sample_activity_key",
  "message": "Times tables created successfully"
}

Fill in the gap

api_e_fill_in_the_gap

#
POST /api/public/v1/fill-in-the-gap 1 to 50 in items
Content

api_c_fill_in_the_gap

Falls back to the name “Fill in the gap API”

Worth knowing
  • Write the full sentence and put asterisks around each word to leave out: "Water boils at *100* degrees." Several words inside one pair are one gap. An entry may also carry an instruction shown above the sentence.
Example request
POST fill-in-the-gap
curl -X POST https://puzzel.org/api/public/v1/fill-in-the-gap \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "Fill in the gap",
  "language": "en",
  "items": [
    {
      "sentence": "The capital of France is *Paris*, and the river that runs through it is the *Seine*."
    },
    {
      "sentence": "*Amsterdam* is the capital of the Netherlands, but the government sits in *The Hague*.",
      "instruction": "Two cities, one of them two words."
    },
    {
      "sentence": "The *Danube* flows through Vienna, Bratislava, *Budapest* and Belgrade."
    }
  ]
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/fill-in-the-gap/embed?p=-Nq8sample_activity_key",
  "message": "Fill in the gap created successfully"
}

Deconstruct the sentence

Sentences in which players label the words: parts of speech, sentence parts, or labels of your own.

#
POST /api/public/v1/deconstruct 1 to 50 in items
Content

An array of sentences. Each word to label is written as [word](label).

Falls back to the name “Sentence analysis API”

Worth knowing
  • Write a sentence as "The [dog](noun) [barks](verb)." Words without a tag are shown and not asked. The labels noun, verb, adjective and subject are shown to each player in their own language.
Settings it reads
FieldTypeWhat it does
categories
optional in settings
string[]
string[]The labels players choose from, in order. Left out, it is the labels used in the sentences. Send it to add a label no word carries, or to fix the order.
Example request
POST deconstruct
curl -X POST https://puzzel.org/api/public/v1/deconstruct \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "Sentence analysis",
  "language": "en",
  "items": [
    {
      "sentence": "The [old](adjective) [farmer](noun) [feeds](verb) the [hungry](adjective) [chickens](noun) [early](adverb).",
      "instruction": "Label the nouns, verbs, adjectives and adverbs."
    },
    {
      "sentence": "A [brown](adjective) [horse](noun) [jumped](verb) [quickly](adverb) over the [fence](noun)."
    },
    {
      "sentence": "[Two small lambs](subject) [sleep](verb) in the [barn](noun), and the [dog](noun) [watches](verb) [quietly](adverb)."
    }
  ],
  "settings": {
    "categories": [
      "noun",
      "verb",
      "adjective",
      "adverb",
      {
        "name": "subject",
        "color": "#224466"
      },
      "preposition"
    ]
  }
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/deconstruct/embed?p=-Nq8sample_activity_key",
  "message": "Sentence analysis created successfully"
}

Logic puzzle

api_e_logic_puzzle

#
POST /api/public/v1/logic-puzzle At least 3 in items
Content

api_c_logic_puzzle

Falls back to the name “Logic Puzzle API”

Worth knowing
  • Every category needs the same number of items, 3 to 6, all different. One category may be marked ordered (prices, times, ages) with an optional unit, which lets the generator write clues about more, less and how much.
Settings it reads
FieldTypeWhat it does
story
optional in settings
string
stringThe background story shown above the clues.
difficulty
optional in settings
string
stringWhich kinds of clue the generator may use.
One of easymediumhard
Default: "easy"
hints
optional in settings
boolean
booleanOffers a button that shows the next step.
Default: true
auto_cross
optional in settings
boolean
booleanMarking a match crosses out the rest of its row and column.
Default: true
clue_mode
optional in settings
string
stringWho writes the clues players see: generated from the table, your own sentences in free_clues, or none.
One of generatedfreenone
Default: "generated"
free_clues
optional in settings
string[]
string[]Your own clue sentences, shown as written, with clue_mode "free". Nothing checks them.
Example request
POST logic-puzzle
curl -X POST https://puzzel.org/api/public/v1/logic-puzzle \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "Logic Puzzle",
  "language": "en",
  "items": [
    {
      "name": "Baker",
      "items": [
        "Amira",
        "Jonas",
        "Priya",
        "Tobias"
      ]
    },
    {
      "name": "Cake",
      "items": [
        "Lemon drizzle",
        "Carrot cake",
        "Brownies",
        "Apple pie"
      ]
    },
    {
      "name": "Price",
      "items": [
        "$2",
        "$4",
        "$6",
        "$8"
      ],
      "ordered": true,
      "unit": "dollars"
    }
  ],
  "settings": {
    "story": "Four friends each baked one thing for the school bake sale and each set a different price. Who baked what, and what did it cost?",
    "difficulty": "medium"
  }
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/logic-puzzle/embed?p=-Nq8sample_activity_key",
  "message": "Logic puzzle created successfully"
}

Scavenger hunt

api_e_scavenger_hunt

#
POST /api/public/v1/scavenger-hunt 1 to 50 in items
Content

api_c_scavenger_hunt

Falls back to the name “Scavenger Hunt API”

Worth knowing
  • A step is an object with title, description, code and optionally accepted_codes (other spellings that count), url and link_text. A code is checked without regard to capitals and spaces. The map with pins can only be added in the builder.
Example request
POST scavenger-hunt
curl -X POST https://puzzel.org/api/public/v1/scavenger-hunt \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "Scavenger Hunt",
  "language": "en",
  "items": [
    {
      "title": "Start at the front desk",
      "description": "Which year is carved above the entrance?",
      "code": "1897",
      "accepted_codes": [
        "eighteen ninety-seven"
      ]
    },
    {
      "title": "The quiet corner",
      "description": "Find the atlas shelf. What colour is the biggest atlas?",
      "code": "crimson",
      "accepted_codes": [
        "dark red"
      ]
    }
  ]
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/scavenger-hunt/embed?p=-Nq8sample_activity_key",
  "message": "Scavenger hunt created successfully"
}

Spatial reasoning

api_e_spatial_reasoning

#
POST /api/public/v1/spatial-reasoning 1 to 50 in items
Content

api_c_spatial_reasoning

Falls back to the name “Spatial Reasoning API”

Worth knowing
  • Objects and targets are square, triangle, circle, hexagon, pentagon, star, diamond or heart. Relations are inside, outside, behind, in_front_of, right_of, left_of, above, below, same_color_as, different_color_from, larger_than and smaller_than. A rule that can never be met answers 400.
Settings it reads
FieldTypeWhat it does
clue_mode
optional in settings
string
stringRules shown as pictures or as sentences.
One of visualtext
Default: "visual"
unique_object_picks
optional in settings
boolean
booleanEach shape may be placed only once.
Default: false
hide_color_picker
optional in settings
boolean
booleanPlayers cannot recolour shapes.
Default: false
Example request
POST spatial-reasoning
curl -X POST https://puzzel.org/api/public/v1/spatial-reasoning \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "Spatial Reasoning",
  "language": "en",
  "items": [
    {
      "rules": [
        {
          "object": "square",
          "relation": "inside",
          "target": "circle"
        }
      ]
    },
    {
      "rules": [
        {
          "object": "triangle",
          "relation": "above",
          "target": "square"
        },
        {
          "object": "star",
          "relation": "left_of",
          "target": "triangle"
        }
      ]
    }
  ],
  "settings": {
    "clue_mode": "text",
    "unique_object_picks": true,
    "hide_color_picker": false
  }
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/spatial-reasoning/embed?p=-Nq8sample_activity_key",
  "message": "Spatial reasoning activity created successfully"
}

Rebus

Sentences written as pictures: players read the pictures and the letter changes back into words.

#
POST /api/public/v1/rebus 1 to 30 in items
Content

An array of sentences. Each lists the words drawn as pictures; every other word stays as its letters.

Falls back to the name “Rebus API”

Worth knowing
  • A word is drawn from parts that together spell it. A part has the letters it stands for (text), an emoji, and shows: the word for what the picture shows ("broom" for a picture standing for "room"). Puzzel works out the letter changes. A part may be a symbol instead, such as 4 for "for".
Settings it reads
FieldTypeWhat it does
rebus_commas
optional in settings
boolean
booleanDraws a dropped first or last letter as a comma beside the picture.
Default: false
Example request
POST rebus
curl -X POST https://puzzel.org/api/public/v1/rebus \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "Rebus",
  "language": "en",
  "items": [
    {
      "sentence": "I sweep the room before the sunflower wilts.",
      "words": [
        {
          "word": "I",
          "parts": [
            {
              "text": "I",
              "kind": "sound",
              "emoji": "👁️"
            }
          ]
        },
        {
          "word": "room",
          "parts": [
            {
              "text": "room",
              "kind": "picture",
              "shows": "broom",
              "emoji": "🧹"
            }
          ]
        },
        {
          "word": "before",
          "parts": [
            {
              "text": "be",
              "kind": "picture",
              "shows": "bee",
              "emoji": "🐝"
            },
            {
              "text": "for",
              "kind": "sound",
              "glyph": "4"
            },
            {
              "text": "e",
              "kind": "letters"
            }
          ]
        },
        {
          "word": "the",
          "position": 6,
          "parts": [
            {
              "text": "the",
              "kind": "picture",
              "shows": "tree",
              "emoji": "🌳"
            }
          ]
        },
        {
          "word": "sunflower",
          "parts": [
            {
              "text": "sun",
              "kind": "picture",
              "shows": "sun",
              "emoji": "☀️"
            },
            {
              "text": "flower",
              "kind": "picture",
              "shows": "flower",
              "emoji": "🌸"
            }
          ]
        }
      ]
    }
  ],
  "settings": {
    "rebus_commas": true
  }
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/rebus/embed?p=-Nq8sample_activity_key",
  "message": "Rebus created successfully"
}
Pictures

Jigsaw puzzle

Cuts a picture into pieces to drag back together.

#
POST /api/public/v1/jigsaw Takes no items
Content

One image URL, in the image field. This endpoint takes no items.

Falls back to the name “Jigsaw Game API”

Worth knowing
  • The API always makes a 4 by 4 jigsaw. Piece count, irregular pieces and flat edges are builder settings — sending rows or columns here does nothing.
  • The URL is stored as you sent it and the file is never copied, so it has to stay publicly reachable for as long as the activity is played.
Settings it reads
FieldTypeWhat it does
image
required
string
stringAbsolute URL of the picture to cut up. Sent at the top level, not inside settings.
Example request
POST jigsaw
curl -X POST https://puzzel.org/api/public/v1/jigsaw \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "Jigsaw Game",
  "language": "en",
  "image": "https://example.com/orchard.jpg"
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/jigsaw/embed?p=-Nq8sample_activity_key",
  "message": "Jigsaw game created successfully"
}

Sliding puzzle

Scrambles a picture into tiles that slide into place.

#
POST /api/public/v1/slidingpuzzle Takes no items
Content

One image URL, inside settings. This endpoint takes no items.

Falls back to the name “Sliding Puzzle API”

Worth knowing
  • Unlike the jigsaw, this endpoint reads its picture from settings.image. A top-level image field is ignored and the call answers 400.
  • The URL is stored as you sent it and the file is never copied, so it has to stay publicly reachable for as long as the activity is played.
Settings it reads
FieldTypeWhat it does
image
required in settings
string
stringAbsolute URL of the picture to scramble. Unlike the jigsaw's, this one lives inside settings.
Example request
POST slidingpuzzle
curl -X POST https://puzzel.org/api/public/v1/slidingpuzzle \
  -H "Content-Type: application/json" \
  -d '{
  "account_api_key": "YOUR_API_KEY",
  "email": "you@example.com",
  "title": "Sliding Puzzle",
  "language": "en",
  "settings": {
    "image": "https://example.com/orchard.jpg"
  }
}'
Success
{
  "success": true,
  "id": "-Nq8sample_activity_key",
  "url": "https://puzzel.org/en/slidingpuzzle/embed?p=-Nq8sample_activity_key",
  "message": "Sliding puzzle created successfully"
}

Something not behaving?

Send the request you tried and the error you got back and you'll get a real answer, from the person who wrote the endpoint.

Email support