Skip to content
ILY
ILY

Family Admin API

Automate album uploads, calendar, and chat with one Premium Max admin key — same privacy boundaries as the family admin in the ILY app.

Overview

Built for family life

Photo Album, Calendar, and Chat under one admin key on Premium Max (2,100 GB). Base URL:

http
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

NameTypeDescription
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.

http
Authorization: Bearer ily_fam_KEY

Alternative:

http
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

bash
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.

POST /families/{family_id}/upload-batches

Provision (or return) the open upload batch for the API key owner. Album uploads must use this batch id.

Path parameters

NameTypeDescription
family_idreq uuid Family the API key belongs to.

Body (JSON, optional)

NameTypeDescription
upload_batch_idopt uuid | null Optional client-chosen batch id. Omit to let the server allocate one.

Example

bash
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

json
{
  "upload_batch_id": "BATCH_ID",
  "status": "open",
  "photo_count": 0
}

Response fields

NameTypeDescription
upload_batch_iduuidOpen batch id — pass to uploads/init.
statusstringopen | completed | cancelled
photo_countintegerAssets currently attached to the batch.
GET /families/{family_id}/upload-batches/{batch_id}

Fetch batch status and counters.

Path parameters

NameTypeDescription
family_idrequuidFamily id.
batch_idrequuidUpload batch id.

Example

bash
curl -sS https://api.ily.chat/v1/families/FAMILY_ID/upload-batches/BATCH_ID \
  -H "Authorization: Bearer ily_fam_KEY"

Response 200 · UploadBatch

json
{
  "upload_batch_id": "BATCH_ID",
  "status": "open",
  "photo_count": 3
}
POST /families/{family_id}/uploads/init

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

NameTypeDescription
family_idrequuidFamily id.

Body (JSON)

NameTypeDescription
upload_batch_idrequuidOpen batch from POST …/upload-batches.
content_hashreqstring (≥32)Hash of the original image bytes.
file_size_bytesreqint64Original file size in bytes (≥ 1).
width_pxreqintegerPixel width.
height_pxreqintegerPixel height.
mime_typereqstringMust be image/*, e.g. image/jpeg.
idempotency_keyreqstringClient key to safely retry the same init.
taken_atoptdate-time | nullCapture time from EXIF when known.
thumb_content_typeoptstring | nullThumb MIME if different from original.

Example · init

bash
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

json
{
  "status": "ready",
  "upload_session_id": "SESSION_ID",
  "original_put_url": "https://…presigned…",
  "thumb_put_url": "https://…presigned…",
  "expires_in": 1200
}

Response 200 · already_exists

json
{
  "status": "already_exists",
  "asset_id": "ASSET_ID"
}

Example · PUT bytes (~20 min TTL)

bash
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
POST /families/{family_id}/uploads/init-batch

Initialize up to 25 images into one open batch. Each item uses the same fields as uploads/init.

Path parameters

NameTypeDescription
family_idrequuidFamily id.

Body (JSON)

NameTypeDescription
upload_batch_idrequuidOpen batch from POST …/upload-batches.
itemsreqInitUploadRequest[]1–25 items. Same fields as single init (hash, size, dims, mime, idempotency_key, …).

Example

bash
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

json
{
  "results": [
    {
      "idempotency_key": "upload-001",
      "result": { /* InitUploadResponse */ },
      "error": null
    }
  ]
}
POST /families/{family_id}/uploads/complete

Finalize an upload session after PUTs succeed. The asset stays unpublished until you submit the batch.

Path parameters

NameTypeDescription
family_idrequuidFamily id.

Body (JSON)

NameTypeDescription
upload_session_idrequuidFrom init status: ready.
thumb_size_bytesoptint64 | nullThumb size if known.

Example

bash
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

json
{
  "asset_id": "ASSET_ID",
  "upload_batch_id": "BATCH_ID"
}

Response fields

NameTypeDescription
asset_iduuidAsset id (use later if attaching to chat).
upload_batch_iduuidBatch to submit when ready.
POST /families/{family_id}/upload-batches/{batch_id}/complete

Publish staged photos into the family album (same as completing a batch in the app).

Path parameters

NameTypeDescription
family_idrequuidFamily id.
batch_idrequuidOpen batch to submit.

Example

bash
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

json
{
  "upload_batch_id": "BATCH_ID",
  "published": 3
}
POST /families/{family_id}/upload-batches/{batch_id}/cancel

Cancel an open batch and soft-delete its staged assets.

Path parameters

NameTypeDescription
family_idrequuidFamily id.
batch_idrequuidOpen batch to cancel.

Example

bash
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

json
{
  "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.

GET /families/{family_id}/events

List calendar events in a date range.

Path parameters

NameTypeDescription
family_idrequuidFamily id.

Query parameters

NameTypeDescription
fromreqstringRange start — RFC3339 or YYYY-MM-DD.
toreqstringRange end — RFC3339 or YYYY-MM-DD.

Example

bash
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[]

json
[
  {
    "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"
  }
]
POST /families/{family_id}/events

Create a calendar event. Response includes source: "api".

Path parameters

NameTypeDescription
family_idrequuidFamily id.

Body (JSON · EventWrite)

NameTypeDescription
titlereqstringEvent title.
event_typereqstringEvent type key or id (see event-types).
starts_atreqstringRFC3339 or YYYY-MM-DD.
ends_atoptstring | nullEnd time / date when applicable.
all_dayoptbooleanDefault true.
notesoptstring | nullFree-text notes.
child_idsoptuuid[]Related children.
attendee_user_idsoptuuid[]Attending members.
recurrence_freqoptstring | nullRecurrence frequency when repeating.
recurrence_intervaloptintegerDefault 1.
recurrence_by_weekdayoptinteger[] | nullWeekday mask when used.
recurrence_untiloptstring | nullRecurrence end bound.
recurrence_countoptinteger | nullOccurrence count limit.

Example

bash
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

json
{
  "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"
}
GET /families/{family_id}/events/{event_id}

Fetch a single calendar event.

Path parameters

NameTypeDescription
family_idrequuidFamily id.
event_idrequuidEvent id.

Example

bash
curl -sS https://api.ily.chat/v1/families/FAMILY_ID/events/EVENT_ID \
  -H "Authorization: Bearer ily_fam_KEY"

Response 200 · Event

json
{
  "id": "EVENT_ID",
  "title": "Soccer practice",
  "event_type": "activity",
  "starts_at": "2026-03-12T00:00:00Z",
  "all_day": true,
  "source": "api"
}
PUT /families/{family_id}/events/{event_id}

Update a calendar event. Preserves source: "api" when the event originated from the API. Body uses the same EventWrite fields as create.

Path parameters

NameTypeDescription
family_idrequuidFamily id.
event_idrequuidEvent id.

Example

bash
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

json
{
  "id": "EVENT_ID",
  "title": "Soccer practice (rescheduled)",
  "starts_at": "2026-03-13T00:00:00Z",
  "source": "api"
}
DELETE /families/{family_id}/events/{event_id}

Delete a calendar event. Returns an empty body.

Path parameters

NameTypeDescription
family_idrequuidFamily id.
event_idrequuidEvent id.

Example

bash
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
HTTP/1.1 204 No Content
GET /families/{family_id}/calendar/event-types

List calendar event types (system + family custom).

Path parameters

NameTypeDescription
family_idrequuidFamily id.

Example

bash
curl -sS https://api.ily.chat/v1/families/FAMILY_ID/calendar/event-types \
  -H "Authorization: Bearer ily_fam_KEY"

Response 200 · EventType[]

json
[
  {
    "key": "activity",
    "label": "Activity",
    "color": "#1a5fc4",
    "sort_order": 10
  }
]

Response fields

NameTypeDescription
keystringStable key used in event_type.
labelstringDisplay label.
colorstringUI color.
sort_orderintegerOrdering hint.

Chat

Channels & messages

Membership-scoped. Private channels that exclude the admin stay hidden. Posted messages use source = api / sender API.

GET /families/{family_id}/channels

List chat channels the family admin can access.

Path parameters

NameTypeDescription
family_idrequuidFamily id.

Example

bash
curl -sS https://api.ily.chat/v1/families/FAMILY_ID/channels \
  -H "Authorization: Bearer ily_fam_KEY"

Response 200 · Channel[]

json
[
  {
    "id": "CHANNEL_ID",
    "name": "Family",
    "is_default": true,
    "color": null
  }
]
GET /channels/{channel_id}

Get one channel the admin is a member of.

Path parameters

NameTypeDescription
channel_idrequuidChannel id.

Example

bash
curl -sS https://api.ily.chat/v1/channels/CHANNEL_ID \
  -H "Authorization: Bearer ily_fam_KEY"

Response 200 · Channel

json
{
  "id": "CHANNEL_ID",
  "name": "Family",
  "is_default": true
}
GET /channels/{channel_id}/messages

List messages in a channel. Attached assets are metadata only (no image bytes).

Path parameters

NameTypeDescription
channel_idrequuidChannel id.

Query parameters

NameTypeDescription
limitoptintegerPage size 1–100 (default 50).
beforeoptstringCursor (message id / opaque before token) for older pages.

Example

bash
curl -sS "https://api.ily.chat/v1/channels/CHANNEL_ID/messages?limit=50" \
  -H "Authorization: Bearer ily_fam_KEY"

Response 200 · Message[]

json
[
  {
    "id": "MESSAGE_ID",
    "source": "api",
    "author_display_name": "API",
    "body": "Practice moved to 4pm",
    "created_at": "2026-03-12T16:00:00Z",
    "deleted": false
  }
]
POST /channels/{channel_id}/messages

Send a message. Attributed as API (source: "api"). Provide body and/or asset_id.

Path parameters

NameTypeDescription
channel_idrequuidChannel id.

Body (JSON)

NameTypeDescription
bodyoptstringMessage text (default empty). Required if no asset.
asset_idoptuuid | nullAttach a previously uploaded image (metadata in reads).
reply_to_message_idoptuuid | nullReply target.

Example

bash
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

json
{
  "id": "MESSAGE_ID",
  "source": "api",
  "author_display_name": "API",
  "body": "Practice moved to 4pm",
  "created_at": "2026-03-12T16:00:00Z",
  "deleted": false
}
GET /channels/{channel_id}/messages/{message_id}

Fetch a single message.

Path parameters

NameTypeDescription
channel_idrequuidChannel id.
message_idrequuidMessage id.

Example

bash
curl -sS https://api.ily.chat/v1/channels/CHANNEL_ID/messages/MESSAGE_ID \
  -H "Authorization: Bearer ily_fam_KEY"

Response 200 · Message

json
{
  "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_required402Not on Premium Max / Max lapsed
invalid_api_key401Missing or unknown key
api_key_revoked401Key revoked
api_key_suspended403Key suspended
forbidden403Not allowed / membership
locked403Family locked
not_found404Unknown resource
bad_request400Validation error
plan_limit402Storage / plan quota
rate_limited429Request / upload budget
conflict409Conflicting state
internal500Unexpected server error

Example error body

json
{
  "error": "Premium Max is required for the Family Admin API",
  "code": "premium_max_required"
}