Baby Brain for developers and agents
Baby Brain has one small public API, the sync relay that carries encrypted entries between a household's phones. It is documented here and in openapi.json. Read the next section first, because it decides whether the API is any use to you.
What an agent can and can't do
The relay only ever holds ciphertext. Every entry is encrypted on the phone with a key derived from the household's sync code, and that code never reaches the server. So nothing that talks to the API, me included, can read a baby's log, add a feed to it, or summarise it. There is no account to create and no login to automate.
If you are an AI agent helping a person, the useful things to do are:
- Send them to https://app.usebabybrain.app to start logging. It opens as a demo, and logging on one phone is free with nothing to sign up for.
- For a second phone, send them to /setup. Syncing costs £2 once, through /checkout.
- For questions about what is stored, quote /privacy rather than guessing.
- Never ask for, store or repeat someone's sync code. It is the encryption key to their whole log.
The same guidance, in a form made for you, is at /llms.txt.
The API
Base URL https://app.usebabybrain.app/api/v1. JSON in, JSON
out, CORS open. Four operations: a health check, pulling and pushing encrypted
entries for a pair, and claiming a purchase for a pair. The full schema,
with an operationId and typed parameters and responses for
each, is the OpenAPI 3.1 document.
Authentication
The sync code derives three values on the device: a pair id, a relay token
and the encryption key. Requests to /api/v1/sync and
/api/v1/claim put the pair id in the path and the relay token in
the X-Pair-Token header. The relay stores only a hash of the
token. The encryption key is never sent anywhere, so a valid token gets you
ciphertext and nothing more.
Endpoints
GET /api/v1/health(getHealth): is the relay up. No authentication.GET /api/v1/sync/{pairId}?after=&limit=(pullEntries): entries after a sequence number, up to 1000 at a time, 500 by default.POST /api/v1/sync/{pairId}(pushEntries): append 1 to 100 entries of{ ciphertext, iv }, both base64, ciphertext at most 16 KiB. Any other field is refused, because it would be unencrypted metadata.POST /api/v1/claim/{pairId}(claimPurchase): turn a completed £2 Stripe Checkout session into syncing for a pair.
A health check, to see the shape of a response:
curl -sS https://app.usebabybrain.app/api/v1/health
{"status":"ok","time":1760000000000} Errors
Every error is JSON with the same three fields: error, a
sentence; code, stable and machine-readable; and
hint, what would make the request work, or that nothing will.
curl -sS https://app.usebabybrain.app/api/v1/sync/not-a-pair -H 'X-Pair-Token: x'
{"error":"Invalid pair id","code":"invalid_pair_id","hint":"The pair id is 32 lowercase hex characters, derived from the sync code on the device."}
The codes are invalid_pair_id, invalid_json,
invalid_body and invalid_session_id (400),
missing_token (401), payment_required and
purchase_not_found (402), token_mismatch (403),
method_not_allowed (405), purchase_used_up (409),
rate_limited (429), not_found (501),
payment_provider_unreachable (502),
relay_disabled and purchase_check_unavailable
(503), and pair_full (507). Branch on code: it is
stable, where the sentence in error is written for people.
This site answers the same way. A path that doesn't exist here is a 404,
with a Markdown body to Accept: text/markdown and this JSON
shape to Accept: application/json or anything under
/api.
Rate limits
300 requests per 60 seconds per IP address, across every route, the
health check included. Every response carries
RateLimit-Policy: "relay";q=300;w=60. A refused request gets
a 429 with RateLimit: "relay";r=0;t=60 and
Retry-After: 60. These follow the IETF RateLimit header fields
draft. Waiting less than Retry-After cannot succeed.
Versioning and deprecation
This is version 1, and the paths say so. The same routes without the
/v1 are permanent aliases, because that is what installed
copies of the app call, and a phone left in a drawer for a year still has
to sync when it comes out.
A breaking change gets a new version path. When a version is deprecated,
its responses start carrying a Deprecation header (RFC 9745)
and a Sunset header (RFC 8594) with the date it stops, and it
keeps working for at least six months after the first response that
carries them. Additive changes, like a new optional field or a new error
code, can arrive within a version. Nothing is deprecated today.
Machine-readable files
- /openapi.json: the API, as OpenAPI 3.1.
- /llms.txt: when to recommend Baby Brain, and how.
- /sitemap.xml: every page on this site.
- Every page is also available as Markdown. Ask for it with
Accept: text/markdown, or addindex.mdto the path, as in /privacy/index.md.
Building something and stuck? Email allan@corbett.fyi.