{"openapi":"3.1.0","info":{"title":"Refine API","description":"Refine proofreading and writing assistance API","version":"1.0.0"},"paths":{"/chatbot/{session_id}/messages":{"post":{"tags":["chatbot"],"summary":"Send chatbot message","description":"Send a message to the proofreading chatbot and stream the response via SSE. The LLM may call tools to retrieve document content, comments, or images.","operationId":"chatbot_sendMessage","security":[{"HTTPBearer":[]}],"parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatMessageRequest"},"examples":{"About a comment":{"summary":"About a comment","value":{"message":"Why is this phrasing a problem?","comment_id":"1792a726-5a83-4d20-ad59-0cf0f72c7faf"}},"About the document":{"summary":"About the document","value":{"message":"What should I prioritise fixing first?","comment_id":null}}}}}},"responses":{"200":{"description":"SSE stream of chat response chunks","content":{"text/event-stream":{"itemSchema":{"type":"object","properties":{"data":{"type":"string"},"event":{"type":"string"},"id":{"type":"string"},"retry":{"type":"integer","minimum":0}}},"schema":{"oneOf":[{"description":"SSE start event — sent immediately to keep connection alive during LLM reasoning.","properties":{"type":{"const":"start","description":"Event type","title":"Type","type":"string"},"status":{"const":"processing","description":"Processing status","title":"Status","type":"string"}},"required":["type","status"],"title":"SSEChatStartEvent","type":"object"},{"description":"SSE data payload for chatbot streaming. Each chunk is a text fragment.","properties":{"type":{"const":"chunk","description":"Event type","title":"Type","type":"string"},"chunk":{"description":"Text chunk of the response","title":"Chunk","type":"string"}},"required":["type","chunk"],"title":"SSEChatChunkEvent","type":"object"},{"description":"SSE tool_call event — the model is calling a tool to retrieve information.","properties":{"type":{"const":"tool_call","description":"Event type","title":"Type","type":"string"},"tool":{"description":"Name of the tool being called","title":"Tool","type":"string"}},"required":["type","tool"],"title":"SSEChatToolCallEvent","type":"object"},{"description":"SSE complete event — stream completed successfully.","properties":{"type":{"const":"complete","description":"Event type","title":"Type","type":"string"},"status":{"const":"completed","description":"Completion status","title":"Status","type":"string"},"meta":{"description":"Metadata bundled on complete/error SSE events.","properties":{"turn_id":{"description":"Router-assigned turn identifier (uuid4)","title":"Turn Id","type":"string"},"quota":{"anyOf":[{"description":"Live snapshot of the chatbot daily quota for the requesting user.","properties":{"used_fraction":{"description":"Fraction of the daily budget consumed (0.0–1.0, clipped). Frontend renders as a progress bar or percentage.","maximum":1.0,"minimum":0.0,"title":"Used Fraction","type":"number"},"resets_at":{"description":"When the counter rolls over (UTC, ISO 8601). Literal Redis TTL expiry — the moment the user's budget is wiped.","format":"date-time","title":"Resets At","type":"string"}},"required":["used_fraction","resets_at"],"title":"QuotaStatus","type":"object"},{"type":"null"}],"description":"User's quota snapshot after enforcement; None if quota was not enforced"}},"required":["turn_id"],"title":"SSEChatTurnMeta","type":"object"}},"required":["type","status","meta"],"title":"SSEChatCompleteEvent","type":"object"},{"description":"SSE error event — stream failed.\n\nMembers mirror the HTTP problem contract so a frontend keys localized copy\noff one taxonomy across both transports: ``error_type`` is the RFC 9457\n``type`` slug, ``error`` the stable title, ``details`` the extension members.\n``error`` used to be ``str(exc)`` -- free-form English with the user's daily\nlimit interpolated into it, which nothing could translate or group.","properties":{"type":{"const":"error","description":"Event type","title":"Type","type":"string"},"error":{"description":"Stable human-readable title; does not vary per occurrence","title":"Error","type":"string"},"error_type":{"description":"Stable RFC 9457 type slug identifying the failure","title":"Error Type","type":"string"},"details":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"description":"Error-specific extension members","title":"Details"},"meta":{"description":"Metadata bundled on complete/error SSE events.","properties":{"turn_id":{"description":"Router-assigned turn identifier (uuid4)","title":"Turn Id","type":"string"},"quota":{"anyOf":[{"description":"Live snapshot of the chatbot daily quota for the requesting user.","properties":{"used_fraction":{"description":"Fraction of the daily budget consumed (0.0–1.0, clipped). Frontend renders as a progress bar or percentage.","maximum":1.0,"minimum":0.0,"title":"Used Fraction","type":"number"},"resets_at":{"description":"When the counter rolls over (UTC, ISO 8601). Literal Redis TTL expiry — the moment the user's budget is wiped.","format":"date-time","title":"Resets At","type":"string"}},"required":["used_fraction","resets_at"],"title":"QuotaStatus","type":"object"},{"type":"null"}],"description":"User's quota snapshot after enforcement; None if quota was not enforced"}},"required":["turn_id"],"title":"SSEChatTurnMeta","type":"object"}},"required":["type","error","error_type","meta"],"title":"SSEChatErrorEvent","type":"object"}],"discriminator":{"propertyName":"type"}}}}},"422":{"$ref":"#/components/responses/ProblemUnprocessable"},"500":{"$ref":"#/components/responses/ProblemInternalServerErrorAuthenticationConfigurationAuthenticationFailedUnexpectedFailure"},"401":{"$ref":"#/components/responses/ProblemUnauthenticated"}}},"get":{"tags":["chatbot"],"summary":"Get chatbot conversation history","description":"Get the message history for a chatbot conversation on a proofreading session. Returns user and assistant messages. The session must have proofreading results before a conversation can exist.","operationId":"chatbot_getConversationHistory","security":[{"HTTPBearer":[]}],"parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationHistoryResponse"},"examples":{"With history":{"summary":"With history","value":{"conversation_id":"c9b1f6d2-4a83-4f21-9c07-2e5b8a1d3f40","messages":[{"role":"user","content":"Why is this phrasing a problem?","comment_id":"1792a726-5a83-4d20-ad59-0cf0f72c7faf","created_at":"2026-07-24T13:02:11.412000+00:00"},{"role":"assistant","content":"The claim is stated without the condition it depends on, so a reader cannot tell when it holds.","created_at":"2026-07-24T13:02:14.887000+00:00","turn_id":"turn_2fK9xLmQ"}],"created_at":"2026-07-24T13:02:11.412000+00:00","last_message_at":"2026-07-24T13:02:14.887000+00:00"}},"No conversation yet":{"summary":"No conversation yet","value":{"conversation_id":null,"messages":[],"created_at":null,"last_message_at":null}}}}}},"422":{"$ref":"#/components/responses/ProblemUnprocessable"},"500":{"$ref":"#/components/responses/ProblemInternalServerErrorAuthenticationConfigurationAuthenticationFailedUnexpectedFailure"},"401":{"$ref":"#/components/responses/ProblemUnauthenticated"}}}},"/chatbot/{session_id}":{"delete":{"tags":["chatbot"],"summary":"Delete chatbot conversation","description":"Delete the chatbot conversation for a proofreading session. Removes all messages. The conversation can be restarted by sending a new message via send_chatbot_message.","operationId":"chatbot_deleteConversation","security":[{"HTTPBearer":[]}],"parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"$ref":"#/components/responses/ProblemUnprocessable"},"500":{"$ref":"#/components/responses/ProblemInternalServerErrorAuthenticationConfigurationAuthenticationFailedUnexpectedFailure"},"401":{"$ref":"#/components/responses/ProblemUnauthenticated"}}}},"/referrals/register":{"post":{"tags":["referrals"],"summary":"Register a referral code","description":"Record that the authenticated user was referred by another user. Call this once during onboarding when the user provides someone else's referral code, and call it before the user's first payment — referrals registered after the first payment do not qualify for rewards. Idempotent: re-registering the same code returns the existing referral. Returns 400 for malformed codes or self-referral, 404 if the code matches no user.","operationId":"referrals_registerReferral","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterReferralRequest"},"examples":{"Referral code":{"summary":"Referral code","value":{"referral_code":"REFINE-7K2QX"}}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterReferralResponse"},"examples":{"Registered":{"summary":"Registered","value":{"referrer_email":"referrer@example.edu"}}}}}},"422":{"$ref":"#/components/responses/ProblemUnprocessable"},"500":{"$ref":"#/components/responses/ProblemInternalServerErrorAuthenticationConfigurationAuthenticationFailedUnexpectedFailure"},"400":{"$ref":"#/components/responses/ProblemBadRequestMalformedReferralCodeOwnReferralCode"},"401":{"$ref":"#/components/responses/ProblemUnauthenticated"},"404":{"$ref":"#/components/responses/ProblemNotFoundReferralCodeNotFound"}},"security":[{"HTTPBearer":[]}]}},"/referrals/status":{"get":{"tags":["referrals"],"summary":"Get referral status","description":"Check if the current user has been referred and the status of any referral rewards.","operationId":"referrals_getReferralStatus","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReferralStatusResponse"},"examples":{"No referral":{"summary":"No referral","value":{"has_referral":false,"referrer_email":null,"referral_code":null,"created_at":null,"first_payment_at":null,"rewards_issued_at":null}},"Awaiting first payment":{"summary":"Awaiting first payment","value":{"has_referral":true,"referrer_email":"referrer@example.edu","referral_code":"REFINE-7K2QX","created_at":"2026-07-12T14:02:00+00:00","first_payment_at":null,"rewards_issued_at":null}},"Rewards issued":{"summary":"Rewards issued","value":{"has_referral":true,"referrer_email":"referrer@example.edu","referral_code":"REFINE-7K2QX","created_at":"2026-07-12T14:02:00+00:00","first_payment_at":"2026-07-18T09:41:00+00:00","rewards_issued_at":"2026-07-18T09:41:30+00:00"}}}}}},"500":{"$ref":"#/components/responses/ProblemInternalServerErrorAuthenticationConfigurationAuthenticationFailedUnexpectedFailure"},"401":{"$ref":"#/components/responses/ProblemUnauthenticated"}},"security":[{"HTTPBearer":[]}]}},"/history":{"get":{"tags":["history"],"summary":"List proofreading sessions","description":"List the user's completed proofreading sessions, ordered by most recent. Each item includes the document title, comment counts, and session ID needed for other operations. Does NOT include uploaded documents that haven't been processed yet.","operationId":"history_listHistory","security":[{"HTTPBearer":[]}],"parameters":[{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/HistoryListItem"},"title":"Response History Listhistory"},"examples":{"Completed review":{"summary":"Completed review","value":[{"session_id":"7ab7324d-0968-40ac-9a0d-68fe4fbf11bf","created_at":"2026-07-24T12:45:39.418365+00:00","title":"Targeting Interventions in Networks","summary":"Studies how a planner optimally targets interventions in a network game with strategic spillovers, decomposing interventions into principal components.","domain":"social_sciences/economics","taxonomy":"academic/research_paper","document_id":"3eef6ca5-9388-45b4-92a8-c144347ad6ec","original_url":"/documents/3eef6ca5-9388-45b4-92a8-c144347ad6ec/original","content_url":"/documents/3eef6ca5-9388-45b4-92a8-c144347ad6ec/content","comments_count":19,"addressed_count":2,"dismissed_count":1,"is_preview":false,"is_public":false,"viewed":true}]},"Unenriched upload":{"summary":"Unenriched upload","value":[{"session_id":"e681ed2d-b844-48d4-81d7-8d499813c157","created_at":"2026-07-24T12:45:39.418365+00:00","title":null,"summary":null,"domain":null,"taxonomy":null,"document_id":"ff12d34a-ba00-4943-b25e-c23f92e68295","original_url":"/documents/ff12d34a-ba00-4943-b25e-c23f92e68295/original","content_url":"/documents/ff12d34a-ba00-4943-b25e-c23f92e68295/content","comments_count":0,"addressed_count":0,"dismissed_count":0,"is_preview":false,"is_public":false,"viewed":true}]}}}}},"422":{"$ref":"#/components/responses/ProblemUnprocessable"},"500":{"$ref":"#/components/responses/ProblemInternalServerErrorAuthenticationConfigurationAuthenticationFailedUnexpectedFailure"},"401":{"$ref":"#/components/responses/ProblemUnauthenticated"}}}},"/history/{session_id}":{"get":{"tags":["history"],"summary":"Get proofreading session details","description":"Get the full details of a proofreading session including all feedback comments, overall feedback, comment actions (dismissed/addressed), and metadata. Use the session_id from list_history.\n\nIMPORTANT: After viewing the results, call POST /history/mark-viewed with the session's session_id to mark it as viewed. This clears the unviewed indicator in GET /processing.","operationId":"history_getHistorySession","security":[{"HTTPBearer":[]}],"parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HistorySessionResponse"},"examples":{"Completed full review":{"summary":"Completed full review","value":{"session_id":"7ab7324d-0968-40ac-9a0d-68fe4fbf11bf","created_at":"2026-07-24T12:45:39.418365+00:00","completed_at":"2026-07-24T12:59:06.387687+00:00","user_email":"author@example.edu","feedback":{"overall":{"id":"overall-feedback","content":"**Scope of the benchmark assumptions**\n\nThe abstract frames the analysis more broadly than the core results support: the headline claims rely on the quadratic cost specification. Delimiting which claims belong to that benchmark would help the reader place the contribution."},"detailed":{"comments":[{"id":"1792a726-5a83-4d20-ad59-0cf0f72c7faf","title":"Large-budget claim is stated more strongly than shown","paragraph":"The intervention raises welfare for large budgets, which follows directly from the spectral decomposition of the network.","message":"The one-principal-component limit holds for the complements case, not for every environment. Qualify the claim, or state the condition it depends on.","quote":"The intervention raises welfare for large budgets, which follows directly from the spectral decomposition of the network.","score":0.34,"is_dismissed":false,"is_addressed":false,"types":["general"]},{"id":"broad-2","title":"Citation does not support the attributed result","paragraph":"As shown by Kingma and Ba (2015), adaptive methods converge on convex objectives.","message":"The cited work introduces the optimiser but does not prove this convergence result. Attribute the claim to its actual source or soften it.","quote":"As shown by Kingma and Ba (2015), adaptive methods converge on convex objectives.","score":0.71,"is_dismissed":false,"is_addressed":false,"types":["external_references"]}],"comments_count":2}},"progress_percentage":100,"processing_status":"completed","is_processing":false,"is_preview":false,"comment_actions":[],"comment_action_summary":{},"title":"Targeting Interventions in Networks","summary":"Studies how a planner optimally targets interventions in a network game with strategic spillovers.","domain":"social_sciences/economics","taxonomy":"academic/research_paper","steering_prompt":null,"document_id":"3eef6ca5-9388-45b4-92a8-c144347ad6ec","original_url":"/documents/3eef6ca5-9388-45b4-92a8-c144347ad6ec/original","content_url":"/documents/3eef6ca5-9388-45b4-92a8-c144347ad6ec/content","filename":"manuscript.pdf","is_public":false,"is_owner":true,"viewed":true,"previous_session_id":null,"revision_check":null}},"Preview review":{"summary":"Preview review","value":{"session_id":"7ab7324d-0968-40ac-9a0d-68fe4fbf11bf","created_at":"2026-07-24T12:45:39.418365+00:00","completed_at":"2026-07-24T12:59:06.387687+00:00","user_email":"author@example.edu","feedback":{"overall":{"id":"overall-feedback","content":"**Scope of the benchmark assumptions**\n\nThe abstract frames the analysis more broadly than the core results support: the headline claims rely on the quadratic cost specification. Delimiting which claims belong to that benchmark would help the reader place the contribution."},"detailed":{"comments":[{"id":"1792a726-5a83-4d20-ad59-0cf0f72c7faf","title":"Large-budget claim is stated more strongly than shown","paragraph":"The intervention raises welfare for large budgets, which follows directly from the spectral decomposition of the network.","message":"The one-principal-component limit holds for the complements case, not for every environment. Qualify the claim, or state the condition it depends on.","quote":"The intervention raises welfare for large budgets, which follows directly from the spectral decomposition of the network.","score":0.34,"is_dismissed":false,"is_addressed":false,"types":["general"]},{"id":"broad-2","title":"Citation does not support the attributed result","paragraph":"As shown by Kingma and Ba (2015), adaptive methods converge on convex objectives.","message":"The cited work introduces the optimiser but does not prove this convergence result. Attribute the claim to its actual source or soften it.","quote":"As shown by Kingma and Ba (2015), adaptive methods converge on convex objectives.","score":0.71,"is_dismissed":false,"is_addressed":false,"types":["external_references"]}],"comments_count":2}},"progress_percentage":100,"processing_status":"completed","is_processing":false,"is_preview":true,"comment_actions":[],"comment_action_summary":{},"title":"Targeting Interventions in Networks","summary":"Studies how a planner optimally targets interventions in a network game with strategic spillovers.","domain":"social_sciences/economics","taxonomy":"academic/research_paper","steering_prompt":null,"document_id":"3eef6ca5-9388-45b4-92a8-c144347ad6ec","original_url":"/documents/3eef6ca5-9388-45b4-92a8-c144347ad6ec/original","content_url":"/documents/3eef6ca5-9388-45b4-92a8-c144347ad6ec/content","filename":"manuscript.pdf","is_public":false,"is_owner":true,"viewed":false,"previous_session_id":null,"revision_check":null}},"Still processing":{"summary":"Still processing","value":{"session_id":"7ab7324d-0968-40ac-9a0d-68fe4fbf11bf","created_at":"2026-07-24T12:45:39.418365+00:00","completed_at":null,"user_email":"author@example.edu","feedback":{"overall":{"id":"overall-feedback","content":""},"detailed":{"comments":[],"comments_count":0}},"progress_percentage":45,"processing_status":"processing","is_processing":true,"is_preview":false,"comment_actions":[],"comment_action_summary":{},"title":null,"summary":null,"domain":null,"taxonomy":null,"steering_prompt":null,"document_id":"3eef6ca5-9388-45b4-92a8-c144347ad6ec","original_url":"/documents/3eef6ca5-9388-45b4-92a8-c144347ad6ec/original","content_url":"/documents/3eef6ca5-9388-45b4-92a8-c144347ad6ec/content","filename":"manuscript.pdf","is_public":false,"is_owner":true,"viewed":false,"previous_session_id":null,"revision_check":null}}}}}},"422":{"$ref":"#/components/responses/ProblemUnprocessable"},"500":{"$ref":"#/components/responses/ProblemInternalServerErrorAuthenticationConfigurationAuthenticationFailedUnexpectedFailure"},"401":{"$ref":"#/components/responses/ProblemUnauthenticated"},"403":{"$ref":"#/components/responses/ProblemForbiddenSessionNotAccessible"},"404":{"$ref":"#/components/responses/ProblemNotFoundSessionMissing"}}},"delete":{"tags":["history"],"summary":"Delete a proofreading session","description":"Permanently delete a proofreading session and all its feedback. Cannot be undone.","operationId":"history_deleteHistorySession","security":[{"HTTPBearer":[]}],"parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"$ref":"#/components/responses/ProblemUnprocessable"},"500":{"$ref":"#/components/responses/ProblemInternalServerErrorAuthenticationConfigurationAuthenticationFailedUnexpectedFailure"},"400":{"$ref":"#/components/responses/ProblemBadRequestMissingIdentifier"},"401":{"$ref":"#/components/responses/ProblemUnauthenticated"},"404":{"$ref":"#/components/responses/ProblemNotFoundSessionMissing"}}}},"/history/mark-viewed":{"post":{"tags":["history"],"summary":"Mark session as viewed","description":"Mark a proofreading session as viewed by the user. Used to track unread results.","operationId":"history_markHistoryViewed","security":[{"HTTPBearer":[]}],"parameters":[{"name":"session_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarkViewedResponse"},"examples":{"Marked viewed":{"summary":"Marked viewed","value":{"session_id":"7ab7324d-0968-40ac-9a0d-68fe4fbf11bf","user_email":"author@example.edu"}}}}}},"422":{"$ref":"#/components/responses/ProblemUnprocessable"},"500":{"$ref":"#/components/responses/ProblemInternalServerErrorAuthenticationConfigurationAuthenticationFailedUnexpectedFailure"},"400":{"$ref":"#/components/responses/ProblemBadRequestMissingIdentifier"},"401":{"$ref":"#/components/responses/ProblemUnauthenticated"},"404":{"$ref":"#/components/responses/ProblemNotFoundSessionMissing"}}}},"/history/{session_id}/comments/{comment_id}/dismiss":{"patch":{"tags":["history"],"summary":"Dismiss a feedback comment","description":"Mark a feedback comment as dismissed (user chose to ignore it). Idempotent — calling again has no effect.","operationId":"history_dismissComment","security":[{"HTTPBearer":[]}],"parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}},{"name":"comment_id","in":"path","required":true,"schema":{"type":"string","title":"Comment Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommentActionItem"},"examples":{"Dismissal":{"summary":"Dismissal","value":{"id":"c2f7a1de-5b90-4f0c-9a11-6d3f2b8e4c07","session_id":"7ab7324d-0968-40ac-9a0d-68fe4fbf11bf","comment_id":"broad-2","user_email":"author@example.edu","action_type":"dismissed","created_at":"2026-07-24T12:59:06.387687+00:00","notes":null}}}}}},"422":{"$ref":"#/components/responses/ProblemUnprocessable"},"500":{"$ref":"#/components/responses/ProblemInternalServerErrorCommentActionNotStored"},"400":{"$ref":"#/components/responses/ProblemBadRequestCommentNotActionableMissingIdentifier"},"401":{"$ref":"#/components/responses/ProblemUnauthenticated"},"404":{"$ref":"#/components/responses/ProblemNotFoundSessionMissing"}}}},"/history/{session_id}/comments/{comment_id}/address":{"patch":{"tags":["history"],"summary":"Mark a feedback comment as addressed","description":"Mark a feedback comment as addressed (user applied the suggestion). Idempotent.","operationId":"history_addressComment","security":[{"HTTPBearer":[]}],"parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}},{"name":"comment_id","in":"path","required":true,"schema":{"type":"string","title":"Comment Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommentActionItem"},"examples":{"Dismissal":{"summary":"Dismissal","value":{"id":"c2f7a1de-5b90-4f0c-9a11-6d3f2b8e4c07","session_id":"7ab7324d-0968-40ac-9a0d-68fe4fbf11bf","comment_id":"broad-2","user_email":"author@example.edu","action_type":"dismissed","created_at":"2026-07-24T12:59:06.387687+00:00","notes":null}}}}}},"422":{"$ref":"#/components/responses/ProblemUnprocessable"},"500":{"$ref":"#/components/responses/ProblemInternalServerErrorCommentActionNotStored"},"400":{"$ref":"#/components/responses/ProblemBadRequestCommentNotActionableMissingIdentifier"},"401":{"$ref":"#/components/responses/ProblemUnauthenticated"},"404":{"$ref":"#/components/responses/ProblemNotFoundSessionMissing"}}}},"/history/{session_id}/comments/{comment_id}/actions/{action_type}":{"delete":{"tags":["history"],"summary":"Undo a comment action","description":"Remove a dismiss or address action from a comment, reverting it to its original state.","operationId":"history_deleteCommentAction","security":[{"HTTPBearer":[]}],"parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}},{"name":"comment_id","in":"path","required":true,"schema":{"type":"string","title":"Comment Id"}},{"name":"action_type","in":"path","required":true,"schema":{"type":"string","title":"Action Type"}}],"responses":{"204":{"description":"Successful Response"},"422":{"$ref":"#/components/responses/ProblemUnprocessable"},"500":{"$ref":"#/components/responses/ProblemInternalServerErrorAuthenticationConfigurationAuthenticationFailedUnexpectedFailure"},"400":{"$ref":"#/components/responses/ProblemBadRequestCommentNotActionableInvalidCommentActionTypeMissingIdentifier"},"401":{"$ref":"#/components/responses/ProblemUnauthenticated"},"404":{"$ref":"#/components/responses/ProblemNotFoundSessionMissing"}}}},"/history/{session_id}/visibility":{"patch":{"tags":["history"],"summary":"Update session visibility","description":"Make a proofreading session public (shareable via link) or private.","operationId":"history_updateVisibility","security":[{"HTTPBearer":[]}],"parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateVisibilityRequest"},"examples":{"Publish":{"summary":"Publish","value":{"is_public":true}},"Unpublish":{"summary":"Unpublish","value":{"is_public":false}}}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateVisibilityResponse"},"examples":{"Now public":{"summary":"Now public","value":{"session_id":"7ab7324d-0968-40ac-9a0d-68fe4fbf11bf","is_public":true,"changed":true}},"Already public":{"summary":"Already public","value":{"session_id":"7ab7324d-0968-40ac-9a0d-68fe4fbf11bf","is_public":true,"changed":false}}}}}},"422":{"$ref":"#/components/responses/ProblemUnprocessable"},"500":{"$ref":"#/components/responses/ProblemInternalServerErrorAuthenticationConfigurationAuthenticationFailedUnexpectedFailure"},"400":{"$ref":"#/components/responses/ProblemBadRequestMissingIdentifier"},"401":{"$ref":"#/components/responses/ProblemUnauthenticated"},"404":{"$ref":"#/components/responses/ProblemNotFoundSessionMissing"}}}},"/history/{session_id}/request-access":{"post":{"tags":["history"],"summary":"Request access to a private session","description":"Request view access to another user's private session. Sends an email notification to the owner.","operationId":"history_requestSessionAccess","security":[{"HTTPBearer":[]}],"parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionAccessRequest"},"examples":{"With a message":{"summary":"With a message","value":{"message":"I am a co-author on this manuscript and would like to see the review."}},"Without a message":{"summary":"Without a message","value":{"message":null}}}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionAccessRequestResponse"},"examples":{"Request submitted":{"summary":"Request submitted","value":{"session_id":"7ab7324d-0968-40ac-9a0d-68fe4fbf11bf"}}}}}},"422":{"$ref":"#/components/responses/ProblemUnprocessable"},"500":{"$ref":"#/components/responses/ProblemInternalServerErrorAuthenticationConfigurationAuthenticationFailedUnexpectedFailure"},"400":{"$ref":"#/components/responses/ProblemBadRequestSessionAlreadyAccessible"},"401":{"$ref":"#/components/responses/ProblemUnauthenticated"},"403":{"$ref":"#/components/responses/ProblemForbiddenSessionSharingRestricted"},"404":{"$ref":"#/components/responses/ProblemNotFoundSessionMissing"}}}},"/credit-score":{"get":{"tags":["credits"],"summary":"Get credit balance","description":"Get the user's current credit balance including paid credits, preview credits, credit source (personal or organization), document size limits, and current chatbot quota usage. Use this on app mount to prime user-state UI.","operationId":"credits_getCreditScore","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreditScoreResponse"},"examples":{"Personal credits":{"summary":"Personal credits","value":{"paid_credits_remaining":4,"preview_credits_remaining":1,"user_has_paid_credits":true,"user_email":"author@example.edu","credit_source":"personal","tier":"default","max_document_words":100000,"max_file_size_mb":50,"max_supplementary_material":3,"chatbot_quota":{"used_fraction":0.25,"resets_at":"2026-08-01T10:17:43.611699Z"}}},"Organization credits, unlimited tier":{"summary":"Organization credits, unlimited tier","value":{"paid_credits_remaining":250,"preview_credits_remaining":0,"user_has_paid_credits":true,"user_email":"researcher@example.edu","credit_source":"organization","tier":"unlimited","max_document_words":null,"max_file_size_mb":200,"max_supplementary_material":10,"chatbot_quota":{"used_fraction":0.25,"resets_at":"2026-08-01T10:17:43.611699Z"}}},"Out of credits":{"summary":"Out of credits","value":{"paid_credits_remaining":0,"preview_credits_remaining":0,"user_has_paid_credits":false,"user_email":"newcomer@example.edu","credit_source":"personal","tier":"default","max_document_words":100000,"max_file_size_mb":50,"max_supplementary_material":3,"chatbot_quota":{"used_fraction":0.0,"resets_at":"2026-08-01T10:17:43.611699Z"}}}}}}},"500":{"$ref":"#/components/responses/ProblemInternalServerErrorAuthenticationConfigurationAuthenticationFailedUnexpectedFailure"},"401":{"$ref":"#/components/responses/ProblemUnauthenticated"}},"security":[{"HTTPBearer":[]}]}},"/products":{"get":{"tags":["products"],"summary":"List available products","description":"List all available credit packs and subscription plans with pricing. Products are sorted by price. Pass a country code (and optionally region + postal_code, e.g. from Vercel geo headers) to get localized pricing with accurate sales tax.","operationId":"products_getProducts","parameters":[{"name":"country","in":"query","required":false,"schema":{"anyOf":[{"type":"string","minLength":2,"maxLength":2,"pattern":"^[A-Za-z]{2}$"},{"type":"null"}],"description":"ISO 3166-1 alpha-2 country code (e.g. 'US', 'GB'). Forwarded from x-vercel-ip-country.","title":"Country"},"description":"ISO 3166-1 alpha-2 country code (e.g. 'US', 'GB'). Forwarded from x-vercel-ip-country."},{"name":"region","in":"query","required":false,"schema":{"anyOf":[{"type":"string","minLength":1,"maxLength":6,"pattern":"^[A-Za-z0-9\\-]{1,6}$"},{"type":"null"}],"description":"State/province code (e.g. 'NY', 'ON'). Forwarded from x-vercel-ip-country-region. Required for state-precision tax in CA/IN/ES-Canary when no postal_code is provided.","title":"Region"},"description":"State/province code (e.g. 'NY', 'ON'). Forwarded from x-vercel-ip-country-region. Required for state-precision tax in CA/IN/ES-Canary when no postal_code is provided."},{"name":"postal_code","in":"query","required":false,"schema":{"anyOf":[{"type":"string","minLength":1,"maxLength":12,"pattern":"^[A-Za-z0-9 \\-]{1,12}$"},{"type":"null"}],"description":"Postal/ZIP code. Forwarded from x-vercel-ip-postal-code. Required for US Stripe Tax; without it the call is skipped and total_cents falls back to price_cents.","title":"Postal Code"},"description":"Postal/ZIP code. Forwarded from x-vercel-ip-postal-code. Required for US Stripe Tax; without it the call is skipped and total_cents falls back to price_cents."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductsResponse"},"examples":{"Catalogue":{"summary":"Catalogue","value":{"credit_packs":[{"price_id":"price_1QeXamplePack","name":"10 credits","credits":10,"price_cents":4900,"currency":"eur","subscriber_price_cents":3900,"tax_included":true,"tax_amount_cents":850,"total_cents":4900,"subscriber_total_cents":3900},{"price_id":"price_1QeXampleSingle","name":"1 credit","credits":1,"price_cents":900,"currency":"eur","subscriber_price_cents":null,"tax_included":true,"tax_amount_cents":156,"total_cents":900,"subscriber_total_cents":null}],"subscriptions":[{"price_id":"price_1QeXampleMonthly","name":"Refine Monthly","credits":20,"price_cents":2900,"currency":"eur","interval":"month","tax_included":true,"tax_amount_cents":503,"total_cents":2900}]}}}}}},"422":{"$ref":"#/components/responses/ProblemUnprocessable"},"500":{"$ref":"#/components/responses/ProblemInternalServerErrorUnexpectedFailure"},"502":{"$ref":"#/components/responses/ProblemBadGatewayPaymentSystem"}}}},"/documents/upload":{"post":{"tags":["documents"],"summary":"Upload and convert a document","description":"Upload a document file, start async conversion, and return task_id for SSE progress. When the SSE 'complete' event arrives, forward `result.previous_session_id` (if set) to `POST /documents/{document_id}/process` to run the review with the prior session as context.","operationId":"documents_uploadDocument","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/DocumentUploadForm"}}},"required":true},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentUploadResponse"},"examples":{"Main document":{"summary":"Main document","value":{"task_id":"a1c4f9e2-6d70-4b83-91ac-5f2e8d0b7c31","filename":"manuscript.pdf","format":"pdf","parent_document_id":null}},"Supplementary material":{"summary":"Supplementary material","value":{"task_id":"b2d5a0f3-7e81-4c94-a2bd-6a3f9e1c8d42","filename":"appendix.docx","format":"docx","parent_document_id":"3eef6ca5-9388-45b4-92a8-c144347ad6ec"}}}}}},"422":{"$ref":"#/components/responses/ProblemUnprocessable"},"500":{"$ref":"#/components/responses/ProblemInternalServerErrorOriginalUploadStorage"},"400":{"$ref":"#/components/responses/ProblemBadRequestInvalidUploadedFileMalformedDocumentIdMissingFilenameNestedSupplementaryMaterialSupplementaryMaterialLimitReached"},"401":{"$ref":"#/components/responses/ProblemUnauthenticated"},"403":{"$ref":"#/components/responses/ProblemForbiddenParentDocumentNotOwned"},"404":{"$ref":"#/components/responses/ProblemNotFoundAuthenticatedUserNotFoundParentDocumentNotFound"}},"security":[{"HTTPBearer":[]}]}},"/documents/upload/events/{task_id}":{"get":{"tags":["documents"],"summary":"SSE endpoint for upload progress","description":"Server-Sent Events stream for document upload progress updates. Authentication is via query parameter `token` (not Bearer header) because EventSource cannot set HTTP headers.","operationId":"documents_uploadEvents","parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string","title":"Task Id"}},{"name":"token","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Authentication token","title":"Token"},"description":"Authentication token"}],"responses":{"200":{"description":"SSE stream of upload progress events","content":{"text/event-stream":{"itemSchema":{"type":"object","properties":{"data":{"type":"string"},"event":{"type":"string"},"id":{"type":"string"},"retry":{"type":"integer","minimum":0}}},"schema":{"oneOf":[{"description":"SSE progress event. `stage` is null while a run is between mapped stages.","properties":{"type":{"const":"progress","description":"Event type","title":"Type","type":"string"},"value":{"description":"Progress percentage 0-100","title":"Value","type":"integer"},"stage":{"anyOf":[{"description":"Where a run currently is, at the granularity clients are given.","enum":["queued","uploading","converting","analyzing","reviewing","finalizing","complete"],"title":"ProgressStage","type":"string"},{"type":"null"}],"description":"Coarse stage the run is in"}},"required":["type","value"],"title":"SSEProgressEvent","type":"object"},{"description":"SSE completion event for upload.","properties":{"type":{"const":"complete","description":"Event type","title":"Type","type":"string"},"result":{"description":"Result for document upload completion.","properties":{"document_id":{"description":"UUID of the uploaded document","title":"Document Id","type":"string"},"filename":{"description":"Original filename","title":"Filename","type":"string"},"format":{"description":"Document format (PDF, DOCX, etc.)","title":"Format","type":"string"},"content_url":{"description":"URL to fetch converted markdown content","title":"Content Url","type":"string"},"original_url":{"description":"URL to fetch original file","title":"Original Url","type":"string"},"word_count":{"description":"Word count of the converted document","title":"Word Count","type":"integer"},"parent_document_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"UUID of parent document if this is an supplementary material","title":"Parent Document Id"},"previous_session_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"UUID of a prior session this upload looks like a revision of, or null if no match was found. Forward to `POST /documents/{document_id}/process` as `previous_session_id` to run the new review with the prior session as context.","title":"Previous Session Id"}},"required":["document_id","filename","format","content_url","original_url","word_count"],"title":"UploadCompleteResult","type":"object"}},"required":["type","result"],"title":"SSEUploadCompleteEvent","type":"object"},{"description":"SSE error event — the same three members the chat stream and HTTP send.","properties":{"type":{"const":"error","description":"Event type","title":"Type","type":"string"},"error":{"description":"Stable human-readable title; does not vary per occurrence","title":"Error","type":"string"},"error_type":{"description":"Stable RFC 9457 type slug identifying the failure","title":"Error Type","type":"string"},"details":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"description":"Error-specific extension members","title":"Details"}},"required":["type","error","error_type"],"title":"SSEErrorEvent","type":"object"}],"discriminator":{"propertyName":"type"}}}}},"422":{"$ref":"#/components/responses/ProblemUnprocessable"},"500":{"$ref":"#/components/responses/ProblemInternalServerErrorAuthenticationConfigurationAuthenticationFailedUnexpectedFailure"},"401":{"$ref":"#/components/responses/ProblemUnauthenticated"}},"security":[]}},"/documents/{document_id}/process/events/{session_id}":{"get":{"tags":["documents"],"summary":"SSE endpoint for document processing progress","description":"Server-Sent Events stream for document processing progress updates. Authentication is via query parameter `token` (not Bearer header) because EventSource cannot set HTTP headers.","operationId":"documents_processEvents","parameters":[{"name":"document_id","in":"path","required":true,"schema":{"type":"string","title":"Document Id"}},{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}},{"name":"token","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Authentication token","title":"Token"},"description":"Authentication token"}],"responses":{"200":{"description":"SSE stream of processing events","content":{"text/event-stream":{"itemSchema":{"type":"object","properties":{"data":{"type":"string"},"event":{"type":"string"},"id":{"type":"string"},"retry":{"type":"integer","minimum":0}}},"schema":{"oneOf":[{"description":"SSE progress event. `stage` is null while a run is between mapped stages.","properties":{"type":{"const":"progress","description":"Event type","title":"Type","type":"string"},"value":{"description":"Progress percentage 0-100","title":"Value","type":"integer"},"stage":{"anyOf":[{"description":"Where a run currently is, at the granularity clients are given.","enum":["queued","uploading","converting","analyzing","reviewing","finalizing","complete"],"title":"ProgressStage","type":"string"},{"type":"null"}],"description":"Coarse stage the run is in"}},"required":["type","value"],"title":"SSEProgressEvent","type":"object"},{"description":"SSE completion event for processing.","properties":{"type":{"const":"complete","description":"Event type","title":"Type","type":"string"},"result":{"description":"Result for document processing completion.","properties":{"session_id":{"description":"UUID of the created history record","title":"Session Id","type":"string"},"preview_credits_remaining":{"description":"User's remaining preview credits","title":"Preview Credits Remaining","type":"integer"},"paid_credits_remaining":{"description":"User's remaining paid credits","title":"Paid Credits Remaining","type":"integer"},"comment_count":{"description":"Number of comments generated","title":"Comment Count","type":"integer"}},"required":["session_id","preview_credits_remaining","paid_credits_remaining","comment_count"],"title":"ProcessCompleteResult","type":"object"}},"required":["type","result"],"title":"SSEProcessCompleteEvent","type":"object"},{"description":"SSE error event — the same three members the chat stream and HTTP send.","properties":{"type":{"const":"error","description":"Event type","title":"Type","type":"string"},"error":{"description":"Stable human-readable title; does not vary per occurrence","title":"Error","type":"string"},"error_type":{"description":"Stable RFC 9457 type slug identifying the failure","title":"Error Type","type":"string"},"details":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"description":"Error-specific extension members","title":"Details"}},"required":["type","error","error_type"],"title":"SSEErrorEvent","type":"object"}],"discriminator":{"propertyName":"type"}}}}},"422":{"$ref":"#/components/responses/ProblemUnprocessable"},"500":{"$ref":"#/components/responses/ProblemInternalServerErrorAuthenticationConfigurationAuthenticationFailedUnexpectedFailure"},"401":{"$ref":"#/components/responses/ProblemUnauthenticated"}},"security":[]}},"/documents/{document_id}/process":{"post":{"tags":["documents"],"summary":"Start proofreading a document","description":"Start the proofreading analysis for an uploaded document. Consumes 1 credit (paid or preview). The document and all its supplementary materials must be fully converted first — wait for the upload SSE complete event at /documents/upload/events/{task_id}. The tier word limit applies to the combined word count of the document plus its supplementary materials.","operationId":"documents_processDocument","security":[{"HTTPBearer":[]}],"parameters":[{"name":"document_id","in":"path","required":true,"schema":{"type":"string","title":"Document Id"}},{"name":"X-POSTHOG-SESSION-ID","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Posthog-Session-Id"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProcessDocumentRequest","default":{"preview":false}},"examples":{"Full review":{"summary":"Full review","value":{"preview":false,"previous_session_id":null,"steering_prompt":null,"supplementary_material_steering":null,"customization":null}},"Preview review":{"summary":"Preview review","value":{"preview":true,"previous_session_id":null,"steering_prompt":null,"supplementary_material_steering":null,"customization":null}},"Revision of a prior session":{"summary":"Revision of a prior session","value":{"preview":false,"previous_session_id":"7ab7324d-0968-40ac-9a0d-68fe4fbf11bf","steering_prompt":"Focus on the statistics in section 4.","supplementary_material_steering":null,"customization":null}}}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProcessDocumentResponse"},"examples":{"Accepted":{"summary":"Accepted","value":{"session_id":"7ab7324d-0968-40ac-9a0d-68fe4fbf11bf","events_endpoint":"/documents/3eef6ca5-9388-45b4-92a8-c144347ad6ec/process/events/7ab7324d-0968-40ac-9a0d-68fe4fbf11bf"}}}}}},"422":{"$ref":"#/components/responses/ProblemUnprocessableDocumentTokenLimitDocumentWordLimitShortDocumentTextUnknownPromptSetUnknownSteeringTarget"},"500":{"$ref":"#/components/responses/ProblemInternalServerErrorProcessingJobNotCreated"},"400":{"$ref":"#/components/responses/ProblemBadRequestMalformedDocumentId"},"401":{"$ref":"#/components/responses/ProblemUnauthenticated"},"403":{"$ref":"#/components/responses/ProblemForbiddenDocumentNotAccessibleNoCreditsReviewCustomizationForbidden"},"404":{"$ref":"#/components/responses/ProblemNotFoundAuthenticatedUserNotFoundDocumentNotFoundDocumentTextNotReadyRevisionSessionNotAccessible"},"409":{"$ref":"#/components/responses/ProblemConflictSupplementaryMaterialNotReady"},"503":{"$ref":"#/components/responses/ProblemServiceUnavailableCreditServiceUnavailableProcessingDispatch"}}}},"/documents/{document_id}/content":{"get":{"tags":["documents"],"summary":"Get converted document text","description":"Return the converted Markdown text of a previously uploaded document. Use this to read or quote the source text after a successful upload — for example, before deciding whether to start proofreading, or to feed the text into another tool. Returns 404 while the document is still converting; if so, retry after a short wait.","operationId":"documents_getDocumentContent","security":[{"HTTPBearer":[]}],"parameters":[{"name":"document_id","in":"path","required":true,"schema":{"type":"string","title":"Document Id"}}],"responses":{"200":{"description":"The document's converted Markdown text.","content":{"text/markdown":{"schema":{"type":"string"}}}},"422":{"$ref":"#/components/responses/ProblemUnprocessable"},"500":{"$ref":"#/components/responses/ProblemInternalServerErrorAuthenticationConfigurationAuthenticationFailedUnexpectedFailure"},"400":{"$ref":"#/components/responses/ProblemBadRequestMalformedDocumentId"},"401":{"$ref":"#/components/responses/ProblemUnauthenticated"},"403":{"$ref":"#/components/responses/ProblemForbiddenDocumentNotAccessible"},"404":{"$ref":"#/components/responses/ProblemNotFoundDocumentNotFoundDocumentTextNotReady"}}}},"/documents/{document_id}/original":{"get":{"tags":["documents"],"summary":"Get original document","description":"Stream the original uploaded document file. The response carries the file's own `Content-Type` (`application/pdf`, a Word type, and so on) and its filename in `Content-Disposition`; read the body as bytes, not as JSON.","operationId":"documents_getOriginalDocument","security":[{"HTTPBearer":[]}],"parameters":[{"name":"document_id","in":"path","required":true,"schema":{"type":"string","title":"Document Id"}}],"responses":{"200":{"description":"The original uploaded file, served under its own stored content type.","content":{"application/octet-stream":{"schema":{"type":"string"}}}},"422":{"$ref":"#/components/responses/ProblemUnprocessable"},"500":{"$ref":"#/components/responses/ProblemInternalServerErrorAuthenticationConfigurationAuthenticationFailedUnexpectedFailure"},"400":{"$ref":"#/components/responses/ProblemBadRequestMalformedDocumentId"},"401":{"$ref":"#/components/responses/ProblemUnauthenticated"},"403":{"$ref":"#/components/responses/ProblemForbiddenDocumentNotAccessible"},"404":{"$ref":"#/components/responses/ProblemNotFoundDocumentNotFound"}}}},"/documents/{document_id}/images/{image_name}":{"get":{"tags":["documents"],"summary":"Get document image","description":"Get an extracted image from a document. Authentication via query parameter `token` for <img> tag compatibility (cannot set HTTP headers).","operationId":"documents_getDocumentImage","parameters":[{"name":"document_id","in":"path","required":true,"schema":{"type":"string","title":"Document Id"}},{"name":"image_name","in":"path","required":true,"schema":{"type":"string","title":"Image Name"}},{"name":"token","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Authentication token","title":"Token"},"description":"Authentication token"}],"responses":{"200":{"description":"The extracted image, served under its own stored image content type.","content":{"application/octet-stream":{"schema":{"type":"string"}}}},"422":{"$ref":"#/components/responses/ProblemUnprocessable"},"500":{"$ref":"#/components/responses/ProblemInternalServerErrorAuthenticationConfigurationAuthenticationFailedUnexpectedFailure"},"400":{"$ref":"#/components/responses/ProblemBadRequestInvalidImageRequestMalformedDocumentId"},"401":{"$ref":"#/components/responses/ProblemUnauthenticated"},"403":{"$ref":"#/components/responses/ProblemForbiddenDocumentNotAccessible"},"404":{"$ref":"#/components/responses/ProblemNotFoundImageNotFound"}},"security":[]}},"/documents/{document_id}":{"delete":{"tags":["documents"],"summary":"Delete a document","description":"Delete a document and its blob storage. If the document is a main document, its supplementary material (DB rows and blob folders) are deleted too.","operationId":"documents_deleteDocument","security":[{"HTTPBearer":[]}],"parameters":[{"name":"document_id","in":"path","required":true,"schema":{"type":"string","title":"Document Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"$ref":"#/components/responses/ProblemUnprocessable"},"500":{"$ref":"#/components/responses/ProblemInternalServerErrorAuthenticationConfigurationAuthenticationFailedUnexpectedFailure"},"400":{"$ref":"#/components/responses/ProblemBadRequestMalformedDocumentId"},"401":{"$ref":"#/components/responses/ProblemUnauthenticated"},"404":{"$ref":"#/components/responses/ProblemNotFoundDocumentNotFound"}}}},"/documents/{document_id}/supplementary-material":{"get":{"tags":["documents"],"summary":"List supplementary material for a document","description":"Get the list of supplementary material documents attached to a main document, ordered by display_order.","operationId":"documents_getSupplementaryMaterial","security":[{"HTTPBearer":[]}],"parameters":[{"name":"document_id","in":"path","required":true,"schema":{"type":"string","title":"Document Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SupplementaryMaterialResponse"},"title":"Response Documents Getsupplementarymaterial"},"examples":{"Appendix":{"summary":"Appendix","value":[{"document_id":"b2d5a0f3-7e81-4c94-a2bd-6a3f9e1c8d42","filename":"appendix.docx","display_order":1,"steering_note":"Reference tables for section 4."}]}}}}},"422":{"$ref":"#/components/responses/ProblemUnprocessable"},"500":{"$ref":"#/components/responses/ProblemInternalServerErrorAuthenticationConfigurationAuthenticationFailedUnexpectedFailure"},"400":{"$ref":"#/components/responses/ProblemBadRequestMalformedDocumentId"},"401":{"$ref":"#/components/responses/ProblemUnauthenticated"},"403":{"$ref":"#/components/responses/ProblemForbiddenDocumentNotAccessible"},"404":{"$ref":"#/components/responses/ProblemNotFoundDocumentNotFound"}}}},"/subscriptions/status":{"get":{"tags":["subscriptions"],"summary":"Get subscription status","description":"Get the current user's subscription status including tier, credits remaining, renewal date, and cancellation status.","operationId":"subscriptions_getStatus","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionStatusResponse"},"examples":{"Active":{"summary":"Active","value":{"has_active_subscription":true,"subscription_tier":"monthly","subscription_credits_remaining":14,"next_credit_renewal_at":"2026-08-12T00:00:00+00:00","stripe_subscription_id":"sub_1QeXampleActive","cancel_at_period_end":false,"current_period_ends_at":"2026-08-12T00:00:00+00:00","stripe_customer_id":"cus_QeXample123"}},"Cancelling at period end":{"summary":"Cancelling at period end","value":{"has_active_subscription":true,"subscription_tier":"monthly","subscription_credits_remaining":6,"next_credit_renewal_at":null,"stripe_subscription_id":"sub_1QeXampleActive","cancel_at_period_end":true,"current_period_ends_at":"2026-08-12T00:00:00+00:00","stripe_customer_id":"cus_QeXample123"}},"No subscription":{"summary":"No subscription","value":{"has_active_subscription":false,"subscription_tier":null,"subscription_credits_remaining":null,"next_credit_renewal_at":null,"stripe_subscription_id":null,"cancel_at_period_end":null,"current_period_ends_at":null,"stripe_customer_id":null}}}}}},"500":{"$ref":"#/components/responses/ProblemInternalServerErrorAuthenticationConfigurationAuthenticationFailedUnexpectedFailure"},"401":{"$ref":"#/components/responses/ProblemUnauthenticated"}},"security":[{"HTTPBearer":[]}]}},"/subscriptions/upgrade":{"post":{"tags":["subscriptions"],"summary":"Create upgrade checkout session","description":"Create a Stripe checkout session for upgrading to a higher subscription plan. Returns a checkout URL for browser redirect.","operationId":"subscriptions_createUpgradeCheckoutSession","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpgradeSubscriptionRequest"},"examples":{"Upgrade to annual":{"summary":"Upgrade to annual","value":{"new_price_id":"price_1QeXampleAnnual","success_url":"https://refine.ink/account/billing?upgraded=1","cancel_url":"https://refine.ink/account/billing"}}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpgradeSubscriptionResponse"},"examples":{"Checkout required":{"summary":"Checkout required","value":{"checkout_url":"https://checkout.stripe.com/c/pay/cs_test_upgrade123","session_id":"cs_test_upgrade123"}}}}}},"422":{"$ref":"#/components/responses/ProblemUnprocessable"},"500":{"$ref":"#/components/responses/ProblemInternalServerErrorAuthenticationConfigurationAuthenticationFailedUnexpectedFailure"},"400":{"$ref":"#/components/responses/ProblemBadRequestUnknownPrice"},"401":{"$ref":"#/components/responses/ProblemUnauthenticated"},"404":{"$ref":"#/components/responses/ProblemNotFoundNoSubscription"}},"security":[{"HTTPBearer":[]}]}},"/subscriptions/downgrade":{"post":{"tags":["subscriptions"],"summary":"Downgrade subscription","description":"Downgrade the current subscription to a lower plan. Takes effect at the next billing cycle.","operationId":"subscriptions_downgrade","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DowngradeSubscriptionRequest"},"examples":{"Downgrade to monthly":{"summary":"Downgrade to monthly","value":{"new_price_id":"price_1QeXampleMonthly"}}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DowngradeSubscriptionResponse"},"examples":{"Applied":{"summary":"Applied","value":{"new_plan_name":"Starter","effective_at":"2026-08-01T14:32:09+00:00"}}}}}},"422":{"$ref":"#/components/responses/ProblemUnprocessable"},"500":{"$ref":"#/components/responses/ProblemInternalServerErrorAuthenticationConfigurationAuthenticationFailedUnexpectedFailure"},"400":{"$ref":"#/components/responses/ProblemBadRequestUnknownPrice"},"401":{"$ref":"#/components/responses/ProblemUnauthenticated"},"404":{"$ref":"#/components/responses/ProblemNotFoundNoSubscription"}},"security":[{"HTTPBearer":[]}]}},"/subscriptions/cancel":{"post":{"tags":["subscriptions"],"summary":"Cancel subscription","description":"Cancel the current subscription. Takes effect at the end of the current billing period.","operationId":"subscriptions_cancel","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelSubscriptionResponse"},"examples":{"Cancelled at period end":{"summary":"Cancelled at period end","value":{"subscription":{"has_active_subscription":true,"subscription_tier":"monthly","subscription_credits_remaining":6,"next_credit_renewal_at":null,"stripe_subscription_id":"sub_1QeXampleActive","cancel_at_period_end":true,"current_period_ends_at":"2026-08-12T00:00:00+00:00","stripe_customer_id":"cus_QeXample123"}}}}}}},"500":{"$ref":"#/components/responses/ProblemInternalServerErrorAuthenticationConfigurationAuthenticationFailedUnexpectedFailure"},"401":{"$ref":"#/components/responses/ProblemUnauthenticated"},"404":{"$ref":"#/components/responses/ProblemNotFoundNoSubscription"}},"security":[{"HTTPBearer":[]}]}},"/organizations/{organization_id}/credits":{"get":{"tags":["organizations"],"summary":"Get organization credit balance","description":"Get the credit pool balance for an organization, including unallocated pool credits and per-user allocations. Requires organization membership.","operationId":"organizations_getCredits","security":[{"HTTPBearer":[]}],"parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","title":"Organization Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationCreditPoolResponse"},"examples":{"Partially allocated pool":{"summary":"Partially allocated pool","value":{"organization_id":"org_2fK9xLmQpR3sT","organization_name":"Example University Research Group","total_pool_credits":500,"user_allocations":{"researcher@example.edu":120,"author@example.edu":80},"total_allocated":200}}}}}},"422":{"$ref":"#/components/responses/ProblemUnprocessable"},"500":{"$ref":"#/components/responses/ProblemInternalServerErrorOrganizationCreditsUnavailable"},"401":{"$ref":"#/components/responses/ProblemUnauthenticated"},"403":{"$ref":"#/components/responses/ProblemForbiddenOrganizationPermission"},"404":{"$ref":"#/components/responses/ProblemNotFoundOrganizationMissing"}}}},"/organizations/{organization_id}/credits/consumption":{"get":{"tags":["organizations"],"summary":"Get organization credit consumption","description":"Get credit consumption data for an organization. Shows how credits have been used across members.","operationId":"organizations_getConsumption","security":[{"HTTPBearer":[]}],"parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","title":"Organization Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationConsumptionResponse"},"examples":{"One active member":{"summary":"One active member","value":{"users":[{"user_email":"researcher@example.edu","events":[{"occurred_at":"2026-07-28T09:14:02+00:00","credit_type":"paid","session_id":"8f1d9c44-2b70-4f0e-9a2f-6d1c53e0b7aa","amount":1}],"total_consumed":1}],"organization_total":1}}}}}},"422":{"$ref":"#/components/responses/ProblemUnprocessable"},"500":{"$ref":"#/components/responses/ProblemInternalServerErrorOrganizationCreditsUnavailable"},"401":{"$ref":"#/components/responses/ProblemUnauthenticated"},"403":{"$ref":"#/components/responses/ProblemForbiddenOrganizationPermission"}}}},"/organizations/{organization_id}/credits/allocate":{"post":{"tags":["organizations"],"summary":"Allocate credits to organization member","description":"Move credits from the organization pool to a specific member. Requires admin or billing admin role.","operationId":"organizations_allocateCreditsToUser","security":[{"HTTPBearer":[]}],"parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","title":"Organization Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AllocateCreditsRequest"},"examples":{"Allocate 50":{"summary":"Allocate 50","value":{"user_email":"researcher@example.edu","amount":50}}}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AllocateCreditsResponse"},"examples":{"Allocated":{"summary":"Allocated","value":{"organization_id":"org_2fK9xLmQpR3sT","user_email":"researcher@example.edu","new_user_balance":170,"pool_remaining":250}}}}}},"422":{"$ref":"#/components/responses/ProblemUnprocessable"},"500":{"$ref":"#/components/responses/ProblemInternalServerErrorAuthenticationConfigurationAuthenticationFailedUnexpectedFailure"},"400":{"$ref":"#/components/responses/ProblemBadRequestAllocationTargetNotAMemberCreditAllocationFailedOrganizationPoolExhausted"},"401":{"$ref":"#/components/responses/ProblemUnauthenticated"},"403":{"$ref":"#/components/responses/ProblemForbiddenOrganizationPermission"}}}},"/organizations/{organization_id}/credits/deallocate":{"post":{"tags":["organizations"],"summary":"Return member credits to organization pool","description":"Move credits from a member back to the organization pool. Requires admin or billing admin role.","operationId":"organizations_deallocateCreditsFromUser","security":[{"HTTPBearer":[]}],"parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","title":"Organization Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeallocateCreditsRequest"},"examples":{"Reclaim 20":{"summary":"Reclaim 20","value":{"user_email":"researcher@example.edu","amount":20}}}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeallocateCreditsResponse"},"examples":{"Reclaimed":{"summary":"Reclaimed","value":{"organization_id":"org_2fK9xLmQpR3sT","user_email":"researcher@example.edu","new_user_balance":150,"pool_total":500}}}}}},"422":{"$ref":"#/components/responses/ProblemUnprocessable"},"500":{"$ref":"#/components/responses/ProblemInternalServerErrorAuthenticationConfigurationAuthenticationFailedUnexpectedFailure"},"400":{"$ref":"#/components/responses/ProblemBadRequestAllocationTargetNotAMemberCreditAllocationFailed"},"401":{"$ref":"#/components/responses/ProblemUnauthenticated"},"403":{"$ref":"#/components/responses/ProblemForbiddenOrganizationPermission"}}}},"/organizations/{organization_id}/credits/request":{"post":{"tags":["organizations"],"summary":"Request more credits from organization admins","description":"Member-initiated request for more credits. Emits an event consumed by a PostHog workflow that notifies the org's admin(s). Does not allocate credits.","operationId":"organizations_requestOrganizationCredits","security":[{"HTTPBearer":[]}],"parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"string","title":"Organization Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationCreditsRequest"},"examples":{"With justification":{"summary":"With justification","value":{"message":"We are onboarding four new PhD students this term."}},"Without a message":{"summary":"Without a message","value":{"message":null}}}}}},"responses":{"202":{"description":"Successful Response"},"422":{"$ref":"#/components/responses/ProblemUnprocessable"},"500":{"$ref":"#/components/responses/ProblemInternalServerErrorAuthenticationConfigurationAuthenticationFailedUnexpectedFailure"},"401":{"$ref":"#/components/responses/ProblemUnauthenticated"},"403":{"$ref":"#/components/responses/ProblemForbiddenOrganizationMembershipRequired"},"404":{"$ref":"#/components/responses/ProblemNotFoundOrganizationMissing"}}}},"/processing":{"get":{"tags":["processing"],"summary":"Check initial processing state","description":"Check if the user has any active proofreading tasks or unviewed results. Use this once on app load to detect in-progress work — do NOT poll this endpoint in a loop. To track progress of a specific task, use the SSE endpoint at /documents/{document_id}/process/events/{session_id} or the watch_processing_progress MCP tool.","operationId":"processing_getProcessingStatus","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProcessingStatusResponse"},"examples":{"Nothing in flight":{"summary":"Nothing in flight","value":{"processing":[],"unviewed_completed":null}},"Active task":{"summary":"Active task","value":{"processing":[{"session_id":"c9b1f6d2-4a83-4f21-9c07-2e5b8a1d3f40","document_id":"3eef6ca5-9388-45b4-92a8-c144347ad6ec","title":"Targeting Interventions in Networks","progress_percentage":45,"created_at":"2026-07-24T12:45:39.418365+00:00"}],"unviewed_completed":null}},"Unviewed result waiting":{"summary":"Unviewed result waiting","value":{"processing":[],"unviewed_completed":{"session_id":"7ab7324d-0968-40ac-9a0d-68fe4fbf11bf","document_id":"3eef6ca5-9388-45b4-92a8-c144347ad6ec","title":"Targeting Interventions in Networks","created_at":"2026-07-24T12:45:39.418365+00:00"}}}}}}},"500":{"$ref":"#/components/responses/ProblemInternalServerErrorAuthenticationConfigurationAuthenticationFailedUnexpectedFailure"},"401":{"$ref":"#/components/responses/ProblemUnauthenticated"}},"security":[{"HTTPBearer":[]}]}},"/marketing/preferences":{"get":{"tags":["marketing"],"summary":"Get marketing email opt-in state","description":"Return the authenticated user's current opt-in state.\n\nCQRS read — direct repository call, no use case. The JWT guarantees the\nuser exists; a missing row at this point indicates a Clerk-vs-DB drift\nbug and surfaces as 404.","operationId":"marketing_getMarketingPreferences","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarketingPreferencesResponse"},"examples":{"Opted in":{"summary":"Opted in","value":{"opt_in":true,"updated_at":"2026-07-20T08:30:00+00:00"}},"Never set":{"summary":"Never set","value":{"opt_in":false,"updated_at":null}}}}}},"500":{"$ref":"#/components/responses/ProblemInternalServerErrorAuthenticationConfigurationAuthenticationFailedUnexpectedFailure"},"401":{"$ref":"#/components/responses/ProblemUnauthenticated"},"404":{"$ref":"#/components/responses/ProblemNotFoundAuthenticatedUserNotFound"}},"security":[{"HTTPBearer":[]}]},"put":{"tags":["marketing"],"summary":"Update marketing email opt-in state","description":"Update and return the authenticated user's opt-in state.\n\nReturns 404 if the JWT resolves to a user we don't have a row for\n(Clerk-vs-DB drift). UNCHANGED and UPDATED both return the post-call\nstate so the frontend can show the latest timestamp.","operationId":"marketing_updateMarketingPreferences","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMarketingPreferencesRequest"},"examples":{"Opt in":{"summary":"Opt in","value":{"opt_in":true}},"Opt out":{"summary":"Opt out","value":{"opt_in":false}}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarketingPreferencesResponse"},"examples":{"Opted in":{"summary":"Opted in","value":{"opt_in":true,"updated_at":"2026-07-20T08:30:00+00:00"}},"Never set":{"summary":"Never set","value":{"opt_in":false,"updated_at":null}}}}}},"422":{"$ref":"#/components/responses/ProblemUnprocessable"},"500":{"$ref":"#/components/responses/ProblemInternalServerErrorMarketingStateUnavailable"},"401":{"$ref":"#/components/responses/ProblemUnauthenticated"},"404":{"$ref":"#/components/responses/ProblemNotFoundAuthenticatedUserNotFound"}},"security":[{"HTTPBearer":[]}]}}},"components":{"schemas":{"AllocateCreditsRequest":{"properties":{"user_email":{"type":"string","format":"email","title":"User Email","description":"Email of user to receive credits"},"amount":{"type":"integer","exclusiveMinimum":0.0,"title":"Amount","description":"Number of credits to allocate"}},"type":"object","required":["user_email","amount"],"title":"AllocateCreditsRequest","description":"Request to allocate credits from pool to user.","examples":[{"user_email":"researcher@example.edu","amount":50}]},"AllocateCreditsResponse":{"properties":{"organization_id":{"type":"string","title":"Organization Id","description":"ID of the organization"},"user_email":{"type":"string","title":"User Email","description":"Email of the user who received credits"},"new_user_balance":{"type":"integer","title":"New User Balance","description":"User's new credit balance"},"pool_remaining":{"type":"integer","title":"Pool Remaining","description":"Remaining credits in the organization pool"}},"type":"object","required":["organization_id","user_email","new_user_balance","pool_remaining"],"title":"AllocateCreditsResponse","description":"Response for credit allocation.","examples":[{"organization_id":"org_2fK9xLmQpR3sT","user_email":"researcher@example.edu","new_user_balance":170,"pool_remaining":250}]},"AssistantChatMessage":{"properties":{"role":{"type":"string","const":"assistant","title":"Role","description":"Always 'assistant'"},"content":{"type":"string","title":"Content"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When the message was stored"},"turn_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Turn Id","description":"Router-assigned turn identifier (uuid4); always present for newly-stored assistant messages"}},"type":"object","required":["role","content","created_at"],"title":"AssistantChatMessage","description":"An assistant message in conversation history."},"CancelSubscriptionResponse":{"properties":{"subscription":{"anyOf":[{"$ref":"#/components/schemas/SubscriptionStatusResponse"},{"type":"null"}],"description":"Updated subscription status after cancellation; `cancel_at_period_end` and `current_period_ends_at` say when access lapses"}},"type":"object","title":"CancelSubscriptionResponse","description":"Response schema for subscription cancellation.\n\nNote: Errors are returned as HTTP exceptions, not in the response body.\nA 200 response always indicates success.","examples":[{"subscription":{"has_active_subscription":true,"subscription_tier":"monthly","subscription_credits_remaining":6,"next_credit_renewal_at":null,"stripe_subscription_id":"sub_1QeXampleActive","cancel_at_period_end":true,"current_period_ends_at":"2026-08-12T00:00:00+00:00","stripe_customer_id":"cus_QeXample123"}}]},"ChatMessageRequest":{"properties":{"message":{"type":"string","maxLength":4000,"minLength":1,"title":"Message","description":"User's message"},"comment_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Comment Id","description":"Optional: Focus on specific comment ID, or 'overall' for overall feedback"}},"type":"object","required":["message"],"title":"ChatMessageRequest","description":"Request body for sending a chatbot message.","examples":[{"message":"Why is this phrasing a problem?","comment_id":"1792a726-5a83-4d20-ad59-0cf0f72c7faf"},{"message":"What should I prioritise fixing first?","comment_id":null}]},"CommentActionItem":{"properties":{"id":{"type":"string","title":"Id","description":"UUID of the action"},"session_id":{"type":"string","title":"Session Id","description":"UUID of the history session the comment belongs to"},"comment_id":{"type":"string","title":"Comment Id","description":"ID of the comment"},"user_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Email","description":"Email of the user who took the action"},"action_type":{"type":"string","title":"Action Type","description":"Type of action (dismissed or addressed)"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When the action was taken"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes","description":"Optional notes for the action"}},"type":"object","required":["id","session_id","comment_id","user_email","action_type","created_at","notes"],"title":"CommentActionItem","description":"A comment action record.","examples":[{"id":"c2f7a1de-5b90-4f0c-9a11-6d3f2b8e4c07","session_id":"7ab7324d-0968-40ac-9a0d-68fe4fbf11bf","comment_id":"broad-2","user_email":"author@example.edu","action_type":"dismissed","created_at":"2026-07-24T12:59:06.387687+00:00","notes":null}]},"CommentSchema":{"properties":{"id":{"type":"string","title":"Id","description":"Unique comment identifier"},"title":{"type":"string","title":"Title","description":"Short title/category of the comment"},"paragraph":{"type":"string","title":"Paragraph","description":"Original quote from document for context"},"message":{"type":"string","title":"Message","description":"The actual feedback/suggestion"},"quote":{"type":"string","title":"Quote","description":"Matched source text for highlighting; empty string when no exact match was found in the source document","default":""},"score":{"type":"number","title":"Score","description":"Final product score (0-1 geometric mean)"},"is_dismissed":{"type":"boolean","title":"Is Dismissed","description":"Whether comment is dismissed","default":false},"is_addressed":{"type":"boolean","title":"Is Addressed","description":"Whether comment is addressed","default":false},"types":{"items":{"$ref":"#/components/schemas/CommentType"},"type":"array","title":"Types","description":"Comment categories (closed public vocabulary). 'general' = segment-level review comment, 'broad' = document-level comment, 'external_references' = citation verification. A comment merged from several categories carries all of them."}},"type":"object","required":["id","title","paragraph","message","score"],"title":"CommentSchema","description":"Schema for a single comment in feedback_detailed.\n\nOnly includes public API fields. Internal pipeline fields\n(reasoning, case, scores, etc.) are stored in DB but stripped here."},"CommentType":{"type":"string","enum":["general","broad","external_references","prior_art","writing"],"title":"CommentType"},"ConsolidationShardingMode":{"type":"string","enum":["off","modular"],"title":"ConsolidationShardingMode","description":"How Stage 4.5 (consolidation) partitions its LLM work.\n\n* ``off`` — today's monolithic call: one LLM pass over the full document\n  plus every surviving comment.\n* ``modular`` — rank-based k-nearest-neighbor candidate edges over comment\n  embeddings kept as pairs, judged in batches by a pairwise-verification\n  LLM, resolved into groups by a deterministic correlation-clustering\n  pivot, then one merge call per multi-member group.\n\n``None`` on ``ReviewCustomization`` defers to the boolean\n``modular_consolidation`` PostHog flag (on -> ``modular``, off ->\n``off``); an explicit value forces the mode for this run in both\ndirections (it can force ``modular`` while the flag is off, or force\n``off`` while the flag is on)."},"ConversationHistoryResponse":{"properties":{"conversation_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Conversation Id"},"messages":{"items":{"oneOf":[{"$ref":"#/components/schemas/UserChatMessage"},{"$ref":"#/components/schemas/AssistantChatMessage"}],"discriminator":{"propertyName":"role","mapping":{"assistant":"#/components/schemas/AssistantChatMessage","user":"#/components/schemas/UserChatMessage"}}},"type":"array","title":"Messages","default":[]},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At"},"last_message_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Message At"}},"type":"object","title":"ConversationHistoryResponse","description":"Response for GET conversation history.","examples":[{"conversation_id":"c9b1f6d2-4a83-4f21-9c07-2e5b8a1d3f40","messages":[{"role":"user","content":"Why is this phrasing a problem?","comment_id":"1792a726-5a83-4d20-ad59-0cf0f72c7faf","created_at":"2026-07-24T13:02:11.412000+00:00"},{"role":"assistant","content":"The claim is stated without the condition it depends on, so a reader cannot tell when it holds.","created_at":"2026-07-24T13:02:14.887000+00:00","turn_id":"turn_2fK9xLmQ"}],"created_at":"2026-07-24T13:02:11.412000+00:00","last_message_at":"2026-07-24T13:02:14.887000+00:00"},{"conversation_id":null,"messages":[],"created_at":null,"last_message_at":null}]},"CreditConsumptionEventResponse":{"properties":{"occurred_at":{"type":"string","format":"date-time","title":"Occurred At","description":"When the credit was consumed"},"credit_type":{"type":"string","title":"Credit Type","description":"Which balance the credit came from: 'paid' or 'preview'"},"session_id":{"type":"string","title":"Session Id","description":"UUID of the review the credit was spent on"},"amount":{"type":"integer","title":"Amount","description":"Number of credits consumed"}},"type":"object","required":["occurred_at","credit_type","session_id","amount"],"title":"CreditConsumptionEventResponse","description":"One credit spend, as published."},"CreditPackProduct":{"properties":{"price_id":{"type":"string","title":"Price Id"},"name":{"type":"string","title":"Name"},"credits":{"type":"integer","title":"Credits"},"price_cents":{"type":"integer","title":"Price Cents"},"currency":{"type":"string","title":"Currency"},"subscriber_price_cents":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Subscriber Price Cents"},"tax_included":{"type":"boolean","title":"Tax Included","default":false},"tax_amount_cents":{"type":"integer","title":"Tax Amount Cents","default":0},"total_cents":{"type":"integer","title":"Total Cents","default":0},"subscriber_total_cents":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Subscriber Total Cents"}},"type":"object","required":["price_id","name","credits","price_cents","currency"],"title":"CreditPackProduct","description":"One-time credit pack purchase."},"CreditScoreResponse":{"properties":{"paid_credits_remaining":{"type":"integer","title":"Paid Credits Remaining","description":"Number of paid credits remaining"},"preview_credits_remaining":{"type":"integer","title":"Preview Credits Remaining","description":"Number of preview/free credits remaining"},"user_has_paid_credits":{"type":"boolean","title":"User Has Paid Credits","description":"Whether user has any paid credits"},"user_email":{"type":"string","title":"User Email","description":"Email of the user"},"credit_source":{"type":"string","title":"Credit Source","description":"Source of credits: 'personal' or 'organization'"},"tier":{"$ref":"#/components/schemas/DocumentWordTier","description":"User's tier (default | extended | unlimited); FE shows plan name and uses it as the basis for all the max_* limits below"},"max_document_words":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Document Words","description":"Max words per document, null=unlimited"},"max_file_size_mb":{"type":"integer","title":"Max File Size Mb","description":"Max file size in MB for upload"},"max_supplementary_material":{"type":"integer","title":"Max Supplementary Material","description":"Max supplementary material documents attachable to a main document"},"chatbot_quota":{"$ref":"#/components/schemas/QuotaStatus","description":"Current chatbot usage over the rolling 24h window; used_fraction=0.0 if the user has no messages in the window (or cache is unavailable, fail-open). resets_at is the moment the oldest counted message ages out (now + remaining TTL), not a fixed clock time."}},"type":"object","required":["paid_credits_remaining","preview_credits_remaining","user_has_paid_credits","user_email","credit_source","tier","max_document_words","max_file_size_mb","max_supplementary_material","chatbot_quota"],"title":"CreditScoreResponse","description":"Response for credit score endpoint.","examples":[{"paid_credits_remaining":4,"preview_credits_remaining":1,"user_has_paid_credits":true,"user_email":"author@example.edu","credit_source":"personal","tier":"default","max_document_words":100000,"max_file_size_mb":50,"max_supplementary_material":3,"chatbot_quota":{"used_fraction":0.25,"resets_at":"2026-08-01T10:17:43.611699Z"}},{"paid_credits_remaining":250,"preview_credits_remaining":0,"user_has_paid_credits":true,"user_email":"researcher@example.edu","credit_source":"organization","tier":"unlimited","max_document_words":null,"max_file_size_mb":200,"max_supplementary_material":10,"chatbot_quota":{"used_fraction":0.25,"resets_at":"2026-08-01T10:17:43.611699Z"}},{"paid_credits_remaining":0,"preview_credits_remaining":0,"user_has_paid_credits":false,"user_email":"newcomer@example.edu","credit_source":"personal","tier":"default","max_document_words":100000,"max_file_size_mb":50,"max_supplementary_material":3,"chatbot_quota":{"used_fraction":0.0,"resets_at":"2026-08-01T10:17:43.611699Z"}}]},"DeallocateCreditsRequest":{"properties":{"user_email":{"type":"string","format":"email","title":"User Email","description":"Email of user to deallocate from"},"amount":{"type":"integer","exclusiveMinimum":0.0,"title":"Amount","description":"Number of credits to return to pool"}},"type":"object","required":["user_email","amount"],"title":"DeallocateCreditsRequest","description":"Request to return credits from user to pool.","examples":[{"user_email":"researcher@example.edu","amount":20}]},"DeallocateCreditsResponse":{"properties":{"organization_id":{"type":"string","title":"Organization Id","description":"ID of the organization"},"user_email":{"type":"string","title":"User Email","description":"Email of the user credits were returned from"},"new_user_balance":{"type":"integer","title":"New User Balance","description":"User's new credit balance"},"pool_total":{"type":"integer","title":"Pool Total","description":"New total credits in the organization pool"}},"type":"object","required":["organization_id","user_email","new_user_balance","pool_total"],"title":"DeallocateCreditsResponse","description":"Response for credit deallocation.","examples":[{"organization_id":"org_2fK9xLmQpR3sT","user_email":"researcher@example.edu","new_user_balance":150,"pool_total":500}]},"DocumentUploadResponse":{"properties":{"task_id":{"type":"string","title":"Task Id","description":"UUID for SSE progress tracking"},"filename":{"type":"string","title":"Filename","description":"Original filename"},"format":{"type":"string","title":"Format","description":"Document format (PDF, DOCX, etc.)"},"parent_document_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Parent Document Id","description":"UUID of parent document if this is an supplementary material"}},"type":"object","required":["task_id","filename","format"],"title":"DocumentUploadResponse","description":"Response from document upload (202 Accepted).\n\nThe document upload is processed asynchronously. Connect to the SSE\nendpoint at /documents/upload/events/{task_id} for progress updates.\nThe document_id will be available in the SSE 'complete' event.","examples":[{"task_id":"a1c4f9e2-6d70-4b83-91ac-5f2e8d0b7c31","filename":"manuscript.pdf","format":"pdf","parent_document_id":null},{"task_id":"b2d5a0f3-7e81-4c94-a2bd-6a3f9e1c8d42","filename":"appendix.docx","format":"docx","parent_document_id":"3eef6ca5-9388-45b4-92a8-c144347ad6ec"}]},"DocumentWordTier":{"type":"string","enum":["default","extended","unlimited"],"title":"DocumentWordTier","description":"Tier defining per-user document size limits.\n\nEach tier controls:\n- Maximum word count (primary, user-facing limit)\n- Maximum token count (secondary safety net, 4x word limit)\n- Maximum file size for upload"},"DowngradeSubscriptionRequest":{"properties":{"new_price_id":{"type":"string","minLength":1,"title":"New Price Id","description":"Stripe price ID for the new subscription tier"}},"type":"object","required":["new_price_id"],"title":"DowngradeSubscriptionRequest","description":"Request schema for downgrading a subscription.\n\nNote: subscription_id, user_email, plan names, and credits are derived\nfrom JWT, database lookup, and pricing configuration.","examples":[{"new_price_id":"price_1QeXampleMonthly"}]},"DowngradeSubscriptionResponse":{"properties":{"new_plan_name":{"type":"string","title":"New Plan Name","description":"The plan the subscription now sits on"},"effective_at":{"type":"string","format":"date-time","title":"Effective At","description":"When the downgrade takes effect"}},"type":"object","required":["new_plan_name","effective_at"],"title":"DowngradeSubscriptionResponse","description":"Response schema for subscription downgrade.\n\nNote: Errors are returned as HTTP exceptions, not in the response body.\nA 200 response always indicates success.","examples":[{"new_plan_name":"Starter","effective_at":"2026-08-01T14:32:09+00:00"}]},"FeedbackDetailed":{"properties":{"comments":{"items":{"$ref":"#/components/schemas/CommentSchema"},"type":"array","title":"Comments","description":"List of comments"},"comments_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Comments Count","description":"Number of comments"}},"type":"object","title":"FeedbackDetailed","description":"Detailed feedback with comments."},"FeedbackResponse":{"properties":{"overall":{"$ref":"#/components/schemas/OverallFeedbackSchema","description":"Structured overall feedback"},"detailed":{"$ref":"#/components/schemas/FeedbackDetailed","description":"Detailed feedback with comments"}},"type":"object","required":["overall","detailed"],"title":"FeedbackResponse","description":"Feedback container."},"HistoryListItem":{"properties":{"session_id":{"type":"string","title":"Session Id","description":"UUID of the history record"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When the record was created"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title","description":"Document title from metadata"},"summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Summary","description":"Document summary from metadata"},"domain":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Domain","description":"Domain classification"},"taxonomy":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Taxonomy","description":"Taxonomy classification"},"document_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Document Id","description":"UUID of uploaded document if any"},"original_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Original Url","description":"URL to original document"},"content_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content Url","description":"URL to processed content"},"comments_count":{"type":"integer","title":"Comments Count","description":"Total number of comments"},"addressed_count":{"type":"integer","title":"Addressed Count","description":"Number of addressed comments"},"dismissed_count":{"type":"integer","title":"Dismissed Count","description":"Number of dismissed comments"},"is_preview":{"type":"boolean","title":"Is Preview","description":"Whether processed in preview mode"},"is_public":{"type":"boolean","title":"Is Public","description":"Whether this session is publicly viewable"},"viewed":{"type":"boolean","title":"Viewed","description":"Whether the user has viewed this record"}},"type":"object","required":["session_id","created_at","title","summary","domain","taxonomy","comments_count","addressed_count","dismissed_count","is_preview","is_public","viewed"],"title":"HistoryListItem","description":"A single history item in the list.","examples":[{"session_id":"7ab7324d-0968-40ac-9a0d-68fe4fbf11bf","created_at":"2026-07-24T12:45:39.418365+00:00","title":"Targeting Interventions in Networks","summary":"Studies how a planner optimally targets interventions in a network game with strategic spillovers, decomposing interventions into principal components.","domain":"social_sciences/economics","taxonomy":"academic/research_paper","document_id":"3eef6ca5-9388-45b4-92a8-c144347ad6ec","original_url":"/documents/3eef6ca5-9388-45b4-92a8-c144347ad6ec/original","content_url":"/documents/3eef6ca5-9388-45b4-92a8-c144347ad6ec/content","comments_count":19,"addressed_count":2,"dismissed_count":1,"is_preview":false,"is_public":false,"viewed":true},{"session_id":"e681ed2d-b844-48d4-81d7-8d499813c157","created_at":"2026-07-24T12:45:39.418365+00:00","title":null,"summary":null,"domain":null,"taxonomy":null,"document_id":"ff12d34a-ba00-4943-b25e-c23f92e68295","original_url":"/documents/ff12d34a-ba00-4943-b25e-c23f92e68295/original","content_url":"/documents/ff12d34a-ba00-4943-b25e-c23f92e68295/content","comments_count":0,"addressed_count":0,"dismissed_count":0,"is_preview":false,"is_public":false,"viewed":true}]},"HistorySessionResponse":{"properties":{"session_id":{"type":"string","title":"Session Id","description":"UUID of the history record; also the identifier for SSE reconnection"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When the record was created"},"completed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Completed At","description":"When processing completed"},"user_email":{"type":"string","title":"User Email","description":"Email of the user who created the session"},"feedback":{"$ref":"#/components/schemas/FeedbackResponse","description":"Feedback data"},"progress_percentage":{"type":"integer","title":"Progress Percentage","description":"Progress percentage (0-100)"},"processing_status":{"type":"string","title":"Processing Status","description":"Processing status string"},"is_processing":{"type":"boolean","title":"Is Processing","description":"Whether processing is in progress"},"is_preview":{"type":"boolean","title":"Is Preview","description":"Whether processed in preview mode"},"comment_actions":{"items":{"$ref":"#/components/schemas/CommentActionItem"},"type":"array","title":"Comment Actions","description":"List of comment actions"},"comment_action_summary":{"additionalProperties":{"additionalProperties":{"type":"boolean"},"type":"object"},"type":"object","title":"Comment Action Summary","description":"Summary of actions per comment ID"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title","description":"Document title from metadata"},"summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Summary","description":"Document summary from metadata"},"domain":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Domain","description":"Domain classification"},"taxonomy":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Taxonomy","description":"Taxonomy classification"},"steering_prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Steering Prompt","description":"The user-provided steering prompt attached at submission, if any."},"document_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Document Id","description":"UUID of uploaded document if any"},"original_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Original Url","description":"URL to original document"},"content_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content Url","description":"URL to processed content"},"filename":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Filename","description":"Original filename of uploaded document"},"is_public":{"type":"boolean","title":"Is Public","description":"Whether this session is publicly viewable"},"is_owner":{"type":"boolean","title":"Is Owner","description":"Whether the current user owns this session"},"viewed":{"type":"boolean","title":"Viewed","description":"Whether the user has viewed this record"},"previous_session_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Previous Session Id","description":"UUID of the prior session this run is a revision of. Null when this session is not a resubmission."},"revision_check":{"anyOf":[{"$ref":"#/components/schemas/RevisionCheckResponse"},{"type":"null"}],"description":"Per-comment verdicts when this session is a resubmission and the revision-check pipeline produced verdicts. Null otherwise."}},"type":"object","required":["session_id","created_at","completed_at","user_email","feedback","progress_percentage","processing_status","is_processing","is_preview","comment_actions","comment_action_summary","title","summary","domain","taxonomy","is_public","is_owner","viewed"],"title":"HistorySessionResponse","description":"Full history session response.","examples":[{"session_id":"7ab7324d-0968-40ac-9a0d-68fe4fbf11bf","created_at":"2026-07-24T12:45:39.418365+00:00","completed_at":"2026-07-24T12:59:06.387687+00:00","user_email":"author@example.edu","feedback":{"overall":{"id":"overall-feedback","content":"**Scope of the benchmark assumptions**\n\nThe abstract frames the analysis more broadly than the core results support: the headline claims rely on the quadratic cost specification. Delimiting which claims belong to that benchmark would help the reader place the contribution."},"detailed":{"comments":[{"id":"1792a726-5a83-4d20-ad59-0cf0f72c7faf","title":"Large-budget claim is stated more strongly than shown","paragraph":"The intervention raises welfare for large budgets, which follows directly from the spectral decomposition of the network.","message":"The one-principal-component limit holds for the complements case, not for every environment. Qualify the claim, or state the condition it depends on.","quote":"The intervention raises welfare for large budgets, which follows directly from the spectral decomposition of the network.","score":0.34,"is_dismissed":false,"is_addressed":false,"types":["general"]},{"id":"broad-2","title":"Citation does not support the attributed result","paragraph":"As shown by Kingma and Ba (2015), adaptive methods converge on convex objectives.","message":"The cited work introduces the optimiser but does not prove this convergence result. Attribute the claim to its actual source or soften it.","quote":"As shown by Kingma and Ba (2015), adaptive methods converge on convex objectives.","score":0.71,"is_dismissed":false,"is_addressed":false,"types":["external_references"]}],"comments_count":2}},"progress_percentage":100,"processing_status":"completed","is_processing":false,"is_preview":false,"comment_actions":[],"comment_action_summary":{},"title":"Targeting Interventions in Networks","summary":"Studies how a planner optimally targets interventions in a network game with strategic spillovers.","domain":"social_sciences/economics","taxonomy":"academic/research_paper","steering_prompt":null,"document_id":"3eef6ca5-9388-45b4-92a8-c144347ad6ec","original_url":"/documents/3eef6ca5-9388-45b4-92a8-c144347ad6ec/original","content_url":"/documents/3eef6ca5-9388-45b4-92a8-c144347ad6ec/content","filename":"manuscript.pdf","is_public":false,"is_owner":true,"viewed":true,"previous_session_id":null,"revision_check":null},{"session_id":"7ab7324d-0968-40ac-9a0d-68fe4fbf11bf","created_at":"2026-07-24T12:45:39.418365+00:00","completed_at":"2026-07-24T12:59:06.387687+00:00","user_email":"author@example.edu","feedback":{"overall":{"id":"overall-feedback","content":"**Scope of the benchmark assumptions**\n\nThe abstract frames the analysis more broadly than the core results support: the headline claims rely on the quadratic cost specification. Delimiting which claims belong to that benchmark would help the reader place the contribution."},"detailed":{"comments":[{"id":"1792a726-5a83-4d20-ad59-0cf0f72c7faf","title":"Large-budget claim is stated more strongly than shown","paragraph":"The intervention raises welfare for large budgets, which follows directly from the spectral decomposition of the network.","message":"The one-principal-component limit holds for the complements case, not for every environment. Qualify the claim, or state the condition it depends on.","quote":"The intervention raises welfare for large budgets, which follows directly from the spectral decomposition of the network.","score":0.34,"is_dismissed":false,"is_addressed":false,"types":["general"]},{"id":"broad-2","title":"Citation does not support the attributed result","paragraph":"As shown by Kingma and Ba (2015), adaptive methods converge on convex objectives.","message":"The cited work introduces the optimiser but does not prove this convergence result. Attribute the claim to its actual source or soften it.","quote":"As shown by Kingma and Ba (2015), adaptive methods converge on convex objectives.","score":0.71,"is_dismissed":false,"is_addressed":false,"types":["external_references"]}],"comments_count":2}},"progress_percentage":100,"processing_status":"completed","is_processing":false,"is_preview":true,"comment_actions":[],"comment_action_summary":{},"title":"Targeting Interventions in Networks","summary":"Studies how a planner optimally targets interventions in a network game with strategic spillovers.","domain":"social_sciences/economics","taxonomy":"academic/research_paper","steering_prompt":null,"document_id":"3eef6ca5-9388-45b4-92a8-c144347ad6ec","original_url":"/documents/3eef6ca5-9388-45b4-92a8-c144347ad6ec/original","content_url":"/documents/3eef6ca5-9388-45b4-92a8-c144347ad6ec/content","filename":"manuscript.pdf","is_public":false,"is_owner":true,"viewed":false,"previous_session_id":null,"revision_check":null},{"session_id":"7ab7324d-0968-40ac-9a0d-68fe4fbf11bf","created_at":"2026-07-24T12:45:39.418365+00:00","completed_at":null,"user_email":"author@example.edu","feedback":{"overall":{"id":"overall-feedback","content":""},"detailed":{"comments":[],"comments_count":0}},"progress_percentage":45,"processing_status":"processing","is_processing":true,"is_preview":false,"comment_actions":[],"comment_action_summary":{},"title":null,"summary":null,"domain":null,"taxonomy":null,"steering_prompt":null,"document_id":"3eef6ca5-9388-45b4-92a8-c144347ad6ec","original_url":"/documents/3eef6ca5-9388-45b4-92a8-c144347ad6ec/original","content_url":"/documents/3eef6ca5-9388-45b4-92a8-c144347ad6ec/content","filename":"manuscript.pdf","is_public":false,"is_owner":true,"viewed":false,"previous_session_id":null,"revision_check":null}]},"MarkViewedResponse":{"properties":{"session_id":{"type":"string","title":"Session Id","description":"UUID of the history record that was marked"},"user_email":{"type":"string","title":"User Email","description":"Email of the user"}},"type":"object","required":["session_id","user_email"],"title":"MarkViewedResponse","description":"Response for mark-viewed action.","examples":[{"session_id":"7ab7324d-0968-40ac-9a0d-68fe4fbf11bf","user_email":"author@example.edu"}]},"MarketingPreferencesResponse":{"properties":{"opt_in":{"type":"boolean","title":"Opt In","description":"True if the user is opted in to marketing email."},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Updated At","description":"When the value was last changed. Null if never touched (default opt-out)."}},"type":"object","required":["opt_in"],"title":"MarketingPreferencesResponse","description":"Current marketing email opt-in state for the authenticated user.","examples":[{"opt_in":true,"updated_at":"2026-07-20T08:30:00+00:00"},{"opt_in":false,"updated_at":null}]},"OrganizationConsumptionResponse":{"properties":{"users":{"items":{"$ref":"#/components/schemas/UserConsumptionResponse"},"type":"array","title":"Users","description":"Per-member consumption, highest first"},"organization_total":{"type":"integer","title":"Organization Total","description":"Credits the organization consumed in the window"}},"type":"object","required":["users","organization_total"],"title":"OrganizationConsumptionResponse","description":"Credit consumption across an organization's members.","examples":[{"users":[{"user_email":"researcher@example.edu","events":[{"occurred_at":"2026-07-28T09:14:02+00:00","credit_type":"paid","session_id":"8f1d9c44-2b70-4f0e-9a2f-6d1c53e0b7aa","amount":1}],"total_consumed":1}],"organization_total":1}]},"OrganizationCreditPoolResponse":{"properties":{"organization_id":{"type":"string","title":"Organization Id"},"organization_name":{"type":"string","title":"Organization Name"},"total_pool_credits":{"type":"integer","title":"Total Pool Credits","description":"Unallocated credits in pool"},"user_allocations":{"additionalProperties":{"type":"integer"},"type":"object","title":"User Allocations","description":"Per-user allocated credits"},"total_allocated":{"type":"integer","title":"Total Allocated","description":"Sum of all user allocations"}},"type":"object","required":["organization_id","organization_name","total_pool_credits","user_allocations","total_allocated"],"title":"OrganizationCreditPoolResponse","description":"Response model for organization credit pool status.","examples":[{"organization_id":"org_2fK9xLmQpR3sT","organization_name":"Example University Research Group","total_pool_credits":500,"user_allocations":{"researcher@example.edu":120,"author@example.edu":80},"total_allocated":200}]},"OrganizationCreditsRequest":{"properties":{"message":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Message","description":"Optional note for the org admins"}},"type":"object","title":"OrganizationCreditsRequest","description":"Request body for a member-initiated credit request.","examples":[{"message":"We are onboarding four new PhD students this term."},{"message":null}]},"OverallFeedbackSchema":{"properties":{"id":{"type":"string","title":"Id","description":"Stable identifier for the overall feedback section"},"content":{"type":"string","title":"Content","description":"Overall feedback summary text"}},"type":"object","required":["id","content"],"title":"OverallFeedbackSchema","description":"Overall feedback with ID. Reasoning is internal and never exposed."},"Problem":{"properties":{"type":{"type":"string","title":"Type","description":"Stable slug identifying the error kind","enum":["admin-access-required","admin-user-not-found","allocation-target-not-a-member","api-key-scope","api-key-user-not-found","authenticated-user-not-found","authentication-configuration","authentication-failed","chat-daily-limit-reached","chat-generation-failed","checkout-session-not-found","comment-action-not-stored","comment-not-actionable","credit-adjustment-rejected","credit-allocation-failed","credit-service-unavailable","document-conversion","document-not-accessible","document-not-found","document-text-not-ready","document-token-limit","document-word-limit","empty-bulk-import","expired-token","image-not-found","incomplete-token","invalid-api-key","invalid-comment-action-type","invalid-image-request","invalid-uploaded-file","invalid-webhook-signature","malformed-document-id","malformed-referral-code","malformed-token","malformed-webhook-payload","marketing-state-unavailable","missing-credentials","missing-filename","missing-identifier","missing-webhook-signature","nested-supplementary-material","no-billing-history","no-credit-change-requested","no-credits","no-subscription","organization-credits-unavailable","organization-membership-required","organization-missing","organization-permission","organization-pool-exhausted","original-upload-storage","own-referral-code","parent-document-not-found","parent-document-not-owned","payment-system","pdf-service-unavailable","premature-token","processing-dispatch","processing-failed","processing-job-missing","processing-job-not-created","redirect-origin-mismatch","redirect-origin-required","referral-code-not-found","reprocess-refused","reprocess-user-missing","review-customization-forbidden","revision-session-not-accessible","session-already-accessible","session-missing","session-not-accessible","session-sharing-restricted","short-document-text","stream-connection","stream-not-yours","supplementary-material-limit-reached","supplementary-material-not-ready","unexpected-failure","unknown-price","unknown-prompt-set","unknown-steering-target","validation-error","webhook-entity-creation","webhook-entity-not-found","webhook-idempotency-unavailable","webhook-payload-invalid","webhook-verification"]},"title":{"type":"string","title":"Title","description":"Stable human-readable summary; does not vary per occurrence"},"status":{"type":"integer","title":"Status","description":"HTTP status code"}},"additionalProperties":true,"type":"object","required":["type","title","status"],"title":"Problem","description":"RFC 9457 problem document. Additional members are error-specific.\n\nDeclared here rather than in ``errors.py`` so the examples gate in\n``tests/unit/infrastructure/api/test_openapi_examples.py`` discovers it and\nholds it to the same standard as every other API model.\n\nThe component name FastAPI publishes comes from ``__qualname__``, baked in at\nclass creation, so it can only be the class's real name -- hence ``Problem``."},"ProcessDocumentRequest":{"properties":{"preview":{"type":"boolean","title":"Preview","description":"Credit type to use. Set to false (default) for full proofreading (1 paid credit), or true for limited preview feedback (1 preview credit).","default":false},"previous_session_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Previous Session Id","description":"Optional UUID of a prior session this submission is a resubmission of. Must be a session the caller can access (own, public, or same-org per the access policy). When provided, the new review's comment refiner and overall-feedback second pass receive the prior session's comments and overall feedback as additional prompt context."},"steering_prompt":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Steering Prompt","description":"Optional free-text steering prompt attached to this submission (e.g. \"focus on grammar, this is a physics PhD thesis, use British English\"). Advisory guidance the reviewer considers when prioritizing attention — it never overrides document classification or the review rubric. Applies to the whole run, is persisted on the session, shown in history, and carried into revision re-runs. Capped at 2000 characters. Whitespace-only is treated as empty."},"supplementary_material_steering":{"anyOf":[{"additionalProperties":{"type":"string","maxLength":2000},"propertyNames":{"format":"uuid"},"type":"object"},{"type":"null"}],"title":"Supplementary Material Steering","description":"Optional per-item steering notes, keyed by supplementary material document ID (must be supplementary material of this document), e.g. {\"<supplementary material-id>\": \"raw instrument output — only use to verify Table 3\"}. Each note describes how that supplementary material should be incorporated into the review; advisory only, like steering_prompt. Provided keys are persisted on the supplementary material (empty/whitespace clears the stored note); omitted keys keep their stored note, which still applies to this run. Notes are returned by GET /documents/{id}/supplementary material. Each note is capped at 2000 characters."},"customization":{"anyOf":[{"$ref":"#/components/schemas/ReviewCustomization"},{"type":"null"}],"description":"Admin-only per-review tuning (issue #1165): prompt set, skeptic mode, and per-stage model/sampling overrides. Rejected with 403 for non-admin callers. A pinned stage is applied onto the code default and bypasses that stage's PostHog flag; untouched stages keep their flag behavior."}},"type":"object","title":"ProcessDocumentRequest","description":"Request to start proofreading analysis on an uploaded document.\n\nConsumes 1 credit. The document must be fully converted before calling this — wait\nfor the upload SSE complete event at /documents/upload/events/{task_id}.","examples":[{"preview":false,"previous_session_id":null,"steering_prompt":null,"supplementary_material_steering":null,"customization":null},{"preview":true,"previous_session_id":null,"steering_prompt":null,"supplementary_material_steering":null,"customization":null},{"preview":false,"previous_session_id":"7ab7324d-0968-40ac-9a0d-68fe4fbf11bf","steering_prompt":"Focus on the statistics in section 4.","supplementary_material_steering":null,"customization":null}]},"ProcessDocumentResponse":{"properties":{"session_id":{"type":"string","title":"Session Id","description":"UUID of the history record"},"events_endpoint":{"type":"string","title":"Events Endpoint","description":"SSE endpoint for progress updates"}},"type":"object","required":["session_id","events_endpoint"],"title":"ProcessDocumentResponse","description":"Response from starting document processing.","examples":[{"session_id":"7ab7324d-0968-40ac-9a0d-68fe4fbf11bf","events_endpoint":"/documents/3eef6ca5-9388-45b4-92a8-c144347ad6ec/process/events/7ab7324d-0968-40ac-9a0d-68fe4fbf11bf"}]},"ProcessingItem":{"properties":{"session_id":{"type":"string","title":"Session Id","description":"History item UUID; also the identifier for SSE reconnection"},"document_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Document Id","description":"Associated document UUID"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title","description":"Document title"},"progress_percentage":{"type":"integer","title":"Progress Percentage","description":"Progress percentage (0-100)"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When processing started"}},"type":"object","required":["session_id","document_id","title","progress_percentage","created_at"],"title":"ProcessingItem","description":"An active processing task."},"ProcessingStatusResponse":{"properties":{"processing":{"items":{"$ref":"#/components/schemas/ProcessingItem"},"type":"array","title":"Processing","description":"Active processing tasks"},"unviewed_completed":{"anyOf":[{"$ref":"#/components/schemas/UnviewedCompletedItem"},{"type":"null"}],"description":"Most recent unviewed completed item"}},"type":"object","title":"ProcessingStatusResponse","description":"Response for GET /processing endpoint.","examples":[{"processing":[],"unviewed_completed":null},{"processing":[{"session_id":"c9b1f6d2-4a83-4f21-9c07-2e5b8a1d3f40","document_id":"3eef6ca5-9388-45b4-92a8-c144347ad6ec","title":"Targeting Interventions in Networks","progress_percentage":45,"created_at":"2026-07-24T12:45:39.418365+00:00"}],"unviewed_completed":null},{"processing":[],"unviewed_completed":{"session_id":"7ab7324d-0968-40ac-9a0d-68fe4fbf11bf","document_id":"3eef6ca5-9388-45b4-92a8-c144347ad6ec","title":"Targeting Interventions in Networks","created_at":"2026-07-24T12:45:39.418365+00:00"}}]},"ProductsResponse":{"properties":{"credit_packs":{"items":{"$ref":"#/components/schemas/CreditPackProduct"},"type":"array","title":"Credit Packs"},"subscriptions":{"items":{"$ref":"#/components/schemas/SubscriptionProduct"},"type":"array","title":"Subscriptions"}},"type":"object","required":["credit_packs","subscriptions"],"title":"ProductsResponse","description":"Response containing all available products, ordered by price (ascending).","examples":[{"credit_packs":[{"price_id":"price_1QeXamplePack","name":"10 credits","credits":10,"price_cents":4900,"currency":"eur","subscriber_price_cents":3900,"tax_included":true,"tax_amount_cents":850,"total_cents":4900,"subscriber_total_cents":3900},{"price_id":"price_1QeXampleSingle","name":"1 credit","credits":1,"price_cents":900,"currency":"eur","subscriber_price_cents":null,"tax_included":true,"tax_amount_cents":156,"total_cents":900,"subscriber_total_cents":null}],"subscriptions":[{"price_id":"price_1QeXampleMonthly","name":"Refine Monthly","credits":20,"price_cents":2900,"currency":"eur","interval":"month","tax_included":true,"tax_amount_cents":503,"total_cents":2900}]}]},"QuotaStatus":{"properties":{"used_fraction":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Used Fraction","description":"Fraction of the daily budget consumed (0.0–1.0, clipped). Frontend renders as a progress bar or percentage."},"resets_at":{"type":"string","format":"date-time","title":"Resets At","description":"When the counter rolls over (UTC, ISO 8601). Literal Redis TTL expiry — the moment the user's budget is wiped."}},"type":"object","required":["used_fraction","resets_at"],"title":"QuotaStatus","description":"Live snapshot of the chatbot daily quota for the requesting user."},"ReasoningEffort":{"type":"string","enum":["low","medium","high","xhigh"],"title":"ReasoningEffort","description":"OpenRouter reasoning effort levels (mirrors the defaults' ``reasoning.effort``)."},"ReferralStatusResponse":{"properties":{"has_referral":{"type":"boolean","title":"Has Referral","description":"Whether the user has been referred by someone"},"referrer_email":{"anyOf":[{"type":"string","format":"email"},{"type":"null"}],"title":"Referrer Email","description":"Email of the user who referred this user"},"referral_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Referral Code","description":"Referral code that was used"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Created At","description":"When the referral was registered (ISO datetime with UTC timezone)"},"first_payment_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"First Payment At","description":"When the referred user made their first payment (ISO datetime with UTC timezone)"},"rewards_issued_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Rewards Issued At","description":"When rewards were issued to both users (ISO datetime with UTC timezone)"}},"type":"object","required":["has_referral"],"title":"ReferralStatusResponse","description":"Response schema for checking if user has a referral.","examples":[{"has_referral":false,"referrer_email":null,"referral_code":null,"created_at":null,"first_payment_at":null,"rewards_issued_at":null},{"has_referral":true,"referrer_email":"referrer@example.edu","referral_code":"REFINE-7K2QX","created_at":"2026-07-12T14:02:00+00:00","first_payment_at":null,"rewards_issued_at":null},{"has_referral":true,"referrer_email":"referrer@example.edu","referral_code":"REFINE-7K2QX","created_at":"2026-07-12T14:02:00+00:00","first_payment_at":"2026-07-18T09:41:00+00:00","rewards_issued_at":"2026-07-18T09:41:30+00:00"}]},"RegisterReferralRequest":{"properties":{"referral_code":{"type":"string","minLength":1,"title":"Referral Code","description":"Referral code from the referrer"}},"type":"object","required":["referral_code"],"title":"RegisterReferralRequest","description":"Request schema for registering a referral.","examples":[{"referral_code":"REFINE-7K2QX"}]},"RegisterReferralResponse":{"properties":{"referrer_email":{"type":"string","format":"email","title":"Referrer Email","description":"Email of the user who referred you"}},"type":"object","required":["referrer_email"],"title":"RegisterReferralResponse","description":"Response schema for registering a referral.","examples":[{"referrer_email":"referrer@example.edu"}]},"ReviewCustomization":{"properties":{"prompt_set":{"anyOf":[{"type":"string","maxLength":64,"pattern":"^[a-z0-9_]+$"},{"type":"null"}],"title":"Prompt Set","description":"Prompt-set overlay directory name (e.g. 'experimental_1'). Existence is validated at the API boundary against prompts/override_sets/. None uses the base prompts/ set unchanged."},"skeptic_mode":{"anyOf":[{"$ref":"#/components/schemas/SkepticMode"},{"type":"null"}],"description":"Commenter mode. None leaves the dual_commenter flag behavior untouched."},"sharded_dedup_mode":{"anyOf":[{"$ref":"#/components/schemas/ShardedPipelineMode"},{"type":"null"}],"description":"Dedup sharding override. An explicit value OVERRIDES the modular_consolidation flag in both directions; None defers to the flag (flag on -> sharded dedup on)."},"sharded_consolidate_mode":{"anyOf":[{"$ref":"#/components/schemas/ConsolidationShardingMode"},{"type":"null"}],"description":"Consolidation sharding mode override (off/modular). An explicit value OVERRIDES the modular_consolidation flag in both directions; None defers to the flag (flag on -> modular, flag off -> off)."},"sharded_context_mode":{"anyOf":[{"$ref":"#/components/schemas/ShardedContextMode"},{"type":"null"}],"description":"Document context for the sharded dedup-bucket/cluster-merge calls (full_doc/segments). An explicit value OVERRIDES the modular_consolidation_segment_context flag in both directions; None defers to the flags (segments only when modular_consolidation AND modular_consolidation_segment_context are both on, else full_doc)."},"commenters_enabled":{"anyOf":[{"additionalProperties":{"type":"boolean"},"type":"object"},{"type":"null"}],"title":"Commenters Enabled","description":"Per-commenter enable override object. Maps commenter name (general, reference, prior_art, ...) to a bool. Keys present here OVERRIDE the commenters_enabled PostHog flag (and the built-in defaults); keys absent defer to the flag/default. None leaves the flag/default behaviour untouched."},"stage_overrides":{"additionalProperties":{"$ref":"#/components/schemas/StageOverride"},"propertyNames":{"$ref":"#/components/schemas/ReviewStage"},"type":"object","title":"Stage Overrides"},"writing_critic_tuning":{"anyOf":[{"$ref":"#/components/schemas/WritingCriticTuning"},{"type":"null"}],"description":"Threshold overrides for the writing critic's deterministic checks (jargon fan-in, punctuation rates, write-pass count, ...). None uses the built-in defaults. Only meaningful when the writing_critic commenter is enabled."}},"additionalProperties":false,"type":"object","title":"ReviewCustomization","description":"Authorized, per-review tuning. Absent or all-default == today's behavior.\n\nRound-trips through a plain dict (``model_dump(mode=\"json\")`` to freeze onto\nthe orchestration input, ``model_validate`` to re-hydrate infra-side)."},"ReviewStage":{"type":"string","enum":["GATEKEEPER","SUMMARIZER","COMMENTER","COMMENTER_SKEPTIC","COMMENT_REFINER","COMMENT_DEDUPLICATOR","COMMENT_CONSOLIDATOR","OVERALL_FEEDBACK_SKILL_GEN","OVERALL_FEEDBACK_FIRST_PASS_GPT","OVERALL_FEEDBACK_FIRST_PASS_GEMINI","OVERALL_FEEDBACK_SECOND_PASS","OVERALL_FEEDBACK_REWRITE","WRITING_CRITIC_ANALYZER","WRITING_CRITIC_WRITER","WRITING_CRITIC_VERIFIER"],"title":"ReviewStage","description":"Stages whose model/sampling an authorized caller may tune.\n\nEach value equals the ``LLMConfig.name`` of the corresponding default config,\nso a ``StageOverride`` keyed here lowers directly onto that stage's resolved\nconfig via ``override_for``."},"RevisionCheckResponse":{"properties":{"verdicts":{"items":{"$ref":"#/components/schemas/VerdictSchema"},"type":"array","title":"Verdicts","description":"Per-prior-comment verdicts"},"overall_verdict":{"anyOf":[{"$ref":"#/components/schemas/VerdictSchema"},{"type":"null"}],"description":"Single overall-feedback verdict, or null when unavailable"},"counts":{"$ref":"#/components/schemas/VerdictCounts","description":"Per-status counts"}},"type":"object","required":["counts"],"title":"RevisionCheckResponse","description":"Per-comment + overall verdicts for a resubmission session.\n\nReturned as ``null`` on the parent ``HistorySessionResponse`` when the\nsession isn't a resubmission or the secondary pipeline degraded."},"SessionAccessRequest":{"properties":{"message":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Message","description":"Optional message to include with the request"}},"type":"object","title":"SessionAccessRequest","description":"Request body for requesting access to a private session.","examples":[{"message":"I am a co-author on this manuscript and would like to see the review."},{"message":null}]},"SessionAccessRequestResponse":{"properties":{"session_id":{"type":"string","title":"Session Id","description":"The session ID for which access was requested"}},"type":"object","required":["session_id"],"title":"SessionAccessRequestResponse","description":"Response for access request action.","examples":[{"session_id":"7ab7324d-0968-40ac-9a0d-68fe4fbf11bf"}]},"ShardedContextMode":{"type":"string","enum":["full_doc","segments"],"title":"ShardedContextMode","description":"Document context the sharded dedup-bucket / cluster-merge prompts receive.\n\n* ``full_doc`` — today's behavior: every shard call opens with the full\n  converted document text.\n* ``segments`` — each call receives only the document segments its\n  comments anchor to (±1 segment, elision markers between non-contiguous\n  runs), built infra-side from ``segment_index_by_comment_id``.\n\nPair verification is document-free either way. ``None`` on\n``ReviewCustomization`` defers to the boolean\n``modular_consolidation_segment_context`` PostHog flag, which only takes\neffect when the ``modular_consolidation`` flag is also on (a segment-\ncontext flag alone changes nothing); an explicit value forces the mode\nfor this run in both directions."},"ShardedPipelineMode":{"type":"string","enum":["off","on"],"title":"ShardedPipelineMode","description":"Per-review override for the sharded-dedup stage's flag-gated behavior.\n\n``None`` (the field default on ``ReviewCustomization``) means \"leave the existing\nPostHog flag behavior untouched\"; an explicit value forces the mode for this run.\nMirrors ``SkepticMode``'s shape/semantics (see ``sharded_dedup_enabled``)."},"SkepticMode":{"type":"string","enum":["off","dual","skeptic_only"],"title":"SkepticMode","description":"Commenter mode, mapped to the dual_commenter / disable_regular_commenter flags.\n\n``None`` (the field default on ``ReviewCustomization``) means \"leave the existing\nPostHog flag behavior untouched\"; an explicit value forces the mode for this run."},"StageOverride":{"properties":{"models":{"anyOf":[{"items":{"type":"string"},"type":"array","minItems":1},{"type":"null"}],"title":"Models","description":"Primary model + ordered fallbacks. Each must be in ALLOWED_MODELS."},"temperature":{"anyOf":[{"type":"number","maximum":2.0,"minimum":0.0},{"type":"null"}],"title":"Temperature"},"top_p":{"anyOf":[{"type":"number","maximum":1.0,"minimum":0.0},{"type":"null"}],"title":"Top P"},"max_tokens":{"anyOf":[{"type":"integer","maximum":64000.0,"minimum":1.0},{"type":"null"}],"title":"Max Tokens"},"reasoning_effort":{"anyOf":[{"$ref":"#/components/schemas/ReasoningEffort"},{"type":"null"}]}},"additionalProperties":false,"type":"object","title":"StageOverride","description":"Partial override for one stage's ``LLMConfig``.\n\nOnly the fields set here override the default; omitted fields fall through to\nthe default -> PostHog-flag resolution. The field set is deliberately limited\nto the Tier-2 knobs (model + sampling) -- there is no ``timeout``/``retries``/\n``slot_caps`` field, so reliability/cost guardrails are unreachable. ``extra``\nis forbidden so a typo'd field is a 422 rather than a silently ignored value."},"SubscriptionProduct":{"properties":{"price_id":{"type":"string","title":"Price Id"},"name":{"type":"string","title":"Name"},"credits":{"type":"integer","title":"Credits"},"price_cents":{"type":"integer","title":"Price Cents"},"currency":{"type":"string","title":"Currency"},"interval":{"type":"string","title":"Interval"},"tax_included":{"type":"boolean","title":"Tax Included","default":false},"tax_amount_cents":{"type":"integer","title":"Tax Amount Cents","default":0},"total_cents":{"type":"integer","title":"Total Cents","default":0}},"type":"object","required":["price_id","name","credits","price_cents","currency","interval"],"title":"SubscriptionProduct","description":"Recurring subscription product."},"SubscriptionStatusResponse":{"properties":{"has_active_subscription":{"type":"boolean","title":"Has Active Subscription","description":"Whether user has an active subscription"},"subscription_tier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subscription Tier","description":"Current subscription tier (starter/professional/enterprise)"},"subscription_credits_remaining":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Subscription Credits Remaining","description":"Monthly credits remaining"},"next_credit_renewal_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Next Credit Renewal At","description":"When credits will be renewed"},"stripe_subscription_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stripe Subscription Id","description":"Stripe subscription ID"},"cancel_at_period_end":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Cancel At Period End","description":"Whether subscription will cancel at period end"},"current_period_ends_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Current Period Ends At","description":"End of the current billing period"},"stripe_customer_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stripe Customer Id","description":"Stripe customer ID (null if user has never paid)"}},"type":"object","required":["has_active_subscription"],"title":"SubscriptionStatusResponse","description":"Response schema for subscription status endpoint.","examples":[{"has_active_subscription":true,"subscription_tier":"monthly","subscription_credits_remaining":14,"next_credit_renewal_at":"2026-08-12T00:00:00+00:00","stripe_subscription_id":"sub_1QeXampleActive","cancel_at_period_end":false,"current_period_ends_at":"2026-08-12T00:00:00+00:00","stripe_customer_id":"cus_QeXample123"},{"has_active_subscription":true,"subscription_tier":"monthly","subscription_credits_remaining":6,"next_credit_renewal_at":null,"stripe_subscription_id":"sub_1QeXampleActive","cancel_at_period_end":true,"current_period_ends_at":"2026-08-12T00:00:00+00:00","stripe_customer_id":"cus_QeXample123"},{"has_active_subscription":false,"subscription_tier":null,"subscription_credits_remaining":null,"next_credit_renewal_at":null,"stripe_subscription_id":null,"cancel_at_period_end":null,"current_period_ends_at":null,"stripe_customer_id":null}]},"SupplementaryMaterialResponse":{"properties":{"document_id":{"type":"string","title":"Document Id","description":"UUID of the supplementary material document"},"filename":{"type":"string","title":"Filename","description":"Original filename"},"display_order":{"type":"integer","title":"Display Order","description":"Ordering position among supplementary material"},"steering_note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Steering Note","description":"User-provided note on how this supplementary material should be incorporated into the review"}},"type":"object","required":["document_id","filename","display_order"],"title":"SupplementaryMaterialResponse","description":"Metadata for an supplementary material document.","examples":[{"document_id":"b2d5a0f3-7e81-4c94-a2bd-6a3f9e1c8d42","filename":"appendix.docx","display_order":1,"steering_note":"Reference tables for section 4."}]},"UnviewedCompletedItem":{"properties":{"session_id":{"type":"string","title":"Session Id","description":"History item UUID"},"document_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Document Id","description":"Associated document UUID"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title","description":"Document title"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When processing completed"}},"type":"object","required":["session_id","document_id","title","created_at"],"title":"UnviewedCompletedItem","description":"A completed item that hasn't been viewed yet."},"UpdateMarketingPreferencesRequest":{"properties":{"opt_in":{"type":"boolean","title":"Opt In","description":"Desired opt-in state."}},"type":"object","required":["opt_in"],"title":"UpdateMarketingPreferencesRequest","description":"Body for PUT /marketing/preferences.","examples":[{"opt_in":true},{"opt_in":false}]},"UpdateVisibilityRequest":{"properties":{"is_public":{"type":"boolean","title":"Is Public","description":"Whether the session should be publicly viewable"}},"type":"object","required":["is_public"],"title":"UpdateVisibilityRequest","description":"Request body for updating session visibility.","examples":[{"is_public":true},{"is_public":false}]},"UpdateVisibilityResponse":{"properties":{"session_id":{"type":"string","title":"Session Id","description":"The session ID that was updated"},"is_public":{"type":"boolean","title":"Is Public","description":"The new visibility setting"},"changed":{"type":"boolean","title":"Changed","description":"False when the session already had this visibility and nothing was written"}},"type":"object","required":["session_id","is_public","changed"],"title":"UpdateVisibilityResponse","description":"Response for visibility update.","examples":[{"session_id":"7ab7324d-0968-40ac-9a0d-68fe4fbf11bf","is_public":true,"changed":true},{"session_id":"7ab7324d-0968-40ac-9a0d-68fe4fbf11bf","is_public":true,"changed":false}]},"UpgradeSubscriptionRequest":{"properties":{"new_price_id":{"type":"string","minLength":1,"title":"New Price Id","description":"Stripe price ID for the new subscription tier"},"success_url":{"type":"string","minLength":1,"title":"Success Url","description":"URL to redirect to after successful payment"},"cancel_url":{"type":"string","minLength":1,"title":"Cancel Url","description":"URL to redirect to if payment is canceled"}},"type":"object","required":["new_price_id","success_url","cancel_url"],"title":"UpgradeSubscriptionRequest","description":"Request schema for upgrading a subscription.\n\nNote: subscription_id, user_email, plan names, and credits are derived\nfrom JWT, database lookup, and pricing configuration.","examples":[{"new_price_id":"price_1QeXampleAnnual","success_url":"https://refine.ink/account/billing?upgraded=1","cancel_url":"https://refine.ink/account/billing"}]},"UpgradeSubscriptionResponse":{"properties":{"checkout_url":{"type":"string","title":"Checkout Url","description":"Stripe checkout URL for the upgrade payment"},"session_id":{"type":"string","title":"Session Id","description":"Stripe checkout session ID"}},"type":"object","required":["checkout_url","session_id"],"title":"UpgradeSubscriptionResponse","description":"Response schema for subscription upgrade.\n\nNote: Errors are returned as HTTP exceptions, not in the response body.\nA 200 response always indicates success.","examples":[{"checkout_url":"https://checkout.stripe.com/c/pay/cs_test_upgrade123","session_id":"cs_test_upgrade123"}]},"UserChatMessage":{"properties":{"role":{"type":"string","const":"user","title":"Role","description":"Always 'user'"},"content":{"type":"string","title":"Content"},"comment_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Comment Id","description":"Optional: the comment ID the user focused this message on"},"created_at":{"type":"string","format":"date-time","title":"Created At","description":"When the message was stored"}},"type":"object","required":["role","content","created_at"],"title":"UserChatMessage","description":"A user message in conversation history."},"UserConsumptionResponse":{"properties":{"user_email":{"type":"string","title":"User Email","description":"Email of the member"},"events":{"items":{"$ref":"#/components/schemas/CreditConsumptionEventResponse"},"type":"array","title":"Events","description":"Individual spends, newest first"},"total_consumed":{"type":"integer","title":"Total Consumed","description":"Credits this member consumed in the window"}},"type":"object","required":["user_email","events","total_consumed"],"title":"UserConsumptionResponse","description":"One member's credit consumption over the reporting window."},"VerdictCounts":{"properties":{"fully_addressed":{"type":"integer","minimum":0.0,"title":"Fully Addressed"},"partially_addressed":{"type":"integer","minimum":0.0,"title":"Partially Addressed"},"not_addressed":{"type":"integer","minimum":0.0,"title":"Not Addressed"},"indeterminate":{"type":"integer","minimum":0.0,"title":"Indeterminate"},"dismissed":{"type":"integer","minimum":0.0,"title":"Dismissed"},"error":{"type":"integer","minimum":0.0,"title":"Error"}},"type":"object","required":["fully_addressed","partially_addressed","not_addressed","indeterminate","dismissed","error"],"title":"VerdictCounts","description":"Per-status counts across all verdicts (including the overall verdict)."},"VerdictSchema":{"properties":{"id":{"type":"string","title":"Id","description":"Stable verdict identifier"},"source_comment_id":{"type":"string","title":"Source Comment Id","description":"ID of the comment in the prior session this verdict scores"},"status":{"type":"string","title":"Status","description":"Whether the prior concern was addressed in the revised version: fully_addressed | partially_addressed | not_addressed | indeterminate (could not be determined from the comments) | dismissed (user dismissed it in the prior version; not re-evaluated) | error (pipeline failure)"},"comment":{"type":"string","title":"Comment","description":"User-facing explanation in Refine voice"}},"type":"object","required":["id","source_comment_id","status","comment"],"title":"VerdictSchema","description":"Public-facing verdict from the revision-check (rerun) pipeline.\n\nReasoning is internal — stripped via ``extra=\"ignore\"``."},"WritingCriticTuning":{"properties":{"jargon_max_fan_in":{"type":"integer","minimum":0.0,"title":"Jargon Max Fan In","description":"Coined term with <= this many direct dependents ...","default":1},"jargon_max_mentions":{"type":"integer","minimum":0.0,"title":"Jargon Max Mentions","description":"... and <= this many substantive mentions is flagged as superfluous jargon.","default":2},"emdash_per_1k":{"type":"number","minimum":0.0,"title":"Emdash Per 1K","description":"Em-dash rate per 1000 prose words above which the tic is flagged.","default":4.0},"colon_per_1k":{"type":"number","minimum":0.0,"title":"Colon Per 1K","description":"Colon-apposition rate per 1000 prose words above which the tic is flagged.","default":6.0},"tic_min_count":{"type":"integer","minimum":0.0,"title":"Tic Min Count","description":"Never flag a punctuation tic on fewer absolute occurrences than this.","default":10},"given_before_new_cap":{"type":"integer","minimum":0.0,"title":"Given Before New Cap","description":"Max given-before-new flags per draft — a systemic habit needs one comment, not a list.","default":6},"write_passes":{"type":"integer","maximum":5.0,"minimum":1.0,"title":"Write Passes","description":"Independent write passes pooled for coverage (prototype default was 3; pipeline starts at 1).","default":1}},"type":"object","title":"WritingCriticTuning","description":"Thresholds for the deterministic writing-critic checks.\n\nSerializes onto the orchestration input (frozen at workflow entry) so\nreplays stay deterministic."},"DocumentUploadForm":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File","description":"Document file to upload"},"parent_document_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Parent Document Id","description":"UUID of parent document. When provided, this upload is an supplementary material attached to the parent."}},"type":"object","required":["file"],"title":"Body_documents_uploadDocument"}},"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"API key or JWT token. Pass as: Authorization: Bearer <your-api-key>"},"OAuth2":{"type":"oauth2","description":"Log in with your account","flows":{"authorizationCode":{"authorizationUrl":"https://clerk.refine.ink/oauth/authorize","tokenUrl":"https://clerk.refine.ink/oauth/token","scopes":{"openid":"OpenID Connect","profile":"User profile","email":"Email address"}}}}},"responses":{"ProblemUnprocessable":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"validation-error":{"$ref":"#/components/examples/validation-error"}}}}},"ProblemInternalServerErrorAuthenticationConfigurationAuthenticationFailedUnexpectedFailure":{"description":"Internal server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"authentication-configuration":{"$ref":"#/components/examples/authentication-configuration"},"authentication-failed":{"$ref":"#/components/examples/authentication-failed"},"unexpected-failure":{"$ref":"#/components/examples/unexpected-failure"}}}}},"ProblemUnauthenticated":{"description":"Unauthenticated","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"api-key-scope":{"$ref":"#/components/examples/api-key-scope"},"api-key-user-not-found":{"$ref":"#/components/examples/api-key-user-not-found"},"expired-token":{"$ref":"#/components/examples/expired-token"},"incomplete-token":{"$ref":"#/components/examples/incomplete-token"},"invalid-api-key":{"$ref":"#/components/examples/invalid-api-key"},"malformed-token":{"$ref":"#/components/examples/malformed-token"},"missing-credentials":{"$ref":"#/components/examples/missing-credentials"},"premature-token":{"$ref":"#/components/examples/premature-token"}}}}},"ProblemBadRequestMalformedReferralCodeOwnReferralCode":{"description":"Bad request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"malformed-referral-code":{"$ref":"#/components/examples/malformed-referral-code"},"own-referral-code":{"$ref":"#/components/examples/own-referral-code"}}}}},"ProblemNotFoundReferralCodeNotFound":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"referral-code-not-found":{"$ref":"#/components/examples/referral-code-not-found"}}}}},"ProblemForbiddenSessionNotAccessible":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"session-not-accessible":{"$ref":"#/components/examples/session-not-accessible"}}}}},"ProblemNotFoundSessionMissing":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"session-missing":{"$ref":"#/components/examples/session-missing"}}}}},"ProblemBadRequestMissingIdentifier":{"description":"Bad request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"missing-identifier":{"$ref":"#/components/examples/missing-identifier"}}}}},"ProblemInternalServerErrorCommentActionNotStored":{"description":"Internal server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"authentication-configuration":{"$ref":"#/components/examples/authentication-configuration"},"authentication-failed":{"$ref":"#/components/examples/authentication-failed"},"comment-action-not-stored":{"$ref":"#/components/examples/comment-action-not-stored"},"unexpected-failure":{"$ref":"#/components/examples/unexpected-failure"}}}}},"ProblemBadRequestCommentNotActionableMissingIdentifier":{"description":"Bad request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"comment-not-actionable":{"$ref":"#/components/examples/comment-not-actionable"},"missing-identifier":{"$ref":"#/components/examples/missing-identifier"}}}}},"ProblemBadRequestCommentNotActionableInvalidCommentActionTypeMissingIdentifier":{"description":"Bad request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"comment-not-actionable":{"$ref":"#/components/examples/comment-not-actionable"},"invalid-comment-action-type":{"$ref":"#/components/examples/invalid-comment-action-type"},"missing-identifier":{"$ref":"#/components/examples/missing-identifier"}}}}},"ProblemBadRequestSessionAlreadyAccessible":{"description":"Bad request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"session-already-accessible":{"$ref":"#/components/examples/session-already-accessible"}}}}},"ProblemForbiddenSessionSharingRestricted":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"session-sharing-restricted":{"$ref":"#/components/examples/session-sharing-restricted"}}}}},"ProblemInternalServerErrorUnexpectedFailure":{"description":"Internal server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"unexpected-failure":{"$ref":"#/components/examples/unexpected-failure"}}}}},"ProblemBadGatewayPaymentSystem":{"description":"Bad gateway","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"payment-system":{"$ref":"#/components/examples/payment-system"}}}}},"ProblemInternalServerErrorOriginalUploadStorage":{"description":"Internal server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"authentication-configuration":{"$ref":"#/components/examples/authentication-configuration"},"authentication-failed":{"$ref":"#/components/examples/authentication-failed"},"original-upload-storage":{"$ref":"#/components/examples/original-upload-storage"},"unexpected-failure":{"$ref":"#/components/examples/unexpected-failure"}}}}},"ProblemBadRequestInvalidUploadedFileMalformedDocumentIdMissingFilenameNestedSupplementaryMaterialSupplementaryMaterialLimitReached":{"description":"Bad request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalid-uploaded-file":{"$ref":"#/components/examples/invalid-uploaded-file"},"malformed-document-id":{"$ref":"#/components/examples/malformed-document-id"},"missing-filename":{"$ref":"#/components/examples/missing-filename"},"nested-supplementary-material":{"$ref":"#/components/examples/nested-supplementary-material"},"supplementary-material-limit-reached":{"$ref":"#/components/examples/supplementary-material-limit-reached"}}}}},"ProblemForbiddenParentDocumentNotOwned":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"parent-document-not-owned":{"$ref":"#/components/examples/parent-document-not-owned"}}}}},"ProblemNotFoundAuthenticatedUserNotFoundParentDocumentNotFound":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"authenticated-user-not-found":{"$ref":"#/components/examples/authenticated-user-not-found"},"parent-document-not-found":{"$ref":"#/components/examples/parent-document-not-found"}}}}},"ProblemUnprocessableDocumentTokenLimitDocumentWordLimitShortDocumentTextUnknownPromptSetUnknownSteeringTarget":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"document-token-limit":{"$ref":"#/components/examples/document-token-limit"},"document-word-limit":{"$ref":"#/components/examples/document-word-limit"},"short-document-text":{"$ref":"#/components/examples/short-document-text"},"unknown-prompt-set":{"$ref":"#/components/examples/unknown-prompt-set"},"unknown-steering-target":{"$ref":"#/components/examples/unknown-steering-target"},"validation-error":{"$ref":"#/components/examples/validation-error"}}}}},"ProblemInternalServerErrorProcessingJobNotCreated":{"description":"Internal server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"authentication-configuration":{"$ref":"#/components/examples/authentication-configuration"},"authentication-failed":{"$ref":"#/components/examples/authentication-failed"},"processing-job-not-created":{"$ref":"#/components/examples/processing-job-not-created"},"unexpected-failure":{"$ref":"#/components/examples/unexpected-failure"}}}}},"ProblemBadRequestMalformedDocumentId":{"description":"Bad request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"malformed-document-id":{"$ref":"#/components/examples/malformed-document-id"}}}}},"ProblemForbiddenDocumentNotAccessibleNoCreditsReviewCustomizationForbidden":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"document-not-accessible":{"$ref":"#/components/examples/document-not-accessible"},"no-credits":{"$ref":"#/components/examples/no-credits"},"review-customization-forbidden":{"$ref":"#/components/examples/review-customization-forbidden"}}}}},"ProblemNotFoundAuthenticatedUserNotFoundDocumentNotFoundDocumentTextNotReadyRevisionSessionNotAccessible":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"authenticated-user-not-found":{"$ref":"#/components/examples/authenticated-user-not-found"},"document-not-found":{"$ref":"#/components/examples/document-not-found"},"document-text-not-ready":{"$ref":"#/components/examples/document-text-not-ready"},"revision-session-not-accessible":{"$ref":"#/components/examples/revision-session-not-accessible"}}}}},"ProblemConflictSupplementaryMaterialNotReady":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"supplementary-material-not-ready":{"$ref":"#/components/examples/supplementary-material-not-ready"}}}}},"ProblemServiceUnavailableCreditServiceUnavailableProcessingDispatch":{"description":"Service unavailable","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"credit-service-unavailable":{"$ref":"#/components/examples/credit-service-unavailable"},"processing-dispatch":{"$ref":"#/components/examples/processing-dispatch"}}}}},"ProblemForbiddenDocumentNotAccessible":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"document-not-accessible":{"$ref":"#/components/examples/document-not-accessible"}}}}},"ProblemNotFoundDocumentNotFoundDocumentTextNotReady":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"document-not-found":{"$ref":"#/components/examples/document-not-found"},"document-text-not-ready":{"$ref":"#/components/examples/document-text-not-ready"}}}}},"ProblemNotFoundDocumentNotFound":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"document-not-found":{"$ref":"#/components/examples/document-not-found"}}}}},"ProblemBadRequestInvalidImageRequestMalformedDocumentId":{"description":"Bad request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"invalid-image-request":{"$ref":"#/components/examples/invalid-image-request"},"malformed-document-id":{"$ref":"#/components/examples/malformed-document-id"}}}}},"ProblemNotFoundImageNotFound":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"image-not-found":{"$ref":"#/components/examples/image-not-found"}}}}},"ProblemBadRequestUnknownPrice":{"description":"Bad request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"unknown-price":{"$ref":"#/components/examples/unknown-price"}}}}},"ProblemNotFoundNoSubscription":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"no-subscription":{"$ref":"#/components/examples/no-subscription"}}}}},"ProblemInternalServerErrorOrganizationCreditsUnavailable":{"description":"Internal server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"authentication-configuration":{"$ref":"#/components/examples/authentication-configuration"},"authentication-failed":{"$ref":"#/components/examples/authentication-failed"},"organization-credits-unavailable":{"$ref":"#/components/examples/organization-credits-unavailable"},"unexpected-failure":{"$ref":"#/components/examples/unexpected-failure"}}}}},"ProblemForbiddenOrganizationPermission":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"organization-permission":{"$ref":"#/components/examples/organization-permission"}}}}},"ProblemNotFoundOrganizationMissing":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"organization-missing":{"$ref":"#/components/examples/organization-missing"}}}}},"ProblemBadRequestAllocationTargetNotAMemberCreditAllocationFailedOrganizationPoolExhausted":{"description":"Bad request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"allocation-target-not-a-member":{"$ref":"#/components/examples/allocation-target-not-a-member"},"credit-allocation-failed":{"$ref":"#/components/examples/credit-allocation-failed"},"organization-pool-exhausted":{"$ref":"#/components/examples/organization-pool-exhausted"}}}}},"ProblemBadRequestAllocationTargetNotAMemberCreditAllocationFailed":{"description":"Bad request","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"allocation-target-not-a-member":{"$ref":"#/components/examples/allocation-target-not-a-member"},"credit-allocation-failed":{"$ref":"#/components/examples/credit-allocation-failed"}}}}},"ProblemForbiddenOrganizationMembershipRequired":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"organization-membership-required":{"$ref":"#/components/examples/organization-membership-required"}}}}},"ProblemNotFoundAuthenticatedUserNotFound":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"authenticated-user-not-found":{"$ref":"#/components/examples/authenticated-user-not-found"}}}}},"ProblemInternalServerErrorMarketingStateUnavailable":{"description":"Internal server error","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"},"examples":{"authentication-configuration":{"$ref":"#/components/examples/authentication-configuration"},"authentication-failed":{"$ref":"#/components/examples/authentication-failed"},"marketing-state-unavailable":{"$ref":"#/components/examples/marketing-state-unavailable"},"unexpected-failure":{"$ref":"#/components/examples/unexpected-failure"}}}}}},"examples":{"validation-error":{"summary":"Request validation failed","value":{"type":"validation-error","title":"Request validation failed","status":422,"errors":[{"field":"body -> count","message":"Input should be a valid integer","type":"int_parsing"}]}},"authentication-configuration":{"summary":"Server is not configured for token validation","value":{"type":"authentication-configuration","title":"Server is not configured for token validation","status":500}},"authentication-failed":{"summary":"Authentication failed unexpectedly","value":{"type":"authentication-failed","title":"Authentication failed unexpectedly","status":500}},"unexpected-failure":{"summary":"The request could not be completed","value":{"type":"unexpected-failure","title":"The request could not be completed","status":500}},"api-key-scope":{"summary":"API key must be scoped to a user","value":{"type":"api-key-scope","title":"API key must be scoped to a user","status":401}},"api-key-user-not-found":{"summary":"No user found for the API key","value":{"type":"api-key-user-not-found","title":"No user found for the API key","status":401}},"expired-token":{"summary":"Authentication token has expired","value":{"type":"expired-token","title":"Authentication token has expired","status":401}},"incomplete-token":{"summary":"Authentication token is missing required claims","value":{"type":"incomplete-token","title":"Authentication token is missing required claims","status":401,"claim":"email"}},"invalid-api-key":{"summary":"API key is not valid","value":{"type":"invalid-api-key","title":"API key is not valid","status":401}},"malformed-token":{"summary":"Authentication token is malformed","value":{"type":"malformed-token","title":"Authentication token is malformed","status":401}},"missing-credentials":{"summary":"Authentication token required","value":{"type":"missing-credentials","title":"Authentication token required","status":401}},"premature-token":{"summary":"Authentication token is not yet valid","value":{"type":"premature-token","title":"Authentication token is not yet valid","status":401}},"malformed-referral-code":{"summary":"Referral code format is not valid","value":{"type":"malformed-referral-code","title":"Referral code format is not valid","status":400}},"own-referral-code":{"summary":"You cannot use your own referral code","value":{"type":"own-referral-code","title":"You cannot use your own referral code","status":400}},"referral-code-not-found":{"summary":"Referral code does not match any user","value":{"type":"referral-code-not-found","title":"Referral code does not match any user","status":404}},"session-not-accessible":{"summary":"Access denied to this session","value":{"type":"session-not-accessible","title":"Access denied to this session","status":403,"session_id":"3fa85f64-5717-4562-b3fc-2c963f66afa6"}},"session-missing":{"summary":"Session not found","value":{"type":"session-missing","title":"Session not found","status":404,"session_id":"3fa85f64-5717-4562-b3fc-2c963f66afa6"}},"missing-identifier":{"summary":"A required identifier was not provided","value":{"type":"missing-identifier","title":"A required identifier was not provided","status":400,"field":"session_id"}},"comment-action-not-stored":{"summary":"Recording the comment action failed","value":{"type":"comment-action-not-stored","title":"Recording the comment action failed","status":500,"comment_id":"3fa85f64-5717-4562-b3fc-2c963f66afa6"}},"comment-not-actionable":{"summary":"Comment cannot be actioned","value":{"type":"comment-not-actionable","title":"Comment cannot be actioned","status":400,"comment_id":"3fa85f64-5717-4562-b3fc-2c963f66afa6"}},"invalid-comment-action-type":{"summary":"Comment action type is not valid","value":{"type":"invalid-comment-action-type","title":"Comment action type is not valid","status":400,"accepted":["dismissed","addressed"],"action_type":"resolved"}},"session-already-accessible":{"summary":"You already have access to this session","value":{"type":"session-already-accessible","title":"You already have access to this session","status":400,"session_id":"3fa85f64-5717-4562-b3fc-2c963f66afa6"}},"session-sharing-restricted":{"summary":"This session cannot be shared outside its organization","value":{"type":"session-sharing-restricted","title":"This session cannot be shared outside its organization","status":403,"session_id":"3fa85f64-5717-4562-b3fc-2c963f66afa6"}},"payment-system":{"summary":"Payment system error","value":{"type":"payment-system","title":"Payment system error","status":502}},"original-upload-storage":{"summary":"Storing the uploaded file failed","value":{"type":"original-upload-storage","title":"Storing the uploaded file failed","status":500}},"invalid-uploaded-file":{"summary":"Uploaded file was rejected","value":{"type":"invalid-uploaded-file","title":"Uploaded file was rejected","status":400,"max_megabytes":100,"reason":"file_too_large"}},"malformed-document-id":{"summary":"Document ID is not a valid UUID","value":{"type":"malformed-document-id","title":"Document ID is not a valid UUID","status":400,"field":"document_id"}},"missing-filename":{"summary":"A filename is required","value":{"type":"missing-filename","title":"A filename is required","status":400}},"nested-supplementary-material":{"summary":"Supplementary material cannot be nested","value":{"type":"nested-supplementary-material","title":"Supplementary material cannot be nested","status":400,"parent_document_id":"3fa85f64-5717-4562-b3fc-2c963f66afa6"}},"supplementary-material-limit-reached":{"summary":"Supplementary material limit reached","value":{"type":"supplementary-material-limit-reached","title":"Supplementary material limit reached","status":400,"max_supplementary_material":5}},"parent-document-not-owned":{"summary":"Parent document belongs to another user","value":{"type":"parent-document-not-owned","title":"Parent document belongs to another user","status":403,"parent_document_id":"3fa85f64-5717-4562-b3fc-2c963f66afa6"}},"authenticated-user-not-found":{"summary":"User not found","value":{"type":"authenticated-user-not-found","title":"User not found","status":404}},"parent-document-not-found":{"summary":"Parent document not found","value":{"type":"parent-document-not-found","title":"Parent document not found","status":404,"parent_document_id":"3fa85f64-5717-4562-b3fc-2c963f66afa6"}},"document-token-limit":{"summary":"Document exceeds the size limit for your plan","value":{"type":"document-token-limit","title":"Document exceeds the size limit for your plan","status":422,"max_tokens":200000,"token_count":243118}},"document-word-limit":{"summary":"Document exceeds the word limit for your plan","value":{"type":"document-word-limit","title":"Document exceeds the word limit for your plan","status":422,"max_document_words":40000,"word_count":52310}},"short-document-text":{"summary":"Document does not contain enough text","value":{"type":"short-document-text","title":"Document does not contain enough text","status":422,"minimum_length":500,"text_length":218}},"unknown-prompt-set":{"summary":"Prompt set does not exist","value":{"type":"unknown-prompt-set","title":"Prompt set does not exist","status":422,"prompt_set":"verbose"}},"unknown-steering-target":{"summary":"Steering targets are not supplementary material of this document","value":{"type":"unknown-steering-target","title":"Steering targets are not supplementary material of this document","status":422,"unknown_supplementary_material_ids":["3fa85f64-5717-4562-b3fc-2c963f66afa6"]}},"processing-job-not-created":{"summary":"Creating the processing task failed","value":{"type":"processing-job-not-created","title":"Creating the processing task failed","status":500}},"document-not-accessible":{"summary":"Access denied to this document","value":{"type":"document-not-accessible","title":"Access denied to this document","status":403,"document_id":"3fa85f64-5717-4562-b3fc-2c963f66afa6"}},"no-credits":{"summary":"No credits remaining","value":{"type":"no-credits","title":"No credits remaining","status":403,"credit_type":"paid"}},"review-customization-forbidden":{"summary":"Review customization is restricted to Refine admins","value":{"type":"review-customization-forbidden","title":"Review customization is restricted to Refine admins","status":403}},"document-not-found":{"summary":"Document not found","value":{"type":"document-not-found","title":"Document not found","status":404,"document_id":"3fa85f64-5717-4562-b3fc-2c963f66afa6"}},"document-text-not-ready":{"summary":"Document has not finished converting","value":{"type":"document-text-not-ready","title":"Document has not finished converting","status":404,"document_id":"3fa85f64-5717-4562-b3fc-2c963f66afa6"}},"revision-session-not-accessible":{"summary":"Previous revision session is not accessible","value":{"type":"revision-session-not-accessible","title":"Previous revision session is not accessible","status":404,"previous_session_id":"3fa85f64-5717-4562-b3fc-2c963f66afa6"}},"supplementary-material-not-ready":{"summary":"Supplementary material is still being converted","value":{"type":"supplementary-material-not-ready","title":"Supplementary material is still being converted","status":409,"unconverted_document_ids":["3fa85f64-5717-4562-b3fc-2c963f66afa6"]}},"credit-service-unavailable":{"summary":"Credit service is temporarily unavailable","value":{"type":"credit-service-unavailable","title":"Credit service is temporarily unavailable","status":503}},"processing-dispatch":{"summary":"Processing service is temporarily unavailable","value":{"type":"processing-dispatch","title":"Processing service is temporarily unavailable","status":503,"credit_refunded":true}},"invalid-image-request":{"summary":"Image name is not valid","value":{"type":"invalid-image-request","title":"Image name is not valid","status":400}},"image-not-found":{"summary":"Image not found","value":{"type":"image-not-found","title":"Image not found","status":404,"image_name":"figure-3.png"}},"unknown-price":{"summary":"Price ID is not recognised","value":{"type":"unknown-price","title":"Price ID is not recognised","status":400,"price_id":"price_1AbCdEfGhIjKlMnO"}},"no-subscription":{"summary":"No active subscription found","value":{"type":"no-subscription","title":"No active subscription found","status":404}},"organization-credits-unavailable":{"summary":"Organization credit data is unavailable","value":{"type":"organization-credits-unavailable","title":"Organization credit data is unavailable","status":500,"organization_id":"org_2abcDEF456"}},"organization-permission":{"summary":"Insufficient permissions for this organization","value":{"type":"organization-permission","title":"Insufficient permissions for this organization","status":403,"action":"view_credits","organization_id":"org_2abcDEF456"}},"organization-missing":{"summary":"Organization not found","value":{"type":"organization-missing","title":"Organization not found","status":404,"organization_id":"org_2abcDEF456"}},"allocation-target-not-a-member":{"summary":"Target user is not a member of this organization","value":{"type":"allocation-target-not-a-member","title":"Target user is not a member of this organization","status":400,"organization_id":"org_2abcDEF456"}},"credit-allocation-failed":{"summary":"Credit allocation could not be completed","value":{"type":"credit-allocation-failed","title":"Credit allocation could not be completed","status":400,"organization_id":"org_2abcDEF456"}},"organization-pool-exhausted":{"summary":"Organization credit pool has insufficient credits","value":{"type":"organization-pool-exhausted","title":"Organization credit pool has insufficient credits","status":400,"organization_id":"org_2abcDEF456"}},"organization-membership-required":{"summary":"You are not a member of this organization","value":{"type":"organization-membership-required","title":"You are not a member of this organization","status":403,"organization_id":"org_2abcDEF456"}},"marketing-state-unavailable":{"summary":"Marketing preference update returned no state","value":{"type":"marketing-state-unavailable","title":"Marketing preference update returned no state","status":500}}}},"security":[{"BearerAuth":[]},{"OAuth2":["openid","profile","email"]}]}