{"openapi":"3.1.0","info":{"title":"Welile ID API","version":"1.0.0","description":"REST API for the Welile ID Android and iOS apps. Sign in with /auth/google or /auth/apple, then send `Authorization: Bearer <access_token>`. Errors: { error: { code, message } }."},"servers":[{"url":"https://welileid.com/api/v1"}],"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}}},"paths":{"/health":{"get":{"tags":["System"],"summary":"Check the API is up.","parameters":[],"responses":{"200":{"description":"OK"},"401":{"description":"Missing or expired token"}}}},"/auth/google":{"post":{"tags":["Authentication"],"summary":"Exchange a native Google Sign-In ID token for a Welile session.","parameters":[],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"id_token":{"description":"string, required — from Google Sign-In SDK"},"nonce":{"description":"string, optional — raw nonce if you hashed one into the request"},"access_token":{"description":"string, optional"}}}}}},"responses":{"200":{"description":"OK"},"401":{"description":"Missing or expired token"}}}},"/auth/apple":{"post":{"tags":["Authentication"],"summary":"Exchange a native Sign in with Apple identity token for a Welile session.","parameters":[],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"id_token":{"description":"string, required — identityToken from ASAuthorization"},"nonce":{"description":"string, recommended — the raw (unhashed) nonce"}}}}}},"responses":{"200":{"description":"OK"},"401":{"description":"Missing or expired token"}}}},"/auth/refresh":{"post":{"tags":["Authentication"],"summary":"Get a new access token before the old one expires (~1 hour).","parameters":[],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"refresh_token":{"description":"string, required"}}}}}},"responses":{"200":{"description":"OK"},"401":{"description":"Missing or expired token"}}}},"/auth/sign-out":{"post":{"tags":["Authentication"],"summary":"End this device's session.","security":[{"bearer":[]}],"parameters":[],"responses":{"200":{"description":"OK"},"401":{"description":"Missing or expired token"}}}},"/me":{"get":{"tags":["Account"],"summary":"Signed-in user, roles and whether they have created their Welile ID.","security":[{"bearer":[]}],"parameters":[],"responses":{"200":{"description":"OK"},"401":{"description":"Missing or expired token"}}},"delete":{"tags":["Account"],"summary":"Permanently delete the account, household and photos.","security":[{"bearer":[]}],"parameters":[],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"confirmation":{"description":"\"DELETE\""}}}}}},"responses":{"200":{"description":"OK"},"401":{"description":"Missing or expired token"}}}},"/uploads":{"post":{"tags":["Photos"],"summary":"Get a one-time upload URL for a photo. PUT the compressed JPEG to it, then save `path` on the profile.","security":[{"bearer":[]}],"parameters":[],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"description":"id_photo | selfie | household_logo"}}}}}},"responses":{"200":{"description":"OK"},"401":{"description":"Missing or expired token"}}}},"/profile":{"get":{"tags":["Profile"],"summary":"Your Welile ID, with 1-hour viewable photo links.","security":[{"bearer":[]}],"parameters":[],"responses":{"200":{"description":"OK"},"401":{"description":"Missing or expired token"}}},"post":{"tags":["Profile"],"summary":"Create your Welile ID (Anchor).","security":[{"bearer":[]}],"parameters":[],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"full_name":{"description":"string, required"},"phone":{"description":"07… or +256…, required"},"id_photo_path":{"description":"path from /uploads, required"},"selfie_path":{"description":"path from /uploads, required"},"birth_date":{"description":"YYYY-MM-DD, optional"},"id_expiry":{"description":"YYYY-MM-DD, optional"}}}}}},"responses":{"200":{"description":"OK"},"401":{"description":"Missing or expired token"}}},"patch":{"tags":["Profile"],"summary":"Update profile and household settings. Send only fields that change.","security":[{"bearer":[]}],"parameters":[],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"full_name":{"description":"string"},"phone":{"description":"string"},"id_photo_path":{"description":"string"},"selfie_path":{"description":"string"},"household_name":{"description":"string | null"},"household_logo_path":{"description":"string | null"},"whatsapp_group_link":{"description":"https://chat.whatsapp.com/… | null"},"birth_date":{"description":"YYYY-MM-DD | null"},"id_expiry":{"description":"YYYY-MM-DD | null"}}}}}},"responses":{"200":{"description":"OK"},"401":{"description":"Missing or expired token"}}}},"/members":{"get":{"tags":["Family members"],"summary":"List everyone under your ID, with search and filters.","security":[{"bearer":[]}],"parameters":[{"name":"q","in":"query","description":"name or phone digits","schema":{"type":"string"}},{"name":"filter","in":"query","description":"all | has_id | no_id | no_smartphone","schema":{"type":"string"}},{"name":"type","in":"query","description":"dependent | provider","schema":{"type":"string"}}],"responses":{"200":{"description":"OK"},"401":{"description":"Missing or expired token"}}},"post":{"tags":["Family members"],"summary":"Add a family member directly (no invite).","security":[{"bearer":[]}],"parameters":[],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"full_name":{"description":"string, required"},"phone":{"description":"string, required"},"parent_id":{"description":"member id they sit under, optional"},"is_provider":{"description":"boolean — true = 'I depend on them'"},"has_smartphone":{"description":"boolean"},"birth_date":{"description":"YYYY-MM-DD"},"id_expiry":{"description":"YYYY-MM-DD"}}}}}},"responses":{"200":{"description":"OK"},"401":{"description":"Missing or expired token"}}}},"/members/{id}":{"get":{"tags":["Family members"],"summary":"One member.","security":[{"bearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK"},"401":{"description":"Missing or expired token"}}},"patch":{"tags":["Family members"],"summary":"Edit a member.","security":[{"bearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"full_name":{"description":"string"},"phone":{"description":"string"},"parent_id":{"description":"string | null"},"is_provider":{"description":"boolean"},"has_smartphone":{"description":"boolean | null"},"birth_date":{"description":"YYYY-MM-DD | null"},"id_expiry":{"description":"YYYY-MM-DD | null"}}}}}},"responses":{"200":{"description":"OK"},"401":{"description":"Missing or expired token"}}},"delete":{"tags":["Family members"],"summary":"Remove a member.","security":[{"bearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK"},"401":{"description":"Missing or expired token"}}}},"/members/linked-photos":{"get":{"tags":["Family members"],"summary":"Selfies and ID status of members who joined with their own login, keyed by member id.","security":[{"bearer":[]}],"parameters":[],"responses":{"200":{"description":"OK"},"401":{"description":"Missing or expired token"}}}},"/family":{"get":{"tags":["Family members"],"summary":"Nested family tree plus dashboard stats (totals, expiring IDs).","security":[{"bearer":[]}],"parameters":[],"responses":{"200":{"description":"OK"},"401":{"description":"Missing or expired token"}}}},"/memberships":{"get":{"tags":["Family members"],"summary":"Households you have joined through an invite.","security":[{"bearer":[]}],"parameters":[],"responses":{"200":{"description":"OK"},"401":{"description":"Missing or expired token"}}}},"/invites":{"get":{"tags":["Invites"],"summary":"Pending invites you sent, with share links.","security":[{"bearer":[]}],"parameters":[],"responses":{"200":{"description":"OK"},"401":{"description":"Missing or expired token"}}},"post":{"tags":["Invites"],"summary":"Create an invite. Returns the link and a ready WhatsApp share URL.","security":[{"bearer":[]}],"parameters":[],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"full_name":{"description":"string, required"},"phone":{"description":"string, required"},"parent_id":{"description":"string, optional"},"is_provider":{"description":"boolean"},"has_smartphone":{"description":"boolean"}}}}}},"responses":{"200":{"description":"OK"},"401":{"description":"Missing or expired token"}}}},"/invites/{id}":{"delete":{"tags":["Invites"],"summary":"Cancel an invite.","security":[{"bearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK"},"401":{"description":"Missing or expired token"}}}},"/join/{token}":{"get":{"tags":["Invites"],"summary":"Preview an invite before signing in.","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK"},"401":{"description":"Missing or expired token"}}}},"/join/{token}/accept":{"post":{"tags":["Invites"],"summary":"Accept an invite as the signed-in user.","security":[{"bearer":[]}],"parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK"},"401":{"description":"Missing or expired token"}}}},"/whatsapp/contacts":{"get":{"tags":["WhatsApp"],"summary":"Household contacts with wa.me links and the saved group link. Add ?format=vcf for a contacts file.","security":[{"bearer":[]}],"parameters":[{"name":"format","in":"query","description":"json | vcf","schema":{"type":"string"}}],"responses":{"200":{"description":"OK"},"401":{"description":"Missing or expired token"}}}},"/ads/active":{"get":{"tags":["Ads"],"summary":"The current advert for the welcome screen.","parameters":[],"responses":{"200":{"description":"OK"},"401":{"description":"Missing or expired token"}}}},"/admin/ads":{"get":{"tags":["Admin"],"summary":"All adverts.","security":[{"bearer":[]}],"parameters":[],"responses":{"200":{"description":"OK"},"401":{"description":"Missing or expired token"}}},"post":{"tags":["Admin"],"summary":"Create an advert.","security":[{"bearer":[]}],"parameters":[],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"description":"string, required"},"image_path":{"description":"from /admin/ads/uploads"},"link_url":{"description":"string"},"is_active":{"description":"boolean"}}}}}},"responses":{"200":{"description":"OK"},"401":{"description":"Missing or expired token"}}}},"/admin/ads/uploads":{"post":{"tags":["Admin"],"summary":"One-time upload URL for an advert image.","security":[{"bearer":[]}],"parameters":[],"responses":{"200":{"description":"OK"},"401":{"description":"Missing or expired token"}}}},"/admin/ads/{id}":{"patch":{"tags":["Admin"],"summary":"Edit or switch an advert on/off.","security":[{"bearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"description":"string"},"link_url":{"description":"string | null"},"is_active":{"description":"boolean"}}}}}},"responses":{"200":{"description":"OK"},"401":{"description":"Missing or expired token"}}},"delete":{"tags":["Admin"],"summary":"Delete an advert and its image.","security":[{"bearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK"},"401":{"description":"Missing or expired token"}}}},"/admin/staff":{"get":{"tags":["Admin"],"summary":"Everyone holding a staff role.","security":[{"bearer":[]}],"parameters":[],"responses":{"200":{"description":"OK"},"401":{"description":"Missing or expired token"}}},"post":{"tags":["Admin"],"summary":"Make an existing account an ad manager.","security":[{"bearer":[]}],"parameters":[],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"description":"string, required"}}}}}},"responses":{"200":{"description":"OK"},"401":{"description":"Missing or expired token"}}}},"/admin/staff/{userId}":{"delete":{"tags":["Admin"],"summary":"Remove the ad manager role.","security":[{"bearer":[]}],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK"},"401":{"description":"Missing or expired token"}}}}}}