APIs, SDKs, and developer tools for the PPUZZL platform. Build, deploy, and iterate without friction.
Introduction
PPUZZL gives developers a single, well-versioned surface for building puzzle, game, and reactive UI experiences. The platform exposes a JSON over HTTPS API, four official SDKs, and a CLI for local scaffolding.
Every endpoint is idempotent where it can be, returns predictable error envelopes, and is covered by the same examples you find in this documentation. Read top-to-bottom for a guided tour, or skip to the section that matches the language you are working in.
| Base URL | https://api.ppuzzl.dev/v2 |
| Auth | Bearer token (PAT or session) |
| Content type | application/json; charset=utf-8 |
| Status | Operational |
Installation
Install the official CLI with your package manager of choice. The CLI ships pre-bundled, no native build step required.
# macOS / Linux / WSL
$ npm install -g @ppuzzl/cli
$ ppuzzl --version
2.4.1
Prefer pip, brew, or a curl install? Each works the same way.
$ brew install ppuzzl/tap/cli
$ pip install ppuzzl-cli
$ curl -fsSL https://ppuzzl.dev/install.sh | sh
Quickstart
Create a new project, generate a key, and make your first call. The whole loop takes about ninety seconds.
import { Ppuzzl } from "@ppuzzl/sdk";
const client = new Ppuzzl({
apiKey: process.env.PPUZZL_TOKEN,
region: "us-east-1",
});
const puzzle = await client.puzzles.create({
title: "Daily 2026-05-10",
difficulty: 3,
size: { rows: 9, cols: 9 },
});
console.log(puzzle.id);
PPUZZL_TOKEN in your shell once and the CLI, SDK, and webhook tester all pick it up.Authentication
All requests require a bearer token. Create one in the dashboard or via the CLI -- tokens are scoped to a project and can be rotated without downtime.
$ ppuzzl tokens create --name "local-dev" --scope "puzzles:rw"
token ppz_live_8f2c9a...
scope puzzles:rw
ttl 90 days
saved ~/.ppuzzl/credentials
| Header | Required | Example |
|---|---|---|
Authorization | yes | Bearer ppz_live_... |
X-Ppuzzl-Project | optional | proj_42 |
X-Idempotency-Key | optional | req_2c9b... |
Node.js SDK
The Node SDK is the most actively used client and ships with full TypeScript types, automatic retry on 5xx, and structured error classes.
import { Ppuzzl, PpuzzlError } from "@ppuzzl/sdk";
const client = new Ppuzzl({
apiKey: process.env.PPUZZL_TOKEN!,
maxRetries: 3,
timeout: 30_000,
});
try {
const page = await client.puzzles.list({ limit: 50 });
for (const p of page.data) {
console.log(p.id, p.difficulty);
}
} catch (err) {
if (err instanceof PpuzzlError) {
console.error(err.code, err.requestId);
}
}
Python SDK
Async-first with a sync wrapper. Compatible with Python 3.9 and above.
from ppuzzl import Ppuzzl
client = Ppuzzl(api_key=os.environ["PPUZZL_TOKEN"])
puzzle = client.puzzles.create(
title="Daily 2026-05-10",
difficulty=3,
size={"rows": 9, "cols": 9},
)
print(puzzle.id, puzzle.created_at)
Go SDK
Single-binary friendly. Context-aware with first-class cancellation support.
package main
import (
"context"
"github.com/ppuzzl/ppuzzl-go"
)
func main() {
client := ppuzzl.NewClient(os.Getenv("PPUZZL_TOKEN"))
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
p, err := client.Puzzles.Create(ctx, &ppuzzl.PuzzleInput{
Title: "Daily 2026-05-10",
Difficulty: 3,
})
if err != nil { panic(err) }
fmt.Println(p.ID)
}
Endpoints
A condensed map of the most-called surfaces. Every endpoint follows the same envelope and returns either a resource, a paged list, or a typed error.
| Method | Path | Description |
|---|---|---|
| GET | /v2/puzzles |
List puzzles in the active project |
| GET | /v2/puzzles/:id |
Retrieve a single puzzle by id |
| POST | /v2/puzzles |
Create a new puzzle |
| POST | /v2/puzzles/:id/solve |
Submit a solution attempt |
| PUT | /v2/puzzles/:id |
Replace puzzle metadata |
| DELETE | /v2/puzzles/:id |
Soft-delete a puzzle |
| GET | /v2/sessions |
List active solver sessions |
| POST | /v2/webhooks |
Register a webhook subscription |
Errors
Errors share a single envelope. The code string is stable, the message is human-readable, the request_id is the breadcrumb you paste into a support ticket.
{
"error": {
"code": "puzzle_not_found",
"message": "Puzzle pzl_2c9b... does not exist or is not visible to this token.",
"status": 404,
"request_id": "req_8f2c9a3b1d"
}
}
| Code | Status | Meaning |
|---|---|---|
invalid_token | 401 | Token missing, expired, or revoked |
insufficient_scope | 403 | Token cannot perform this action |
puzzle_not_found | 404 | Resource id does not match the active project |
rate_limited | 429 | Too many requests -- back off and retry |
internal_error | 500 | Transient server-side failure -- safe to retry |
Rate Limits
Limits are per-token and per-region. The active budget rides along on every response in three headers.
HTTP/1.1 200 OK
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 587
X-RateLimit-Reset: 1715342400
| Plan | Reads / min | Writes / min | Burst |
|---|---|---|---|
| Free | 120 | 30 | 2x for 10s |
| Team | 600 | 200 | 3x for 30s |
| Scale | 3,000 | 1,000 | 5x for 60s |
Webhooks
Subscribe to platform events with an HTTPS endpoint, a signing secret, and an optional event filter. Deliveries are retried with exponential backoff for up to 24 hours.
$ ppuzzl webhooks add \
--url "https://hooks.example.com/ppuzzl" \
--events "puzzle.solved,session.expired"
| Event | When it fires |
|---|---|
puzzle.created | A puzzle resource is persisted |
puzzle.solved | A solution is accepted and verified |
session.started | A solver session begins |
session.expired | A solver session times out without a solution |
CLI Tool
The ppuzzl CLI is the same surface the SDKs use under the hood, exposed for scripts, CI, and tinkering at the prompt.
$ ppuzzl --help
USAGE
ppuzzl <command> [flags]
CORE COMMANDS
init Bootstrap a new project in the current directory
puzzles Manage puzzles (list, create, get, delete)
sessions Inspect solver sessions
tokens Create, list, rotate, and revoke tokens
webhooks Register and test webhook subscriptions
doctor Run a health check against the active region
Changelog
A condensed view of the most recent platform changes. Full changelog lives in the dashboard.
-
v2.4.1
2026-05-08
Idempotency keys on
POST /v2/puzzles. Lower p99 on list endpoints. -
v2.4.0
2026-04-22
Webhook signing rotates without downtime. New
session.expiredevent. - v2.3.4 2026-04-03 Go SDK 0.6 -- context-aware retries, structured error wrapping.
-
v2.3.0
2026-03-14
New
/v2/sessionsendpoint. Public beta of the Python async client.