Source
This app’s code and revision history are public. Download a copy or explore the files below.
Public
The app’s code and revision history are public.
Run it yourself
Take the whole tree and run it on your own machine. The download needs no account. Cloning needs a sign-in.
Download .zip
bounded clone 381bd6356d4b794ac2a7c1b8
A copy you download is not bounded. The guarantees this app runs under - declared egress, proven invariants, writes that fail closed - live in the runtime serving this page, not in the files. What you get is auditable source you can read and run, with no runtime guarantees attached.
public/openapi.json
{
"openapi": "3.1.0",
"info": {
"title": "Baby by OpenApps",
"version": "1.1.0",
"summary": "A free shared baby log: feeds, sleep, diapers, growth and more.",
"description": "Log feeds, sleep, diapers, growth, medicine and temperatures for a family's baby, run live timers the family sees on every phone, and read where things stand today. Every route except GET / needs the family's assistant key in the x-household-key header; the person finds it in the app under Family, \"For your assistant\". Anyone with the key can read and add to that family's log, so keep it private. A 403 means the family made a new key: ask the person for the current one. People start or join a family log in the web app; the API cannot create one or invite people. Baby is a log, not a medical device: it makes no predictions and gives no medical advice. Errors are JSON with a plain error sentence that says what to change. More notes for assistants: https://baby-free.openapps.xyz/llms.txt",
"contact": {
"name": "OpenApps",
"url": "https://free-apps.openapps.xyz/"
}
},
"externalDocs": {
"description": "Notes for assistants (llms.txt)",
"url": "https://baby-free.openapps.xyz/llms.txt"
},
"servers": [
{
"url": "https://functions.bounded.sh/apps/381bd6356d4b794ac2a7c1b8/api"
}
],
"security": [
{
"householdKey": []
}
],
"paths": {
"/": {
"get": {
"operationId": "listRoutes",
"summary": "List the routes",
"description": "Needs no key.",
"security": [],
"responses": {
"200": {
"description": "The routes, one line each.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/RouteList"
},
"example": {
"name": "Baby by OpenApps",
"about": "A free shared baby log: feeds, sleep, diapers, growth and more. Send the family's assistant key in the x-household-key header.",
"docs": "https://baby-free.openapps.xyz/llms.txt",
"routes": [
"GET /today?baby=&tz=&units=us -> where things stand and today's totals, with a sentence to read out"
]
}
}
}
}
}
}
},
"/today": {
"get": {
"operationId": "getToday",
"summary": "Where things stand and today's totals",
"description": "For each baby (or the one named in baby): what is happening now, the last feed, diaper and sleep, today's totals, and say: one or two plain sentences to read out.",
"parameters": [
{
"$ref": "#/components/parameters/babyQuery"
},
{
"$ref": "#/components/parameters/tz"
},
{
"$ref": "#/components/parameters/units"
}
],
"responses": {
"200": {
"description": "One summary per baby.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TodayResponse"
},
"example": {
"family": {
"name": "Ada's family",
"url": "https://baby-free.openapps.xyz/app",
"timeZone": "America/New_York"
},
"babies": [
{
"id": "rbPBLYqkF9pu",
"name": "Ada",
"age": "6 weeks old",
"now": {
"asleep": false,
"asleepFor": null,
"feeding": null,
"timers": []
},
"lastFeed": {
"at": "2026-10-19T13:28:16.000Z",
"ago": "2h 10m ago",
"text": "Bottle · 4 oz formula"
},
"lastDiaper": {
"at": "2026-10-19T14:53:00.000Z",
"ago": "45m ago",
"text": "Diaper · Wet"
},
"lastSleep": {
"at": "2026-10-19T12:00:00.000Z",
"ago": "3h 38m ago",
"text": "Sleep · 1h 18m",
"ended": "2026-10-19T13:18:00.000Z",
"awakeFor": "2h 20m"
},
"today": {
"date": "2026-10-19",
"feeds": 6,
"breastfeeds": 4,
"breastMinutes": 70,
"bottles": 2,
"bottle": "8 oz",
"bottleMl": 237,
"sleepMinutes": 570,
"sleep": "9h 30m",
"diapers": 7,
"wet": 6,
"dirty": 2,
"pumped": "0 oz",
"pumpedMl": 0,
"solids": 0
},
"say": "Ada last ate 2h 10m ago (bottle, 4 oz formula). Last diaper 45m ago, wet. Awake for 2h 20m. Today: 6 feeds, 7 diapers, 9h 30m of sleep."
}
]
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/NoKey"
},
"403": {
"$ref": "#/components/responses/WrongKey"
},
"409": {
"$ref": "#/components/responses/NoBaby"
}
}
}
},
"/events": {
"get": {
"operationId": "listEvents",
"summary": "One day's entries",
"description": "Entries for one baby on one day (default today, in the family's time zone), oldest first.",
"parameters": [
{
"name": "date",
"in": "query",
"description": "The day, as YYYY-MM-DD. Default: today.",
"schema": {
"type": "string",
"pattern": "^\\d{4}-\\d{2}-\\d{2}$"
},
"example": "2026-10-19"
},
{
"$ref": "#/components/parameters/babyQuery"
},
{
"$ref": "#/components/parameters/tz"
},
{
"$ref": "#/components/parameters/units"
}
],
"responses": {
"200": {
"description": "The day's entries.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DayResponse"
},
"example": {
"family": {
"name": "Ada's family",
"url": "https://baby-free.openapps.xyz/app",
"timeZone": "America/New_York"
},
"baby": "Ada",
"date": "2026-10-19",
"entries": [
{
"id": "pd8tVARKhBJ4c9",
"type": "breast",
"start": "2026-10-19T11:10:00.000Z",
"end": "2026-10-19T11:30:00.000Z",
"running": false,
"minutes": 20,
"text": "Breastfeed · L 12m, R 8m",
"details": {
"seg": [
[
"L",
1792408200,
1792408920
],
[
"R",
1792408920,
1792409400
]
]
}
},
{
"id": "BLDwmMSspxmgeJ",
"type": "diaper",
"start": "2026-10-19T11:35:00.000Z",
"end": null,
"running": false,
"text": "Diaper · Wet",
"details": {
"kind": "wet"
}
}
]
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/NoKey"
},
"403": {
"$ref": "#/components/responses/WrongKey"
},
"409": {
"$ref": "#/components/responses/NoBaby"
}
}
},
"post": {
"operationId": "logEntry",
"summary": "Log an entry",
"description": "Logs a bottle, breastfeed, pumping, solids, sleep, diaper, growth, medicine, temperature or note. Add time (ISO 8601) or minutesAgo for something earlier; the default is now. Add note to any entry. Read back created.text so the person can catch a mistake. The answer uses the units you sent unless you pass ?units.",
"parameters": [
{
"$ref": "#/components/parameters/tz"
},
{
"$ref": "#/components/parameters/units"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/EntryInput"
},
"examples": {
"bottle": {
"summary": "A 4 oz bottle of formula",
"value": {
"type": "bottle",
"amount": 4,
"unit": "oz",
"milk": "formula"
}
},
"breast": {
"summary": "A breastfeed that just ended",
"value": {
"type": "breast",
"left": 12,
"right": 8
}
},
"breastOneSide": {
"summary": "15 minutes on the left",
"value": {
"type": "breast",
"side": "left",
"minutes": 15
}
},
"pump": {
"summary": "Pumped per side",
"value": {
"type": "pump",
"left": 60,
"right": 50,
"unit": "ml"
}
},
"diaper": {
"summary": "A wet diaper",
"value": {
"type": "diaper",
"kind": "wet"
}
},
"dirtyDiaper": {
"summary": "A dirty diaper, with its color",
"value": {
"type": "diaper",
"kind": "dirty",
"color": "yellow"
}
},
"sleep": {
"summary": "A 90 minute nap that just ended",
"value": {
"type": "sleep",
"minutes": 90
}
},
"sleepRange": {
"summary": "A sleep with start and end",
"value": {
"type": "sleep",
"start": "2026-10-19T01:00:00-04:00",
"end": "2026-10-19T04:30:00-04:00"
}
},
"solids": {
"summary": "Solids",
"value": {
"type": "solids",
"food": "banana",
"amount": "3 spoons"
}
},
"growth": {
"summary": "A checkup",
"value": {
"type": "growth",
"weight": 9.5,
"weightUnit": "lb",
"length": 22,
"lengthUnit": "in",
"head": 38,
"headUnit": "cm"
}
},
"medicine": {
"summary": "Medicine",
"value": {
"type": "medicine",
"name": "Vitamin D",
"dose": "1 drop"
}
},
"temp": {
"summary": "A temperature",
"value": {
"type": "temp",
"value": 99.1,
"unit": "f"
}
},
"note": {
"summary": "A note",
"value": {
"type": "note",
"text": "First smile"
}
},
"earlier": {
"summary": "A diaper 30 minutes ago",
"value": {
"type": "diaper",
"kind": "dirty",
"minutesAgo": 30
}
}
}
}
}
},
"responses": {
"201": {
"description": "Saved. created is the new entry; baby is the same summary as GET /today.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CreatedResponse"
},
"example": {
"created": {
"id": "TyQtWf3S6BxrXj",
"type": "bottle",
"start": "2026-10-19T15:38:00.000Z",
"end": null,
"running": false,
"text": "Bottle · 4 oz formula",
"details": {
"ml": 118,
"milk": "formula"
}
},
"baby": {
"id": "rbPBLYqkF9pu",
"name": "Ada",
"age": "6 weeks old",
"now": {
"asleep": false,
"asleepFor": null,
"feeding": null,
"timers": []
},
"lastFeed": {
"at": "2026-10-19T15:38:00.000Z",
"ago": "just now",
"text": "Bottle · 4 oz formula"
},
"lastDiaper": null,
"lastSleep": null,
"today": {
"date": "2026-10-19",
"feeds": 1,
"breastfeeds": 0,
"breastMinutes": 0,
"bottles": 1,
"bottle": "4 oz",
"bottleMl": 118,
"sleepMinutes": 0,
"sleep": "under a minute",
"diapers": 0,
"wet": 0,
"dirty": 0,
"pumped": "0 oz",
"pumpedMl": 0,
"solids": 0
},
"say": "Ada last ate just now (bottle, 4 oz formula). Today: 1 feed, 0 diapers, no sleep logged."
}
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/NoKey"
},
"403": {
"$ref": "#/components/responses/WrongKey"
},
"409": {
"$ref": "#/components/responses/NoBaby"
}
}
}
},
"/events/{id}": {
"delete": {
"operationId": "deleteEntry",
"summary": "Remove a mistaken entry",
"description": "The id comes back when you log an entry, and in GET /events.",
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"description": "The entry's id.",
"schema": {
"type": "string"
},
"example": "TyQtWf3S6BxrXj"
}
],
"responses": {
"200": {
"description": "Removed.",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"deleted"
],
"properties": {
"deleted": {
"type": "string",
"description": "The removed entry's id."
}
}
},
"example": {
"deleted": "TyQtWf3S6BxrXj"
}
}
}
},
"401": {
"$ref": "#/components/responses/NoKey"
},
"403": {
"$ref": "#/components/responses/WrongKey"
},
"404": {
"$ref": "#/components/responses/NotFound"
}
}
}
},
"/timers/start": {
"post": {
"operationId": "startTimer",
"summary": "Start a live timer",
"description": "Starts a sleep timer (the baby fell asleep) or a breastfeed timer. The family sees it running on every phone.",
"parameters": [
{
"$ref": "#/components/parameters/units"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"$ref": "#/components/schemas/TimerType"
},
"side": {
"type": "string",
"enum": [
"left",
"right"
],
"description": "Breastfeed only. Without it, the side after the last feed's last side."
},
"baby": {
"$ref": "#/components/schemas/BabyRef"
}
}
},
"examples": {
"sleep": {
"summary": "She fell asleep",
"value": {
"type": "sleep"
}
},
"breast": {
"summary": "Feeding on the left",
"value": {
"type": "breast",
"side": "left"
}
}
}
}
}
},
"responses": {
"201": {
"description": "Started.",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"started"
],
"properties": {
"started": {
"$ref": "#/components/schemas/Entry"
}
}
},
"example": {
"started": {
"id": "BLDwmMSspxmgeJ",
"type": "sleep",
"start": "2026-10-19T15:40:00.000Z",
"end": null,
"running": true,
"text": "Sleep · 0s so far",
"details": {}
}
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/NoKey"
},
"403": {
"$ref": "#/components/responses/WrongKey"
},
"409": {
"description": "A timer of that type is already running for this baby, or the family has no baby yet.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
},
"example": {
"error": "A sleep timer is already running for Ada."
}
}
}
}
}
}
},
"/timers/stop": {
"post": {
"operationId": "stopTimer",
"summary": "Stop a timer and save it",
"description": "Stops the running timer of that type (the baby woke up, or the feed is done). Leave out type to stop every running timer for that baby.",
"parameters": [
{
"$ref": "#/components/parameters/units"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"type": {
"$ref": "#/components/schemas/TimerType"
},
"baby": {
"$ref": "#/components/schemas/BabyRef"
}
}
},
"examples": {
"wokeUp": {
"summary": "She woke up",
"value": {
"type": "sleep"
}
},
"all": {
"summary": "Stop every timer",
"value": {}
}
}
}
}
},
"responses": {
"200": {
"description": "Stopped and saved.",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"stopped"
],
"properties": {
"stopped": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Entry"
}
}
}
},
"example": {
"stopped": [
{
"id": "BLDwmMSspxmgeJ",
"type": "sleep",
"start": "2026-10-19T15:40:00.000Z",
"end": "2026-10-19T17:05:00.000Z",
"running": false,
"minutes": 85,
"text": "Sleep · 1h 25m",
"details": {}
}
]
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/NoKey"
},
"403": {
"$ref": "#/components/responses/WrongKey"
},
"409": {
"$ref": "#/components/responses/NoBaby"
},
"404": {
"description": "No timer is running.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
},
"example": {
"error": "No timer is running for Ada."
}
}
}
}
}
}
},
"/timers/switch": {
"post": {
"operationId": "switchSide",
"summary": "Switch breast sides",
"description": "Switches the running breastfeed to the other side.",
"parameters": [
{
"$ref": "#/components/parameters/units"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"baby": {
"$ref": "#/components/schemas/BabyRef"
}
}
},
"example": {}
}
}
},
"responses": {
"200": {
"description": "Switched.",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"switched",
"feed"
],
"properties": {
"switched": {
"type": "string",
"enum": [
"left",
"right"
],
"description": "The side feeding now."
},
"feed": {
"$ref": "#/components/schemas/Entry"
}
}
},
"example": {
"switched": "right",
"feed": {
"id": "pd8tVARKhBJ4c9",
"type": "breast",
"start": "2026-10-19T15:40:00.000Z",
"end": null,
"running": true,
"minutes": 9,
"text": "Breastfeed · L 9m",
"details": {
"seg": [
[
"L",
1792424400,
1792424940
],
[
"R",
1792424940,
null
]
]
}
}
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/NoKey"
},
"403": {
"$ref": "#/components/responses/WrongKey"
},
"409": {
"$ref": "#/components/responses/NoBaby"
},
"404": {
"description": "No feed timer is running.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
},
"example": {
"error": "No feed timer is running for Ada."
}
}
}
}
}
}
}
},
"components": {
"securitySchemes": {
"householdKey": {
"type": "apiKey",
"in": "header",
"name": "x-household-key",
"description": "The family's assistant key (44 letters and digits), from Family, \"For your assistant\" in the app. It is the same secret as the family link."
}
},
"parameters": {
"babyQuery": {
"name": "baby",
"in": "query",
"description": "The baby's name or id. Needed when the family has more than one baby.",
"schema": {
"type": "string"
},
"example": "Ada"
},
"tz": {
"name": "tz",
"in": "query",
"description": "A time zone name that sets what today means. Default: the family's time zone.",
"schema": {
"type": "string"
},
"example": "America/New_York"
},
"units": {
"name": "units",
"in": "query",
"description": "us (or imperial) gives oz, lb and inches in the text fields; anything else gives metric. Without it, answers are metric, except that POST /events answers in the units you sent. Fields named ...Ml are always ml.",
"schema": {
"type": "string",
"enum": [
"us",
"imperial",
"metric"
]
},
"example": "us"
}
},
"responses": {
"BadRequest": {
"description": "Something in the request needs changing; the error says what.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
},
"example": {
"error": "Say the unit for amount: \"ml\" or \"oz\"."
}
}
}
},
"NoKey": {
"description": "No assistant key, or not a complete one.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
},
"example": {
"error": "Send the family's assistant key in the x-household-key header. Find it in the app under Family, \"For your assistant\"."
}
}
}
},
"WrongKey": {
"description": "The key does not work, usually because the family made a new one.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
},
"example": {
"error": "That assistant key does not work. It may have been replaced: copy the current one from Family in the app."
}
}
}
},
"NoBaby": {
"description": "The family has no baby yet.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
},
"example": {
"error": "This family has no baby yet. Add one in the app first."
}
}
}
},
"NotFound": {
"description": "No entry with that id in this family.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
},
"example": {
"error": "No entry with that id in this family."
}
}
}
}
},
"schemas": {
"Error": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string",
"description": "A sentence for a person that says what to change."
}
}
},
"RouteList": {
"type": "object",
"required": [
"name",
"about",
"docs",
"routes"
],
"properties": {
"name": {
"type": "string"
},
"about": {
"type": "string"
},
"docs": {
"type": "string",
"format": "uri"
},
"routes": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"BabyRef": {
"type": "string",
"description": "The baby's name or id. Leave it out when the family has one baby."
},
"TimerType": {
"type": "string",
"enum": [
"sleep",
"breast"
],
"description": "sleep or breast. nap, breastfeed, nursing and feed are read the same way."
},
"Family": {
"type": "object",
"required": [
"name",
"url",
"timeZone"
],
"properties": {
"name": {
"type": "string"
},
"url": {
"type": "string",
"format": "uri",
"description": "The web app."
},
"timeZone": {
"type": "string",
"description": "The time zone the days are counted in."
}
}
},
"EventType": {
"type": "string",
"enum": [
"breast",
"bottle",
"pump",
"solids",
"sleep",
"diaper",
"growth",
"medicine",
"temp",
"note"
]
},
"Details": {
"type": "object",
"description": "What was logged, in metric units: ml, kg, cm and degrees C.",
"properties": {
"seg": {
"type": "array",
"description": "Breastfeed stretches: [side, from, to] in unix seconds; to is null while that side is feeding now.",
"items": {
"type": "array",
"prefixItems": [
{
"type": "string",
"enum": [
"L",
"R"
]
},
{
"type": "integer"
},
{
"type": [
"integer",
"null"
]
}
],
"minItems": 3,
"maxItems": 3
}
},
"milk": {
"type": "string",
"enum": [
"breast",
"formula"
]
},
"ml": {
"type": "number",
"description": "Bottle amount."
},
"l": {
"type": "number",
"description": "Pumped on the left, ml."
},
"r": {
"type": "number",
"description": "Pumped on the right, ml."
},
"food": {
"type": "string"
},
"amount": {
"type": "string",
"description": "How much solid food."
},
"kind": {
"type": "string",
"enum": [
"wet",
"dirty",
"both"
]
},
"color": {
"type": "string",
"enum": [
"yellow",
"green",
"brown",
"black",
"red",
"pale"
],
"description": "A dirty diaper's color, when noted."
},
"kg": {
"type": "number"
},
"cm": {
"type": "number",
"description": "Length."
},
"head": {
"type": "number",
"description": "Head size, cm."
},
"name": {
"type": "string",
"description": "Medicine."
},
"dose": {
"type": "string"
},
"c": {
"type": "number",
"description": "Temperature, degrees C."
},
"text": {
"type": "string",
"description": "A note's text."
},
"note": {
"type": "string",
"description": "A note on any entry."
}
}
},
"Entry": {
"type": "object",
"required": [
"id",
"type",
"start",
"end",
"running",
"text",
"details"
],
"properties": {
"id": {
"type": "string"
},
"type": {
"$ref": "#/components/schemas/EventType"
},
"start": {
"type": "string",
"format": "date-time"
},
"end": {
"type": [
"string",
"null"
],
"format": "date-time",
"description": "Set for a finished breastfeed or sleep."
},
"running": {
"type": "boolean",
"description": "A breastfeed or sleep timer that is still going."
},
"minutes": {
"type": "integer",
"description": "How long a breastfeed or sleep lasted, or has lasted so far. Absent for other entries."
},
"text": {
"type": "string",
"description": "One line to read out, like \"Bottle · 4 oz formula\"."
},
"details": {
"$ref": "#/components/schemas/Details"
}
}
},
"Last": {
"type": [
"object",
"null"
],
"required": [
"at",
"ago",
"text"
],
"properties": {
"at": {
"type": "string",
"format": "date-time"
},
"ago": {
"type": "string",
"example": "2h 10m ago"
},
"text": {
"type": "string"
}
}
},
"BabySummary": {
"type": "object",
"required": [
"id",
"name",
"age",
"now",
"lastFeed",
"lastDiaper",
"lastSleep",
"today",
"say"
],
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"age": {
"type": [
"string",
"null"
],
"description": "Like \"6 weeks old\"; null without a birth date."
},
"now": {
"type": "object",
"required": [
"asleep",
"asleepFor",
"feeding",
"timers"
],
"properties": {
"asleep": {
"type": "boolean"
},
"asleepFor": {
"type": [
"string",
"null"
]
},
"feeding": {
"type": [
"object",
"null"
],
"required": [
"side",
"for"
],
"properties": {
"side": {
"type": "string",
"enum": [
"left",
"right",
"paused"
]
},
"for": {
"type": "string"
}
}
},
"timers": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Entry"
}
}
}
},
"lastFeed": {
"$ref": "#/components/schemas/Last"
},
"lastDiaper": {
"$ref": "#/components/schemas/Last"
},
"lastSleep": {
"type": [
"object",
"null"
],
"description": "The last finished sleep.",
"required": [
"at",
"ago",
"text",
"ended",
"awakeFor"
],
"properties": {
"at": {
"type": "string",
"format": "date-time"
},
"ago": {
"type": "string"
},
"text": {
"type": "string"
},
"ended": {
"type": "string",
"format": "date-time"
},
"awakeFor": {
"type": [
"string",
"null"
],
"description": "null while asleep."
}
}
},
"today": {
"type": "object",
"required": [
"date",
"feeds",
"breastfeeds",
"breastMinutes",
"bottles",
"bottle",
"bottleMl",
"sleepMinutes",
"sleep",
"diapers",
"wet",
"dirty",
"pumped",
"pumpedMl",
"solids"
],
"properties": {
"date": {
"type": "string",
"format": "date"
},
"feeds": {
"type": "integer"
},
"breastfeeds": {
"type": "integer"
},
"breastMinutes": {
"type": "integer"
},
"bottles": {
"type": "integer"
},
"bottle": {
"type": "string",
"description": "Bottle total in the answer's units."
},
"bottleMl": {
"type": "integer"
},
"sleepMinutes": {
"type": "integer"
},
"sleep": {
"type": "string"
},
"diapers": {
"type": "integer"
},
"wet": {
"type": "integer"
},
"dirty": {
"type": "integer"
},
"pumped": {
"type": "string"
},
"pumpedMl": {
"type": "integer"
},
"solids": {
"type": "integer"
}
}
},
"say": {
"type": "string",
"description": "One or two plain sentences to read out."
}
}
},
"TodayResponse": {
"type": "object",
"required": [
"family",
"babies"
],
"properties": {
"family": {
"$ref": "#/components/schemas/Family"
},
"babies": {
"type": "array",
"items": {
"$ref": "#/components/schemas/BabySummary"
}
}
}
},
"DayResponse": {
"type": "object",
"required": [
"family",
"baby",
"date",
"entries"
],
"properties": {
"family": {
"$ref": "#/components/schemas/Family"
},
"baby": {
"type": "string",
"description": "The baby's name."
},
"date": {
"type": "string",
"format": "date"
},
"entries": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Entry"
}
}
}
},
"CreatedResponse": {
"type": "object",
"required": [
"created",
"baby"
],
"properties": {
"created": {
"$ref": "#/components/schemas/Entry"
},
"baby": {
"$ref": "#/components/schemas/BabySummary"
}
}
},
"EntryInput": {
"description": "One entry. type picks the shape. Common fields: baby, time or minutesAgo, note. Types also accept everyday names: breastfeed, nursing, formula, nap, nappy, temperature, fever, medication, weight, food.",
"oneOf": [
{
"$ref": "#/components/schemas/BottleInput"
},
{
"$ref": "#/components/schemas/BreastInput"
},
{
"$ref": "#/components/schemas/PumpInput"
},
{
"$ref": "#/components/schemas/SolidsInput"
},
{
"$ref": "#/components/schemas/SleepInput"
},
{
"$ref": "#/components/schemas/DiaperInput"
},
{
"$ref": "#/components/schemas/GrowthInput"
},
{
"$ref": "#/components/schemas/MedicineInput"
},
{
"$ref": "#/components/schemas/TempInput"
},
{
"$ref": "#/components/schemas/NoteInput"
}
],
"discriminator": {
"propertyName": "type",
"mapping": {
"bottle": "#/components/schemas/BottleInput",
"breast": "#/components/schemas/BreastInput",
"pump": "#/components/schemas/PumpInput",
"solids": "#/components/schemas/SolidsInput",
"sleep": "#/components/schemas/SleepInput",
"diaper": "#/components/schemas/DiaperInput",
"growth": "#/components/schemas/GrowthInput",
"medicine": "#/components/schemas/MedicineInput",
"temp": "#/components/schemas/TempInput",
"note": "#/components/schemas/NoteInput"
}
}
},
"Common": {
"type": "object",
"properties": {
"baby": {
"$ref": "#/components/schemas/BabyRef"
},
"time": {
"type": "string",
"format": "date-time",
"description": "When it happened (for a breastfeed or sleep with minutes: when it started). Default: now. Not in the future.",
"example": "2026-10-19T03:10:00-04:00"
},
"minutesAgo": {
"type": "number",
"minimum": 0,
"maximum": 10080,
"description": "Instead of time: how many minutes ago."
},
"note": {
"type": "string",
"maxLength": 500
}
}
},
"VolumeUnit": {
"type": "string",
"enum": [
"ml",
"oz"
]
},
"LengthUnit": {
"type": "string",
"enum": [
"cm",
"in"
]
},
"BottleInput": {
"allOf": [
{
"$ref": "#/components/schemas/Common"
}
],
"type": "object",
"required": [
"type",
"amount",
"unit"
],
"properties": {
"type": {
"const": "bottle"
},
"amount": {
"type": "number",
"exclusiveMinimum": 0,
"maximum": 2000
},
"unit": {
"$ref": "#/components/schemas/VolumeUnit"
},
"milk": {
"type": "string",
"enum": [
"formula",
"breast milk"
]
}
}
},
"BreastInput": {
"allOf": [
{
"$ref": "#/components/schemas/Common"
}
],
"type": "object",
"required": [
"type"
],
"description": "A breastfeed that already happened: left and right minutes, or side and minutes. Without time it ended now. To start a live timer, use POST /timers/start.",
"properties": {
"type": {
"const": "breast"
},
"left": {
"type": "number",
"minimum": 0,
"maximum": 180,
"description": "Minutes on the left."
},
"right": {
"type": "number",
"minimum": 0,
"maximum": 180,
"description": "Minutes on the right."
},
"side": {
"type": "string",
"enum": [
"left",
"right"
]
},
"minutes": {
"type": "number",
"minimum": 0,
"maximum": 180,
"description": "With side."
}
}
},
"PumpInput": {
"allOf": [
{
"$ref": "#/components/schemas/Common"
}
],
"type": "object",
"required": [
"type",
"unit"
],
"description": "Send left and right, or amount.",
"properties": {
"type": {
"const": "pump"
},
"left": {
"type": "number",
"minimum": 0,
"maximum": 2000
},
"right": {
"type": "number",
"minimum": 0,
"maximum": 2000
},
"amount": {
"type": "number",
"minimum": 0,
"maximum": 2000
},
"unit": {
"$ref": "#/components/schemas/VolumeUnit"
}
}
},
"SolidsInput": {
"allOf": [
{
"$ref": "#/components/schemas/Common"
}
],
"type": "object",
"required": [
"type",
"food"
],
"properties": {
"type": {
"const": "solids"
},
"food": {
"type": "string",
"maxLength": 120
},
"amount": {
"type": "string",
"maxLength": 80,
"description": "How much, in words."
}
}
},
"SleepInput": {
"allOf": [
{
"$ref": "#/components/schemas/Common"
}
],
"type": "object",
"required": [
"type"
],
"description": "A sleep that already happened: minutes (ended now, or started at time), or start and end. To start a live timer, use POST /timers/start.",
"properties": {
"type": {
"const": "sleep"
},
"minutes": {
"type": "number",
"exclusiveMinimum": 0,
"maximum": 1440
},
"start": {
"type": "string",
"format": "date-time"
},
"end": {
"type": "string",
"format": "date-time",
"description": "With start. Default: now."
}
}
},
"DiaperInput": {
"allOf": [
{
"$ref": "#/components/schemas/Common"
}
],
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"const": "diaper"
},
"kind": {
"type": "string",
"enum": [
"wet",
"dirty",
"both"
],
"default": "wet"
},
"color": {
"type": "string",
"enum": [
"yellow",
"green",
"brown",
"black",
"red",
"pale"
],
"description": "Optional, for a dirty diaper (kind dirty or both). Also accepts white, grey or gray (pale), mustard or orange (yellow) and tan (brown)."
}
}
},
"GrowthInput": {
"allOf": [
{
"$ref": "#/components/schemas/Common"
}
],
"type": "object",
"required": [
"type"
],
"description": "Any of weight, length and head, each with its unit.",
"properties": {
"type": {
"const": "growth"
},
"weight": {
"type": "number",
"minimum": 0,
"maximum": 80
},
"weightUnit": {
"type": "string",
"enum": [
"kg",
"lb"
]
},
"length": {
"type": "number",
"minimum": 0,
"maximum": 200
},
"lengthUnit": {
"$ref": "#/components/schemas/LengthUnit"
},
"head": {
"type": "number",
"minimum": 0,
"maximum": 100
},
"headUnit": {
"$ref": "#/components/schemas/LengthUnit"
}
}
},
"MedicineInput": {
"allOf": [
{
"$ref": "#/components/schemas/Common"
}
],
"type": "object",
"required": [
"type",
"name"
],
"properties": {
"type": {
"const": "medicine"
},
"name": {
"type": "string",
"maxLength": 80
},
"dose": {
"type": "string",
"maxLength": 80
}
}
},
"TempInput": {
"allOf": [
{
"$ref": "#/components/schemas/Common"
}
],
"type": "object",
"required": [
"type",
"value",
"unit"
],
"description": "The value must come to 30 to 45 degrees C.",
"properties": {
"type": {
"const": "temp"
},
"value": {
"type": "number",
"minimum": 0,
"maximum": 120
},
"unit": {
"type": "string",
"enum": [
"c",
"f"
]
}
}
},
"NoteInput": {
"allOf": [
{
"$ref": "#/components/schemas/Common"
}
],
"type": "object",
"required": [
"type",
"text"
],
"properties": {
"type": {
"const": "note"
},
"text": {
"type": "string",
"maxLength": 1000
}
}
}
}
}
}
Change history
Quality pass: undo on timers, sleep by hour chart, diaper color, fixes
Bounded source sync
Bounded source sync
Bounded source sync