baby-free.openapps.xyz

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.
Owned app · rev c84ed8821371
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.
← All files
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
c84ed88213 · 5 hours ago
Bounded source sync
1ed137d95d · 16 hours ago
Bounded source sync
851999f793 · 17 hours ago
Bounded source sync
9623bc231c · 17 hours ago