{"openapi":"3.1.0","info":{"title":"Swifre API","description":"Swifre Axum API — auth, chats, translate, workspace, staff.","license":{"name":"UNLICENSED","identifier":"UNLICENSED"},"version":"0.1.0"},"paths":{"/":{"get":{"tags":["meta"],"summary":"API landing page with links to docs and probes.","operationId":"landing","responses":{"200":{"description":"HTML landing page","content":{"text/html":{}}}}},"post":{"tags":["meta"],"summary":"Cloud Build / uptime probes often `POST /` — return JSON so they don't 405.","operationId":"root_probe","responses":{"200":{"description":"OK probe"}}}},"/health":{"get":{"tags":["health"],"summary":"Liveness probe (unversioned).","operationId":"health","responses":{"200":{"description":"Service is up","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}}}}},"/v1/auth/login":{"post":{"tags":["auth"],"summary":"Request OTP for an existing account.","operationId":"login","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRequest"}}},"required":true},"responses":{"200":{"description":"OTP sent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtpChallengeResponse"}}}},"404":{"description":"Unknown phone"}}}},"/v1/auth/logout":{"post":{"tags":["auth"],"summary":"Revoke a refresh token.","operationId":"logout","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LogoutRequest"}}},"required":true},"responses":{"204":{"description":"Logged out"}}}},"/v1/auth/refresh":{"post":{"tags":["auth"],"summary":"Rotate refresh token.","operationId":"refresh","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshRequest"}}},"required":true},"responses":{"200":{"description":"New tokens","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthTokenResponse"}}}},"401":{"description":"Invalid refresh token"}}}},"/v1/auth/signup":{"post":{"tags":["auth"],"summary":"Register with phone + email + display name; sends OTP to email.","operationId":"signup","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignupRequest"}}},"required":true},"responses":{"200":{"description":"OTP sent to email","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtpChallengeResponse"}}}},"400":{"description":"Validation error"},"409":{"description":"Phone or email already registered"}}}},"/v1/auth/verify":{"post":{"tags":["auth"],"summary":"Verify OTP and receive access + refresh tokens.","operationId":"verify","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyRequest"}}},"required":true},"responses":{"200":{"description":"Tokens issued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthTokenResponse"}}}},"401":{"description":"Invalid OTP"}}}},"/v1/blocks":{"post":{"tags":["social"],"operationId":"block_user","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserIdBody"}}},"required":true},"responses":{"204":{"description":"Blocked"}},"security":[{"bearer_auth":[]}]}},"/v1/chats":{"get":{"tags":["chats"],"operationId":"list_chats","responses":{"200":{"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ChatResponse"}}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["chats"],"operationId":"create_chat","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateChatRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/v1/chats/{id}/messages":{"get":{"tags":["chats"],"operationId":"list_messages","parameters":[{"name":"id","in":"path","description":"Chat id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MessageResponse"}}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["chats"],"operationId":"send_message","parameters":[{"name":"id","in":"path","description":"Chat id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendMessageRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/v1/contacts":{"get":{"tags":["social"],"operationId":"list_contacts","responses":{"200":{"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SearchUserHit"}}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["social"],"operationId":"add_contact","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserIdBody"}}},"required":true},"responses":{"204":{"description":"Added"}},"security":[{"bearer_auth":[]}]}},"/v1/echo":{"post":{"tags":["debug"],"summary":"Echo a JSON body (scaffold / debugging).","operationId":"echo","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EchoBody"}}},"required":true},"responses":{"200":{"description":"Payload echoed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EchoBody"}}}}}}},"/v1/health":{"get":{"tags":["health"],"summary":"Liveness probe under the `/v1` API prefix.","operationId":"health_v1","responses":{"200":{"description":"Service is up","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}}}}},"/v1/me":{"get":{"tags":["me"],"operationId":"get_me","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["me"],"operationId":"patch_me","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMeRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeResponse"}}}},"401":{"description":"Unauthorized"},"409":{"description":"Conflict"}},"security":[{"bearer_auth":[]}]}},"/v1/messages/{id}/report":{"post":{"tags":["social"],"operationId":"report_message","parameters":[{"name":"id","in":"path","description":"Message id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportRequest"}}},"required":true},"responses":{"204":{"description":"Reported"}},"security":[{"bearer_auth":[]}]}},"/v1/search":{"get":{"tags":["social"],"operationId":"search","parameters":[{"name":"q","in":"query","description":"Search query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SearchUserHit"}}}}}},"security":[{"bearer_auth":[]}]}},"/v1/staff/flags":{"get":{"tags":["staff"],"operationId":"list_flags","responses":{"200":{"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/FlagResponse"}}}}}},"security":[{"bearer_auth":[]}]}},"/v1/staff/flags/{key}":{"put":{"tags":["staff"],"operationId":"upsert_flag","parameters":[{"name":"key","in":"path","description":"Flag key","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertFlagRequest"}}},"required":true},"responses":{"204":{"description":"Saved"}},"security":[{"bearer_auth":[]}]}},"/v1/staff/health":{"get":{"tags":["staff"],"operationId":"staff_health","responses":{"200":{"description":"OK"}},"security":[{"bearer_auth":[]}]}},"/v1/staff/moderation":{"get":{"tags":["staff"],"operationId":"list_moderation","responses":{"200":{"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ModerationCaseResponse"}}}}}},"security":[{"bearer_auth":[]}]}},"/v1/staff/users":{"get":{"tags":["staff"],"operationId":"list_users","responses":{"200":{"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/StaffUserRow"}}}}}},"security":[{"bearer_auth":[]}]}},"/v1/staff/users/{id}/status":{"post":{"tags":["staff"],"operationId":"set_status","parameters":[{"name":"id","in":"path","description":"User id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuspendRequest"}}},"required":true},"responses":{"204":{"description":"Updated"}},"security":[{"bearer_auth":[]}]}},"/v1/translate/packs":{"get":{"tags":["translate"],"operationId":"list_packs","responses":{"200":{"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OfflinePackResponse"}}}}}},"security":[{"bearer_auth":[]}]}},"/v1/translate/packs/downloaded":{"post":{"tags":["translate"],"operationId":"mark_downloaded","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DownloadPackRequest"}}},"required":true},"responses":{"204":{"description":"Recorded"}},"security":[{"bearer_auth":[]}]}},"/v1/translate/settings":{"get":{"tags":["translate"],"operationId":"get_settings","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TranslationSettingsResponse"}}}}},"security":[{"bearer_auth":[]}]},"patch":{"tags":["translate"],"operationId":"patch_settings","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTranslationSettingsRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TranslationSettingsResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/v1/workspace/orgs":{"get":{"tags":["workspace"],"operationId":"list_orgs","responses":{"200":{"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OrgResponse"}}}}}},"security":[{"bearer_auth":[]}]},"post":{"tags":["workspace"],"operationId":"create_org","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOrgRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/v1/workspace/orgs/{id}":{"get":{"tags":["workspace"],"operationId":"get_org","parameters":[{"name":"id","in":"path","description":"Org id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgResponse"}}}}},"security":[{"bearer_auth":[]}]}},"/v1/workspace/orgs/{id}/members":{"get":{"tags":["workspace"],"operationId":"list_members","parameters":[{"name":"id","in":"path","description":"Org id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OrgMemberResponse"}}}}}},"security":[{"bearer_auth":[]}]}}},"components":{"schemas":{"AuthTokenResponse":{"type":"object","required":["access_token","refresh_token","token_type","expires_in"],"properties":{"access_token":{"type":"string"},"expires_in":{"type":"integer","format":"int64"},"refresh_token":{"type":"string"},"token_type":{"type":"string"}}},"ChatResponse":{"type":"object","required":["id","kind","updated_at","unread"],"properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string"},"last_text":{"type":["string","null"]},"title":{"type":["string","null"]},"unread":{"type":"integer","format":"int64"},"updated_at":{"type":"string","format":"date-time"}}},"CreateChatRequest":{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","description":"`direct` or `group`"},"member_ids":{"type":["array","null"],"items":{"type":"string","format":"uuid"}},"peer_user_id":{"type":["string","null"],"format":"uuid","description":"Required for direct chats"},"title":{"type":["string","null"],"description":"Required for groups"}}},"CreateOrgRequest":{"type":"object","required":["name","slug"],"properties":{"name":{"type":"string"},"slug":{"type":"string"}}},"DownloadPackRequest":{"type":"object","required":["lang","version"],"properties":{"lang":{"type":"string"},"version":{"type":"string"}}},"EchoBody":{"type":"object","required":["payload"],"properties":{"payload":{"type":"object","description":"Free-form JSON value echoed back (scaffold endpoint)."}}},"FlagResponse":{"type":"object","required":["key","rollout_pct","enabled"],"properties":{"enabled":{"type":"boolean"},"key":{"type":"string"},"rollout_pct":{"type":"integer","format":"int32"}}},"HealthResponse":{"type":"object","required":["status","service"],"properties":{"service":{"type":"string","description":"Service identifier."},"status":{"type":"string","description":"Overall status (`ok` when the process is up)."}}},"LoginRequest":{"type":"object","required":["phone"],"properties":{"device_label":{"type":["string","null"]},"phone":{"type":"string"}}},"LogoutRequest":{"type":"object","required":["refresh_token"],"properties":{"refresh_token":{"type":"string"}}},"MeResponse":{"type":"object","required":["id","phone","email","display_name","primary_lang","speak_lang","read_lang","default_tone"],"properties":{"default_tone":{"type":"string"},"display_name":{"type":"string"},"email":{"type":"string"},"id":{"type":"string","format":"uuid"},"phone":{"type":"string"},"primary_lang":{"type":"string"},"read_lang":{"type":"string"},"speak_lang":{"type":"string"},"username":{"type":["string","null"]}}},"MessageResponse":{"type":"object","required":["id","chat_id","sender_id","source_text","source_lang","kind","created_at","translations"],"properties":{"chat_id":{"type":"string","format":"uuid"},"client_id":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"},"id":{"type":"string","format":"uuid"},"kind":{"type":"string"},"sender_id":{"type":"string","format":"uuid"},"source_lang":{"type":"string"},"source_text":{"type":"string"},"tone":{"type":["string","null"]},"translations":{"type":"array","items":{"$ref":"#/components/schemas/TranslationDto"}}}},"ModerationCaseResponse":{"type":"object","required":["id","case_type","status"],"properties":{"case_type":{"type":"string"},"id":{"type":"string","format":"uuid"},"message_id":{"type":["string","null"],"format":"uuid"},"notes":{"type":["string","null"]},"reported_user_id":{"type":["string","null"],"format":"uuid"},"status":{"type":"string"}}},"OfflinePackResponse":{"type":"object","required":["lang","version","url","checksum","size_bytes"],"properties":{"checksum":{"type":"string"},"lang":{"type":"string"},"size_bytes":{"type":"integer","format":"int64"},"url":{"type":"string"},"version":{"type":"string"}}},"OrgMemberResponse":{"type":"object","required":["user_id","role","status"],"properties":{"role":{"type":"string"},"status":{"type":"string"},"user_id":{"type":"string","format":"uuid"}}},"OrgResponse":{"type":"object","required":["id","name","slug","plan"],"properties":{"accent_color":{"type":["string","null"]},"id":{"type":"string","format":"uuid"},"logo_url":{"type":["string","null"]},"name":{"type":"string"},"plan":{"type":"string"},"slug":{"type":"string"}}},"OtpChallengeResponse":{"type":"object","required":["phone","email","message"],"properties":{"dev_otp":{"type":["string","null"],"description":"Present only when `AUTH_DEV_MODE=true` (local email OTP stand-in)."},"email":{"type":"string"},"message":{"type":"string"},"phone":{"type":"string"}}},"RefreshRequest":{"type":"object","required":["refresh_token"],"properties":{"device_label":{"type":["string","null"]},"refresh_token":{"type":"string"}}},"ReportRequest":{"type":"object","properties":{"notes":{"type":["string","null"]},"user_id":{"type":["string","null"],"format":"uuid"}}},"SearchUserHit":{"type":"object","required":["id","display_name","primary_lang"],"properties":{"display_name":{"type":"string"},"id":{"type":"string","format":"uuid"},"primary_lang":{"type":"string"},"username":{"type":["string","null"]}}},"SendMessageRequest":{"type":"object","required":["text"],"properties":{"client_id":{"type":["string","null"]},"source_lang":{"type":["string","null"]},"text":{"type":"string"},"tone":{"type":["string","null"]}}},"SignupRequest":{"type":"object","required":["phone","email","display_name"],"properties":{"device_label":{"type":["string","null"]},"display_name":{"type":"string"},"email":{"type":"string","description":"Required — OTP is delivered to this address"},"phone":{"type":"string","description":"E.164 phone, e.g. `+2348012345678`"}}},"StaffUserRow":{"type":"object","required":["id","phone","email","display_name"],"properties":{"display_name":{"type":"string"},"email":{"type":"string"},"id":{"type":"string","format":"uuid"},"phone":{"type":"string"}}},"SuspendRequest":{"type":"object","required":["status"],"properties":{"status":{"type":"string"}}},"TranslationDto":{"type":"object","required":["target_lang","status"],"properties":{"body":{"type":["string","null"]},"cultural_note":{"type":["string","null"]},"status":{"type":"string"},"target_lang":{"type":"string"}}},"TranslationSettingsResponse":{"type":"object","required":["auto_translate","show_original","offline_enabled"],"properties":{"auto_translate":{"type":"boolean"},"offline_enabled":{"type":"boolean"},"show_original":{"type":"boolean"}}},"UpdateMeRequest":{"type":"object","properties":{"default_tone":{"type":["string","null"]},"display_name":{"type":["string","null"]},"email":{"type":["string","null"]},"primary_lang":{"type":["string","null"]},"read_lang":{"type":["string","null"]},"speak_lang":{"type":["string","null"]},"username":{"type":["string","null"]}}},"UpdateTranslationSettingsRequest":{"type":"object","properties":{"auto_translate":{"type":["boolean","null"]},"offline_enabled":{"type":["boolean","null"]},"show_original":{"type":["boolean","null"]}}},"UpsertFlagRequest":{"type":"object","required":["enabled","rollout_pct"],"properties":{"enabled":{"type":"boolean"},"rollout_pct":{"type":"integer","format":"int32"}}},"UserIdBody":{"type":"object","required":["user_id"],"properties":{"user_id":{"type":"string","format":"uuid"}}},"VerifyRequest":{"type":"object","required":["phone","otp"],"properties":{"device_label":{"type":["string","null"]},"otp":{"type":"string"},"phone":{"type":"string"}}}},"securitySchemes":{"bearer_auth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Access token from `/v1/auth/verify`"}}},"tags":[{"name":"meta","description":"Landing / discovery"},{"name":"health","description":"Liveness probes"},{"name":"auth","description":"Phone + email OTP auth"},{"name":"me","description":"Profile"},{"name":"chats","description":"Conversations and messages"},{"name":"translate","description":"Translation prefs and offline packs"},{"name":"social","description":"Search and reports"},{"name":"workspace","description":"Org admin APIs"},{"name":"staff","description":"Platform ops APIs"},{"name":"debug","description":"Scaffold helpers"}]}