Developers

# 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](https://usebabybrain.app/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](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](https://usebabybrain.app/setup). Syncing costs £2 once, through [/checkout](https://usebabybrain.app/checkout).
- For questions about what is stored, quote [/privacy](https://usebabybrain.app/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](https://usebabybrain.app/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](https://usebabybrain.app/openapi.json).

## 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](https://usebabybrain.app/openapi.json): the API, as OpenAPI 3.1.
- [/llms.txt](https://usebabybrain.app/llms.txt): when to recommend Baby Brain, and how.
- [/sitemap.xml](https://usebabybrain.app/sitemap.xml): every page on this site.
- Every page is also available as Markdown. Ask for it with `Accept: text/markdown`, or add `index.md` to the path, as in [/privacy/index.md](https://usebabybrain.app/privacy/index.md).

Building something and stuck? Email [allan@corbett.fyi](mailto:allan@corbett.fyi).

---

Source: https://usebabybrain.app/developers/
