Overview
Built for family life
Photo Album, Calendar, and Chat under one admin key on Premium Max (2,100 GB). Base URL:
https://api.ily.chat/v1
- Chat mirrors membership — private channels without the admin stay invisible.
- Album uploads use the same batch lifecycle as the ILY app.
- API-created calendar events and chat messages show source = API.
Examples on this page
All curl samples use the placeholder key ily_fam_KEY
and path ids like FAMILY_ID,
BATCH_ID, and CHANNEL_ID.
Replace them with your real values.
Create a key in the ILY app
Settings → Family Admin API (owner). Email OTP required. Secret shown once.
Call /v1 with the key
Bearer ily_fam_KEY — never send app JWTs to /v1.
Auth
Family Admin API keys
One rotateable key per family. Active Premium Max required. Keys may suspend with
premium_max_required if Max lapses.
Request headers
Headers
| Name | Type | Description |
|---|---|---|
| Authorizationreq* | string | Bearer ily_fam_KEY — preferred. |
| X-ILY-Family-Api-Keyalt | string | Same key without Bearer, if your client cannot set Authorization. |
| Content-Typebody | string | application/json on POST/PUT with a body. |
* Provide Authorization or X-ILY-Family-Api-Key.
Authorization: Bearer ily_fam_KEY
Alternative:
X-ILY-Family-Api-Key: ily_fam_KEY
Key lifecycle
- Create in Settings → Family Admin API (owner only)
- Email OTP on create and regenerate
- Plaintext secret shown once; regenerate invalidates the old secret
Example
curl -sS https://api.ily.chat/v1/families/FAMILY_ID/calendar/event-types \
-H "Authorization: Bearer ily_fam_KEY"
Per-key / per-family rate limits apply. Uploads also claim a 100 GB/day API budget plus family storage limits.
Photos
Batch album upload
Same lifecycle as the ILY app: provision a batch, add images, submit when ready. Photos in v1 are publish-only — get images into the family album. There is no album timeline or asset listing.
Browse, view, and export photos through the ILY mobile and desktop apps.
v1 media policy
- Images only — album uploads require an open batch
- Assets stay staged until you submit the batch
- No timeline, asset metadata reads, download URLs, or delete
- No video upload via API
Provision batch
POST …/upload-batches → open upload_batch_id
Init (+ PUT)
Init with that batch id, then PUT original + thumb (~20 min TTL). Or init-batch (≤25).
Complete sessions
Assets stay staged (staged: true).
Submit batch
POST …/upload-batches/{id}/complete publishes into the album.
Provision (or return) the open upload batch for the API key owner. Album uploads must use this batch id.
Path parameters
| Name | Type | Description |
|---|---|---|
| family_idreq | uuid | Family the API key belongs to. |
Body (JSON, optional)
| Name | Type | Description |
|---|---|---|
| upload_batch_idopt | uuid | null | Optional client-chosen batch id. Omit to let the server allocate one. |
Example
curl -sS -X POST https://api.ily.chat/v1/families/FAMILY_ID/upload-batches \
-H "Authorization: Bearer ily_fam_KEY" \
-H "Content-Type: application/json" \
-d '{}'
Response 200 · UploadBatch
{
"upload_batch_id": "BATCH_ID",
"status": "open",
"photo_count": 0
}
Response fields
| Name | Type | Description |
|---|---|---|
| upload_batch_id | uuid | Open batch id — pass to uploads/init. |
| status | string | open | completed | cancelled |
| photo_count | integer | Assets currently attached to the batch. |
Fetch batch status and counters.
Path parameters
| Name | Type | Description |
|---|---|---|
| family_idreq | uuid | Family id. |
| batch_idreq | uuid | Upload batch id. |
Example
curl -sS https://api.ily.chat/v1/families/FAMILY_ID/upload-batches/BATCH_ID \
-H "Authorization: Bearer ily_fam_KEY"
Response 200 · UploadBatch
{
"upload_batch_id": "BATCH_ID",
"status": "open",
"photo_count": 3
}
Start one image upload into the family album. Returns presigned PUT URLs for original + thumb, or
already_exists when the content hash is already present.
upload_batch_id is always required. Images only. Claims against the 100 GB/day API upload budget.
Path parameters
| Name | Type | Description |
|---|---|---|
| family_idreq | uuid | Family id. |
Body (JSON)
| Name | Type | Description |
|---|---|---|
| upload_batch_idreq | uuid | Open batch from POST …/upload-batches. |
| content_hashreq | string (≥32) | Hash of the original image bytes. |
| file_size_bytesreq | int64 | Original file size in bytes (≥ 1). |
| width_pxreq | integer | Pixel width. |
| height_pxreq | integer | Pixel height. |
| mime_typereq | string | Must be image/*, e.g. image/jpeg. |
| idempotency_keyreq | string | Client key to safely retry the same init. |
| taken_atopt | date-time | null | Capture time from EXIF when known. |
| thumb_content_typeopt | string | null | Thumb MIME if different from original. |
Example · init
curl -sS -X POST https://api.ily.chat/v1/families/FAMILY_ID/uploads/init \
-H "Authorization: Bearer ily_fam_KEY" \
-H "Content-Type: application/json" \
-d '{
"upload_batch_id": "BATCH_ID",
"content_hash": "a1b2c3d4e5f6789012345678901234567890abcd",
"file_size_bytes": 2457600,
"width_px": 4032,
"height_px": 3024,
"mime_type": "image/jpeg",
"idempotency_key": "upload-001",
"taken_at": "2026-03-12T09:15:00Z"
}'
Response 200 · ready
{
"status": "ready",
"upload_session_id": "SESSION_ID",
"original_put_url": "https://…presigned…",
"thumb_put_url": "https://…presigned…",
"expires_in": 1200
}
Response 200 · already_exists
{
"status": "already_exists",
"asset_id": "ASSET_ID"
}
Example · PUT bytes (~20 min TTL)
curl -sS -X PUT "$ORIGINAL_PUT_URL" \
-H "Content-Type: image/jpeg" \
--data-binary @photo.jpg
curl -sS -X PUT "$THUMB_PUT_URL" \
-H "Content-Type: image/jpeg" \
--data-binary @photo-thumb.jpg
Initialize up to 25 images into one open batch. Each item uses the same fields as uploads/init.
Path parameters
| Name | Type | Description |
|---|---|---|
| family_idreq | uuid | Family id. |
Body (JSON)
| Name | Type | Description |
|---|---|---|
| upload_batch_idreq | uuid | Open batch from POST …/upload-batches. |
| itemsreq | InitUploadRequest[] | 1–25 items. Same fields as single init (hash, size, dims, mime, idempotency_key, …). |
Example
curl -sS -X POST https://api.ily.chat/v1/families/FAMILY_ID/uploads/init-batch \
-H "Authorization: Bearer ily_fam_KEY" \
-H "Content-Type: application/json" \
-d '{
"upload_batch_id": "BATCH_ID",
"items": [
{
"content_hash": "a1b2c3d4e5f6789012345678901234567890abcd",
"file_size_bytes": 2457600,
"width_px": 4032,
"height_px": 3024,
"mime_type": "image/jpeg",
"idempotency_key": "upload-001"
},
{
"content_hash": "b2c3d4e5f6789012345678901234567890abcdef",
"file_size_bytes": 1884160,
"width_px": 3024,
"height_px": 4032,
"mime_type": "image/jpeg",
"idempotency_key": "upload-002"
}
]
}'
Response 200
{
"results": [
{
"idempotency_key": "upload-001",
"result": { /* InitUploadResponse */ },
"error": null
}
]
}
Finalize an upload session after PUTs succeed. The asset stays unpublished until you submit the batch.
Path parameters
| Name | Type | Description |
|---|---|---|
| family_idreq | uuid | Family id. |
Body (JSON)
| Name | Type | Description |
|---|---|---|
| upload_session_idreq | uuid | From init status: ready. |
| thumb_size_bytesopt | int64 | null | Thumb size if known. |
Example
curl -sS -X POST https://api.ily.chat/v1/families/FAMILY_ID/uploads/complete \
-H "Authorization: Bearer ily_fam_KEY" \
-H "Content-Type: application/json" \
-d '{
"upload_session_id": "SESSION_ID",
"thumb_size_bytes": 48210
}'
Response 200
{
"asset_id": "ASSET_ID",
"upload_batch_id": "BATCH_ID"
}
Response fields
| Name | Type | Description |
|---|---|---|
| asset_id | uuid | Asset id (use later if attaching to chat). |
| upload_batch_id | uuid | Batch to submit when ready. |
Publish staged photos into the family album (same as completing a batch in the app).
Path parameters
| Name | Type | Description |
|---|---|---|
| family_idreq | uuid | Family id. |
| batch_idreq | uuid | Open batch to submit. |
Example
curl -sS -X POST https://api.ily.chat/v1/families/FAMILY_ID/upload-batches/BATCH_ID/complete \
-H "Authorization: Bearer ily_fam_KEY"
Response 200
{
"upload_batch_id": "BATCH_ID",
"published": 3
}
Cancel an open batch and soft-delete its staged assets.
Path parameters
| Name | Type | Description |
|---|---|---|
| family_idreq | uuid | Family id. |
| batch_idreq | uuid | Open batch to cancel. |
Example
curl -sS -X POST https://api.ily.chat/v1/families/FAMILY_ID/upload-batches/BATCH_ID/cancel \
-H "Authorization: Bearer ily_fam_KEY"
Response 200
{
"upload_batch_id": "BATCH_ID",
"status": "cancelled"
}
Calendar
Events
Full read/write. API-created events keep source = api; the admin can still edit them in the app.
List calendar events in a date range.
Path parameters
| Name | Type | Description |
|---|---|---|
| family_idreq | uuid | Family id. |
Query parameters
| Name | Type | Description |
|---|---|---|
| fromreq | string | Range start — RFC3339 or YYYY-MM-DD. |
| toreq | string | Range end — RFC3339 or YYYY-MM-DD. |
Example
curl -sS "https://api.ily.chat/v1/families/FAMILY_ID/events?from=2026-03-01&to=2026-03-31" \
-H "Authorization: Bearer ily_fam_KEY"
Response 200 · Event[]
[
{
"id": "EVENT_ID",
"title": "Soccer practice",
"event_type": "activity",
"starts_at": "2026-03-12T00:00:00Z",
"ends_at": null,
"all_day": true,
"notes": "Bring water bottle",
"recurrence_freq": null,
"recurrence_interval": 1,
"child_ids": [],
"attendee_user_ids": [],
"source": "api"
}
]
Create a calendar event. Response includes source: "api".
Path parameters
| Name | Type | Description |
|---|---|---|
| family_idreq | uuid | Family id. |
Body (JSON · EventWrite)
| Name | Type | Description |
|---|---|---|
| titlereq | string | Event title. |
| event_typereq | string | Event type key or id (see event-types). |
| starts_atreq | string | RFC3339 or YYYY-MM-DD. |
| ends_atopt | string | null | End time / date when applicable. |
| all_dayopt | boolean | Default true. |
| notesopt | string | null | Free-text notes. |
| child_idsopt | uuid[] | Related children. |
| attendee_user_idsopt | uuid[] | Attending members. |
| recurrence_freqopt | string | null | Recurrence frequency when repeating. |
| recurrence_intervalopt | integer | Default 1. |
| recurrence_by_weekdayopt | integer[] | null | Weekday mask when used. |
| recurrence_untilopt | string | null | Recurrence end bound. |
| recurrence_countopt | integer | null | Occurrence count limit. |
Example
curl -sS -X POST https://api.ily.chat/v1/families/FAMILY_ID/events \
-H "Authorization: Bearer ily_fam_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Soccer practice",
"event_type": "activity",
"starts_at": "2026-03-12",
"all_day": true,
"notes": "Bring water bottle"
}'
Response 200 · Event
{
"id": "EVENT_ID",
"title": "Soccer practice",
"event_type": "activity",
"starts_at": "2026-03-12T00:00:00Z",
"ends_at": null,
"all_day": true,
"notes": "Bring water bottle",
"recurrence_interval": 1,
"child_ids": [],
"attendee_user_ids": [],
"source": "api"
}
Fetch a single calendar event.
Path parameters
| Name | Type | Description |
|---|---|---|
| family_idreq | uuid | Family id. |
| event_idreq | uuid | Event id. |
Example
curl -sS https://api.ily.chat/v1/families/FAMILY_ID/events/EVENT_ID \
-H "Authorization: Bearer ily_fam_KEY"
Response 200 · Event
{
"id": "EVENT_ID",
"title": "Soccer practice",
"event_type": "activity",
"starts_at": "2026-03-12T00:00:00Z",
"all_day": true,
"source": "api"
}
Update a calendar event. Preserves source: "api" when the event originated from the API. Body uses the same EventWrite fields as create.
Path parameters
| Name | Type | Description |
|---|---|---|
| family_idreq | uuid | Family id. |
| event_idreq | uuid | Event id. |
Example
curl -sS -X PUT https://api.ily.chat/v1/families/FAMILY_ID/events/EVENT_ID \
-H "Authorization: Bearer ily_fam_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Soccer practice (rescheduled)",
"event_type": "activity",
"starts_at": "2026-03-13",
"all_day": true,
"notes": "Field B"
}'
Response 200 · Event
{
"id": "EVENT_ID",
"title": "Soccer practice (rescheduled)",
"starts_at": "2026-03-13T00:00:00Z",
"source": "api"
}
Delete a calendar event. Returns an empty body.
Path parameters
| Name | Type | Description |
|---|---|---|
| family_idreq | uuid | Family id. |
| event_idreq | uuid | Event id. |
Example
curl -sS -X DELETE https://api.ily.chat/v1/families/FAMILY_ID/events/EVENT_ID \
-H "Authorization: Bearer ily_fam_KEY" \
-w "\n%{http_code}\n"
Response 204 No Content
HTTP/1.1 204 No Content
List calendar event types (system + family custom).
Path parameters
| Name | Type | Description |
|---|---|---|
| family_idreq | uuid | Family id. |
Example
curl -sS https://api.ily.chat/v1/families/FAMILY_ID/calendar/event-types \
-H "Authorization: Bearer ily_fam_KEY"
Response 200 · EventType[]
[
{
"key": "activity",
"label": "Activity",
"color": "#1a5fc4",
"sort_order": 10
}
]
Response fields
| Name | Type | Description |
|---|---|---|
| key | string | Stable key used in event_type. |
| label | string | Display label. |
| color | string | UI color. |
| sort_order | integer | Ordering hint. |
Chat
Channels & messages
Membership-scoped. Private channels that exclude the admin stay hidden. Posted messages use source = api / sender API.
List chat channels the family admin can access.
Path parameters
| Name | Type | Description |
|---|---|---|
| family_idreq | uuid | Family id. |
Example
curl -sS https://api.ily.chat/v1/families/FAMILY_ID/channels \
-H "Authorization: Bearer ily_fam_KEY"
Response 200 · Channel[]
[
{
"id": "CHANNEL_ID",
"name": "Family",
"is_default": true,
"color": null
}
]
Get one channel the admin is a member of.
Path parameters
| Name | Type | Description |
|---|---|---|
| channel_idreq | uuid | Channel id. |
Example
curl -sS https://api.ily.chat/v1/channels/CHANNEL_ID \
-H "Authorization: Bearer ily_fam_KEY"
Response 200 · Channel
{
"id": "CHANNEL_ID",
"name": "Family",
"is_default": true
}
List messages in a channel. Attached assets are metadata only (no image bytes).
Path parameters
| Name | Type | Description |
|---|---|---|
| channel_idreq | uuid | Channel id. |
Query parameters
| Name | Type | Description |
|---|---|---|
| limitopt | integer | Page size 1–100 (default 50). |
| beforeopt | string | Cursor (message id / opaque before token) for older pages. |
Example
curl -sS "https://api.ily.chat/v1/channels/CHANNEL_ID/messages?limit=50" \
-H "Authorization: Bearer ily_fam_KEY"
Response 200 · Message[]
[
{
"id": "MESSAGE_ID",
"source": "api",
"author_display_name": "API",
"body": "Practice moved to 4pm",
"created_at": "2026-03-12T16:00:00Z",
"deleted": false
}
]
Send a message. Attributed as API (source: "api"). Provide body and/or asset_id.
Path parameters
| Name | Type | Description |
|---|---|---|
| channel_idreq | uuid | Channel id. |
Body (JSON)
| Name | Type | Description |
|---|---|---|
| bodyopt | string | Message text (default empty). Required if no asset. |
| asset_idopt | uuid | null | Attach a previously uploaded image (metadata in reads). |
| reply_to_message_idopt | uuid | null | Reply target. |
Example
curl -sS -X POST https://api.ily.chat/v1/channels/CHANNEL_ID/messages \
-H "Authorization: Bearer ily_fam_KEY" \
-H "Content-Type: application/json" \
-d '{"body":"Practice moved to 4pm"}'
Response 200 · Message
{
"id": "MESSAGE_ID",
"source": "api",
"author_display_name": "API",
"body": "Practice moved to 4pm",
"created_at": "2026-03-12T16:00:00Z",
"deleted": false
}
Fetch a single message.
Path parameters
| Name | Type | Description |
|---|---|---|
| channel_idreq | uuid | Channel id. |
| message_idreq | uuid | Message id. |
Example
curl -sS https://api.ily.chat/v1/channels/CHANNEL_ID/messages/MESSAGE_ID \
-H "Authorization: Bearer ily_fam_KEY"
Response 200 · Message
{
"id": "MESSAGE_ID",
"source": "api",
"author_display_name": "API",
"body": "Practice moved to 4pm",
"created_at": "2026-03-12T16:00:00Z",
"deleted": false
}
Errors
Error codes
Errors return JSON with error (human message) and
code (stable machine code).
| Code | HTTP | When |
|---|---|---|
| premium_max_required | 402 | Not on Premium Max / Max lapsed |
| invalid_api_key | 401 | Missing or unknown key |
| api_key_revoked | 401 | Key revoked |
| api_key_suspended | 403 | Key suspended |
| forbidden | 403 | Not allowed / membership |
| locked | 403 | Family locked |
| not_found | 404 | Unknown resource |
| bad_request | 400 | Validation error |
| plan_limit | 402 | Storage / plan quota |
| rate_limited | 429 | Request / upload budget |
| conflict | 409 | Conflicting state |
| internal | 500 | Unexpected server error |
Example error body
{
"error": "Premium Max is required for the Family Admin API",
"code": "premium_max_required"
}