JetPunk APIjetpunk.com ↗
Access JetPunk quiz data via API. Search quizzes by keyword, browse by category tag, and retrieve full question/answer content for any quiz.
What is the JetPunk API?
The JetPunk API provides 3 endpoints for discovering and extracting trivia quiz data from JetPunk.com. Use search_quizzes to find quizzes by keyword and get back titles, URL paths, and take counts, or use get_quiz to retrieve a complete quiz including all question-answer pairs, column headers, categories, and description. The API covers thousands of quizzes across geography, history, science, and more.
curl -X GET 'https://api.parse.bot/scraper/8393ef45-4706-4d61-9693-127af45c4246/search_quizzes?page=1&query=capitals' \ -H 'X-API-Key: $PARSE_API_KEY'
Typed, relational, agent-ready
A generated client with real types, enums, and the links between objects — the structure a flat JSON response can't carry. Autocompletes in your editor and reads cleanly to coding agents.
- Fully typed · autocompletes
- Objects link to objects
- Typed errors & pagination
Typed Python client. Set up the SDK in your uv project, then pull this API’s typed client:
uv add parse-sdk uv run parse init uv run parse add --marketplace jetpunk-com-api
uv run parse add --marketplace pulls a pinned snapshot of this canonical API — it won’t change underneath you. To customize it, subscribe and swap to your own copy.
"""
JetPunk Trivia API Parse Client
Search and discover trivia quizzes from JetPunk by category or tag, then access
detailed quiz questions and answers to test your knowledge or build custom trivia experiences.
Get your API key from: https://parse.bot/settings
"""
import os
import requests
from typing import Any, Dict, List, Optional
class ParseClient:
"""Client for interacting with the JetPunk Trivia Parse API."""
def __init__(self, api_key: Optional[str] = None):
"""
Initialize the Parse API client.
Args:
api_key: API key for authentication. If not provided, reads from PARSE_API_KEY env var.
"""
self.base_url = "https://api.parse.bot"
self.scraper_id = "8393ef45-4706-4d61-9693-127af45c4246"
self.api_key = api_key or os.getenv("PARSE_API_KEY")
if not self.api_key:
raise ValueError("API key not provided. Set PARSE_API_KEY environment variable.")
def _call(
self,
endpoint: str,
method: str = "POST",
**params: Any
) -> Dict[str, Any]:
"""
Make a request to the Parse API.
Args:
endpoint: The endpoint name (e.g., 'search_quizzes')
method: HTTP method ('GET' or 'POST')
**params: Query or body parameters
Returns:
Parsed JSON response
"""
url = f"{self.base_url}/scraper/{self.scraper_id}/{endpoint}"
headers = {
"X-API-Key": self.api_key,
"Content-Type": "application/json"
}
if method.upper() == "GET":
response = requests.get(url, headers=headers, params=params)
elif method.upper() == "POST":
response = requests.post(url, headers=headers, json=params)
else:
raise ValueError(f"Unsupported HTTP method: {method}")
response.raise_for_status()
return response.json()
def search_quizzes(
self,
query: str,
page: int = 1
) -> Dict[str, Any]:
"""
Search for quizzes by keyword on JetPunk.
Args:
query: Search keyword (e.g., 'Capitals', 'Countries')
page: Page number for pagination (default: 1)
Returns:
Dictionary containing quizzes list, page info, and has_next flag
"""
return self._call(
"search_quizzes",
method="GET",
query=query,
page=page
)
def get_quizzes_by_tag(
self,
tag: str,
page: int = 1
) -> Dict[str, Any]:
"""
List quizzes in a specific category or tag.
Args:
tag: Tag or category name (e.g., 'geography', 'history', 'science')
page: Page number for pagination (default: 1)
Returns:
Dictionary containing quizzes list, tag, and pagination info
"""
return self._call(
"get_quizzes_by_tag",
method="GET",
tag=tag,
page=page
)
def get_quiz(self, path: str) -> Dict[str, Any]:
"""
Get full details of a quiz, including title, description, categories, and all questions/answers.
Args:
path: The URL path of the quiz (e.g., '/quizzes/european-capitals-quiz')
Returns:
Dictionary containing quiz details, headers, and content (question/answer pairs)
"""
return self._call(
"get_quiz",
method="GET",
path=path
)
def format_takes(takes_str: str) -> str:
"""Format takes count with commas for readability."""
try:
return f"{int(takes_str):,}"
except (ValueError, TypeError):
return takes_str
def print_quiz_table(quiz: Dict[str, Any], max_rows: int = 5) -> None:
"""Print quiz content in a formatted table."""
headers = quiz.get('headers', [])
content = quiz.get('content', [])
if not headers or not content:
print(" No content available")
return
# Calculate column widths
col_widths = {header: len(header) for header in headers}
for row in content[:max_rows]:
for header in headers:
col_widths[header] = max(col_widths[header], len(str(row.get(header, ''))))
# Print header
header_line = " | ".join(f"{h:<{col_widths[h]}}" for h in headers)
print(f" {header_line}")
print(f" {'-' * len(header_line)}")
# Print rows
for row in content[:max_rows]:
row_line = " | ".join(f"{str(row.get(h, '')):<{col_widths[h]}}" for h in headers)
print(f" {row_line}")
if len(content) > max_rows:
print(f" ... and {len(content) - max_rows} more")
if __name__ == "__main__":
# Initialize the client
client = ParseClient()
print("🧠 JetPunk Trivia API - Practical Workflow\n")
print("=" * 70)
# Step 1: Search for quizzes about capitals
print("\n📍 Step 1: Searching for 'capitals' quizzes...")
search_results = client.search_quizzes(query="capitals", page=1)
quizzes_list = search_results.get('quizzes', [])
print(f" ✓ Found {len(quizzes_list)} quizzes")
print(f" ✓ Has next page: {search_results.get('has_next', False)}")
print(f" ✓ Query: '{search_results.get('query')}'")
# Step 2: Get top quiz from search results
if quizzes_list:
top_quiz_info = quizzes_list[0]
print(f"\n📍 Step 2: Fetching details for top search result...")
print(f" Title: {top_quiz_info['title']}")
print(f" Takes: {format_takes(top_quiz_info['takes'])}")
try:
top_quiz = client.get_quiz(path=top_quiz_info['path'])
print(f" ✓ Loaded quiz ID: {top_quiz.get('id')}")
print(f" ✓ Questions: {len(top_quiz.get('content', []))}")
print(f" ✓ Categories: {', '.join(top_quiz.get('categories', []))}")
print(f"\n Quiz Description: {top_quiz.get('description', 'N/A')}")
print(f"\n Sample Q&A Data:")
print_quiz_table(top_quiz, max_rows=4)
except Exception as e:
print(f" ✗ Error loading quiz: {e}")
# Step 3: Browse quizzes by geography tag
print(f"\n\n📍 Step 3: Browsing 'geography' category...")
geography_results = client.get_quizzes_by_tag(tag="geography", page=1)
geo_quizzes = geography_results.get('quizzes', [])
print(f" ✓ Found {len(geo_quizzes)} geography quizzes")
print(f" ✓ Tag: {geography_results.get('tag')}")
print(f" ✓ Has next page: {geography_results.get('has_next', False)}")
# Step 4: Fetch and display details for top geography quizzes
print(f"\n📍 Step 4: Loading details for top 2 geography quizzes...")
for idx, geo_quiz_info in enumerate(geo_quizzes[:2], 1):
print(f"\n [{idx}] {geo_quiz_info['title']}")
print(f" Takes: {format_takes(geo_quiz_info['takes'])}")
try:
geo_quiz = client.get_quiz(path=geo_quiz_info['path'])
print(f" ✓ Quiz ID: {geo_quiz.get('id')}")
print(f" ✓ Total questions: {len(geo_quiz.get('content', []))}")
print(f" ✓ Categories: {', '.join(geo_quiz.get('categories', []))}")
print(f"\n Sample Content:")
print_quiz_table(geo_quiz, max_rows=3)
except Exception as e:
print(f" ✗ Error: {e}")
print("\n" + "=" * 70)
print("✅ Workflow completed successfully!")
print("\nYou can now:")
print(" • Search for any quiz topic using search_quizzes()")
print(" • Browse categories using get_quizzes_by_tag()")
print(" • Extract Q&A data using get_quiz(path)")Search for quizzes by keyword on JetPunk. Returns a paginated list of matching quizzes with their paths and take counts.
| Param | Type | Description |
|---|---|---|
| page | integer | Page number for pagination |
| queryrequired | string | Search keyword (e.g. 'Capitals', 'Countries') |
{
"type": "object",
"fields": {
"page": "integer, current page number",
"query": "string, the search query echoed back",
"quizzes": "array of objects with title, path, and takes",
"has_next": "boolean, whether more pages exist"
},
"sample": {
"data": {
"page": 1,
"query": "capitals",
"quizzes": [
{
"path": "/quizzes/name-state-capitals",
"takes": "1688350",
"title": "U.S. State Capitals Quiz"
},
{
"path": "/quizzes/european-capitals-quiz",
"takes": "1584806",
"title": "Europe Capitals Quiz"
}
],
"has_next": true
},
"status": "success"
}
}About the JetPunk API
Search and Browse Quizzes
The search_quizzes endpoint accepts a required query string (e.g. 'Capitals' or 'Countries') and an optional page integer for pagination. It returns a quizzes array where each object includes a title, a path (the quiz's URL slug), and a takes count indicating how many times that quiz has been completed. The has_next boolean tells you whether additional pages exist, making it straightforward to iterate through large result sets.
The get_quizzes_by_tag endpoint works similarly but filters by category. Pass a tag slug such as 'geography', 'history', or 'science', and receive a paginated list of quizzes under that tag. The normalized tag slug is echoed back in the response alongside the page and has_next fields. Both browse endpoints return the same quiz object shape, so you can feed the path field directly into the next endpoint.
Retrieving Full Quiz Content
Once you have a quiz path from either browse endpoint, pass it to get_quiz to retrieve complete quiz data. The response includes the quiz id, title, description, and a categories array listing all associated tags. The content field is an array of objects where each entry maps column header names to answer values — the headers array tells you what those column names are. For a capitals quiz, for example, headers might be ['Country', 'Capital'] and each content object maps those keys to the corresponding values. This structure supports both single-answer and multi-column quiz formats.
Coverage and Data Shape
Quiz take counts (takes) give a rough signal of popularity without requiring any additional calls. The path field returned in list endpoints is the canonical identifier for fetching quiz details — it matches the URL path on JetPunk.com. Categories returned in get_quiz responses are the same tag slugs accepted by get_quizzes_by_tag, so you can build category-aware workflows that chain all three endpoints.
The JetPunk API is a managed, monitored endpoint for jetpunk.com — not a raw scraper you maintain. Every endpoint is automatically health-checked on a schedule, and when jetpunk.com changes and a check fails, the API is automatically queued for repair and re-verified. It is built to keep working as the site underneath it changes.
This isn't an official jetpunk.com API — it's an independent, maintained REST wrapper over public data. Where the source has no official API (or only a limited one), Parse gives you a stable contract over a source that never promised one, and keeps it current. Need a new endpoint or field? You can revise it yourself in plain English and the agent rebuilds it against the live site in minutes — contributing the change back to the shared API is free.
Will this API break when the source site changes?+
Is this an official API from the source site?+
Can I fix or extend this API myself if I need a new endpoint or field?+
What happens if I call an endpoint that has an issue?+
- Build a trivia app seeded with JetPunk geography or history quizzes and their full question/answer data
- Index quiz titles and take counts to surface the most-played quizzes in a given category tag
- Generate flashcard decks from the
contentarray returned byget_quiz - Search for quizzes by keyword to power a quiz recommendation or search feature
- Extract
categoriesarrays from quizzes to analyze how topics are distributed across the JetPunk catalog - Pipe multi-column quiz content (via the
headersandcontentfields) into a database for structured trivia storage - Compare take counts across quizzes in the same tag to rank quiz popularity by subject
| Tier | Price | Credits/month | Rate limit |
|---|---|---|---|
| Free | $0/mo | 100 | 5 req/min |
| Hobby | $30/mo | 1,000 | 20 req/min |
| Developer | $100/mo | 5,000 | 100 req/min |
One credit = one API call regardless of which marketplace API you call. Exceeding the rate limit returns a 429 response. Authenticate with the X-API-Key header.
Does JetPunk have an official developer API?+
What does `get_quiz` return beyond the questions and answers?+
id, title, description, a categories array of associated tag slugs, a headers array naming the column labels, and a content array where each object maps those header names to their corresponding values. This covers all the structured data visible on a quiz page.Does the API return user scores, leaderboards, or per-user quiz history?+
How does pagination work across the list endpoints?+
search_quizzes and get_quizzes_by_tag accept an optional page integer parameter (defaulting to the first page). Each response includes a has_next boolean. When has_next is true, increment page by one and repeat the request to fetch the next batch of results.Can I filter quizzes by difficulty or date created?+
title, path, and takes count per quiz, without difficulty ratings or creation dates. You can fork this API on Parse and revise it to add those fields if they appear on the relevant pages.