Luna Profile API
The child's profile and family settings (region, units, timezone).
The child's profile and family settings (region, units, timezone).
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
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.curl "https://apis.io/api/v1/apis/getmyluna-app:getmyluna-app-profile-api"
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.
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: 3.2.0
info:
title: Luna Profile 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: Profile
description: The child's profile and family settings (region, units, timezone).
paths:
/api/vega/profile:
get:
tags:
- Profile
summary: Child profile and family settings
description: Name, date of birth, computed age, region, units, timezone and member count.
operationId: get_profile
responses:
'200':
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/Profile'
'401':
description: Missing or invalid credentials
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
security:
- bearerAuth: []
- sessionCookie: []
x-required-scope: read
post:
tags:
- Profile
summary: Update profile or settings
description: Admin only. Any subset of fields; setting `region` also sets `units` unless given.
operationId: update_profile
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/ProfileUpdateRequest'
required: true
responses:
'200':
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/ProfileUpdateResponse'
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: Forbidden, or `insufficient_scope` when a bearer token lacks the `write` scope
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'401':
description: Missing or invalid credentials
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
security:
- bearerAuth: []
- sessionCookie: []
x-requires-role: admin
x-required-scope: write
/api/vega/clinic:
get:
tags:
- Profile
summary: Clinic schedule and help numbers
description: 'South Africa families: the EPI (SA) 2024 clinic immunisation schedule (Road to Health booklet), the next visit for the baby''s age, and help numbers (10177, 112, National Health Hotline, poisons line). Empty lists for other regions.'
operationId: get_clinic
responses:
'200':
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/ClinicResponse'
'401':
description: Missing or invalid credentials
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
security:
- bearerAuth: []
- sessionCookie: []
x-required-scope: read
/api/vega/due-date:
post:
tags:
- Profile
summary: Change the due date
description: 'Any caregiver. Only while expecting: moves the due date (up to 14 days ago to 10 months ahead). Returns `409` once a date of birth is set; the profile is not changed.'
operationId: update_due_date
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/DueDateRequest'
required: true
responses:
'200':
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/DueDateResponse'
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'409':
description: Conflict
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/arrived:
post:
tags:
- Profile
summary: The baby has arrived
description: 'Any caregiver. Only while expecting: sets the date of birth, clears the due date and starts the daily log. Returns `409` if a date of birth is already set.'
operationId: confirm_arrival
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/ArrivedRequest'
required: true
responses:
'200':
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/ProfileUpdateResponse'
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'409':
description: Conflict
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
components:
schemas:
ProfileUpdateRequest:
description: Any subset of fields; admin only.
properties:
baby_name:
anyOf:
- maxLength: 80
type: string
- type: 'null'
default: null
title: Baby Name
dob:
anyOf:
- type: string
- type: 'null'
default: null
description: YYYY-MM-DD, not in the future, within 0-5 years. Setting it clears `due_date`.
title: Dob
due_date:
anyOf:
- type: string
- type: 'null'
default: null
description: YYYY-MM-DD, up to 14 days ago to 10 months ahead. Only while there is no date of birth.
title: Due Date
gender:
anyOf:
- enum:
- girl
- boy
- female
- male
- other
- unknown
- prefer_not_to_say
- ''
type: string
- type: 'null'
default: null
title: Gender
family_name:
anyOf:
- maxLength: 120
type: string
- type: 'null'
default: null
title: Family Name
timezone:
anyOf:
- type: string
- type: 'null'
default: null
description: IANA zone, e.g. `America/New_York`.
title: Timezone
region:
anyOf:
- enum:
- uk
- us
- za
type: string
- type: 'null'
default: null
description: '`uk`, `us` or `za` (South Africa). Sets `units` to match unless `units` is given.'
title: Region
units:
anyOf:
- enum:
- metric
- imperial
type: string
- type: 'null'
default: null
title: Units
title: ProfileUpdateRequest
type: object
DueDateRequest:
properties:
due_date:
description: YYYY-MM-DD, up to 14 days ago to 10 months ahead.
examples:
- '2027-03-12'
title: Due Date
type: string
client_today:
anyOf:
- type: string
- type: 'null'
default: null
description: 'Optional: the browser''s local date (YYYY-MM-DD), used when within a day of the family''s local date.'
title: Client Today
required:
- due_date
title: DueDateRequest
type: object
ClinicResponse:
properties:
region:
type: string
enum:
- uk
- us
- za
title: Region
country:
type: string
title: Country
suggested_timezone:
anyOf:
- type: string
- type: 'null'
title: Suggested Timezone
age_days:
anyOf:
- type: integer
- type: 'null'
title: Age Days
schedule:
items:
$ref: '#/components/schemas/ClinicVisit'
type: array
title: Schedule
description: 'South Africa: EPI (SA) 2024 childhood schedule. Empty elsewhere.'
next_visit_age:
anyOf:
- type: string
- type: 'null'
title: Next Visit Age
help_numbers:
items:
$ref: '#/components/schemas/HelpNumber'
type: array
title: Help Numbers
description: 'South Africa: ambulance, cell emergency, National Health Hotline, poisons line. Empty elsewhere.'
type: object
required:
- region
- country
title: ClinicResponse
HelpNumber:
properties:
key:
type: string
title: Key
examples:
- ambulance
number:
type: string
title: Number
examples:
- '10177'
tel:
type: string
title: Tel
kind:
type: string
enum:
- emergency
- advice
- poisons
title: Kind
label:
type: string
title: Label
type: object
required:
- key
- number
- tel
- kind
- label
title: HelpNumber
Expecting:
properties:
due_date:
type: string
title: Due Date
examples:
- '2027-03-12'
days_until_due:
type: integer
title: Days Until Due
description: 0 once the due date arrives.
due_date_reached:
type: boolean
title: Due Date Reached
days_overdue:
type: integer
title: Days Overdue
description: Days since the due date while the birth isn't confirmed yet (0 before it). The family stays expecting until a caregiver confirms the arrival.
default: 0
type: object
required:
- due_date
- days_until_due
- due_date_reached
title: Expecting
description: 'Set while the baby isn''t born yet: there is no age and no age-based target.'
DueDateResponse:
properties:
ok:
type: boolean
title: Ok
due_date:
type: string
title: Due Date
expecting:
anyOf:
- $ref: '#/components/schemas/Expecting'
- type: 'null'
type: object
required:
- ok
- due_date
title: DueDateResponse
ClinicVisit:
properties:
age:
type: string
title: Age
examples:
- 6 weeks
age_days:
type: integer
title: Age Days
description: The stated age in days, only used to find the next visit.
vaccines:
items:
type: string
type: array
title: Vaccines
note:
type: string
title: Note
default: ''
type: object
required:
- age
- age_days
- vaccines
title: ClinicVisit
ProfileUpdateResponse:
properties:
ok:
type: boolean
title: Ok
profile:
additionalProperties: true
type: object
title: Profile
type: object
required:
- ok
- profile
title: ProfileUpdateResponse
ArrivedRequest:
properties:
dob:
description: YYYY-MM-DD, not in the future.
examples:
- '2026-10-18'
title: Dob
type: string
required:
- dob
title: ArrivedRequest
type: object
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.
Profile:
properties:
baby_name:
type: string
title: Baby Name
dob:
type: string
title: Dob
description: YYYY-MM-DD, or empty while the family is expecting (see `due_date`).
gender:
type: string
title: Gender
default: ''
family_name:
type: string
title: Family Name
default: ''
timezone:
type: string
title: Timezone
description: IANA zone.
default: Europe/London
region:
type: string
enum:
- uk
- us
- za
title: Region
default: uk
units:
type: string
enum:
- metric
- imperial
title: Units
default: metric
age_months:
anyOf:
- type: number
- type: 'null'
title: Age Months
age_display:
anyOf:
- type: string
- type: 'null'
title: Age Display
solids_started:
type: boolean
title: Solids Started
default: false
member_count:
type: integer
title: Member Count
default: 1
age_band_targets:
additionalProperties: true
type: object
title: Age Band Targets
due_date:
anyOf:
- type: string
- type: 'null'
title: Due Date
description: YYYY-MM-DD while expecting; null once the date of birth is set.
expecting:
anyOf:
- $ref: '#/components/schemas/Expecting'
- type: 'null'
type: object
required:
- baby_name
- dob
title: Profile
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