{
  "openapi": "3.1.0",
  "info": {
    "title": "ChatStack Agent API",
    "version": "1.1.0",
    "description": "Authenticated REST API for AI agents. Two auth models: (1) AGENT_API_KEY for skip-interview PRD submit; (2) personal access token (cst_\u2026) for Interview API session/turn/action/status/submit-prd \u2014 never put AGENT_API_KEY in MCP config.\n\nAfter a PRD is submitted, project tools are catalogued at https://www.portal.chatstack.app/api/agent.",
    "contact": {
      "name": "ChatStack",
      "url": "https://www.chatstack.app/speak-to-a-human"
    },
    "license": {
      "name": "Proprietary"
    }
  },
  "servers": [
    {
      "url": "https://www.chatstack.app",
      "description": "Production"
    }
  ],
  "security": [
    {
      "AgentApiKey": []
    }
  ],
  "paths": {
    "/api/agent/interview/session": {
      "post": {
        "operationId": "createInterviewSession",
        "summary": "Create a user-bound interview thread",
        "description": "Validates a personal access token against the CRM, then creates an empty ChatKit thread scoped to agent:{profile_id}.",
        "security": [
          {
            "PersonalAccessToken": []
          }
        ],
        "responses": {
          "201": {
            "description": "Session created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "thread_id",
                    "profile_id"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "thread_id": {
                      "type": "string"
                    },
                    "profile_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "flow_stage": {
                      "type": "string"
                    },
                    "pending_gate": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "pending_gate_payload": {
                      "type": [
                        "object",
                        "null"
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing PAT"
          }
        }
      }
    },
    "/api/agent/interview/turn": {
      "post": {
        "operationId": "interviewTurn",
        "summary": "Send one interview / workflow turn",
        "security": [
          {
            "PersonalAccessToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "thread_id"
                ],
                "anyOf": [
                  {
                    "required": ["input_as_text"]
                  },
                  {
                    "required": ["interaction_mode"]
                  }
                ],
                "properties": {
                  "thread_id": {
                    "type": "string"
                  },
                  "input_as_text": {
                    "type": "string",
                    "minLength": 1
                  },
                  "interaction_mode": {
                    "type": "string",
                    "enum": [
                      "clarify_first",
                      "auto_complete"
                    ],
                    "description": "Optional review-mode switch persisted on the thread before this turn"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Turn result with pending_gate / widget_payloads",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InterviewTurnResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/agent/interview/action": {
      "post": {
        "operationId": "interviewAction",
        "summary": "Submit a pending-gate action (approve, MCQ answers, mode select, \u2026)",
        "security": [
          {
            "PersonalAccessToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "thread_id",
                  "action_type"
                ],
                "properties": {
                  "thread_id": {
                    "type": "string"
                  },
                  "action_type": {
                    "type": "string",
                    "description": "e.g. clarifying_questions_submit, mode_select_a, stories_approve, interview_summary_update"
                  },
                  "payload": {
                    "type": "object",
                    "additionalProperties": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Action result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InterviewTurnResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/agent/interview/status": {
      "get": {
        "operationId": "interviewStatus",
        "summary": "Read durable flow_stage / pending_gate for a thread",
        "security": [
          {
            "PersonalAccessToken": []
          }
        ],
        "parameters": [
          {
            "name": "thread_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Status",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "flow_stage": {
                      "type": "string"
                    },
                    "composer_locked": {
                      "type": "boolean"
                    },
                    "pending_gate": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "pending_gate_payload": {
                      "type": [
                        "object",
                        "null"
                      ]
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/agent/interview/submit-prd": {
      "post": {
        "operationId": "interviewSubmitPrd",
        "summary": "Submit PRD artifacts from an interview thread (or explicit artifacts)",
        "description": "Auth is PAT. When thread_id is set, artifacts are loaded from chatkit-server and any client-supplied artifacts field is ignored. Without thread_id, submit explicit artifacts. Forwards to CRM with the server CRM key. Not AGENT_API_KEY identity.",
        "security": [
          {
            "PersonalAccessToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "thread_id": {
                    "type": "string"
                  },
                  "artifacts": {
                    "$ref": "#/components/schemas/Artifacts"
                  },
                  "interview_summary": {
                    "type": "string"
                  },
                  "first_name": {
                    "type": "string"
                  },
                  "last_name": {
                    "type": "string"
                  },
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "project_name": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "CRM submit success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubmitSuccess"
                }
              }
            }
          },
          "422": {
            "description": "V2 project normalization failed (no usable project_id/version_id).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/agent/submit": {
      "post": {
        "operationId": "submitPrd",
        "summary": "Submit a structured PRD",
        "description": "Submit a complete set of PRD artifacts to ChatStack. The payload must include approved user stories and functional requirements at minimum. Technical specifications and cost estimates are optional but strongly recommended for the best review experience.\n\nThe response includes the submission ID and, if an email was provided, the created project and version IDs that can be viewed in the ChatStack portal.",
        "security": [
          {
            "AgentApiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubmitRequest"
              },
              "example": {
                "artifacts": {
                  "stories_json_approved": {
                    "stories": [
                      {
                        "id": "US-1",
                        "user_type": "admin",
                        "user_story": "As an admin, I want to invite team members by email so that I can manage access to the workspace.",
                        "acceptance_criteria": [
                          "Admin can enter one or more email addresses",
                          "Invitee receives an email with a signup link",
                          "Invitee is assigned the 'member' role by default"
                        ],
                        "nfr": [
                          "Invitation email delivered within 60 seconds"
                        ],
                        "notes": "",
                        "mvp": true
                      }
                    ],
                    "global_nfr": [
                      "App must be responsive on mobile and desktop"
                    ]
                  },
                  "requirements_json_approved": {
                    "requirements": [
                      {
                        "id": "FR-1",
                        "category": "functional",
                        "description": "The system must allow admins to invite users via email.",
                        "priority": "must-have",
                        "linked_stories": [
                          "US-1"
                        ]
                      }
                    ]
                  },
                  "techspec_json_approved": {
                    "specifications": [
                      {
                        "id": "TS-1",
                        "area": "Authentication",
                        "description": "Use Supabase Auth with magic-link email for passwordless sign-in.",
                        "linked_requirements": [
                          "FR-1"
                        ]
                      }
                    ]
                  },
                  "estimate_json": {
                    "meta": {},
                    "rows": [
                      {
                        "row_id": "FR-1",
                        "row_type": "requirements",
                        "category": "Auth",
                        "title": "Admin invites team members",
                        "notes": "",
                        "our_hours": 4,
                        "our_cost_usd": 220
                      }
                    ],
                    "totals": {
                      "our_estimate_hours": 4,
                      "our_estimate_cost_usd": 220
                    },
                    "assumptions": [],
                    "risks": []
                  }
                },
                "interview_summary": "A SaaS workspace app for small teams. Core features: user invitations, project boards, real-time collaboration, and Slack notifications.",
                "first_name": "My",
                "last_name": "Agent",
                "email": "builder@example.com",
                "country": "US",
                "project_name": "Team workspace MVP",
                "acquisition_source": "search"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "PRD submitted successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubmitSuccess"
                }
              }
            }
          },
          "400": {
            "description": "Validation error \u2014 the request body failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "V2 project normalization failed (hollow project rolled back; no usable version_id).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "413": {
            "description": "Payload exceeds the 10 MB limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "415": {
            "description": "Content-Type is not application/json.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Maximum 5 submissions per hour per IP.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "AgentApiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key issued by ChatStack for autonomous agent access. Contact the ChatStack team to request a key."
      },
      "PersonalAccessToken": {
        "type": "http",
        "scheme": "bearer",
        "description": "Portal personal access token (cst_\u2026). Mint in Portal \u2192 Settings \u2192 API access. Used for the Interview API on this site. After a PRD is submitted, project tools are catalogued at https://www.portal.chatstack.app/api/agent."
      }
    },
    "schemas": {
      "SubmitRequest": {
        "type": "object",
        "required": [
          "artifacts",
          "interview_summary"
        ],
        "properties": {
          "artifacts": {
            "$ref": "#/components/schemas/Artifacts"
          },
          "interview_summary": {
            "type": "string",
            "description": "A plain-text narrative describing the project. This is shown to the ChatStack reviewer and used as context for the portal. Aim for 2\u20135 sentences covering the problem, target users, and key goals.",
            "minLength": 20
          },
          "first_name": {
            "type": "string",
            "description": "First name of the person or organisation on whose behalf the agent is submitting."
          },
          "last_name": {
            "type": "string",
            "description": "Last name of the person or organisation on whose behalf the agent is submitting."
          },
          "email": {
            "type": "string",
            "format": "email",
            "description": "Email address used to create or match a portal account. If omitted, the submission is stored as anonymous and no portal project is created."
          },
          "country": {
            "type": "string",
            "description": "Country of the submitter (ISO 3166-1 alpha-2 code or full country name)."
          },
          "message": {
            "type": "string",
            "description": "Optional free-text note to the ChatStack team."
          },
          "project_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Optional project title. When omitted, null, or blank after trimming, the CRM stores null and may derive the project name from the interview summary."
          },
          "acquisition_source": {
            "type": [
              "string",
              "null"
            ],
            "description": "Optional attribution (e.g. how the user heard about ChatStack). When omitted, null, or blank, stored as null; for a new portal profile only, may be set on the profile and is not overwritten on repeat submits."
          }
        }
      },
      "Artifacts": {
        "type": "object",
        "required": [
          "stories_json_approved",
          "requirements_json_approved"
        ],
        "description": "The four structured PRD artifacts. stories_json_approved and requirements_json_approved are required. techspec_json_approved and estimate_json are strongly recommended.",
        "properties": {
          "stories_json_approved": {
            "$ref": "#/components/schemas/StoriesDocument"
          },
          "requirements_json_approved": {
            "$ref": "#/components/schemas/RequirementsDocument"
          },
          "techspec_json_approved": {
            "$ref": "#/components/schemas/TechSpecDocument"
          },
          "estimate_json": {
            "$ref": "#/components/schemas/EstimateDocument"
          }
        }
      },
      "StoriesDocument": {
        "type": "object",
        "required": [
          "stories"
        ],
        "description": "User stories following the 'As a <user_type>, I want <goal> so that <benefit>' format.",
        "properties": {
          "stories": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UserStory"
            }
          },
          "global_nfr": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Non-functional requirements that apply to the entire system.",
            "default": []
          }
        }
      },
      "UserStory": {
        "type": "object",
        "required": [
          "id",
          "user_type",
          "user_story",
          "acceptance_criteria",
          "mvp"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Stable identifier in the format US-<n> (e.g. US-1, US-2).",
            "pattern": "^US-\\d+$"
          },
          "user_type": {
            "type": "string",
            "description": "The role or persona of the user (e.g. 'admin', 'guest', 'customer')."
          },
          "user_story": {
            "type": "string",
            "description": "Full user story in the canonical format: 'As a <user_type>, I want <goal> so that <benefit>.'"
          },
          "acceptance_criteria": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "2\u20135 testable conditions that define when this story is complete.",
            "minItems": 1
          },
          "nfr": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Non-functional requirements specific to this story. Empty array if none.",
            "default": []
          },
          "notes": {
            "type": "string",
            "description": "Optional clarifying notes. Empty string if none.",
            "default": ""
          },
          "mvp": {
            "type": "boolean",
            "description": "Whether this story is in the Minimum Viable Product scope.",
            "default": true
          }
        }
      },
      "RequirementsDocument": {
        "type": "object",
        "required": [
          "requirements"
        ],
        "properties": {
          "requirements": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Requirement"
            }
          }
        }
      },
      "Requirement": {
        "type": "object",
        "required": [
          "id",
          "category",
          "description"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Stable identifier (e.g. FR-1, NFR-1, ASS-1)."
          },
          "category": {
            "type": "string",
            "enum": [
              "functional",
              "non-functional",
              "assumption"
            ],
            "description": "Classification of the requirement."
          },
          "description": {
            "type": "string"
          },
          "priority": {
            "type": "string",
            "enum": [
              "must-have",
              "should-have",
              "could-have",
              "won't-have"
            ],
            "description": "MoSCoW priority."
          },
          "linked_stories": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "IDs of user stories this requirement traces to (e.g. ['US-1']).",
            "default": []
          }
        }
      },
      "TechSpecDocument": {
        "type": "object",
        "required": [
          "specifications"
        ],
        "properties": {
          "specifications": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TechSpec"
            }
          }
        }
      },
      "TechSpec": {
        "type": "object",
        "required": [
          "id",
          "area",
          "description"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Stable identifier (e.g. TS-1)."
          },
          "area": {
            "type": "string",
            "description": "Architectural area (e.g. 'Authentication', 'Database', 'Frontend', 'API', 'Infrastructure')."
          },
          "description": {
            "type": "string",
            "description": "Technical decision or constraint for this area."
          },
          "linked_requirements": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "IDs of requirements this spec addresses.",
            "default": []
          }
        }
      },
      "EstimateDocument": {
        "type": "object",
        "required": [
          "meta",
          "rows",
          "totals"
        ],
        "description": "Indicative development cost. Quote our_hours, our_cost_usd, our_estimate_hours, and our_estimate_cost_usd. Do not quote meta or internal comparison totals. meta is required on submit and may be an empty object.",
        "properties": {
          "meta": {
            "type": "object",
            "description": "Required when submitting estimate_json. Internal bookkeeping. Do not quote it. An empty object is accepted.",
            "additionalProperties": true
          },
          "rows": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EstimateRow"
            }
          },
          "totals": {
            "type": "object",
            "description": "ChatStack totals across all rows.",
            "properties": {
              "our_estimate_hours": {
                "type": "number",
                "minimum": 0
              },
              "our_estimate_cost_usd": {
                "type": "number",
                "minimum": 0
              }
            },
            "required": [
              "our_estimate_hours",
              "our_estimate_cost_usd"
            ]
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Assumptions underpinning the estimate.",
            "default": []
          },
          "risks": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Risks that could affect the estimate.",
            "default": []
          }
        }
      },
      "EstimateRow": {
        "type": "object",
        "required": [
          "row_id",
          "row_type",
          "title",
          "our_hours",
          "our_cost_usd"
        ],
        "properties": {
          "row_id": {
            "type": "string",
            "description": "Requirement id (FR-<n>) or overhead id (OH-<n>)."
          },
          "row_type": {
            "type": "string",
            "enum": [
              "requirements",
              "overhead"
            ]
          },
          "category": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "notes": {
            "type": "string"
          },
          "our_hours": {
            "type": "number",
            "minimum": 0
          },
          "our_cost_usd": {
            "type": "number",
            "minimum": 0
          }
        }
      },
      "SubmitSuccess": {
        "type": "object",
        "required": [
          "ok",
          "id",
          "project_id",
          "version_id"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Submission record ID."
          },
          "project_id": {
            "type": "string",
            "format": "uuid",
            "description": "Created project ID in the ChatStack portal."
          },
          "version_id": {
            "type": "string",
            "format": "uuid",
            "description": "Created working project version ID. Required for a usable submit."
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Non-fatal warnings (e.g. artifact repair). Structural V2 failures return HTTP 422 instead."
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "Human-readable error description."
          },
          "details": {
            "description": "Additional validation details \u2014 present on 400 errors.",
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "path": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            ]
          }
        }
      },
      "InterviewTurnResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "output_text": {
            "type": "string"
          },
          "flow_stage": {
            "type": "string"
          },
          "pending_gate": {
            "type": [
              "string",
              "null"
            ]
          },
          "pending_gate_payload": {
            "type": [
              "object",
              "null"
            ]
          },
          "widgets": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "widget_payloads": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "stories_json": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      }
    }
  }
}
