{"openapi":"3.1.0","info":{"title":"DeepDrive API","version":"2.0.0","description":"Private topics, prompts, and session summaries for one person. Send Authorization: Bearer with a personal API token (dd_...) from Settings, or a Firebase ID token. The app makes no AI calls. Every query is scoped to the token's user. Do not send topic text or email addresses anywhere except the topic and session fields the person asked you to save."},"servers":[{"url":"https://deepdrive.app"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Personal API token created in DeepDrive Settings (prefix dd_) or a Firebase ID token. No cookies."}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]},"Topic":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"category":{"type":"string"},"why":{"type":"string"},"opening_prompt":{"type":"string"},"rating":{"type":"integer","minimum":0,"maximum":5,"description":"0 means unrated."},"status":{"type":"string","enum":["new","active","parked","done"]},"minutes":{"type":"integer","minimum":1,"maximum":240},"notes":{"type":"string"},"library_id":{"type":["string","null"]},"last_used_at":{"type":["string","null"]},"created_at":{"type":"string"},"updated_at":{"type":"string"},"session_count":{"type":"integer"},"last_session":{"type":["string","null"]},"sessions":{"type":"array","items":{"$ref":"#/components/schemas/Session"}}}},"Session":{"type":"object","properties":{"id":{"type":"string"},"topic_id":{"type":"string"},"date":{"type":"string","description":"YYYY-MM-DD"},"kind":{"type":"string","enum":["summary","interim"]},"summary":{"type":"string"},"decisions":{"type":"string"},"open_questions":{"type":"string"},"next_steps":{"type":"string"},"source":{"type":"string"},"created_at":{"type":"string"}}},"TopicDraft":{"type":"object","additionalProperties":false,"required":["title"],"description":"One topic. A good title is open-ended, personal, and decision-oriented.","properties":{"title":{"type":"string","maxLength":300},"why":{"type":"string","maxLength":2000},"category":{"type":"string","maxLength":60,"description":"Personal, Business & side projects, Money, Home, Travel & planning, Health & habits, Relationships & family, Learning, Career, or a short custom label."},"tags":{"type":"array","maxItems":12,"items":{"type":"string","maxLength":40},"description":"Stored in notes as a line starting with Tags:."},"rating":{"type":"integer","minimum":0,"maximum":5},"status":{"type":"string","enum":["new","active","parked","done"]},"minutes":{"type":"integer","minimum":1,"maximum":240},"opening_prompt":{"type":"string","maxLength":8000},"notes":{"type":"string","maxLength":20000}}},"TopicBulkBody":{"type":"object","additionalProperties":false,"required":["topics"],"properties":{"format":{"const":"deepdrive-topics"},"topics":{"type":"array","minItems":1,"maxItems":100,"items":{"$ref":"#/components/schemas/TopicDraft"}}}},"TopicBulkResult":{"type":"object","properties":{"created":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"}}}},"skipped":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string"},"reason":{"type":"string"}}}},"topics_added":{"type":"integer"},"topics_skipped":{"type":"integer"}}},"LibraryTopic":{"type":"object","required":["id","category","title","why","opening_prompt","added"],"properties":{"id":{"type":"string"},"category":{"type":"string"},"title":{"type":"string"},"why":{"type":"string"},"opening_prompt":{"type":"string"},"hook":{"type":"string","description":"Optional. A short question for cards, distinct from why."},"tags":{"type":"array","items":{"type":"string"},"description":"Optional. Lowercase labels for badges and search."},"drive_length_minutes":{"type":"integer","minimum":1,"description":"Optional. Rough length of a conversation this topic fits."},"added":{"type":"boolean","description":"True when the caller already has this library topic."}}},"LibraryList":{"type":"object","properties":{"categories":{"type":"array","items":{"type":"string"}},"topics":{"type":"array","items":{"$ref":"#/components/schemas/LibraryTopic"}}}},"LibraryAddBody":{"type":"object","additionalProperties":false,"required":["ids"],"properties":{"ids":{"type":"array","minItems":1,"maxItems":40,"items":{"type":"string"}}}},"TopicCreate":{"type":"object","required":["title"],"properties":{"title":{"type":"string","examples":["What good work looks like this quarter"]},"category":{"type":"string","examples":["Career"]},"why":{"type":"string"},"opening_prompt":{"type":"string"},"status":{"type":"string","enum":["new","active","parked","done"]},"rating":{"type":"integer","minimum":0,"maximum":5},"minutes":{"type":"integer","minimum":1,"maximum":240},"notes":{"type":"string"}}},"TopicPatch":{"type":"object","description":"Send only fields that change.","properties":{"title":{"type":"string"},"category":{"type":"string"},"why":{"type":"string"},"opening_prompt":{"type":"string"},"notes":{"type":"string"},"status":{"type":"string","enum":["new","active","parked","done"]},"rating":{"type":"integer","minimum":0,"maximum":5},"minutes":{"type":"integer","minimum":1,"maximum":240}}},"RatingBody":{"type":"object","required":["rating"],"properties":{"rating":{"type":"integer","minimum":0,"maximum":5,"description":"0 clears the rating."}}},"SessionCreate":{"type":"object","description":"At least one text field is required.","properties":{"summary":{"type":"string"},"decisions":{"type":"string"},"open_questions":{"type":"string"},"next_steps":{"type":"string"},"kind":{"type":"string","enum":["summary","interim"]},"date":{"type":"string"},"source":{"type":"string"}}},"PickBody":{"type":"object","properties":{"category":{"type":"string"},"include_done":{"type":"boolean","description":"Default false."},"include_parked":{"type":"boolean","description":"Default true."}}},"Prompt":{"type":"object","properties":{"prompt":{"type":"string","description":"Text the person pastes into their own voice chat."}},"required":["prompt"]},"Recommendation":{"type":"object","required":["id","category","title","why","slot","score","reason","reason_code"],"properties":{"id":{"type":"string"},"category":{"type":"string"},"title":{"type":"string"},"why":{"type":"string"},"hook":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"drive_length_minutes":{"type":"integer"},"slot":{"type":"string","enum":["fit","surprise"],"description":"About one in five picks is a surprise from a category the person has not tried."},"score":{"type":"number"},"reason":{"type":"string","description":"One plain-English sentence to show the person before they add it."},"reason_code":{"type":"string","enum":["category_affinity","tag_affinity","session_affinity","explore","cold_start"]}}},"RecommendationList":{"type":"object","properties":{"generated_at":{"type":"string"},"recommendations":{"type":"array","items":{"$ref":"#/components/schemas/Recommendation"}}}},"RecommendationFeedback":{"type":"object","additionalProperties":false,"required":["action"],"properties":{"action":{"type":"string","enum":["shown","added","dismissed","not_interested","more_like_this"]},"slot":{"type":"string","enum":["fit","surprise"],"description":"Defaults to fit."}}}}},"security":[{"bearerAuth":[]}],"paths":{"/api/health":{"get":{"operationId":"getHealth","summary":"Liveness","description":"Returns ok. No authentication.","tags":["Meta"],"security":[],"responses":{"200":{"description":"Up"}}}},"/api/config":{"get":{"operationId":"getConfig","summary":"Public web config","description":"Firebase web config for the browser. Not a secret.","tags":["Meta"],"security":[]}},"/api/openapi.json":{"get":{"operationId":"getOpenApi","summary":"This document","description":"OpenAPI 3.1 description of the API.","tags":["Meta"],"security":[]}},"/api/me":{"get":{"operationId":"getMe","summary":"Current user","description":"Returns the signed-in user and creates the row on first call.","tags":["Account"]},"delete":{"operationId":"deleteMe","summary":"Delete account","description":"Deletes topics, sessions, ratings, API tokens, and the user. Requires a Firebase sign-in, not an API token.","tags":["Account"]}},"/api/topics":{"get":{"operationId":"listTopics","summary":"List or search topics","description":"Returns only the caller's topics. Use q for a title search, status for new|active|parked|done, and category for an exact category.","tags":["Topics"],"parameters":[{"name":"q","in":"query","schema":{"type":"string"},"description":"Title search. Truncated to 40 UTF-8 bytes."},{"name":"status","in":"query","schema":{"type":"string","enum":["new","active","parked","done"]}},{"name":"category","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Topics","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Topic"}},"example":[{"id":"3f1c2a40-7b3e-4d1a-9c2e-1a2b3c4d5e6f","title":"What good work looks like this quarter","category":"Career","why":"If I cannot describe it, the week fills with motion.","opening_prompt":"I want a thinking partner for this: What good work looks like this quarter.","rating":4,"status":"active","minutes":10,"notes":"","library_id":null,"last_used_at":"2026-11-03T12:00:00Z","created_at":"2026-11-01T09:00:00Z","updated_at":"2026-11-03T12:00:00Z","session_count":1,"last_session":"2026-11-03"}]}}}}},"post":{"operationId":"createTopic","summary":"Create a topic","description":"title is required. Other fields are optional.","tags":["Topics"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopicCreate"},"example":{"title":"What good work looks like this quarter","category":"Career","why":"If I cannot describe it, the week fills with motion."}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Topic"},"example":{"id":"3f1c2a40-7b3e-4d1a-9c2e-1a2b3c4d5e6f","title":"What good work looks like this quarter","category":"Career","why":"If I cannot describe it, the week fills with motion.","opening_prompt":"I want a thinking partner for this: What good work looks like this quarter.","rating":4,"status":"active","minutes":10,"notes":"","library_id":null,"last_used_at":"2026-11-03T12:00:00Z","created_at":"2026-11-01T09:00:00Z","updated_at":"2026-11-03T12:00:00Z","session_count":1,"last_session":"2026-11-03"}}}}}}},"/api/topics/bulk":{"post":{"operationId":"createTopicsBulk","summary":"Create topics in bulk","description":"Creates up to 100 topics. Duplicate titles, including repeats in this call, are skipped and not overwritten. API tokens may call this. Confirm the list with the person first. A good topic is open-ended, personal, and decision-oriented.","tags":["Topics"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopicBulkBody"},"example":{"format":"deepdrive-topics","topics":[{"title":"What good work looks like this quarter","category":"Career","why":"If I cannot describe it, the week fills with motion."}]}}}},"responses":{"201":{"description":"Created and skipped titles","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopicBulkResult"}}}},"400":{"description":"Validation error, such as topics[0].title is required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]},"example":{"error":"topics[0].rating must be an integer 0-5"}}}}}}},"/api/topics/{id}":{"get":{"operationId":"getTopic","summary":"Get a topic","description":"Includes sessions, newest first.","tags":["Topics"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Topic","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Topic"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]},"example":{"error":"topic not found"}}}}}},"patch":{"operationId":"updateTopic","summary":"Update a topic","description":"Partial update. Unknown fields are ignored.","tags":["Topics"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopicPatch"},"example":{"status":"active"}}}}},"delete":{"operationId":"deleteTopic","summary":"Delete a topic","description":"Deletes the topic, its sessions, and its rating log.","tags":["Topics"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]}},"/api/topics/{id}/sessions":{"get":{"operationId":"listSessions","summary":"List sessions","description":"Newest first.","tags":["Sessions"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]},"post":{"operationId":"createSession","summary":"Save a session summary","description":"At least one of summary, decisions, open_questions, or next_steps. Saving a session moves a new topic to active.","tags":["Sessions"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionCreate"},"example":{"id":"8b2d4e61-1c4a-4f90-8d11-9e0f1a2b3c4d","topic_id":"3f1c2a40-7b3e-4d1a-9c2e-1a2b3c4d5e6f","date":"2026-11-03","kind":"summary","summary":"The quarter succeeds if the proposal is sent.","decisions":"Send it Friday.","open_questions":"Who reviews it?","next_steps":"Draft the one-pager.","source":"user","created_at":"2026-11-03T18:00:00Z"}}}},"responses":{"201":{"description":"Saved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Session"},"example":{"id":"8b2d4e61-1c4a-4f90-8d11-9e0f1a2b3c4d","topic_id":"3f1c2a40-7b3e-4d1a-9c2e-1a2b3c4d5e6f","date":"2026-11-03","kind":"summary","summary":"The quarter succeeds if the proposal is sent.","decisions":"Send it Friday.","open_questions":"Who reviews it?","next_steps":"Draft the one-pager.","source":"user","created_at":"2026-11-03T18:00:00Z"}}}}}}},"/api/topics/{id}/ratings":{"get":{"operationId":"listRatings","summary":"Rating history","description":"Oldest first.","tags":["Ratings"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]},"post":{"operationId":"setRating","summary":"Set a rating","description":"Integer 0 through 5. 0 clears the rating. A change is appended to the rating log.","tags":["Ratings"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RatingBody"},"example":{"rating":4}}}}}},"/api/sessions/{id}":{"get":{"operationId":"getSession","summary":"Get a session","description":"One session belonging to the caller.","tags":["Sessions"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]},"patch":{"operationId":"updateSession","summary":"Update a session","description":"Replaces the text fields you send.","tags":["Sessions"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]},"delete":{"operationId":"deleteSession","summary":"Delete a session","description":"Removes one session.","tags":["Sessions"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]}},"/api/pick":{"post":{"operationId":"pickTopic","summary":"Weighted random topic","description":"Higher ratings and active topics are more likely. A topic used in the last day is less likely. Done topics are excluded unless include_done is true.","tags":["Topics"],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PickBody"},"example":{"category":"Career"}}}},"responses":{"200":{"description":"Chosen topic","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Topic"},"example":{"id":"3f1c2a40-7b3e-4d1a-9c2e-1a2b3c4d5e6f","title":"What good work looks like this quarter","category":"Career","why":"If I cannot describe it, the week fills with motion.","opening_prompt":"I want a thinking partner for this: What good work looks like this quarter.","rating":4,"status":"active","minutes":10,"notes":"","library_id":null,"last_used_at":"2026-11-03T12:00:00Z","created_at":"2026-11-01T09:00:00Z","updated_at":"2026-11-03T12:00:00Z","session_count":1,"last_session":"2026-11-03"}}}}}}},"/api/prompts/opening":{"get":{"operationId":"getOpeningPrompt","summary":"Opening prompt","description":"Prompt that asks a voice chat to be a thinking partner, one question at a time, and to wrap up in a fixed summary.","tags":["Prompts"],"parameters":[{"name":"topic","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Prompt","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Prompt"}}}}}}},"/api/prompts/continue":{"get":{"operationId":"getContinuePrompt","summary":"Continue prompt","description":"Same shape as the opening prompt, plus the most recent session summaries so the chat can pick up where the person left off.","tags":["Prompts"],"parameters":[{"name":"topic","in":"query","required":true,"schema":{"type":"string"}}]}},"/api/prompts/wrapup":{"get":{"operationId":"getWrapUpPrompt","summary":"Wrap-up prompt","description":"Short prompt the person pastes at the end of a conversation to get Summary, Decisions, Open questions, and Next steps.","tags":["Prompts"],"parameters":[{"name":"topic","in":"query","required":false,"schema":{"type":"string"}}]}},"/api/library":{"get":{"operationId":"listLibrary","summary":"Built-in topic library","description":"Curated topics. added is true when this account already has that library topic. Each topic may also carry hook, tags, and drive_length_minutes.","tags":["Library"],"responses":{"200":{"description":"Library","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LibraryList"}}}}}}},"/api/library/starter":{"get":{"operationId":"getStarterLibrary","summary":"Starter topics","description":"About eight diverse library topics for onboarding. added is true when this account already has that topic.","tags":["Library"],"responses":{"200":{"description":"Starter topics","content":{"application/json":{"schema":{"type":"object","properties":{"topics":{"type":"array","items":{"$ref":"#/components/schemas/LibraryTopic"}}}}}}}}}},"/api/library/add":{"post":{"operationId":"addLibraryTopics","summary":"Add library topics","description":"Copies several library topics onto the caller's account. Unknown ids and topics already added are skipped. At most 40 ids.","tags":["Library"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LibraryAddBody"},"example":{"ids":["health-sleep","career-good-work"]}}}}}},"/api/library/{id}/add":{"post":{"operationId":"addLibraryTopic","summary":"Add a library topic","description":"Copies one library topic onto the caller's account. Idempotent.","tags":["Library"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]}},"/api/recommendations":{"get":{"operationId":"listRecommendations","summary":"Personalized library recommendations","description":"Ranked library topics the caller has not added yet, learned from their picks, ratings, and sessions. About one in five is a deliberate surprise from a category they have not explored. Does not include opening_prompt; add a topic with the existing library add endpoints.","tags":["Library"],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":20,"default":5}},{"name":"minutes","in":"query","schema":{"type":"integer","minimum":1,"maximum":240},"description":"Favor topics that fit this many minutes."},{"name":"surprise","in":"query","schema":{"type":"integer","enum":[0,1],"default":1}}],"responses":{"200":{"description":"Recommendations","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecommendationList"}}}}}}},"/api/recommendations/surprise":{"post":{"operationId":"getSurprise","summary":"One surprise topic","description":"Returns one surprise-slot recommendation for a Surprise me button.","tags":["Library"],"responses":{"200":{"description":"Surprise pick","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Recommendation"}}}}}}},"/api/recommendations/{library_id}/feedback":{"post":{"operationId":"sendRecommendationFeedback","summary":"Recommendation feedback","description":"dismissed hides the item for 30 days, not_interested hides it for good and downweights similar topics, more_like_this upweights similar topics. shown is optional and never written by a GET.","tags":["Library"],"parameters":[{"name":"library_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecommendationFeedback"},"example":{"action":"more_like_this","slot":"fit"}}}},"responses":{"200":{"description":"Recorded"},"400":{"description":"Bad action or slot","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"404":{"description":"Unknown library id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/api/tokens":{"get":{"operationId":"listTokens","summary":"List API tokens","description":"Names and prefixes only. Requires a Firebase sign-in.","tags":["Account"]},"post":{"operationId":"createToken","summary":"Create an API token","description":"Returns the dd_ token once. Requires a Firebase sign-in.","tags":["Account"]}},"/api/tokens/{id}":{"delete":{"operationId":"deleteToken","summary":"Revoke an API token","description":"Requires a Firebase sign-in.","tags":["Account"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]}},"/api/export":{"get":{"operationId":"exportData","summary":"Export JSON","description":"deepdrive-v2 document with topics, sessions, and rating_log. Tokens are omitted.","tags":["Account"],"responses":{"200":{"description":"Export","content":{"application/json":{"example":{"format":"deepdrive-v2","topics":[{"id":"3f1c2a40-7b3e-4d1a-9c2e-1a2b3c4d5e6f","title":"What good work looks like this quarter","category":"Career","why":"If I cannot describe it, the week fills with motion.","opening_prompt":"I want a thinking partner for this: What good work looks like this quarter.","rating":4,"status":"active","minutes":10,"notes":"","library_id":null,"last_used_at":"2026-11-03T12:00:00Z","created_at":"2026-11-01T09:00:00Z","updated_at":"2026-11-03T12:00:00Z","session_count":1,"last_session":"2026-11-03"}],"sessions":[{"id":"8b2d4e61-1c4a-4f90-8d11-9e0f1a2b3c4d","topic_id":"3f1c2a40-7b3e-4d1a-9c2e-1a2b3c4d5e6f","date":"2026-11-03","kind":"summary","summary":"The quarter succeeds if the proposal is sent.","decisions":"Send it Friday.","open_questions":"Who reviews it?","next_steps":"Draft the one-pager.","source":"user","created_at":"2026-11-03T18:00:00Z"}],"rating_log":[]}}}}}}},"/api/import":{"post":{"operationId":"importData","summary":"Import JSON","description":"Imports a deepdrive-v2 export, a v1 export when the shape matches, or a simple deepdrive-topics list (title, why, category, optional tags and rating). Requires a Firebase sign-in, not an API token. The simple list is also what POST /api/topics/bulk accepts. Idempotent for v1 and v2. Simple imports skip duplicate titles.","tags":["Account"]}},"/api/usage":{"get":{"operationId":"getUsage","summary":"Token balance","description":"DeepDrive tokens left for voice sessions (1 token = $0.0005 of provider cost; about 100 tokens per minute of voice). Returns plan, tokens_left, tokens_used_period, approx_minutes_left, period_end, sessions_left_estimate and the effective session limits. The prompt-copy flow never uses tokens.","tags":["Account"]}},"/api/import/v1":{"post":{"operationId":"importV1","summary":"Import a v1 export","description":"Always treats the body as a v1 export. Requires a Firebase sign-in.","tags":["Account"]}}}}