{
  "openapi": "3.1.0",
  "info": { "title": "Walkthru API", "version": "1.0.0", "description": "Punch lists for home builders. Jobs (projects) contain items; subs are shared across the company. Authenticate with an API key from Settings → Connect AI.", "contact": { "email": "help@walkthru.build" } },
  "servers": [{ "url": "https://walkthru.build/api/v1" }],
  "security": [{ "bearer": [] }],
  "components": {
    "securitySchemes": { "bearer": { "type": "http", "scheme": "bearer", "description": "API key, e.g. Bearer wt_live_..." } },
    "schemas": {
      "Project": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "address": { "type": "string" }, "status": { "type": "string", "enum": ["active", "archived"] }, "open": { "type": "integer" }, "done": { "type": "integer" } } },
      "Item": { "type": "object", "properties": { "id": { "type": "string" }, "title": { "type": "string" }, "room": { "type": "string" }, "subId": { "type": "string" }, "subName": { "type": "string" }, "priority": { "type": "string", "enum": ["low", "normal", "high"] }, "notes": { "type": "string" }, "due": { "type": "string", "description": "YYYY-MM-DD" }, "photos": { "type": "array", "items": { "type": "string" } }, "status": { "type": "string", "enum": ["open", "done"] }, "createdAt": { "type": "string" }, "doneAt": { "type": "string" } } },
      "ItemInput": { "type": "object", "required": ["title"], "properties": { "title": { "type": "string" }, "room": { "type": "string" }, "sub": { "type": "string", "description": "Subcontractor name; created if it doesn't exist. Empty string unassigns." }, "priority": { "type": "string", "enum": ["low", "normal", "high"] }, "notes": { "type": "string" }, "due": { "type": "string" }, "status": { "type": "string", "enum": ["open", "done"] }, "photos": { "type": "array", "items": { "type": "string" } } } },
      "Sub": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "trade": { "type": "string" }, "phone": { "type": "string" }, "email": { "type": "string" }, "notes": { "type": "string" } } },
      "Error": { "type": "object", "properties": { "error": { "type": "string" }, "upgrade": { "type": "string" } } }
    }
  },
  "paths": {
    "/projects": {
      "get": { "operationId": "listProjects", "summary": "List jobs", "parameters": [{ "name": "archived", "in": "query", "schema": { "type": "string", "enum": ["1"] }, "description": "Include archived jobs" }], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object", "properties": { "projects": { "type": "array", "items": { "$ref": "#/components/schemas/Project" } } } } } } } } },
      "post": { "operationId": "createProject", "summary": "Create a job", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["name"], "properties": { "name": { "type": "string" }, "address": { "type": "string" } } } } } }, "responses": { "201": { "description": "Created", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Project" } } } }, "402": { "description": "Free plan limit", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }
    },
    "/projects/{id}": {
      "get": { "operationId": "getProject", "summary": "Get a job with all items", "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }], "responses": { "200": { "description": "OK" } } },
      "patch": { "operationId": "updateProject", "summary": "Rename, re-address, archive or reopen a job", "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string" }, "address": { "type": "string" }, "status": { "type": "string", "enum": ["active", "archived"] } } } } } }, "responses": { "200": { "description": "OK" } } }
    },
    "/projects/{id}/items": {
      "get": { "operationId": "listItems", "summary": "List items", "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "status", "in": "query", "schema": { "type": "string", "enum": ["open", "done", "all"], "default": "open" } }, { "name": "sub", "in": "query", "schema": { "type": "string" }, "description": "Filter by sub name (contains)" }, { "name": "room", "in": "query", "schema": { "type": "string" } }], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object", "properties": { "items": { "type": "array", "items": { "$ref": "#/components/schemas/Item" } } } } } } } } },
      "post": { "operationId": "createItem", "summary": "Add a punch list item", "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ItemInput" } } } }, "responses": { "201": { "description": "Created", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Item" } } } } } }
    },
    "/projects/{id}/items/{iid}": {
      "patch": { "operationId": "updateItem", "summary": "Update an item (reassign, edit, mark done)", "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "iid", "in": "path", "required": true, "schema": { "type": "string" } }], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ItemInput" } } } }, "responses": { "200": { "description": "OK" } } },
      "delete": { "operationId": "deleteItem", "summary": "Delete an item", "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "iid", "in": "path", "required": true, "schema": { "type": "string" } }], "responses": { "200": { "description": "OK" } } }
    },
    "/projects/{id}/summary": { "get": { "operationId": "projectSummary", "summary": "Open/done counts by sub and room", "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }], "responses": { "200": { "description": "OK" } } } },
    "/projects/{id}/share": { "get": { "operationId": "shareLink", "summary": "Read-only link for a sub", "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }, { "name": "sub", "in": "query", "schema": { "type": "string" } }], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object", "properties": { "url": { "type": "string" } } } } } } } } },
    "/subs": {
      "get": { "operationId": "listSubs", "summary": "List subcontractors", "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object", "properties": { "subs": { "type": "array", "items": { "$ref": "#/components/schemas/Sub" } } } } } } } } },
      "post": { "operationId": "createSub", "summary": "Add a subcontractor", "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Sub" } } } }, "responses": { "201": { "description": "Created" } } }
    },
    "/subs/{id}": {
      "patch": { "operationId": "updateSub", "summary": "Update a subcontractor", "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Sub" } } } }, "responses": { "200": { "description": "OK" } } },
      "delete": { "operationId": "deleteSub", "summary": "Delete a subcontractor", "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }], "responses": { "200": { "description": "OK" } } }
    },
    "/photos": { "post": { "operationId": "uploadPhoto", "summary": "Upload a photo (raw image body)", "requestBody": { "required": true, "content": { "image/jpeg": { "schema": { "type": "string", "format": "binary" } }, "image/png": { "schema": { "type": "string", "format": "binary" } } } }, "responses": { "201": { "description": "Created", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string" }, "url": { "type": "string" } } } } } } } } },
    "/photos/{id}": { "get": { "operationId": "getPhoto", "summary": "Fetch a photo", "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }], "responses": { "200": { "description": "Image" } } } }
  }
}
