Error shape
Every/v1 error has the same shape, with an HTTP status to match:
type is stable and meant for your code. message is written for a person and may change; log it or show it, but don’t match on it. Some errors add fields, such as active_task_id above, or code and answered_by when a question was already answered.
Common causes and fixes
400 invalid_request
"prompt" (string) is required: send a non-emptypromptwhen starting a task.- Metadata rejected:
metadatamust be an object with up to 50 keys, keys up to 40 characters, and string values up to 500 characters. Numbers and nested objects aren’t allowed; send"42", not42. - Agent id rejected:
agent_idis 2 to 40 lowercase letters, numbers and dashes.effortislow,medium,highornull. - Webhook URL refused: it must be
httpsand resolve to a public address. See Webhooks. /respondwithout an id: sendquestion_idwithanswer, orapproval_idwithdecision.
401 authentication
Send Authorization: Bearer gh_live_… with an org API key from Settings → API keys. Check that the key wasn’t revoked, and that you aren’t sending a session token (gh_sk_…), which only works with the older session-token API.
402 payment_required
Starting a task on the free plan after its free minutes are used, or in an org that has no free minutes. An owner can pick a plan in the console under Settings → Plan and usage. A running task on the free plan is also stopped when the minutes run out; its stopped event says so.
403 permission
The signed-in person’s role is too low, for example a member deleting a session. API keys act with the admin role, so this comes up mainly with console sign-ins.
404 not_found
The id doesn’t exist in the org the key belongs to. Session ids are codes like K7QM-24XP; task ids start with task_. A session whose code has expired returns 404 when you start a task on it: create a new session.
409 conflict
- “No computer is connected to this session.” The session’s
statusisn’tconnected. The customer may have quit the app, closed the laptop or lost the network. Wait forsession.connected, or ask them to open GuidingHand. - “A task is already running on this computer.” One task runs at a time per computer.
error.active_task_idis the running task: follow it to the end, or stop it withPOST /v1/tasks/{task_id}/stop. - “An agent with that address already exists.” Pick another
agent_id, orPATCHthe existing agent. - “That was already answered by the person at the computer.” (
code: "already_answered",answered_by: "customer") The customer answered the question, or decided the approval, on their screen before you did, and theirs is the one the task used. Nothing to fix: carry on following the task. Withanswered_by: "operator", someone on your team (another process, or the console) answered first. See questions the customer can answer and approvals the customer can decide. - “That question/approval is not pending.” (
code: "not_pending") The id belongs to an earlier question, or the task has ended. Read the task again and respond to the currentpending.
429 rate_limit
- Too many requests (see rate limits). Wait and retry with backoff.
- Your plan’s limit on tasks running at the same time across the org. Wait for a task to finish, or move to a plan with more.
500 server_error
Retry with backoff. If you start tasks with a request_id, retrying is safe: you get the same task rather than a second one.
Tasks that fail
Afailed task is not an HTTP error: the task ran and couldn’t finish. error has the reason, for example:
- the computer disconnected in the middle of a step,
- macOS was dropping the app’s clicks and typing (a permission problem the app reports and offers to fix with a restart),
- the task ran 150 steps without finishing,
- the server was restarted during the task. Start it again.
request_id. For recurring failures, the task’s replay_url and GET /v1/tasks/{task_id}?include=trace show what happened; the trace is safe to share with GuidingHand support.
Pagination
GET /v1/sessions and GET /v1/tasks return the newest first, one page at a time:
limitsets the page size, 1 to 100 (default 20).- When
has_moreistrue, passnext_cursorascursorto get the next, older page. When it isfalse,next_cursorisnull. - Keep the same filters (
session_id,agent_id,status) on every page.
gh is the helper from the Quickstart.)
GET /v1/agents returns all agents in one page.
Rate limits
Past a limit, requests return
429 rate_limit. Long polls count as one request each, so following a task with wait_ms=25000 uses about 144 requests an hour.