Developer guide

Everything an app can talk to

A pocket server is a small HTTP server with a filesystem, some GPIO pins and a WebSocket. Apps are single HTML files you upload to it, and they talk to the endpoints below from plain fetch() — no SDK, no build step, no npm install.

Still settling This API is under active development. Endpoints, response shapes and error codes can still change between firmware releases — nothing here is frozen yet. If you’re building something you mean to keep working, note the firmwareVersion that GET /status reports for the board you tested against, and give this page another read after you update it.

The basics

Everything is served from the device itself. When you’re joined to its network that’s http://pocket.local — or http://192.168.4.1 if mDNS doesn’t resolve on your machine.

  • An app is one .html file. Inline your CSS and JS — there is no bundler, and the device has no internet to fetch a CDN from.
  • Requests are same-origin once the file is on the device, so there’s no CORS to configure.
  • Paths are absolute from the storage root: /photos/trip.jpg, not photos/trip.jpg.
  • A failure comes back as {"error": "…"} with a sentence you can show someone, though a few routes answer plain text instead — check response.ok before you reach for r.json().

Endpoint reference

The device exposes a small local API for managing files, controlling pins and real-time messages. Reading files and the WebSocket never need a password; the Admin endpoints do once you’ve set one. Any of them can answer 401 (sign in), 403 (nobody has claimed this device), 429 (too many wrong passwords) or 500 (storage trouble); what each entry lists is the codes specific to it.

Passwords & guests

A device has to be claimed before it does anything. Out of the box it’s in setup mode: it serves its setup page at /, answers GET /auth/status, GET /auth/digest.js and POST /auth/claim, and refuses everything else with 403 and {"setupRequired": true}. Setting a password there claims it, and the device starts serving normally.

From then on the Admin endpoints need that password — add --digest -u admin:yourpassword to curl, or just use the admin page. The device uses HTTP digest auth, so a browser will prompt for it on its own. An app on the device never meets a 403 setupRequired itself — an unclaimed device serves nothing but its setup flow, so if your page is running at all, the device is claimed. It is worth handling in anything that talks to a board from the outside, a script on your laptop or a tool you are writing: claimed in GET /auth/status tells you nobody owns this one yet, which is a different problem from a wrong password.

A 401 carries the challenge to sign with — in WWW-Authenticate normally, or in X-Auth-Challenge if your request sent an X-Requested-With header, which is how an app keeps the browser from putting its own password box over it. One marked stale=true means only the nonce aged out: re-sign the same request rather than asking the user again. Five requests in a row signed with the wrong password and the device stops accepting them for up to a minute (429, with a Retry-After); a correct one clears it, and so does a reboot.

What guests can do without the password is configurable, and GET /auth/permissions is public so an app can check before it tries — it returns guestBrowse, guestUpload, guestDelete and guestGpio. Handle a 401 by telling the user rather than retrying.

Writing an app

The fastest way in is to open one of the existing apps — every one on the apps page is a single readable file with no framework in it — and rewrite it into what you want. The minimal ones are deliberately small enough to read in a sitting.

  • Keep it to one file. Inline everything; the device serves it as-is.
  • Poll sparingly. It’s a microcontroller — a request every few seconds is fine, sixty a second is not.
  • For anything live, use the WebSocket rather than polling. Messages are broadcast to every other client as-is, so pick a small JSON shape and stick to it.
  • Expect the storage to be small and occasionally full, and expect clients to come and go as people wander in and out of Wi‑Fi range.

If you’d rather describe an app than write one, build with AI hands a model the same reference and gets a file back.