{"openapi":"3.1.0","info":{"title":"Tamloot Public API","version":"1.0.0","description":"Read-only relationship intelligence data for a Tamloot account."},"servers":[{"url":"https://api.tamloot.cc/v1"}],"components":{"securitySchemes":{"TamlootApiKey":{"type":"http","scheme":"bearer","bearerFormat":"Tamloot API key"}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","description":"HTTP status code as a string, e.g. \"404\""},"message":{"type":"string"}}}}},"Pagination":{"type":"object","required":["limit","offset","has_more","next_offset"],"properties":{"limit":{"type":"integer"},"offset":{"type":"integer"},"has_more":{"type":"boolean"},"next_offset":{"type":"integer","nullable":true,"description":"Pass as `offset` to fetch the next page. null when has_more is false."}}},"ContactRef":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"full_name":{"type":"string"}}},"SessionRef":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string","nullable":true},"subtitle":{"type":"string","nullable":true},"session_date":{"type":"string","format":"date-time","nullable":true},"recording_status":{"type":"string"}}},"Contact":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"full_name":{"type":"string"},"email":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true},"notes":{"type":"string","nullable":true},"memory":{"type":"string","nullable":true,"description":"AI-maintained memory of this contact"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"notes_timeline":{"type":"array","description":"Manually written notes about this contact, newest first","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"content":{"type":"string"},"source":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}}},"recent_sessions":{"type":"array","description":"This contact’s most recent past sessions","items":{"$ref":"#/components/schemas/SessionRef"}}}},"SessionSummary":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string","nullable":true},"subtitle":{"type":"string","nullable":true},"session_date":{"type":"string","format":"date-time","nullable":true},"session_date_end":{"type":"string","format":"date-time","nullable":true},"recording_status":{"type":"string"},"source":{"type":"string","nullable":true},"conference_provider":{"type":"string","nullable":true},"client":{"$ref":"#/components/schemas/ContactRef"}}},"SessionDetail":{"allOf":[{"$ref":"#/components/schemas/SessionSummary"},{"type":"object","properties":{"conference_url":{"type":"string","nullable":true},"google_doc_url":{"type":"string","nullable":true},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"notes":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string","nullable":true},"title_slug":{"type":"string","nullable":true},"content":{"type":"string"},"position":{"type":"integer"},"type":{"type":"string","enum":["user_manual","ai_meeting_prep","user_template","ai_predefined"]}}}}}}]},"Transcript":{"type":"object","properties":{"session_id":{"type":"string","format":"uuid"},"transcript":{"type":"string","nullable":true,"description":"null when no transcript has been generated yet"},"recording":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"duration_seconds":{"type":"number","nullable":true},"recording_started_at":{"type":"string","format":"date-time","nullable":true},"recording_ended_at":{"type":"string","format":"date-time","nullable":true}}}}},"NoteMatch":{"type":"object","properties":{"kind":{"type":"string","enum":["contact","session"]},"parent_id":{"type":"string","format":"uuid"},"parent_label":{"type":"string","nullable":true},"note_type":{"type":"string","nullable":true},"content":{"type":"string","description":"Truncated to 1000 characters"},"truncated":{"type":"boolean"},"created_at":{"type":"string","format":"date-time","nullable":true}}},"HealthStatus":{"type":"object","properties":{"status":{"type":"string"},"version":{"type":"string"}}}}},"paths":{"/health":{"get":{"operationId":"health","summary":"Check service health","responses":{"200":{"description":"Healthy","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthStatus"}}},"headers":{"RateLimit-Limit":{"description":"Requests allowed per one-second window.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The rate-limit policy, as `<limit>;w=<window seconds>`.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded. Wait the number of seconds in Retry-After and retry; the limit in force is on every response as RateLimit-Limit.","headers":{"RateLimit-Limit":{"description":"Requests allowed per one-second window.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The rate-limit policy, as `<limit>;w=<window seconds>`.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/contacts":{"get":{"operationId":"searchContacts","summary":"Search contacts","security":[{"TamlootApiKey":[]}],"parameters":[{"name":"query","in":"query","description":"Search term (name, email, or phone)","required":true,"schema":{"type":"string","minLength":2,"maxLength":100}}],"responses":{"200":{"description":"Matching contacts, most relevant first (max 10)","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Contact"}}}}}},"headers":{"RateLimit-Limit":{"description":"Requests allowed per one-second window.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The rate-limit policy, as `<limit>;w=<window seconds>`.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"RateLimit-Limit":{"description":"Requests allowed per one-second window.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The rate-limit policy, as `<limit>;w=<window seconds>`.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded. Wait the number of seconds in Retry-After and retry; the limit in force is on every response as RateLimit-Limit.","headers":{"RateLimit-Limit":{"description":"Requests allowed per one-second window.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The rate-limit policy, as `<limit>;w=<window seconds>`.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/contacts/{contact_id}":{"get":{"operationId":"getContact","summary":"Get a contact","security":[{"TamlootApiKey":[]}],"parameters":[{"name":"contact_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Contact","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Contact"}}}}},"headers":{"RateLimit-Limit":{"description":"Requests allowed per one-second window.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The rate-limit policy, as `<limit>;w=<window seconds>`.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"RateLimit-Limit":{"description":"Requests allowed per one-second window.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The rate-limit policy, as `<limit>;w=<window seconds>`.","schema":{"type":"string"}}}},"404":{"description":"Contact not found, or not visible to this account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"RateLimit-Limit":{"description":"Requests allowed per one-second window.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The rate-limit policy, as `<limit>;w=<window seconds>`.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded. Wait the number of seconds in Retry-After and retry; the limit in force is on every response as RateLimit-Limit.","headers":{"RateLimit-Limit":{"description":"Requests allowed per one-second window.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The rate-limit policy, as `<limit>;w=<window seconds>`.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/sessions":{"get":{"operationId":"searchSessions","summary":"Browse or search sessions","security":[{"TamlootApiKey":[]}],"parameters":[{"name":"query","in":"query","description":"Search term (matches title, subtitle, and contact name)","required":false,"schema":{"type":"string","minLength":2,"maxLength":100}},{"name":"contact_id","in":"query","description":"Filter to sessions with this contact","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"from","in":"query","description":"Only sessions on or after this date","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","description":"Only sessions on or before this date","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"limit","in":"query","description":"Max results per page","required":false,"schema":{"type":"integer","minimum":1,"maximum":25,"default":10}},{"name":"offset","in":"query","description":"Number of results to skip","required":false,"schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"A page of sessions","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SessionSummary"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}},"headers":{"RateLimit-Limit":{"description":"Requests allowed per one-second window.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The rate-limit policy, as `<limit>;w=<window seconds>`.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"RateLimit-Limit":{"description":"Requests allowed per one-second window.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The rate-limit policy, as `<limit>;w=<window seconds>`.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded. Wait the number of seconds in Retry-After and retry; the limit in force is on every response as RateLimit-Limit.","headers":{"RateLimit-Limit":{"description":"Requests allowed per one-second window.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The rate-limit policy, as `<limit>;w=<window seconds>`.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/sessions/{session_id}":{"get":{"operationId":"getSession","summary":"Get a session","security":[{"TamlootApiKey":[]}],"parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Session, including its notes","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SessionDetail"}}}}},"headers":{"RateLimit-Limit":{"description":"Requests allowed per one-second window.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The rate-limit policy, as `<limit>;w=<window seconds>`.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"RateLimit-Limit":{"description":"Requests allowed per one-second window.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The rate-limit policy, as `<limit>;w=<window seconds>`.","schema":{"type":"string"}}}},"404":{"description":"Session not found, or not visible to this account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"RateLimit-Limit":{"description":"Requests allowed per one-second window.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The rate-limit policy, as `<limit>;w=<window seconds>`.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded. Wait the number of seconds in Retry-After and retry; the limit in force is on every response as RateLimit-Limit.","headers":{"RateLimit-Limit":{"description":"Requests allowed per one-second window.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The rate-limit policy, as `<limit>;w=<window seconds>`.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/sessions/{session_id}/transcript":{"get":{"operationId":"getSessionTranscript","summary":"Get a session transcript","security":[{"TamlootApiKey":[]}],"parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Transcript","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Transcript"}}},"headers":{"RateLimit-Limit":{"description":"Requests allowed per one-second window.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The rate-limit policy, as `<limit>;w=<window seconds>`.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"RateLimit-Limit":{"description":"Requests allowed per one-second window.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The rate-limit policy, as `<limit>;w=<window seconds>`.","schema":{"type":"string"}}}},"404":{"description":"Session not found, or not visible to this account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"RateLimit-Limit":{"description":"Requests allowed per one-second window.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The rate-limit policy, as `<limit>;w=<window seconds>`.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded. Wait the number of seconds in Retry-After and retry; the limit in force is on every response as RateLimit-Limit.","headers":{"RateLimit-Limit":{"description":"Requests allowed per one-second window.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The rate-limit policy, as `<limit>;w=<window seconds>`.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/notes":{"get":{"operationId":"searchNotes","summary":"Search notes","security":[{"TamlootApiKey":[]}],"parameters":[{"name":"query","in":"query","description":"Search term","required":true,"schema":{"type":"string","minLength":2,"maxLength":100}},{"name":"limit","in":"query","description":"Max results per page","required":false,"schema":{"type":"integer","minimum":1,"maximum":25,"default":10}},{"name":"offset","in":"query","description":"Number of results to skip","required":false,"schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"A page of matching notes","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/NoteMatch"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}},"headers":{"RateLimit-Limit":{"description":"Requests allowed per one-second window.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The rate-limit policy, as `<limit>;w=<window seconds>`.","schema":{"type":"string"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"RateLimit-Limit":{"description":"Requests allowed per one-second window.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The rate-limit policy, as `<limit>;w=<window seconds>`.","schema":{"type":"string"}}}},"429":{"description":"Rate limit exceeded. Wait the number of seconds in Retry-After and retry; the limit in force is on every response as RateLimit-Limit.","headers":{"RateLimit-Limit":{"description":"Requests allowed per one-second window.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"The rate-limit policy, as `<limit>;w=<window seconds>`.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}