{
  "openapi": "3.1.0",
  "info": {
    "title": "GuidingHand API",
    "version": "1.0.0",
    "description": "Create sessions (an invite link with a code for the person at the computer), run tasks on their computer with one of your agents, follow them, answer their questions and approvals, and fetch history and recordings."
  },
  "servers": [
    {
      "url": "https://guidinghand.ai",
      "description": "Production"
    },
    {
      "url": "https://dev.guidinghand.ai",
      "description": "Development (Stripe test mode)"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Agents"
    },
    {
      "name": "Sessions"
    },
    {
      "name": "Tasks"
    },
    {
      "name": "Webhooks"
    }
  ],
  "paths": {
    "/v1/agents": {
      "get": {
        "tags": [
          "Agents"
        ],
        "summary": "List agents",
        "description": "Every org has a `default` agent, even before it is customized.",
        "operationId": "listAgents",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "has_more",
                    "next_cursor"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Agent"
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Pass as `cursor` to get the next page."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          }
        }
      },
      "post": {
        "tags": [
          "Agents"
        ],
        "summary": "Create an agent",
        "operationId": "createAgent",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AgentInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Agent"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          }
        }
      }
    },
    "/v1/agents/{agent_id}": {
      "parameters": [
        {
          "name": "agent_id",
          "in": "path",
          "required": true,
          "description": "The agent’s id, e.g. `billing` or `default`.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "Agents"
        ],
        "summary": "Get an agent",
        "operationId": "getAgent",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Agent"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          }
        }
      },
      "patch": {
        "tags": [
          "Agents"
        ],
        "summary": "Update an agent",
        "description": "Send only the fields to change.",
        "operationId": "updateAgent",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AgentUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Agent"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          }
        }
      },
      "delete": {
        "tags": [
          "Agents"
        ],
        "summary": "Delete an agent",
        "description": "Sessions made with it switch to the default agent. Deleting `default` resets it to GuidingHand’s own instructions.",
        "operationId": "deleteAgent",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Deleted"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          }
        }
      }
    },
    "/v1/sessions": {
      "post": {
        "tags": [
          "Sessions"
        ],
        "summary": "Create a session",
        "operationId": "createSession",
        "description": "Makes a pairing code and its invite link. Send the `invite_url` to the person at the computer: it walks them through installing GuidingHand and connecting. Codes expire after 72 hours without use.",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "agent_id": {
                    "type": "string",
                    "description": "The agent to run. Defaults to `default`.",
                    "example": "billing"
                  },
                  "metadata": {
                    "$ref": "#/components/schemas/Metadata"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SessionCreated"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      },
      "get": {
        "tags": [
          "Sessions"
        ],
        "summary": "List sessions",
        "operationId": "listSessions",
        "parameters": [
          {
            "name": "agent_id",
            "in": "query",
            "required": false,
            "description": "Only sessions of this agent.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many to return, 1 to 100.",
            "schema": {
              "type": "integer",
              "default": 20,
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "`next_cursor` from the previous page.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "has_more",
                    "next_cursor"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Session"
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Pass as `cursor` to get the next page."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          }
        }
      }
    },
    "/v1/sessions/{session_id}": {
      "parameters": [
        {
          "name": "session_id",
          "in": "path",
          "required": true,
          "description": "The session’s code, e.g. `K7QM-24XP`.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "Sessions"
        ],
        "summary": "Get a session",
        "operationId": "getSession",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Session"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          }
        }
      },
      "delete": {
        "tags": [
          "Sessions"
        ],
        "summary": "Delete a session",
        "description": "Disconnects the computer, stops a running task, and deletes the session’s tasks, events and recordings for good.",
        "operationId": "deleteSession",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Deleted"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          }
        }
      }
    },
    "/v1/sessions/{session_id}/tasks": {
      "parameters": [
        {
          "name": "session_id",
          "in": "path",
          "required": true,
          "description": "The session’s code.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "tags": [
          "Tasks"
        ],
        "summary": "Start a task",
        "operationId": "createTask",
        "description": "Starts a task on the session’s computer, which must be connected (`status: connected`). One task runs at a time per computer.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "prompt"
                ],
                "properties": {
                  "prompt": {
                    "type": "string",
                    "maxLength": 8000,
                    "description": "What should happen on their computer, in plain language.",
                    "example": "Turn on Dark Mode"
                  },
                  "agent_id": {
                    "type": "string",
                    "description": "Run a different agent than the session’s."
                  },
                  "request_id": {
                    "type": "string",
                    "description": "Idempotency key: the same `request_id` returns the same task instead of starting another."
                  },
                  "metadata": {
                    "$ref": "#/components/schemas/Metadata"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Task"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "402": {
            "$ref": "#/components/responses/E402"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        }
      }
    },
    "/v1/tasks": {
      "get": {
        "tags": [
          "Tasks"
        ],
        "summary": "List tasks",
        "operationId": "listTasks",
        "parameters": [
          {
            "name": "session_id",
            "in": "query",
            "required": false,
            "description": "Only this session’s tasks.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "agent_id",
            "in": "query",
            "required": false,
            "description": "Only tasks run by this agent.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only tasks with this status.",
            "schema": {
              "$ref": "#/components/schemas/TaskStatus"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many to return, 1 to 100.",
            "schema": {
              "type": "integer",
              "default": 20,
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "`next_cursor` from the previous page.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "has_more",
                    "next_cursor"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Task"
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Pass as `cursor` to get the next page."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          }
        }
      }
    },
    "/v1/tasks/{task_id}": {
      "parameters": [
        {
          "name": "task_id",
          "in": "path",
          "required": true,
          "description": "The task’s id.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "Tasks"
        ],
        "summary": "Get a task",
        "operationId": "getTask",
        "parameters": [
          {
            "name": "include",
            "in": "query",
            "required": false,
            "description": "Comma-separated: `events` (everything that happened), `trace` (timings for support).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Task"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          }
        }
      }
    },
    "/v1/tasks/{task_id}/events": {
      "parameters": [
        {
          "name": "task_id",
          "in": "path",
          "required": true,
          "description": "The task’s id.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "Tasks"
        ],
        "summary": "Follow a task",
        "operationId": "getTaskEvents",
        "description": "Events after `after`. With `wait_ms`, waits for the next event (long poll). Call again with the returned `cursor` until `task.done` is true, answering `task.pending` when it is set.",
        "parameters": [
          {
            "name": "after",
            "in": "query",
            "required": false,
            "description": "The last `cursor` you have. 0 for everything.",
            "schema": {
              "type": "integer",
              "default": 0
            }
          },
          {
            "name": "wait_ms",
            "in": "query",
            "required": false,
            "description": "Wait up to this long for new events.",
            "schema": {
              "type": "integer",
              "default": 0,
              "maximum": 55000
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "cursor",
                    "task"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Event"
                      }
                    },
                    "cursor": {
                      "type": "integer"
                    },
                    "task": {
                      "$ref": "#/components/schemas/Task"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          }
        }
      }
    },
    "/v1/tasks/{task_id}/respond": {
      "parameters": [
        {
          "name": "task_id",
          "in": "path",
          "required": true,
          "description": "The task’s id.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "tags": [
          "Tasks"
        ],
        "summary": "Answer a question or approval",
        "operationId": "respondToTask",
        "description": "When `task.pending.type` is `question`, send its `question_id` and your `answer`. When it is `approval`, send its `approval_id` and a `decision`. When the person at the computer can answer or decide it too (`pending.customer_can_answer`, `pending.customer_can_approve`), the first one is used: a later one returns 409 with `code: \"already_answered\"` and `answered_by`.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "title": "Answer a question",
                    "type": "object",
                    "required": [
                      "question_id",
                      "answer"
                    ],
                    "properties": {
                      "question_id": {
                        "type": "string"
                      },
                      "answer": {
                        "type": "string",
                        "maxLength": 4000
                      }
                    }
                  },
                  {
                    "title": "Decide an approval",
                    "type": "object",
                    "required": [
                      "approval_id",
                      "decision"
                    ],
                    "properties": {
                      "approval_id": {
                        "type": "string"
                      },
                      "decision": {
                        "type": "string",
                        "enum": [
                          "approve",
                          "deny"
                        ]
                      },
                      "note": {
                        "type": "string",
                        "maxLength": 1000,
                        "description": "Passed to the agent, e.g. why you denied it."
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Task"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          }
        }
      }
    },
    "/v1/tasks/{task_id}/stop": {
      "parameters": [
        {
          "name": "task_id",
          "in": "path",
          "required": true,
          "description": "The task’s id.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "tags": [
          "Tasks"
        ],
        "summary": "Stop a task",
        "operationId": "stopTask",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Task"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "interrupted": {
                          "type": "boolean",
                          "description": "False when the task had already finished."
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          }
        }
      }
    },
    "/v1/tasks/{task_id}/recording": {
      "parameters": [
        {
          "name": "task_id",
          "in": "path",
          "required": true,
          "description": "The task’s id.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "Tasks"
        ],
        "summary": "Get a task recording",
        "description": "The screens the agent saw, in order, with their time from the start of the task. The console replays them with the agent’s cursor at `replay_url`.",
        "operationId": "getRecording",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Recording"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          }
        }
      }
    },
    "/v1/tasks/{task_id}/recording/{seq}": {
      "parameters": [
        {
          "name": "task_id",
          "in": "path",
          "required": true,
          "description": "The task’s id.",
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "seq",
          "in": "path",
          "required": true,
          "schema": {
            "type": "integer"
          }
        }
      ],
      "get": {
        "tags": [
          "Tasks"
        ],
        "summary": "Get a recorded screen",
        "operationId": "getRecordingFrame",
        "responses": {
          "200": {
            "description": "The screen as a PNG.",
            "content": {
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          }
        }
      }
    },
    "/v1/webhook": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Get the webhook endpoint",
        "operationId": "getWebhook",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Webhook"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          }
        }
      },
      "put": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Set the webhook endpoint",
        "operationId": "setWebhook",
        "description": "Only the fields you send change: without `url` the endpoint stays, without `events` the filter stays (so `{ \"rotate_secret\": true }` alone just makes a new secret). Send `{ \"url\": null }` to remove the endpoint. The signing secret is returned when it is first made (or with `rotate_secret`), never again.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "uri",
                    "example": "https://example.com/guidinghand",
                    "description": "A public https URL. Required the first time; null removes the endpoint."
                  },
                  "events": {
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/WebhookEventType"
                    },
                    "description": "Only these events; an empty list for all. Unknown types are a 400."
                  },
                  "rotate_secret": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Webhook"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          }
        }
      }
    }
  },
  "webhooks": {
    "event": {
      "post": {
        "summary": "Webhook event",
        "description": "Sent to your endpoint with a `GuidingHand-Signature: t=<unix>,v1=<hex>` header: the HMAC-SHA256 of `<t>.<raw body>` with your secret. Retried up to 4 times over about 3 minutes until you answer 2xx.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Received."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "An org API key (`gh_live_…`) from Settings → API keys in the console."
      }
    },
    "responses": {
      "E400": {
        "description": "The request is invalid.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "E401": {
        "description": "Missing or invalid API key.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "E402": {
        "description": "The org’s plan doesn’t allow this (e.g. free minutes used up).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "E403": {
        "description": "Your role can’t do this.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "E404": {
        "description": "Not found in this org.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "E409": {
        "description": "Conflicts with the current state (e.g. no computer connected, a task already running, nothing pending).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "E429": {
        "description": "Too many requests.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "type",
              "message"
            ],
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "invalid_request",
                  "authentication",
                  "payment_required",
                  "permission",
                  "not_found",
                  "conflict",
                  "rate_limit",
                  "server_error"
                ]
              },
              "message": {
                "type": "string"
              },
              "code": {
                "type": "string",
                "description": "Why an answer or decision was refused (on `/respond`): `already_answered` (someone answered or decided first: see `answered_by`) or `not_pending` (that question or approval isn’t open any more). The GuidingHand app hears two more, which the API never returns: `customer_answers_off` and `customer_approvals_off` (the agent keeps its questions or approvals for your team)."
              },
              "answered_by": {
                "type": "string",
                "enum": [
                  "customer",
                  "operator"
                ],
                "description": "With `already_answered`: who answered or decided first (`customer`: the person at the computer)."
              }
            }
          }
        }
      },
      "Metadata": {
        "type": "object",
        "additionalProperties": {
          "type": "string",
          "maxLength": 500
        },
        "maxProperties": 50,
        "description": "Your own ids and labels (e.g. a ticket or customer id), returned as given.",
        "example": {
          "customer_id": "cus_42"
        }
      },
      "Deleted": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string"
          },
          "deleted": {
            "type": "boolean",
            "const": true
          }
        }
      },
      "Effort": {
        "type": [
          "string",
          "null"
        ],
        "enum": [
          "low",
          "medium",
          "high",
          null
        ],
        "description": "How much the model thinks per step. Null for GuidingHand’s default."
      },
      "Agent": {
        "type": "object",
        "properties": {
          "object": {
            "const": "agent"
          },
          "agent_id": {
            "type": "string",
            "example": "billing"
          },
          "name": {
            "type": "string",
            "example": "Billing help"
          },
          "instructions": {
            "type": "string",
            "description": "Added under GuidingHand’s own rules, which always win."
          },
          "effort": {
            "$ref": "#/components/schemas/Effort"
          },
          "greeting": {
            "type": "string",
            "description": "Shown to the person on the invite page."
          },
          "display_name": {
            "type": "string",
            "description": "What the GuidingHand app calls the agent on the person’s screen while it works (“Acme Support is typing”). Empty means “GuidingHand”.",
            "example": "Acme Support"
          },
          "narration": {
            "type": "boolean",
            "description": "The app shows the agent’s thoughts and steps on the person’s screen as it works, and its summary when it finishes. These are the agent’s own words, so they can repeat what your team answered. Off: no thoughts, steps or summary; they see the banner with the Stop button (and the agent’s questions and approval requests, if `customer_answers` and `customer_approvals` are on)."
          },
          "customer_answers": {
            "type": "boolean",
            "description": "The person at the computer can answer the agent’s questions in the GuidingHand app (your team still can too; the first answer is used). Off: only your team answers, and the question isn’t shown on the person’s screen."
          },
          "customer_approvals": {
            "type": "boolean",
            "description": "The person at the computer can approve or deny the agent’s approval requests in the GuidingHand app (your team still can too; the first decision is used). Off: only your team decides, and the request isn’t shown on the person’s screen."
          },
          "is_default": {
            "type": "boolean"
          },
          "invite_url_template": {
            "type": "string",
            "example": "https://guidinghand.ai/acme/billing/{code}"
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "AgentInput": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "agent_id": {
            "type": "string",
            "pattern": "^[a-z0-9](?:[a-z0-9-]{0,38}[a-z0-9])?$",
            "description": "Lowercase letters, numbers and dashes; part of invite links. Made from the name when not given."
          },
          "name": {
            "type": "string",
            "maxLength": 80
          },
          "instructions": {
            "type": "string",
            "maxLength": 20000
          },
          "effort": {
            "$ref": "#/components/schemas/Effort"
          },
          "greeting": {
            "type": "string",
            "maxLength": 500
          },
          "display_name": {
            "type": "string",
            "maxLength": 40,
            "description": "What the app calls the agent on the person’s screen, in place of “GuidingHand”. One line; empty goes back to “GuidingHand”."
          },
          "narration": {
            "type": "boolean",
            "default": true,
            "description": "Show the agent’s thoughts and steps on the person’s screen as it works, and its summary when it finishes. Off: the banner with the Stop button only (and the agent’s questions and approval requests, if `customer_answers` and `customer_approvals` are on)."
          },
          "customer_answers": {
            "type": "boolean",
            "default": true,
            "description": "Let the person at the computer answer the agent’s questions in the GuidingHand app."
          },
          "customer_approvals": {
            "type": "boolean",
            "default": true,
            "description": "Let the person at the computer approve or deny the agent’s approval requests in the GuidingHand app."
          }
        }
      },
      "AgentUpdate": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 80
          },
          "instructions": {
            "type": "string",
            "maxLength": 20000
          },
          "effort": {
            "$ref": "#/components/schemas/Effort"
          },
          "greeting": {
            "type": "string",
            "maxLength": 500
          },
          "display_name": {
            "type": "string",
            "maxLength": 40,
            "description": "What the app calls the agent on the person’s screen, in place of “GuidingHand”. One line; empty goes back to “GuidingHand”."
          },
          "narration": {
            "type": "boolean",
            "description": "Show the agent’s thoughts and steps on the person’s screen as it works, and its summary when it finishes. Off: the banner with the Stop button only (and the agent’s questions and approval requests, if `customer_answers` and `customer_approvals` are on)."
          },
          "customer_answers": {
            "type": "boolean",
            "description": "Let the person at the computer answer the agent’s questions in the GuidingHand app."
          },
          "customer_approvals": {
            "type": "boolean",
            "description": "Let the person at the computer approve or deny the agent’s approval requests in the GuidingHand app."
          }
        }
      },
      "Device": {
        "type": [
          "object",
          "null"
        ],
        "properties": {
          "os": {
            "type": "string",
            "enum": [
              "mac",
              "windows",
              "linux",
              "unknown"
            ]
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "width": {
            "type": "integer"
          },
          "height": {
            "type": "integer"
          },
          "app_version": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "Session": {
        "type": "object",
        "properties": {
          "object": {
            "const": "session"
          },
          "session_id": {
            "type": "string",
            "example": "K7QM-24XP"
          },
          "code": {
            "type": "string",
            "example": "K7QM-24XP"
          },
          "agent_id": {
            "type": "string"
          },
          "invite_url": {
            "type": "string",
            "example": "https://guidinghand.ai/acme/billing/K7QM-24XP"
          },
          "status": {
            "type": "string",
            "enum": [
              "waiting",
              "connected",
              "disconnected",
              "expired"
            ],
            "description": "`waiting`: no computer has used the code yet. `connected`: its computer is online now."
          },
          "device": {
            "$ref": "#/components/schemas/Device"
          },
          "metadata": {
            "$ref": "#/components/schemas/Metadata"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "paired_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "last_active_at": {
            "type": "string",
            "format": "date-time"
          },
          "expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "task_count": {
            "type": "integer"
          },
          "latest_task_id": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "SessionCreated": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Session"
          },
          {
            "type": "object",
            "properties": {
              "session_token": {
                "type": "string",
                "description": "A token for this one session (the older task API). Shown once."
              }
            }
          }
        ]
      },
      "TaskStatus": {
        "type": "string",
        "enum": [
          "queued",
          "running",
          "waiting_for_user",
          "waiting_for_approval",
          "completed",
          "failed",
          "stopped"
        ]
      },
      "Pending": {
        "oneOf": [
          {
            "title": "Question",
            "type": "object",
            "properties": {
              "type": {
                "const": "question"
              },
              "question_id": {
                "type": "string"
              },
              "question": {
                "type": "string"
              },
              "options": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "customer_can_answer": {
                "type": "boolean",
                "description": "The person at the computer can answer it in the GuidingHand app too (the agent allows it and their app can). The first answer is used: answering after them returns 409 with `code: \"already_answered\"`."
              }
            }
          },
          {
            "title": "Approval",
            "type": "object",
            "properties": {
              "type": {
                "const": "approval"
              },
              "approval_id": {
                "type": "string"
              },
              "action": {
                "type": "string",
                "description": "Exactly what the agent is about to do."
              },
              "risk": {
                "type": "string",
                "enum": [
                  "low",
                  "medium",
                  "high"
                ]
              },
              "customer_can_approve": {
                "type": "boolean",
                "description": "The person at the computer can approve or deny it in the GuidingHand app too (the agent allows it and their app can). The first decision is used: deciding after them returns 409 with `code: \"already_answered\"`."
              }
            }
          }
        ]
      },
      "Task": {
        "type": "object",
        "properties": {
          "object": {
            "const": "task"
          },
          "task_id": {
            "type": "string"
          },
          "session_id": {
            "type": "string"
          },
          "agent_id": {
            "type": "string"
          },
          "status": {
            "$ref": "#/components/schemas/TaskStatus"
          },
          "done": {
            "type": "boolean"
          },
          "prompt": {
            "type": "string"
          },
          "result": {
            "type": [
              "string",
              "null"
            ],
            "description": "The agent’s summary when it finished."
          },
          "error": {
            "type": [
              "string",
              "null"
            ]
          },
          "pending": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Pending"
              },
              {
                "type": "null"
              }
            ],
            "description": "What the agent waits on: answer it with /respond."
          },
          "cursor": {
            "type": "integer",
            "description": "The latest event’s cursor."
          },
          "metadata": {
            "$ref": "#/components/schemas/Metadata"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "active_seconds": {
            "type": "integer",
            "description": "Time spent running (not waiting on a person)."
          },
          "billed_minutes": {
            "type": [
              "integer",
              "null"
            ]
          },
          "replay_url": {
            "type": "string",
            "description": "The replay in the console."
          },
          "recording": {
            "type": "object",
            "properties": {
              "frames": {
                "type": "integer"
              }
            }
          },
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Event"
            },
            "description": "With `include=events`."
          }
        }
      },
      "Event": {
        "type": "object",
        "properties": {
          "cursor": {
            "type": "integer"
          },
          "type": {
            "type": "string",
            "enum": [
              "started",
              "progress",
              "thinking",
              "action",
              "message",
              "question",
              "answer",
              "approval_required",
              "approved",
              "denied",
              "completed",
              "error",
              "stopped"
            ]
          },
          "message": {
            "type": "string"
          },
          "ts": {
            "type": "string",
            "format": "date-time"
          },
          "data": {
            "type": "object",
            "description": "For `action`: `{ action: { type, x, y, text, keys, ... } }`. For `answer`: `{ question_id, answered_by: \"customer\" | \"operator\" }`. For `approved` and `denied`: `{ approval_id, answered_by, note? }`."
          }
        }
      },
      "Recording": {
        "type": "object",
        "properties": {
          "object": {
            "const": "recording"
          },
          "task_id": {
            "type": "string"
          },
          "frames": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "seq": {
                  "type": "integer"
                },
                "t_ms": {
                  "type": "number",
                  "description": "Milliseconds from the start of the task."
                },
                "after_event": {
                  "type": "integer",
                  "description": "The cursor of the last event before this screen."
                },
                "width": {
                  "type": "integer"
                },
                "height": {
                  "type": "integer"
                },
                "url": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "WebhookEventType": {
        "type": "string",
        "enum": [
          "session.connected",
          "session.disconnected",
          "task.started",
          "task.waiting_for_user",
          "task.question_answered",
          "task.waiting_for_approval",
          "task.approval_decided",
          "task.completed",
          "task.failed",
          "task.stopped"
        ]
      },
      "Webhook": {
        "type": "object",
        "properties": {
          "object": {
            "const": "webhook"
          },
          "url": {
            "type": [
              "string",
              "null"
            ]
          },
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookEventType"
            }
          },
          "has_secret": {
            "type": "boolean"
          },
          "secret": {
            "type": "string",
            "description": "Only when it was just made."
          },
          "event_types": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookEventType"
            }
          }
        }
      },
      "WebhookEvent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "type": {
            "$ref": "#/components/schemas/WebhookEventType"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "org_id": {
            "type": "string"
          },
          "data": {
            "type": "object",
            "properties": {
              "task": {
                "$ref": "#/components/schemas/Task"
              },
              "session": {
                "$ref": "#/components/schemas/Session"
              },
              "answer": {
                "type": "object",
                "description": "For `task.question_answered`.",
                "properties": {
                  "question_id": {
                    "type": "string"
                  },
                  "answer": {
                    "type": "string"
                  },
                  "answered_by": {
                    "type": "string",
                    "enum": [
                      "customer",
                      "operator"
                    ],
                    "description": "`customer`: the person at the computer answered in the app."
                  }
                }
              },
              "decision": {
                "type": "object",
                "description": "For `task.approval_decided`.",
                "properties": {
                  "approval_id": {
                    "type": "string"
                  },
                  "decision": {
                    "type": "string",
                    "enum": [
                      "approve",
                      "deny"
                    ]
                  },
                  "note": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "Your team’s note to the agent, if any."
                  },
                  "answered_by": {
                    "type": "string",
                    "enum": [
                      "customer",
                      "operator"
                    ],
                    "description": "`customer`: the person at the computer decided in the app."
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
