Luna Tracker API

Log and read the family's events: feeds, sleep, nappies, solids, notes, measurements, supplements.

GitHub OpenAPI

Operations 9

POST /api/vega/log Log an event #
GET /api/vega/food/suggestions Recently logged foods #
POST /api/vega/event/edit Edit an event #
POST /api/vega/event/delete Delete an event #
POST /api/vega/event/react React to an event #
POST /api/vega/recipes Save a recipe #
POST /api/vega/undo Undo the last event #
GET /api/vega/today Today's events #
GET /api/vega/events Events for a day #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/getmyluna-app:getmyluna-app-tracker-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

getmyluna-app-tracker-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Luna Tracker API
  description: 'Luna is a baby tracker for feeds, sleep, nappies, solids and routines, shared between parents and invited caregivers.


    This REST API is the same one the Luna web app uses. Every request is scoped to **one family**: the family is resolved from the bearer token (or session cookie) and there is no way to address another family''s data.


    ## Authentication


    * **Bearer token** (`Authorization: Bearer `), the way agents and scripts should call the API. Create one in the app (Settings → Connect an assistant) or `POST /api/vega/token` from a signed-in session. Tokens are stored hashed and can carry `read` or `read`+`write` scopes. A `read` token may call every `GET` (and `HEAD`) route plus `POST /api/ask` (asking only; a `remember:` question saves a note and needs `write`). Any other `POST`, `PUT`, `PATCH` or `DELETE` with a token that lacks `write` returns `403 {"error": "insufficient_scope", "required_scope": "write"}`. Each operation''s `x-required-scope` says which it needs.

    * **Session cookie** (`luna_session`), what the browser uses after `POST /login` or `POST /api/vega/onboard`.


    Only `GET /api/health` and `POST /api/vega/onboard` are reachable without credentials. Unauthenticated calls to anything else return `401 {"error": "unauthorized"}`.


    ## Conventions


    * Timestamps are ISO 8601 in the family''s local time (`YYYY-MM-DDTHH:MM:SS`); omit `ts` to log "now". Future timestamps are rejected.

    * Volumes are millilitres, weights kilograms, lengths centimetres. Families with `units: imperial` still store metric.

    * Errors are JSON `{"error": ""}` with a 4xx status.

    * Luna is not a medical device: nothing here diagnoses, assesses symptoms or advises on medication.


    ## Other ways in


    * **MCP connector** at `https://getmyluna.app/mcp` (streamable HTTP; OAuth sign-in, or the same bearer token): 23 tools, resources and prompts for Meta Muse, Claude Code and any MCP client. Manifest: `/.well-known/luna-connector.json`.

    * **Agent instructions**: `/llms.txt`. **Developer portal**: `/developers`. **CLI**: `/cli/luna.py`.'
  termsOfService: https://getmyluna.app/terms
  contact:
    name: Luna support
    url: https://getmyluna.app/contact
    email: hello@getmyluna.app
  version: 1.1.0
servers:
- url: https://getmyluna.app
  description: Production
tags:
- name: Tracker
  description: 'Log and read the family''s events: feeds, sleep, nappies, solids, notes, measurements, supplements.'
paths:
  /api/vega/log:
    post:
      tags:
      - Tracker
      summary: Log an event
      description: 'Append a feed, sleep/wake, nappy, solid meal, note, supplement or measurement. Validates ranges (milk 0-500 ml, weight 0.5-30 kg, length 40-120 cm) and rejects future timestamps. Returns the saved event, the refreshed live status, and a soft `warning` if the time conflicts with a recorded sleep span.


        **Safe retries:** send an `Idempotency-Key` header (or body `client_id`), a random value you make once per entry and resend unchanged on every retry. Keys are scoped to the family. The first request logs the entry; any later request with the same key logs nothing and returns `200` with `replayed: true` and the original entry, even when two retries arrive at once. Keep `ts` as the time it happened, not the time you send it. A key reused for a different `type` returns `409 idempotency_key_reused`. Keys are kept for 30 days, and a keyed entry with `ts` more than 30 days ago is refused (`400`). The Luna app uses this for logs saved while offline.'
      operationId: log_event
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/LogEventRequest'
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LogEventResponse'
        '400':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: Bad Request
        '409':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: Conflict
        '401':
          description: Missing or invalid credentials
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: '`insufficient_scope`: the bearer token lacks the `write` scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      parameters:
      - name: Idempotency-Key
        in: header
        required: false
        description: 'Random per-entry key (8-128 characters: letters, digits, `_ - . :`). Resend the same key on retries.'
        schema:
          type: string
          minLength: 8
          maxLength: 128
          pattern: ^[A-Za-z0-9][A-Za-z0-9_.:-]{7,127}$
      security:
      - bearerAuth: []
      - sessionCookie: []
      x-required-scope: write
  /api/vega/food/suggestions:
    get:
      tags:
      - Tracker
      summary: Recently logged foods
      description: 'Foods logged in the last 14 days, most recent first: handy for autocomplete.'
      operationId: food_suggestions
      parameters:
      - name: limit
        in: query
        required: false
        schema:
          type: integer
          maximum: 100
          minimum: 1
          description: Maximum number of foods to return.
          default: 12
          title: Limit
        description: Maximum number of foods to return.
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FoodSuggestionsResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          description: Missing or invalid credentials
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
      - sessionCookie: []
      x-required-scope: read
  /api/vega/event/edit:
    post:
      tags:
      - Tracker
      summary: Edit an event
      description: Change editable fields (ts, ml, foods, note, meal_type, kind, author) on one event by id.
      operationId: edit_event
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EventEditRequest'
        required: true
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EventMutationResponse'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Missing or invalid credentials
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: '`insufficient_scope`: the bearer token lacks the `write` scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
      - sessionCookie: []
      x-required-scope: write
  /api/vega/event/delete:
    post:
      tags:
      - Tracker
      summary: Delete an event
      description: Remove one event by id.
      operationId: delete_event
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EventIdRequest'
        required: true
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EventMutationResponse'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Missing or invalid credentials
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: '`insufficient_scope`: the bearer token lacks the `write` scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
      - sessionCookie: []
      x-required-scope: write
  /api/vega/event/react:
    post:
      tags:
      - Tracker
      summary: React to an event
      description: Add an emoji reaction from the current caregiver to an event.
      operationId: react_to_event
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EventReactRequest'
        required: true
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EventMutationResponse'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: '`insufficient_scope`: the bearer token lacks the `write` scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
      - sessionCookie: []
      x-required-scope: write
  /api/vega/recipes:
    post:
      tags:
      - Tracker
      summary: Save a recipe
      description: Store a named ingredient list so it can be logged as one solid meal.
      operationId: save_recipe
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RecipeRequest'
        required: true
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RecipeResponse'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Missing or invalid credentials
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: '`insufficient_scope`: the bearer token lacks the `write` scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
      - sessionCookie: []
      x-required-scope: write
  /api/vega/undo:
    post:
      tags:
      - Tracker
      summary: Undo the last event
      description: 'Removes the most recently logged event. Returns `removed: null` when the log is empty.'
      operationId: undo_last_event
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UndoResponse'
        '401':
          description: Missing or invalid credentials
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: '`insufficient_scope`: the bearer token lacks the `write` scope'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
      - sessionCookie: []
      x-required-scope: write
  /api/vega/today:
    get:
      tags:
      - Tracker
      summary: Today's events
      description: Shortcut for `GET /api/vega/events` with today's date.
      operationId: today_events
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EventsResponse'
        '401':
          description: Missing or invalid credentials
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
      - sessionCookie: []
      x-required-scope: read
  /api/vega/events:
    get:
      tags:
      - Tracker
      summary: Events for a day
      description: All events for `date` (YYYY-MM-DD), oldest first. Defaults to today.
      operationId: list_events
      parameters:
      - name: date
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          description: Day to list, YYYY-MM-DD. Defaults to today (family-local).
          examples:
          - '2026-09-20'
          title: Date
        description: Day to list, YYYY-MM-DD. Defaults to today (family-local).
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EventsResponse'
        '400':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: Bad Request
        '401':
          description: Missing or invalid credentials
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - bearerAuth: []
      - sessionCookie: []
      x-required-scope: read
components:
  schemas:
    EventEditRequest:
      properties:
        id:
          examples:
          - af73aec9
          title: Id
          type: string
        changes:
          additionalProperties: true
          description: 'Editable fields only: ts, ml, foods, note, meal_type, kind, author.'
          examples:
          - ml: 180
          title: Changes
          type: object
      required:
      - id
      - changes
      title: EventEditRequest
      type: object
    ValidationError:
      properties:
        loc:
          items:
            anyOf:
            - type: string
            - type: integer
          type: array
          title: Location
        msg:
          type: string
          title: Message
        type:
          type: string
          title: Error Type
      type: object
      required:
      - loc
      - msg
      - type
      title: ValidationError
    RecipeResponse:
      properties:
        status:
          type: string
          const: ok
          title: Status
        recipe:
          additionalProperties: true
          type: object
          title: Recipe
      type: object
      required:
      - status
      - recipe
      title: RecipeResponse
    LogEventRequest:
      description: Body for `POST /api/vega/log`. Provide the fields that make sense for `type`.
      properties:
        type:
          enum:
          - milk
          - sleep
          - wake
          - nappy
          - poop
          - solid
          - note
          - supplement
          - weight
          - length
          examples:
          - milk
          title: Type
          type: string
        ts:
          anyOf:
          - type: string
          - type: 'null'
          default: null
          description: ISO 8601 local time; defaults to now. Cannot be in the future.
          examples:
          - '2026-09-20T14:30:00'
          title: Ts
        ml:
          anyOf:
          - maximum: 500
            minimum: 0
            type: integer
          - type: 'null'
          default: null
          description: '`milk`: millilitres, 0-500. Use 0 (or omit) for a breastfeed.'
          examples:
          - 150
          title: Ml
        kind:
          anyOf:
          - type: string
          - type: 'null'
          default: null
          description: '`nappy`: wet|dirty|both|dry. `supplement`: vitd|iron|multivitamin.'
          examples:
          - wet
          title: Kind
        foods:
          anyOf:
          - items:
              type: string
            type: array
          - type: 'null'
          default: null
          description: '`solid`: foods eaten.'
          examples:
          - - scrambled egg
            - toast
          title: Foods
        meal_type:
          anyOf:
          - enum:
            - meal
            - snack
            type: string
          - type: 'null'
          default: null
          description: '`solid` only.'
          title: Meal Type
        kg:
          anyOf:
          - type: number
          - type: 'null'
          default: null
          description: '`weight`: kilograms, 0.5-30.'
          examples:
          - 8.45
          title: Kg
        cm:
          anyOf:
          - type: number
          - type: 'null'
          default: null
          description: '`length`: centimetres, 40-120.'
          examples:
          - 72.5
          title: Cm
        ug:
          anyOf:
          - type: integer
          - type: 'null'
          default: null
          description: '`supplement`: micrograms.'
          examples:
          - 10
          title: Ug
        note:
          anyOf:
          - maxLength: 300
            type: string
          - type: 'null'
          default: null
          description: Free text, up to 300 characters.
          title: Note
        author:
          anyOf:
          - type: string
          - type: 'null'
          default: null
          description: Defaults to the calling user's username.
          title: Author
        timezone:
          anyOf:
          - type: string
          - type: 'null'
          default: null
          description: IANA zone if `ts` is in a different zone from the family's.
          title: Timezone
        client_id:
          anyOf:
          - type: string
          - type: 'null'
          default: null
          description: 'Same as the `Idempotency-Key` header, for clients that can''t set headers. 8-128 characters: letters, digits, `_ - . :`. If both are sent they must match.'
          examples:
          - lq_3f2b7c9e-1d4a-4e0b-9a51-7c2d8e6f0a13
          title: Client Id
      required:
      - type
      title: LogEventRequest
      type: object
    Warning_:
      properties:
        type:
          type: string
          title: Type
          examples:
          - asleep_at_time
        message:
          type: string
          title: Message
        sleep_span:
          anyOf:
          - additionalProperties: true
            type: object
          - type: 'null'
          title: Sleep Span
      type: object
      required:
      - type
      - message
      title: Warning_
    UndoResponse:
      properties:
        status:
          type: string
          const: ok
          title: Status
        removed:
          anyOf:
          - $ref: '#/components/schemas/Event'
          - type: 'null'
          description: '`null` when there was nothing to undo.'
        message:
          anyOf:
          - type: string
          - type: 'null'
          title: Message
        live:
          anyOf:
          - additionalProperties: true
            type: object
          - type: 'null'
          title: Live
      type: object
      required:
      - status
      title: UndoResponse
    RecipeRequest:
      properties:
        name:
          examples:
          - lentil dahl
          title: Name
          type: string
        ingredients:
          examples:
          - - red lentils
            - carrot
            - coconut milk
          items:
            type: string
          title: Ingredients
          type: array
      required:
      - name
      - ingredients
      title: RecipeRequest
      type: object
    EventIdRequest:
      properties:
        id:
          examples:
          - af73aec9
          title: Id
          type: string
      required:
      - id
      title: EventIdRequest
      type: object
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
      type: object
      title: HTTPValidationError
    Event:
      properties:
        id:
          type: string
          title: Id
          description: 8-hex-char id, unique within the family.
          examples:
          - af73aec9
        ts:
          type: string
          title: Ts
          description: ISO 8601 local timestamp.
          examples:
          - '2026-09-20T09:49:53'
        type:
          type: string
          enum:
          - milk
          - sleep
          - wake
          - nappy
          - poop
          - solid
          - note
          - supplement
          - weight
          - length
          title: Type
        author:
          type: string
          title: Author
          description: 'Who logged it: the caregiver''s first name, or `Family admin` / `Partner` until they''ve set one (`app`/`agent` for non-human). Never an email or username.'
          default: app
        author_name:
          anyOf:
          - type: string
          - type: 'null'
          title: Author Name
          description: Same as `author` (display name).
        author_is_me:
          anyOf:
          - type: boolean
          - type: 'null'
          title: Author Is Me
          description: 'Web session/token only: true when the current caregiver logged it.'
        ml:
          anyOf:
          - type: integer
            maximum: 500.0
            minimum: 0.0
          - type: 'null'
          title: Ml
          description: '`milk` only: millilitres (0 for a breastfeed).'
        kind:
          anyOf:
          - type: string
          - type: 'null'
          title: Kind
          description: '`nappy`: wet|dirty|both|dry. `supplement`: vitd|iron|multivitamin.'
        foods:
          anyOf:
          - items:
              type: string
            type: array
          - type: 'null'
          title: Foods
          description: '`solid` only: what was eaten.'
        meal_type:
          anyOf:
          - type: string
            enum:
            - meal
            - snack
          - type: 'null'
          title: Meal Type
          description: '`solid` only.'
        kg:
          anyOf:
          - type: number
          - type: 'null'
          title: Kg
          description: '`weight` only.'
        cm:
          anyOf:
          - type: number
          - type: 'null'
          title: Cm
          description: '`length` only.'
        ug:
          anyOf:
          - type: integer
          - type: 'null'
          title: Ug
          description: '`supplement` only: micrograms.'
        note:
          anyOf:
          - type: string
            maxLength: 300
          - type: 'null'
          title: Note
        reactions:
          anyOf:
          - items:
              additionalProperties: true
              type: object
            type: array
          - type: 'null'
          title: Reactions
          description: 'Emoji reactions from caregivers: `emoji`, `ts`, `user` (display name), `mine`.'
      type: object
      required:
      - id
      - ts
      - type
      title: Event
      description: One logged event. Fields beyond `id`/`ts`/`type`/`author` depend on `type`.
    FoodSuggestionsResponse:
      properties:
        suggestions:
          items:
            type: string
          type: array
          title: Suggestions
          description: Recently logged foods, most recent first.
      type: object
      required:
      - suggestions
      title: FoodSuggestionsResponse
    LogEventResponse:
      properties:
        status:
          type: string
          const: ok
          title: Status
        event:
          anyOf:
          - $ref: '#/components/schemas/Event'
          - type: 'null'
          description: The saved entry. On a replay, the entry the first request made (null if it has since been deleted).
        replayed:
          type: boolean
          title: Replayed
          description: 'True when this `Idempotency-Key` was already used: nothing new was logged.'
          default: false
        live:
          additionalProperties: true
          type: object
          title: Live
          description: The refreshed live-status block (same shape as `GET /api/vega/live`).
        unknown_foods:
          items:
            type: string
          type: array
          title: Unknown Foods
          description: '`solid` foods with no nutrient data.'
        warning:
          anyOf:
          - $ref: '#/components/schemas/Warning_'
          - type: 'null'
          description: Soft conflict, e.g. a feed logged inside a recorded sleep span. The event was still saved.
      type: object
      required:
      - status
      - event
      - live
      title: LogEventResponse
    EventReactRequest:
      properties:
        id:
          examples:
          - af73aec9
          title: Id
          type: string
        emoji:
          examples:
          - ❤️
          title: Emoji
          type: string
      required:
      - id
      - emoji
      title: EventReactRequest
      type: object
    EventMutationResponse:
      properties:
        status:
          type: string
          const: ok
          title: Status
        event:
          anyOf:
          - $ref: '#/components/schemas/Event'
          - type: 'null'
        removed:
          anyOf:
          - $ref: '#/components/schemas/Event'
          - type: 'null'
        live:
          anyOf:
          - additionalProperties: true
            type: object
          - type: 'null'
          title: Live
      type: object
      required:
      - status
      title: EventMutationResponse
    ErrorResponse:
      properties:
        error:
          type: string
          title: Error
          description: Machine-readable code (e.g. `unauthorized`, `not_found`) or a short message.
          examples:
          - unauthorized
        message:
          anyOf:
          - type: string
          - type: 'null'
          title: Message
          description: Optional human-readable detail.
      type: object
      required:
      - error
      title: ErrorResponse
      description: Every error is a JSON object with an `error` code or message.
    EventsResponse:
      properties:
        events:
          items:
            $ref: '#/components/schemas/Event'
          type: array
          title: Events
      type: object
      required:
      - events
      title: EventsResponse
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: opaque
      description: 'Token from Settings → Connect an assistant or `POST /api/vega/token`. Scopes: `read`, `write`. A `read` token gets `403 insufficient_scope` on any operation whose `x-required-scope` is `write`.'
    sessionCookie:
      type: apiKey
      in: cookie
      name: luna_session
      description: Browser session set by `POST /login` or `POST /api/vega/onboard`.
externalDocs:
  description: Developer portal
  url: https://getmyluna.app/developers