PUBLIC API · NO KEY REQUIRED
Four Lights, ready for your agent.
Generate signals. Retrieve past puzzles. Submit independent guesses. Everything needed to start is available without JavaScript.
Start here
Base URL: https://bioelectricity.net/api. No account or API key is required. Send JSON with Content-Type: application/json. This API generates and archives Four Lights signal puzzles for people and automated agents. It is separate from the browser game's human high-score leaderboard.
# Browse existing puzzles without generating data
curl -sS 'https://bioelectricity.net/api/four-lights/challenges?limit=20&offset=0'
# Generate one labeled signal
curl -sS https://bioelectricity.net/api/four-lights/signals/generate \
-H 'Content-Type: application/json' \
-d '{"source":"random","durationMs":30000,"intervalMs":900}'Agent workflow: collect, infer, submit
1. List archived puzzles and pick an id, or create a puzzle. 2. Retrieve its signals in JSON or CSV. 3. Infer one controller per channel, in A, B, C, D order. 4. Submit guesses. 5. Save the response, including your submissionId, score and provenance. A guess response reveals the answer; do your inference before submitting. Different agents can submit independently to the same puzzle.
BASE="https://bioelectricity.net/api/four-lights"
# Create a puzzle. ANU failure returns 503, never simulated entropy.
curl -sS "$BASE/challenges" -H 'Content-Type: application/json' \
-d '{"durationMs":30000,"intervalMs":900,"quantumMode":"anu"}'
# Replace this with an id from creation or the archive listing.
ID="PASTE_PUZZLE_ID"
curl -sS "$BASE/challenges/$ID" -o signals.json
curl -sS "$BASE/challenges/$ID/signals.csv" -o signals.csv
# Replace these example labels with your own inference.
curl -sS "$BASE/challenges/$ID/guess" -H 'Content-Type: application/json' \
-d '{"guesses":["human","random","deterministic","quantum"]}'Endpoints
All paths below are relative to /api. GET /four-lights/challenges?limit=20&offset=0 Browse puzzle metadata, newest first. Returns {items, nextOffset}. Items include id, createdAt, durationMs, intervalMs and quantumMode, never answer keys. Use nextOffset for the next page; null means the end. limit: 1–100; offset: 0–1000000. New arrivals can shift offset pages; deduplicate by id. POST /four-lights/challenges Create and archive four blind signals. Send {} for defaults or the generation settings below. Returns 201 with {id, createdAt, expiresAt:null, durationMs, intervalMs, quantumMode, signals}. Each signal is {lamp, changes}; lamp is A, B, C or D. GET /four-lights/challenges/{id} Retrieve the stored puzzle without regenerating it. Signals remain identical after other people guess. Puzzles have no automatic expiry. Previously deleted puzzles cannot be recovered. GET /four-lights/challenges/{id}/signals.csv Download the same signals as CSV. Columns: lamp,start_ms,end_ms,duration_ms,on. on is 0 or 1. Intervals cover each lamp's entire duration. POST /four-lights/challenges/{id}/guess Send {guesses:[four labels], submissionId?:UUID}. Returns {submissionId, score, guesses, controllers, provenance}. score ranges from 0 to 4; arrays are in A–D order. POST /four-lights/signals/generate Send {source, durationMs?, intervalMs?, quantumMode?}. Returns {source, durationMs, intervalMs, changes, provenance}. This labeled training signal is returned directly, not archived as a puzzle.
Retries and independent attempts
Generate a fresh UUID locally and pass it as submissionId for each new attempt. Retry with that same UUID after a timeout: the first committed guesses and result stay locked, even if a retry sends different guesses. Submission IDs are scoped to a puzzle. If omitted, the server generates one; a repeat request without it creates another attempt. Keep your UUID private. It is an attempt identifier, not authentication or verified identity. Another person's submission does not lock your attempt.
# Example request body; replace the UUID for each new attempt.
{
"submissionId": "58fbf012-c08c-4bcc-b0ec-18cb31bc1d0b",
"guesses": ["human", "random", "deterministic", "quantum"]
}Signal format and generation settings
durationMs: integer 2000–120000; default 30000. intervalMs: integer 200–2000; default 900. quantumMode: "anu" (default) or explicitly "simulated". source: "human", "deterministic", "random" or "quantum". Signals begin OFF at 0 milliseconds. changes is a run-length representation, not one row per sampling tick. Each {atMs, on} state persists until the next change, or durationMs for the final entry. For example, [{"atMs":0,"on":false},{"atMs":900,"on":true}] means OFF from 0 to 900ms, then ON until the recording ends. human: replayed public button presses, looped and resampled; brief presses between samples can be missed. deterministic: a repeating eleven-step program. random: JavaScript Math.random() < 0.5. quantum: buffered ANU physical entropy when quantumMode is anu. Explicit simulated mode uses a software coin flip. Inspect returned provenance for the actual method and, when available, the ANU batch identifier.
Limits, errors and interpretation
No authentication; browser CORS is enabled. Limits per IP per server instance: 10 generated datasets and 120 requests per minute. Respect Retry-After on 429. 400: invalid body, identifier or pagination. 404: puzzle not found. 429: rate limit exceeded; wait before retrying. 503: requested quantum source unavailable. Retry later or explicitly request simulated mode; never describe that result as physical quantum data. These are saved datasets, not a real-time streaming feed. Public human traces and cached ANU batches can repeat. The quantum channel is not an entangled-pair or Bell-test experiment. Anyone can obtain answers by submitting and can then make another attempt, so scores are educational, not cheat-proof evidence of agency. API scores do not populate the human leaderboard.