{"openapi": "3.1.0", "info": {"title": "Tinyhat Chores API", "x-model-rubric": "decisions-rubric-6", "version": "1", "description": "These instructions follow the AI Agent Manifesto: <https://tinyhat.ai/chore/manifesto>. Anonymous Markdown Hat reads and account-owned manual request intake. Intake receipt means triage, not provider matching or booking."}, "paths": {"/api/service-requests": {"post": {"tags": ["Tinyhat Chores"], "summary": "Submit a service request", "description": "Save a job brief as a service request for Tinyhat's manual review when the user wants help seeking providers. Requires the owner's token and permission to share the file. Returns HTTP 202 with a unique service_request_id for retrieving the saved item and checking status. This does not contact providers or make a booking.", "operationId": "create_service_request", "security": [{"TinyhatHumanSession": []}], "parameters": [{"name": "Idempotency-Key", "in": "header", "required": true, "schema": {"type": "string", "minLength": 8, "maxLength": 80, "title": "Idempotency-Key"}}, {"name": "X-File-Name", "in": "header", "required": true, "schema": {"type": "string", "maxLength": 100, "title": "X-File-Name"}}, {"name": "X-Tinyhat-Share-With-Team", "in": "header", "required": true, "schema": {"const": "true", "type": "string", "description": "Set true only with the user's permission to share this complete business body with Tinyhat's review team and configured Slack audience.", "title": "X-Tinyhat-Share-With-Team"}, "description": "Set true only with the user's permission to share this complete business body with Tinyhat's review team and configured Slack audience."}], "responses": {"202": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ServiceRequestReceipt"}}}}, "401": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Unauthorized"}, "404": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Not Found"}, "409": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Conflict"}, "413": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Request Entity Too Large"}, "415": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Unsupported Media Type"}, "422": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Unprocessable Entity"}, "429": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Too Many Requests"}, "503": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Service Unavailable"}}, "requestBody": {"required": true, "content": {"text/markdown": {"schema": {"type": "string", "format": "binary", "maxLength": 65536}}, "text/plain": {"schema": {"type": "string", "format": "binary", "maxLength": 65536}}, "application/json": {"schema": {"type": "string", "format": "binary", "maxLength": 65536}}}}}, "get": {"tags": ["Tinyhat Chores"], "summary": "List Service Requests", "description": "Check your recent home-service submissions and notification status. Requires the owner's token. Returns only your service-request receipts, newest first, without the job-brief text.", "operationId": "list_service_requests", "security": [{"TinyhatHumanSession": []}], "parameters": [{"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "maximum": 100, "minimum": 1, "default": 20, "title": "Limit"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "array", "items": {"$ref": "#/components/schemas/ServiceRequestReceipt"}, "title": "Response List Service Requests"}}}}, "401": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Unauthorized"}, "404": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Not Found"}, "409": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Conflict"}, "413": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Request Entity Too Large"}, "415": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Unsupported Media Type"}, "422": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Unprocessable Entity"}, "429": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Too Many Requests"}, "503": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Service Unavailable"}}}}, "/api/service-requests/{service_request_id}": {"get": {"tags": ["Tinyhat Chores"], "summary": "Get Service Request", "description": "Reopen a service request using its service_request_id. Requires the same owner's token. Returns the saved job brief and receipt; another owner's item or a Hat-request ID returns 404.", "operationId": "get_service_request", "security": [{"TinyhatHumanSession": []}], "parameters": [{"name": "service_request_id", "in": "path", "required": true, "schema": {"type": "string", "format": "uuid", "title": "Service Request Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ServiceRequestDetail"}}}}, "401": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Unauthorized"}, "404": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Not Found"}, "409": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Conflict"}, "413": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Request Entity Too Large"}, "415": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Unsupported Media Type"}, "422": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Unprocessable Entity"}, "429": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Too Many Requests"}, "503": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Service Unavailable"}}}}, "/api/hat-requests": {"post": {"tags": ["Tinyhat Chores"], "summary": "Request a missing Hat", "description": "Tell Tinyhat which missing Hat would help your agent handle a chore. Requires the owner's token. Saves the question for manual review and returns HTTP 202 with a unique hat_request_id. It does not immediately create a Hat or arrange a service.", "operationId": "create_hat_request", "security": [{"TinyhatHumanSession": []}], "parameters": [{"name": "Idempotency-Key", "in": "header", "required": true, "schema": {"type": "string", "minLength": 8, "maxLength": 80, "title": "Idempotency-Key"}}, {"name": "X-Tinyhat-Share-With-Team", "in": "header", "required": true, "schema": {"const": "true", "type": "string", "description": "Set true only with the user's permission to share this complete business body with Tinyhat's review team and configured Slack audience.", "title": "X-Tinyhat-Share-With-Team"}, "description": "Set true only with the user's permission to share this complete business body with Tinyhat's review team and configured Slack audience."}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HatRequest"}}}}, "responses": {"202": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HatRequestReceipt"}}}}, "401": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Unauthorized"}, "404": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Not Found"}, "409": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Conflict"}, "413": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Request Entity Too Large"}, "415": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Unsupported Media Type"}, "422": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Unprocessable Entity"}, "429": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Too Many Requests"}, "503": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Service Unavailable"}}}, "get": {"tags": ["Tinyhat Chores"], "summary": "List your Hat requests", "description": "Check your requests for missing Hats. Requires the owner's token. Returns only your Hat-request receipts, newest first, without the saved questions.", "operationId": "list_hat_requests", "security": [{"TinyhatHumanSession": []}], "parameters": [{"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "maximum": 100, "minimum": 1, "default": 20, "title": "Limit"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"type": "array", "items": {"$ref": "#/components/schemas/HatRequestReceipt"}, "title": "Response List Hat Requests"}}}}, "401": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Unauthorized"}, "404": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Not Found"}, "409": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Conflict"}, "413": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Request Entity Too Large"}, "415": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Unsupported Media Type"}, "422": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Unprocessable Entity"}, "429": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Too Many Requests"}, "503": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Service Unavailable"}}}}, "/api/hat-requests/{hat_request_id}": {"get": {"tags": ["Tinyhat Chores"], "summary": "Read your Hat request", "description": "Reopen a missing-Hat request using its hat_request_id. Requires the same owner's token. Returns the saved question and receipt; another owner's item or a service-request ID returns 404.", "operationId": "get_hat_request", "security": [{"TinyhatHumanSession": []}], "parameters": [{"name": "hat_request_id", "in": "path", "required": true, "schema": {"type": "string", "format": "uuid", "title": "Hat Request Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HatRequestDetail"}}}}, "401": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Unauthorized"}, "404": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Not Found"}, "409": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Conflict"}, "413": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Request Entity Too Large"}, "415": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Unsupported Media Type"}, "422": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Unprocessable Entity"}, "429": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Too Many Requests"}, "503": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}, "description": "Service Unavailable"}}}}, "/api/delegations": {"post": {"tags": ["Tinyhat Delegations"], "summary": "Submit Delegation", "operationId": "submit_delegation", "security": [{"TinyhatHumanSession": []}], "parameters": [{"name": "Idempotency-Key", "in": "header", "required": true, "schema": {"type": "string", "minLength": 8, "maxLength": 80, "title": "Idempotency-Key"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DelegationInput"}}}}, "responses": {"202": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DelegationReceipt"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "description": "Ask Tinyhat to take over provider finding using the exact authorized job file, service and city/region. Requires the existing owner's bearer session and explicit team-sharing permission. Returns a delegation_id, PENDING and a server decision_deadline within five minutes. PENDING and Slack delivery are not acceptance. Approval configuration and actual host authentication remain release gates."}}, "/api/delegations/{delegation_id}": {"get": {"tags": ["Tinyhat Delegations"], "summary": "Get Delegation Status", "description": "Read only your delegation's authoritative decision and deadline. Poll the same ID about every ten seconds and at the deadline. A failed read means uncertainty; recover the same ID. APPROVED transfers provider coordination only; reconcile parallel inquiries. No provider booking, payment or completion is implied.", "operationId": "get_delegation_status", "security": [{"TinyhatHumanSession": []}], "parameters": [{"name": "delegation_id", "in": "path", "required": true, "schema": {"type": "string", "format": "uuid", "title": "Delegation Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DelegationReceipt"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/delegations/{delegation_id}/cancel": {"post": {"tags": ["Tinyhat Delegations"], "summary": "Cancel Delegation", "description": "Cancel your pending delegation. An approved request cannot be undone by this operation; agree any handback with Tinyhat. Repeated cancellation returns the existing terminal state.", "operationId": "cancel_delegation", "security": [{"TinyhatHumanSession": []}], "parameters": [{"name": "delegation_id", "in": "path", "required": true, "schema": {"type": "string", "format": "uuid", "title": "Delegation Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DelegationReceipt"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/delegations/{delegation_id}/content": {"delete": {"tags": ["Tinyhat Delegations"], "summary": "Delete Delegation Content", "description": "Permanently remove your backend delegation file and service/location labels after confirming irreversible removal. Cancels pending requests; approved provider coordination remains owned by Tinyhat until an agreed handback. Keeps the decision, hashes and retry record. Prior Slack copies may remain under workspace retention and cannot be recalled through the incoming webhook. Backend file removal is scheduled after 30 days, with owner removal available sooner.", "operationId": "delete_delegation_content", "security": [{"TinyhatHumanSession": []}], "parameters": [{"name": "delegation_id", "in": "path", "required": true, "schema": {"type": "string", "format": "uuid", "title": "Delegation Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DelegationReceipt"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/chores": {"get": {"tags": ["Tiny Chores"], "summary": "Recent Chores", "operationId": "recent_chores", "security": [{"TinyhatChoresReadSession": []}], "parameters": [{"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "maximum": 20, "minimum": 1, "default": 20, "title": "Limit"}}, {"name": "cursor", "in": "query", "required": false, "schema": {"anyOf": [{"type": "string", "maxLength": 256}, {"type": "null"}], "title": "Cursor"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ChorePage"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "description": "Read up to twenty of your delegated chores, newest delegation first. Requires your verified owner session or linked OAuth token with chores:status. An optional cursor continues older records; another owner's records are never included. No job file, quote, appointment or completion is inferred."}}, "/api/chores/{chore_id}": {"get": {"tags": ["Tiny Chores"], "summary": "Chore Detail", "operationId": "chore_detail", "security": [{"TinyhatChoresReadSession": []}], "parameters": [{"name": "chore_id", "in": "path", "required": true, "schema": {"type": "string", "format": "uuid", "title": "Chore Id"}}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ChoreSummary"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "description": "Read a minimal description, delegation timestamp, status and ID for your own chore. Requires the same verified owner session. Another owner's or missing ID returns 404. This does not change, book or cancel a chore."}}, "/api/hats": {"get": {"operationId": "search_hats", "summary": "Find Hats", "parameters": [{"name": "q", "in": "query", "required": true, "schema": {"type": "string", "minLength": 1, "maxLength": 300}}, {"name": "location", "in": "query", "schema": {"type": "string", "maxLength": 150, "default": ""}}, {"name": "limit", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 10, "default": 10}}, {"name": "use_model", "in": "query", "schema": {"type": "boolean", "default": false}, "description": "Explicit opt-in to share this query/city with OpenAI Decisions."}], "responses": {"200": {"description": "Plain Markdown", "content": {"text/markdown": {"schema": {"type": "string"}}}}}, "security": [], "description": "Describe a chore and location to find relevant Hats. Use this first to choose what to read. Returns up to ten ranked Markdown Hat links; no sign-in is required."}}, "/api/hats/content/{path}": {"get": {"operationId": "get_hat", "summary": "Read a Hat", "parameters": [{"name": "path", "in": "path", "required": true, "description": "Canonical slash-separated Hat path returned by search", "schema": {"type": "string"}}], "responses": {"200": {"description": "Plain Markdown", "content": {"text/markdown": {"schema": {"type": "string"}}}}}, "security": [], "description": "Read a Hat using a path returned by search. It explains what providers need and how an agent can progress the chore. Returns the exact Markdown shown on the Hat page and download; no sign-in is required."}}, "/hapi/v2/auth/email/request": {"post": {"tags": ["Tinyhat agent API v2"], "summary": "Request Email Code", "description": "Start the existing Tinyhat email sign-in flow when the owner has authorized it. Returns a challenge ID and expiry without revealing whether an account exists. It sends a one-time code to that email; never log the code.", "operationId": "tinyhat_v2_request_email_code", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/EmailCodeRequest"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EmailCodeRequested"}}}}, "401": {"description": "Unauthorized", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}}, "402": {"description": "Payment Required", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}}, "404": {"description": "Not Found", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}}, "409": {"description": "Conflict", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}}, "422": {"description": "Unprocessable Entity", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}}, "429": {"description": "Too Many Requests", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}}, "503": {"description": "Service Unavailable", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}}}, "servers": [{"url": "https://apii.tinyloop.co"}]}}, "/hapi/v2/auth/email/verify": {"post": {"tags": ["Tinyhat agent API v2"], "summary": "Verify Email Code", "description": "Complete the email challenge with the owner's matching code. Returns the existing expiring owner bearer session and account information. Keep the token private; this does not submit a service request.", "operationId": "tinyhat_v2_verify_email_code", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/EmailCodeVerify"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentSessionOut"}}}}, "401": {"description": "Unauthorized", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}}, "402": {"description": "Payment Required", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}}, "404": {"description": "Not Found", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}}, "409": {"description": "Conflict", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}}, "422": {"description": "Unprocessable Entity", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}}, "429": {"description": "Too Many Requests", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}}, "503": {"description": "Service Unavailable", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}}}, "servers": [{"url": "https://apii.tinyloop.co"}]}}, "/auth/session": {"delete": {"tags": ["Tinyhat agent API v2"], "summary": "Sign Out", "description": "Revoke only the current owner's bearer session. Requires that token and returns HTTP 204. Saved service requests are retained; no provider is contacted.", "operationId": "tinyhat_v2_sign_out", "responses": {"204": {"description": "Successful Response"}, "401": {"description": "Unauthorized", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}}, "402": {"description": "Payment Required", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}}, "404": {"description": "Not Found", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}}, "409": {"description": "Conflict", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}}, "422": {"description": "Unprocessable Entity", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}}, "429": {"description": "Too Many Requests", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}}, "503": {"description": "Service Unavailable", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AgentErrorResponse"}}}}}, "security": [{"TinyhatHumanSession": []}]}}}, "components": {"schemas": {"AgentErrorDetail": {"properties": {"code": {"type": "string", "title": "Code"}, "message": {"type": "string", "title": "Message"}, "fields": {"anyOf": [{"items": {"type": "string"}, "type": "array"}, {"type": "null"}], "title": "Fields"}, "stripe_code": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Stripe Code"}, "stripe_message": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Stripe Message"}, "stripe_request_id": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Stripe Request Id"}}, "type": "object", "required": ["code", "message"], "title": "AgentErrorDetail"}, "AgentErrorResponse": {"properties": {"error": {"$ref": "#/components/schemas/AgentErrorDetail"}}, "type": "object", "required": ["error"], "title": "AgentErrorResponse"}, "ChorePage": {"properties": {"items": {"items": {"$ref": "#/components/schemas/ChoreSummary"}, "type": "array", "maxItems": 20, "title": "Items"}, "next_cursor": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Next Cursor"}}, "type": "object", "required": ["items"], "title": "ChorePage"}, "ChoreSummary": {"properties": {"id": {"type": "string", "title": "Id"}, "description": {"type": "string", "title": "Description"}, "status": {"type": "string", "enum": ["PENDING", "IN_PROGRESS", "DECLINED", "CANCELLED"], "title": "Status"}, "delegated_at": {"type": "string", "format": "date-time", "title": "Delegated At"}, "synthetic": {"type": "boolean", "title": "Synthetic", "default": false}, "cost": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Cost"}, "time": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Time"}}, "additionalProperties": false, "type": "object", "required": ["id", "description", "status", "delegated_at"], "title": "ChoreSummary"}, "DelegationInput": {"properties": {"service": {"type": "string", "maxLength": 150, "minLength": 1, "title": "Service", "description": "Service needed, without personal details."}, "location": {"type": "string", "maxLength": 150, "minLength": 1, "title": "Location", "description": "City/region, without a street address or access codes."}, "filename": {"type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9_-]{0,90}\\.(?:md|txt|json)$", "title": "Filename"}, "content": {"type": "string", "maxLength": 65536, "minLength": 1, "pattern": "\\S", "title": "Content", "description": "The exact provider-ready UTF-8 file authorized for Tinyhat's team."}, "share_with_team": {"type": "boolean", "const": true, "title": "Share With Team", "description": "True only with permission to share this exact file, service and location with Tinyhat's existing internal Slack audience for provider coordination."}}, "additionalProperties": false, "type": "object", "required": ["service", "location", "filename", "content", "share_with_team"], "title": "DelegationInput"}, "DelegationReceipt": {"properties": {"delegation_id": {"type": "string", "title": "Delegation Id"}, "status": {"type": "string", "enum": ["PENDING", "APPROVED", "DECLINED", "CANCELLED"], "title": "Status"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}, "decision_deadline": {"type": "string", "format": "date-time", "title": "Decision Deadline"}, "decided_at": {"anyOf": [{"type": "string", "format": "date-time"}, {"type": "null"}], "title": "Decided At"}, "decision_reason": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Decision Reason"}, "filename": {"type": "string", "title": "Filename"}, "content_sha256": {"type": "string", "title": "Content Sha256"}, "delivery_status": {"type": "string", "enum": ["BLOCKED", "SENDING", "DELIVERED", "FAILED", "UNKNOWN"], "title": "Delivery Status"}, "delivery_code": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Delivery Code"}, "next_action": {"type": "string", "title": "Next Action"}, "poll_after_seconds": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Poll After Seconds"}, "content_expires_at": {"type": "string", "format": "date-time", "title": "Content Expires At"}, "content_deleted_at": {"anyOf": [{"type": "string", "format": "date-time"}, {"type": "null"}], "title": "Content Deleted At"}, "slack_copy_may_remain": {"type": "boolean", "title": "Slack Copy May Remain", "description": "A file already sent to Slack follows workspace retention and cannot be recalled through the incoming webhook.", "default": false}}, "type": "object", "required": ["delegation_id", "status", "created_at", "decision_deadline", "decided_at", "decision_reason", "filename", "content_sha256", "delivery_status", "delivery_code", "next_action", "poll_after_seconds", "content_expires_at"], "title": "DelegationReceipt"}, "HTTPValidationError": {"properties": {"detail": {"items": {"$ref": "#/components/schemas/ValidationError"}, "type": "array", "title": "Detail"}}, "type": "object", "title": "HTTPValidationError"}, "HatRequest": {"properties": {"question": {"type": "string", "maxLength": 4000, "minLength": 8, "title": "Question", "description": "The task your agent wants to handle more independently; omit personal data."}}, "additionalProperties": false, "type": "object", "required": ["question"], "title": "Request a missing Hat"}, "HatRequestDetail": {"properties": {"hat_request_id": {"type": "string", "title": "Hat Request Id"}, "status": {"type": "string", "const": "RECEIVED", "title": "Status"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}, "usage_kind": {"type": "string", "enum": ["test", "actual"], "title": "Usage Kind"}, "filename": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Filename"}, "content_sha256": {"type": "string", "title": "Content Sha256"}, "delivery_status": {"type": "string", "enum": ["BLOCKED", "SENDING", "DELIVERED", "FAILED", "UNKNOWN"], "title": "Delivery Status"}, "delivery_code": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Delivery Code"}, "delivered_at": {"anyOf": [{"type": "string", "format": "date-time"}, {"type": "null"}], "title": "Delivered At"}, "message": {"type": "string", "title": "Message", "default": "Received for manual triage. No provider has been contacted, matched or booked."}, "content": {"type": "string", "title": "Content"}}, "type": "object", "required": ["hat_request_id", "status", "created_at", "usage_kind", "filename", "content_sha256", "delivery_status", "delivery_code", "delivered_at", "content"], "title": "HatRequestDetail"}, "HatRequestReceipt": {"properties": {"hat_request_id": {"type": "string", "title": "Hat Request Id"}, "status": {"type": "string", "const": "RECEIVED", "title": "Status"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}, "usage_kind": {"type": "string", "enum": ["test", "actual"], "title": "Usage Kind"}, "filename": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Filename"}, "content_sha256": {"type": "string", "title": "Content Sha256"}, "delivery_status": {"type": "string", "enum": ["BLOCKED", "SENDING", "DELIVERED", "FAILED", "UNKNOWN"], "title": "Delivery Status"}, "delivery_code": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Delivery Code"}, "delivered_at": {"anyOf": [{"type": "string", "format": "date-time"}, {"type": "null"}], "title": "Delivered At"}, "message": {"type": "string", "title": "Message", "default": "Received for manual triage. No provider has been contacted, matched or booked."}}, "type": "object", "required": ["hat_request_id", "status", "created_at", "usage_kind", "filename", "content_sha256", "delivery_status", "delivery_code", "delivered_at"], "title": "HatRequestReceipt"}, "ServiceRequestDetail": {"properties": {"service_request_id": {"type": "string", "title": "Service Request Id"}, "status": {"type": "string", "const": "RECEIVED", "title": "Status"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}, "usage_kind": {"type": "string", "enum": ["test", "actual"], "title": "Usage Kind"}, "filename": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Filename"}, "content_sha256": {"type": "string", "title": "Content Sha256"}, "delivery_status": {"type": "string", "enum": ["BLOCKED", "SENDING", "DELIVERED", "FAILED", "UNKNOWN"], "title": "Delivery Status"}, "delivery_code": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Delivery Code"}, "delivered_at": {"anyOf": [{"type": "string", "format": "date-time"}, {"type": "null"}], "title": "Delivered At"}, "message": {"type": "string", "title": "Message", "default": "Received for manual triage. No provider has been contacted, matched or booked."}, "content": {"type": "string", "title": "Content"}}, "type": "object", "required": ["service_request_id", "status", "created_at", "usage_kind", "filename", "content_sha256", "delivery_status", "delivery_code", "delivered_at", "content"], "title": "ServiceRequestDetail"}, "ServiceRequestReceipt": {"properties": {"service_request_id": {"type": "string", "title": "Service Request Id"}, "status": {"type": "string", "const": "RECEIVED", "title": "Status"}, "created_at": {"type": "string", "format": "date-time", "title": "Created At"}, "usage_kind": {"type": "string", "enum": ["test", "actual"], "title": "Usage Kind"}, "filename": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Filename"}, "content_sha256": {"type": "string", "title": "Content Sha256"}, "delivery_status": {"type": "string", "enum": ["BLOCKED", "SENDING", "DELIVERED", "FAILED", "UNKNOWN"], "title": "Delivery Status"}, "delivery_code": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Delivery Code"}, "delivered_at": {"anyOf": [{"type": "string", "format": "date-time"}, {"type": "null"}], "title": "Delivered At"}, "message": {"type": "string", "title": "Message", "default": "Received for manual triage. No provider has been contacted, matched or booked."}}, "type": "object", "required": ["service_request_id", "status", "created_at", "usage_kind", "filename", "content_sha256", "delivery_status", "delivery_code", "delivered_at"], "title": "ServiceRequestReceipt"}, "ValidationError": {"properties": {"loc": {"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, "type": "array", "title": "Location"}, "msg": {"type": "string", "title": "Message"}, "type": {"type": "string", "title": "Error Type"}, "input": {"title": "Input"}, "ctx": {"type": "object", "title": "Context"}}, "type": "object", "required": ["loc", "msg", "type"], "title": "ValidationError"}, "AccountAddress": {"properties": {"line1": {"type": "string", "maxLength": 200, "minLength": 1, "title": "Line1"}, "line2": {"anyOf": [{"type": "string", "maxLength": 200}, {"type": "null"}], "title": "Line2"}, "city": {"type": "string", "maxLength": 100, "minLength": 1, "title": "City"}, "state": {"anyOf": [{"type": "string", "maxLength": 100}, {"type": "null"}], "title": "State"}, "postal_code": {"type": "string", "maxLength": 32, "minLength": 1, "title": "Postal Code"}}, "additionalProperties": false, "type": "object", "required": ["line1", "city", "postal_code"], "title": "AccountAddress"}, "AgentAccountOut": {"properties": {"account_handle": {"type": "string", "title": "Account Handle"}, "email": {"type": "string", "title": "Email"}, "phone": {"type": "string", "title": "Phone", "default": ""}, "display_name": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Display Name"}, "stage": {"type": "string", "enum": ["basic", "full"], "title": "Stage"}, "profile": {"anyOf": [{"$ref": "#/components/schemas/AgentAccountProfile"}, {"type": "null"}]}, "stripe_readiness": {"type": "string", "enum": ["not_connected", "pending", "needs_information", "ready", "setup_required", "recovery_required"], "title": "Stripe Readiness", "default": "not_connected"}, "stripe_detail": {"type": "string", "title": "Stripe Detail", "default": "A saved profile does not complete Stripe verification or enable provider purchases."}, "credit_balance_cents": {"type": "integer", "title": "Credit Balance Cents"}, "currency": {"type": "string", "const": "usd", "title": "Currency", "default": "usd"}, "computer_limit": {"type": "integer", "title": "Computer Limit"}, "computer_count": {"type": "integer", "title": "Computer Count"}, "is_vip": {"type": "boolean", "title": "Is Vip"}}, "type": "object", "required": ["account_handle", "email", "display_name", "stage", "profile", "credit_balance_cents", "computer_limit", "computer_count", "is_vip"], "title": "AgentAccountOut"}, "AgentAccountProfile": {"properties": {"legal_name": {"type": "string", "maxLength": 200, "minLength": 1, "title": "Legal Name"}, "country": {"type": "string", "maxLength": 2, "minLength": 2, "title": "Country"}, "identity_type": {"type": "string", "enum": ["individual", "sole_proprietor", "company"], "title": "Identity Type"}, "address": {"$ref": "#/components/schemas/AccountAddress"}}, "additionalProperties": false, "type": "object", "required": ["legal_name", "country", "identity_type", "address"], "title": "AgentAccountProfile", "description": "Saved facts, distinct from Stripe verification and consent."}, "AgentSessionOut": {"properties": {"access_token": {"type": "string", "title": "Access Token"}, "token_type": {"type": "string", "const": "Bearer", "title": "Token Type", "default": "Bearer"}, "expires_at": {"type": "string", "format": "date-time", "title": "Expires At"}, "account": {"$ref": "#/components/schemas/AgentAccountOut"}, "applied_invitation_count": {"type": "integer", "title": "Applied Invitation Count"}}, "type": "object", "required": ["access_token", "expires_at", "account", "applied_invitation_count"], "title": "AgentSessionOut"}, "EmailCodeRequest": {"properties": {"email": {"type": "string", "maxLength": 254, "format": "email", "title": "Email", "description": "The human's email address."}}, "additionalProperties": false, "type": "object", "required": ["email"], "title": "EmailCodeRequest"}, "EmailCodeRequested": {"properties": {"challenge_id": {"type": "string", "title": "Challenge Id"}, "expires_at": {"type": "string", "format": "date-time", "title": "Expires At"}, "resend_after_seconds": {"type": "integer", "title": "Resend After Seconds"}, "message": {"type": "string", "title": "Message"}}, "type": "object", "required": ["challenge_id", "expires_at", "resend_after_seconds", "message"], "title": "EmailCodeRequested"}, "EmailCodeVerify": {"properties": {"challenge_id": {"type": "string", "pattern": "^thec_[A-Za-z0-9_-]{32}$", "title": "Challenge Id"}, "code": {"type": "string", "pattern": "^[0-9]{6}$", "title": "Code"}, "client_name": {"type": "string", "maxLength": 80, "minLength": 1, "title": "Client Name", "default": "Coding agent"}}, "additionalProperties": false, "type": "object", "required": ["challenge_id", "code"], "title": "EmailCodeVerify"}}, "securitySchemes": {"TinyhatHumanSession": {"type": "http", "description": "Human session from email verification. Never an admin or machine token.", "scheme": "bearer"}, "TinyhatChoresReadSession": {"type": "http", "description": "Existing email-verified owner session or linked OAuth token with chores:status. An anonymized subject is not a credential.", "scheme": "bearer"}}}, "servers": [{"url": "https://tinyhat.ai/chore"}]}