{"openapi": "3.1.0", "info": {"title": "ExpertRelay API", "version": "1", "description": "Your workspace’s data and actions: for an agency its clients, for an expert its customers and sales, and for both what people asked, skills and help requests. Authenticate with an API key from Settings: Authorization: Bearer er_…"}, "servers": [{"url": "https://expertrelay.ai"}], "components": {"securitySchemes": {"apiKey": {"type": "http", "scheme": "bearer"}}}, "security": [{"apiKey": []}], "paths": {"/api/v1/needs-you": {"get": {"operationId": "needs_you_get_needs-you", "summary": "What needs you", "description": "What needs the expert right now: customers asking for help, setup left to do (Stripe, a price, skills to make live), people who have access but never used it, open questions. Start here.", "tags": ["Everyone"], "x-acts": false, "parameters": [], "responses": {"200": {"description": "The result, as JSON."}, "400": {"description": "Something to fix, said in `error`."}, "401": {"description": "No valid API key."}, "403": {"description": "This key can’t write."}}}}, "/api/v1/week": {"get": {"operationId": "week_summary_get_week", "summary": "How the week went", "description": "The last 7 days: revenue, refunds, new and paying customers, answers given, and how many have access or connected but haven’t used it.", "tags": ["Everyone"], "x-acts": false, "parameters": [], "responses": {"200": {"description": "The result, as JSON."}, "400": {"description": "Something to fix, said in `error`."}, "401": {"description": "No valid API key."}, "403": {"description": "This key can’t write."}}}}, "/api/v1/activity": {"get": {"operationId": "list_activity_get_activity", "summary": "What clients asked", "description": "Questions your clients or customers asked, newest first, each with the skill, the decision and whether it needs a look. Use get_answer with a run_id for the full answer.", "tags": ["Everyone"], "x-acts": false, "parameters": [{"name": "client", "in": "query", "required": false, "schema": {"type": "string", "description": "An agency’s client: name, email or id."}}, {"name": "customer", "in": "query", "required": false, "schema": {"type": "string", "description": "An expert’s customer: email, name or id."}}, {"name": "skill", "in": "query", "required": false, "schema": {"type": "string", "description": "Part of a skill’s name."}}, {"name": "since_days", "in": "query", "required": false, "schema": {"type": "integer", "minimum": 1, "maximum": 365, "description": "How far back, in days (default 7)."}}, {"name": "needs_a_look", "in": "query", "required": false, "schema": {"type": "boolean", "description": "Only questions that need the agency."}}, {"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "minimum": 1, "maximum": 100, "description": "At most this many rows (default 25)."}}], "responses": {"200": {"description": "The result, as JSON."}, "400": {"description": "Something to fix, said in `error`."}, "401": {"description": "No valid API key."}, "403": {"description": "This key can’t write."}}}}, "/api/v1/answers/{run_id}": {"get": {"operationId": "get_answer_get_answers_run_id", "summary": "One answer", "description": "One question in full: what the client asked, the whole answer, the data it used, what the agency said about it, and any help request with the agency’s reply.", "tags": ["Everyone"], "x-acts": false, "parameters": [{"name": "run_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "The result, as JSON."}, "400": {"description": "Something to fix, said in `error`."}, "401": {"description": "No valid API key."}, "403": {"description": "This key can’t write."}}}}, "/api/v1/answers/{run_id}/right": {"post": {"operationId": "mark_answer_right_post_answers_run_id_right", "summary": "Mark an answer right", "description": "Record that an answer a client got was right.", "tags": ["Everyone"], "x-acts": true, "parameters": [{"name": "run_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "The result, as JSON."}, "400": {"description": "Something to fix, said in `error`."}, "401": {"description": "No valid API key."}, "403": {"description": "This key can’t write."}}}}, "/api/v1/answers/{run_id}/correction": {"post": {"operationId": "teach_correction_post_answers_run_id_correction", "summary": "Teach the skill from an answer", "description": "Teach a skill what an answer should have said. We write the next version with it; clients keep the current one until make_version_available.", "tags": ["Everyone"], "x-acts": true, "parameters": [{"name": "run_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "The result, as JSON."}, "400": {"description": "Something to fix, said in `error`."}, "401": {"description": "No valid API key."}, "403": {"description": "This key can’t write."}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"what_went_wrong": {"type": "string", "enum": ["missed_rule", "wrong_question", "wrong_facts", "format", "should_decline", "other"]}, "should_have_said": {"type": "string", "maxLength": 4000}}, "required": ["what_went_wrong", "should_have_said"]}}}}}}, "/api/v1/help-requests/{run_id}/rerun": {"post": {"operationId": "rerun_help_request_post_help-requests_run_id_rerun", "summary": "Run a help request again", "description": "Run a client’s request that asked for help again, on the current version with their data now. Only the agency sees the answer (get_answer → help_request.rerun).", "tags": ["Everyone"], "x-acts": true, "parameters": [{"name": "run_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "The result, as JSON."}, "400": {"description": "Something to fix, said in `error`."}, "401": {"description": "No valid API key."}, "403": {"description": "This key can’t write."}}}}, "/api/v1/help-requests/{run_id}/reply": {"post": {"operationId": "reply_to_help_request_post_help-requests_run_id_reply", "summary": "Reply to a help request", "description": "Email the client from the agency about their help request, optionally with the re-run answer, and mark it handled. Needs the owner’s approval in the app.", "tags": ["Everyone"], "x-acts": true, "parameters": [{"name": "run_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "The result, as JSON."}, "400": {"description": "Something to fix, said in `error`."}, "401": {"description": "No valid API key."}, "403": {"description": "This key can’t write."}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"message": {"type": "string", "maxLength": 4000}, "include_answer": {"type": "boolean"}}, "required": ["message"]}}}}}}, "/api/v1/help-requests/{run_id}/handled": {"post": {"operationId": "mark_help_handled_post_help-requests_run_id_handled", "summary": "Mark a help request handled", "description": "Close a help request handled another way, like a call. Sends nothing.", "tags": ["Everyone"], "x-acts": true, "parameters": [{"name": "run_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "The result, as JSON."}, "400": {"description": "Something to fix, said in `error`."}, "401": {"description": "No valid API key."}, "403": {"description": "This key can’t write."}}}}, "/api/v1/skills": {"get": {"operationId": "list_skills_get_skills", "summary": "Skills", "description": "Your skills: version, status, open questions and questions this week; for an agency who gets each and what client data it reads, for an expert its price and how many customers have it.", "tags": ["Everyone"], "x-acts": false, "parameters": [], "responses": {"200": {"description": "The result, as JSON."}, "400": {"description": "Something to fix, said in `error`."}, "401": {"description": "No valid API key."}, "403": {"description": "This key can’t write."}}}}, "/api/v1/skills/{skill}/try": {"post": {"operationId": "try_new_version_post_skills_skill_try", "summary": "Try a skill’s new version", "description": "Run a skill’s newest version: on the corrected question when it was made from a correction, otherwise on its sample. Only the agency sees the answer (get_try).", "tags": ["Everyone"], "x-acts": true, "parameters": [{"name": "skill", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "The result, as JSON."}, "400": {"description": "Something to fix, said in `error`."}, "401": {"description": "No valid API key."}, "403": {"description": "This key can’t write."}}}}, "/api/v1/skills/{skill}/release": {"post": {"operationId": "make_version_available_post_skills_skill_release", "summary": "Give clients the new version", "description": "Make a skill’s newest version the one clients use. Needs the owner’s approval in the app.", "tags": ["Everyone"], "x-acts": true, "parameters": [{"name": "skill", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "The result, as JSON."}, "400": {"description": "Something to fix, said in `error`."}, "401": {"description": "No valid API key."}, "403": {"description": "This key can’t write."}}}}, "/api/v1/tries/{run_id}": {"get": {"operationId": "get_try_get_tries_run_id", "summary": "A try’s answer", "description": "The state and answer of a try started with try_new_version.", "tags": ["Everyone"], "x-acts": false, "parameters": [{"name": "run_id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "The result, as JSON."}, "400": {"description": "Something to fix, said in `error`."}, "401": {"description": "No valid API key."}, "403": {"description": "This key can’t write."}}}}, "/api/v1/skills/from-session": {"post": {"operationId": "teach_from_session_post_skills_from-session", "summary": "Make a skill from this session", "description": "Use when the owner has just worked out how they decide or do something in this conversation (a price, a triage, a review, a reply), corrected you on how they do it, or asks you to remember it or make it a skill: offer to turn it into one of their skills, as a private draft only they can use. Call list_skills first; if one of theirs already does this job, use add_session_to_skill instead, so one job stays one skill. Prefer a packet: the job, the method step by step, the rules and thresholds they used, every place they corrected you (corrections), worked examples from the session (situation, what they had, what they decided, why), and what isn’t settled; we write the skill from it and ask open questions. If they already have a finished skill, send it instead as skill_md (the SKILL.md text), files (a skill folder as {path, content}), or zip_base64; its description must say when to use it, in a sentence starting “Use when”. Before sending: replace client and customer names, emails and identifying numbers with placeholders, show the owner what you’ll send, and only then call with personal_details_removed true.", "tags": ["Everyone"], "x-acts": true, "parameters": [], "responses": {"200": {"description": "The result, as JSON."}, "400": {"description": "Something to fix, said in `error`."}, "401": {"description": "No valid API key."}, "403": {"description": "This key can’t write."}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"packet": {"type": "object", "properties": {"title": {"type": "string", "description": "A short name for the skill."}, "job": {"type": "string", "description": "What it helps someone do."}, "method": {"type": "array", "items": {"type": "string"}}, "rules": {"type": "array", "items": {"type": "string"}}, "examples": {"type": "array", "items": {"type": "object", "properties": {"situation": {"type": "string"}, "inputs": {"type": "string"}, "decision": {"type": "string"}, "why": {"type": "string"}}}}, "corrections": {"type": "array", "description": "Where the owner corrected you in this conversation: what you had said or done, and what they said instead, in their words.", "items": {"type": "object", "properties": {"ai_said": {"type": "string"}, "owner_said": {"type": "string"}}, "required": ["owner_said"]}}, "changes": {"type": "array", "items": {"type": "string"}, "description": "For add_session_to_skill: what this session changes from what the skill does now, in the owner’s words. It becomes their latest word over anything said before."}, "unsure": {"type": "array", "items": {"type": "string"}}, "notes": {"type": "string"}, "file_texts": {"type": "array", "items": {"type": "object", "properties": {"name": {"type": "string"}, "text": {"type": "string"}}}}}, "required": ["title", "job"]}, "skill_md": {"type": "string", "description": "A finished SKILL.md, with a name and a description that says when to use it (“Use when …”)."}, "files": {"type": "array", "description": "A finished skill folder, including SKILL.md.", "items": {"type": "object", "properties": {"path": {"type": "string"}, "content": {"type": "string"}, "content_base64": {"type": "string"}}, "required": ["path"]}}, "zip_base64": {"type": "string", "description": "A finished skill as a ZIP, base64, under 8 MB."}, "source": {"type": "string", "description": "Where the session was, e.g. Claude or ChatGPT."}, "personal_details_removed": {"type": "boolean"}}, "required": ["personal_details_removed"]}}}}}}, "/api/v1/skills/{skill}/status": {"get": {"operationId": "skill_status_get_skills_skill_status", "summary": "Where a skill stands", "description": "Whether a skill from teach_from_session is still being written, ready to try (with its open questions), or what went wrong. By its job_id, or by the skill’s name.", "tags": ["Everyone"], "x-acts": false, "parameters": [{"name": "skill", "in": "path", "required": true, "schema": {"type": "string"}}, {"name": "job_id", "in": "query", "required": false, "schema": {"type": "string"}}], "responses": {"200": {"description": "The result, as JSON."}, "400": {"description": "Something to fix, said in `error`."}, "401": {"description": "No valid API key."}, "403": {"description": "This key can’t write."}}}}, "/api/v1/teach-jobs/{job_id}": {"get": {"operationId": "skill_status_get_teach-jobs_job_id", "summary": "Where a skill stands", "description": "Whether a skill from teach_from_session is still being written, ready to try (with its open questions), or what went wrong. By its job_id, or by the skill’s name.", "tags": ["Everyone"], "x-acts": false, "parameters": [{"name": "job_id", "in": "path", "required": true, "schema": {"type": "string"}}, {"name": "skill", "in": "query", "required": false, "schema": {"type": "string", "description": "The skill’s name."}}], "responses": {"200": {"description": "The result, as JSON."}, "400": {"description": "Something to fix, said in `error`."}, "401": {"description": "No valid API key."}, "403": {"description": "This key can’t write."}}}}, "/api/v1/skills/{skill}/answers": {"post": {"operationId": "answer_open_questions_post_skills_skill_answers", "summary": "Answer a skill’s open questions", "description": "Ask the owner the open questions skill_status lists, then send their answers by number. We write the skill’s next version with them, privately; answers are kept for later versions too.", "tags": ["Everyone"], "x-acts": true, "parameters": [{"name": "skill", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "The result, as JSON."}, "400": {"description": "Something to fix, said in `error`."}, "401": {"description": "No valid API key."}, "403": {"description": "This key can’t write."}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"answers": {"type": "array", "items": {"type": "object", "properties": {"number": {"type": "integer", "minimum": 1}, "answer": {"type": "string"}}, "required": ["number", "answer"]}}, "note": {"type": "string", "description": "Anything else that changed."}}, "required": ["answers"]}}}}}}, "/api/v1/skills/{skill}/sessions": {"post": {"operationId": "add_session_to_skill_post_skills_skill_sessions", "summary": "Add this session to a skill", "description": "Use when this conversation showed something one of the owner’s existing skills should know: a new case, an edge case, a rule they hadn’t said, or a correction to an answer the skill gave. list_skills names their skills. Send a packet, with what it changes from what the skill does now in changes (we add it to what the skill was written from), or, for a skill uploaded as finished, the updated skill as skill_md, files or zip_base64. Makes its next version, privately. Take personal details out and show the owner first, as with teach_from_session.", "tags": ["Everyone"], "x-acts": true, "parameters": [{"name": "skill", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "The result, as JSON."}, "400": {"description": "Something to fix, said in `error`."}, "401": {"description": "No valid API key."}, "403": {"description": "This key can’t write."}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"packet": {"type": "object", "properties": {"title": {"type": "string", "description": "A short name for the skill."}, "job": {"type": "string", "description": "What it helps someone do."}, "method": {"type": "array", "items": {"type": "string"}}, "rules": {"type": "array", "items": {"type": "string"}}, "examples": {"type": "array", "items": {"type": "object", "properties": {"situation": {"type": "string"}, "inputs": {"type": "string"}, "decision": {"type": "string"}, "why": {"type": "string"}}}}, "corrections": {"type": "array", "description": "Where the owner corrected you in this conversation: what you had said or done, and what they said instead, in their words.", "items": {"type": "object", "properties": {"ai_said": {"type": "string"}, "owner_said": {"type": "string"}}, "required": ["owner_said"]}}, "changes": {"type": "array", "items": {"type": "string"}, "description": "For add_session_to_skill: what this session changes from what the skill does now, in the owner’s words. It becomes their latest word over anything said before."}, "unsure": {"type": "array", "items": {"type": "string"}}, "notes": {"type": "string"}, "file_texts": {"type": "array", "items": {"type": "object", "properties": {"name": {"type": "string"}, "text": {"type": "string"}}}}}, "required": ["title", "job"]}, "skill_md": {"type": "string", "description": "A finished SKILL.md, with a name and a description that says when to use it (“Use when …”)."}, "files": {"type": "array", "description": "A finished skill folder, including SKILL.md.", "items": {"type": "object", "properties": {"path": {"type": "string"}, "content": {"type": "string"}, "content_base64": {"type": "string"}}, "required": ["path"]}}, "zip_base64": {"type": "string", "description": "A finished skill as a ZIP, base64, under 8 MB."}, "personal_details_removed": {"type": "boolean"}}, "required": ["personal_details_removed"]}}}}}}, "/api/v1/skills/{skill}/export": {"get": {"operationId": "export_skill_get_skills_skill_export", "summary": "A skill as SKILL.md", "description": "One of the owner’s skills as a Claude skill: its SKILL.md and other text files, to read, keep or use elsewhere, with a download link for the whole folder.", "tags": ["Everyone"], "x-acts": false, "parameters": [{"name": "skill", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "The result, as JSON."}, "400": {"description": "Something to fix, said in `error`."}, "401": {"description": "No valid API key."}, "403": {"description": "This key can’t write."}}}}, "/api/v1/upload-link": {"get": {"operationId": "upload_link_get_upload-link", "summary": "A link for big files", "description": "When files are too big to send through the chat (or the AI can’t read their bytes), a link the owner opens in their browser to drop them: a finished skill ZIP, material to write a new skill from, or files to add to an existing skill.", "tags": ["Everyone"], "x-acts": false, "parameters": [{"name": "what", "in": "query", "required": false, "schema": {"type": "string", "enum": ["material", "finished_skill"]}}, {"name": "skill", "in": "query", "required": false, "schema": {"type": "string", "description": "The skill’s name."}}], "responses": {"200": {"description": "The result, as JSON."}, "400": {"description": "Something to fix, said in `error`."}, "401": {"description": "No valid API key."}, "403": {"description": "This key can’t write."}}}}, "/api/v1/customers": {"get": {"operationId": "list_customers_get_customers", "summary": "Customers", "description": "Everyone with access to your skills: their skills, how far they got (has access, connected, used it), answers, and when they last asked.", "tags": ["Experts"], "x-acts": false, "parameters": [{"name": "stage", "in": "query", "required": false, "schema": {"type": "string", "enum": ["has access, not used", "connected, not used", "used it"]}}, {"name": "skill", "in": "query", "required": false, "schema": {"type": "string", "description": "The skill’s name."}}, {"name": "query", "in": "query", "required": false, "schema": {"type": "string", "description": "Part of a name or email."}}, {"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "minimum": 1, "maximum": 100, "description": "At most this many rows (default 25)."}}], "responses": {"200": {"description": "The result, as JSON."}, "400": {"description": "Something to fix, said in `error`."}, "401": {"description": "No valid API key."}, "403": {"description": "This key can’t write."}}}}, "/api/v1/customers/{customer}": {"get": {"operationId": "get_customer_get_customers_customer", "summary": "One customer", "description": "One customer in full: their access and how they got it, purchases, and last 10 questions.", "tags": ["Experts"], "x-acts": false, "parameters": [{"name": "customer", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "The result, as JSON."}, "400": {"description": "Something to fix, said in `error`."}, "401": {"description": "No valid API key."}, "403": {"description": "This key can’t write."}}}}, "/api/v1/customers/{customer}/remind": {"post": {"operationId": "send_reminder_post_customers_customer_remind", "summary": "Remind customers to use it", "description": "Email a reminder with their sign-in link: to one customer, or to everyone who has access but hasn’t used it (who = claimed-not-run) or connected but hasn’t (connected-not-run). Needs the owner’s approval in the app.", "tags": ["Experts"], "x-acts": true, "parameters": [{"name": "customer", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "The result, as JSON."}, "400": {"description": "Something to fix, said in `error`."}, "401": {"description": "No valid API key."}, "403": {"description": "This key can’t write."}}, "requestBody": {"required": false, "content": {"application/json": {"schema": {"type": "object", "properties": {"who": {"type": "string", "enum": ["claimed-not-run", "connected-not-run"]}, "skill": {"type": "string", "description": "The skill’s name."}}}}}}}}, "/api/v1/reminders": {"post": {"operationId": "send_reminder_post_reminders", "summary": "Remind customers to use it", "description": "Email a reminder with their sign-in link: to one customer, or to everyone who has access but hasn’t used it (who = claimed-not-run) or connected but hasn’t (connected-not-run). Needs the owner’s approval in the app.", "tags": ["Experts"], "x-acts": true, "parameters": [], "responses": {"200": {"description": "The result, as JSON."}, "400": {"description": "Something to fix, said in `error`."}, "401": {"description": "No valid API key."}, "403": {"description": "This key can’t write."}}, "requestBody": {"required": false, "content": {"application/json": {"schema": {"type": "object", "properties": {"customer": {"type": "string", "description": "The customer’s email, name or id."}, "who": {"type": "string", "enum": ["claimed-not-run", "connected-not-run"]}, "skill": {"type": "string", "description": "The skill’s name."}}}}}}}}, "/api/v1/access": {"post": {"operationId": "grant_access_post_access", "summary": "Give someone a skill", "description": "Give someone a skill for free by email, and email them a sign-in link. Needs the owner’s approval in the app.", "tags": ["Experts"], "x-acts": true, "parameters": [], "responses": {"200": {"description": "The result, as JSON."}, "400": {"description": "Something to fix, said in `error`."}, "401": {"description": "No valid API key."}, "403": {"description": "This key can’t write."}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"email": {"type": "string"}, "name": {"type": "string"}, "skill": {"type": "string", "description": "The skill’s name."}, "send_email": {"type": "boolean", "description": "Default true."}}, "required": ["email", "skill"]}}}}}}, "/api/v1/sales": {"get": {"operationId": "list_sales_get_sales", "summary": "Sales", "description": "Purchases and subscriptions, newest first, with the total paid.", "tags": ["Experts"], "x-acts": false, "parameters": [{"name": "since_days", "in": "query", "required": false, "schema": {"type": "integer", "minimum": 1, "maximum": 365, "description": "How far back, in days (default 30)."}}, {"name": "limit", "in": "query", "required": false, "schema": {"type": "integer", "minimum": 1, "maximum": 100, "description": "At most this many rows (default 25)."}}], "responses": {"200": {"description": "The result, as JSON."}, "400": {"description": "Something to fix, said in `error`."}, "401": {"description": "No valid API key."}, "403": {"description": "This key can’t write."}}}}, "/api/v1/skills/{skill}/price": {"put": {"operationId": "set_price_put_skills_skill_price", "summary": "Change a skill’s price", "description": "Set a skill’s price: free, one_time, monthly or yearly, with an amount in your currency. People who already have it keep it. Needs the owner’s approval in the app.", "tags": ["Experts"], "x-acts": true, "parameters": [{"name": "skill", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "The result, as JSON."}, "400": {"description": "Something to fix, said in `error`."}, "401": {"description": "No valid API key."}, "403": {"description": "This key can’t write."}}, "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "properties": {"pricing": {"type": "string", "enum": ["free", "one_time", "monthly", "yearly"]}, "amount": {"type": "number", "minimum": 0}}, "required": ["pricing"]}}}}}}}}