{
 "security": [{"bearer": []}],
 "components": {
  "schemas": {
   "Error": {
    "type": "object",
    "required": [
     "error",
     "message",
     "request_id"
    ],
    "properties": {
     "error": {
      "type": "string",
      "enum": [
       "bad_request",
       "unauthorized",
       "forbidden_source",
       "capability_disabled",
       "permission_denied",
       "access_needed",
       "pairing_closed",
       "screen_denied",
       "consent_expired",
       "setting_locked",
       "email_required",
       "agent_not_allowed",
       "not_found",
       "photo_not_found",
       "sensor_busy",
       "device_locked",
       "payload_too_large",
       "invalid_parameter",
       "not_supported",
       "rate_limited",
       "too_many_open",
       "notifications_required",
       "forbidden",
       "in_progress",
       "conflict",
       "idempotency_expired",
       "quota_exceeded",
       "too_many_waits",
       "upstream_failed",
       "callback_failed",
       "internal_error",
       "service_start_blocked",
       "team_unavailable",
       "capture_timeout",
       "phone_unreachable"
      ]
     },
     "message": {"type": "string"},
     "request_id": {"type": "string"}
    }
   },
   "Pending": {
    "type": "object",
    "properties": {
     "retry_after_s": {"type": "integer"},
     "code": {
      "type": "string",
      "enum": [
       "consent_pending",
       "job_queued"
      ]
     },
     "pending": {"type": "boolean"},
     "id": {"type": "string"},
     "request_id": {"type": "string"},
     "poll_url": {"type": "string"}
    }
   }
  },
  "securitySchemes": {"bearer": {
   "scheme": "bearer",
   "type": "http"
  }}
 },
 "servers": [{
  "variables": {
   "port": {
    "default": "8734",
    "description": "The port from your setup prompt"
   },
   "host": {
    "default": "phone",
    "description": "The phone's Tailscale name or IP, from your setup prompt"
   }
  },
  "description": "The owner's phone, on their Tailscale network (base_url in GET /v1/health)",
  "url": "http://{host}:{port}"
 }],
 "openapi": "3.1.0",
 "paths": {
  "/v1/feedback/{id}": {"get": {
   "summary": "One report with its status history, team note and what you can send back; agents in Fixer Mode also get images, context and the attached log (and their first read marks a new report seen)",
   "operationId": "getFeedbackId",
   "responses": {
    "200": {"description": "report: ref (team number, e.g. M0042, or null until sent), description, status, team_note, history[at, kind, status, by, note], followup_outcomes; Fixer Mode: context, images[data_base64], log[], allowed_next"},
    "401": {"description": "unauthorized"},
    "404": {
     "description": "not_found",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    }
   },
   "parameters": [
    {
     "schema": {"type": "string"},
     "in": "path",
     "name": "id",
     "required": true
    },
    {
     "schema": {
      "type": "string",
      "enum": [
       "agent",
       "thumb",
       "large",
       "original"
      ]
     },
     "in": "query",
     "name": "size",
     "description": "Preset: agent (1568 px, q85), thumb (512, q75), large (2560, q90), original",
     "required": false
    },
    {
     "schema": {"type": "integer"},
     "in": "query",
     "name": "max_edge_px",
     "description": "Long edge limit, 64-20000; overrides the preset",
     "required": false
    },
    {
     "schema": {"type": "integer"},
     "in": "query",
     "name": "max_width_px",
     "description": "Width limit, 64-20000",
     "required": false
    },
    {
     "schema": {"type": "integer"},
     "in": "query",
     "name": "quality",
     "description": "JPEG quality 40-100",
     "required": false
    }
   ],
   "tags": ["feedback"]
  }},
  "/v1/pair": {"post": {
   "summary": "Fetch your key with a 6-digit code shown on the phone (alternative to the setup prompt)",
   "security": [],
   "requestBody": {"content": {"application/json": {"schema": {
    "type": "object",
    "properties": {"code": {
     "description": "6-digit code from the phone",
     "type": "string"
    }},
    "required": ["code"]
   }}}},
   "operationId": "postPair",
   "responses": {
    "200": {"description": "key, agent, base_url (once per pairing window)"},
    "401": {
     "description": "unauthorized",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "403": {
     "description": "pairing_closed",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "429": {
     "description": "rate_limited",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    }
   },
   "tags": ["status"]
  }},
  "/v1/settings": {
   "post": {
    "summary": "Change settings (agents with Agent Super Powers, once the owner turns on App settings); every change is checked first, so one bad change changes nothing (SET-02)",
    "requestBody": {"content": {"application/json": {"schema": {
     "type": "object",
     "properties": {"changes": {
      "description": "{\"<key>\": <value>, ...}, up to 50; keys and allowed values from GET /v1/settings",
      "type": "object"
     }},
     "required": ["changes"]
    }}}},
    "operationId": "postSettings",
    "responses": {
     "200": {"description": "changed[key, from, to], unchanged, settings (as in GET)"},
     "422": {
      "description": "invalid_parameter",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "401": {"description": "unauthorized"},
     "403": {
      "description": "capability_disabled, forbidden, setting_locked, access_needed",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     }
    },
    "parameters": [{
     "schema": {"type": "string"},
     "in": "header",
     "name": "Idempotency-Key",
     "description": "Any UUID; a repeat within 24 h returns the first result"
    }],
    "tags": ["settings"]
   },
   "get": {
    "summary": "Every Bridgit setting and the phone settings it manages: value, type, range, and whether you may change it (SET-01)",
    "operationId": "getSettings",
    "responses": {
     "200": {"description": "can_write, write_blocked_reason, write_blocked_why, sections, settings[key, section, type, value, description, enum, min, max, writable, locked_reason, why]"},
     "422": {
      "description": "invalid_parameter",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "401": {"description": "unauthorized"},
     "404": {
      "description": "not_found",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     }
    },
    "parameters": [
     {
      "schema": {
       "type": "string",
       "enum": [
        "features",
        "listener",
        "privacy",
        "log",
        "alerts",
        "appearance",
        "speaker",
        "listening",
        "captures",
        "notifications",
        "phone",
        "android",
        "agent"
       ]
      },
      "in": "query",
      "name": "section",
      "description": "Only this section",
      "required": false
     },
     {
      "schema": {"type": "string"},
      "in": "query",
      "name": "key",
      "description": "Only this setting, e.g. appearance.theme",
      "required": false
     }
    ],
    "tags": ["settings"]
   }
  },
  "/v1/camera/snapshot": {"post": {
   "summary": "Take a photo now",
   "requestBody": {"content": {"application/json": {"schema": {
    "type": "object",
    "properties": {
     "max_width_px": {
      "description": "Width limit, 64-20000, or null for full size (default 2048 unless size is given)",
      "type": "integer"
     },
     "max_edge_px": {
      "description": "Long edge limit, 64-20000; overrides the preset",
      "type": "integer"
     },
     "size": {
      "description": "Preset: agent (1568 px, q85), thumb (512, q75), large (2560, q90), original",
      "type": "string",
      "enum": [
       "agent",
       "thumb",
       "large",
       "original"
      ]
     },
     "raw": {
      "description": "1 = return the image bytes, details in X-Bridgit-* headers",
      "type": "integer"
     },
     "zoom": {
      "description": "Zoom ratio, e.g. 0.5 (ultra-wide), 1, 2, 5 (telephoto); the range is in /v1/capabilities after the first photo",
      "type": "number"
     },
     "store": {
      "description": "Keep this capture too: any of memory (fetch it later from GET /v1/captures/{id}), files (a copy in the phone's Downloads/Bridgit), upload (POSTed to your upload_url). [] or \"none\" = only return it. Default: your POST /v1/captures/storage choice, else only returned",
      "type": "array"
     },
     "camera": {
      "description": "rear (default) or front",
      "type": "string",
      "enum": [
       "rear",
       "front"
      ]
     },
     "flash": {
      "description": "Fire the flash (default false)",
      "type": "boolean"
     },
     "quality": {
      "description": "JPEG quality 40-100",
      "type": "integer"
     }
    },
    "required": []
   }}}},
   "operationId": "postCameraSnapshot",
   "responses": {
    "200": {"description": "captured_at, width_px, height_px, format, size_bytes, data_base64 (or JPEG bytes with raw=1); capture {capture_id, stored, url, memory_until, file} when kept (X-Bridgit-Capture-Id with raw=1)"},
    "401": {"description": "unauthorized"},
    "413": {
     "description": "payload_too_large",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "403": {
     "description": "capability_disabled, permission_denied, notifications_required",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "503": {
     "description": "service_start_blocked",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "504": {
     "description": "capture_timeout",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "409": {
     "description": "device_locked, sensor_busy",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    }
   },
   "parameters": [{
    "schema": {"type": "string"},
    "in": "header",
    "name": "Idempotency-Key",
    "description": "Any UUID; a repeat within 24 h returns the first result"
   }],
   "tags": ["camera"]
  }},
  "/v1/sensors": {"get": {
   "summary": "Supported fresh sensor values or explicit unavailable status",
   "operationId": "getSensors",
   "responses": {
    "200": {"description": "Supported fresh sensor values or explicit unavailable status"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "parameters": [{
    "schema": {"type": "string"},
    "in": "query",
    "name": "which",
    "description": "Comma separated: light,pressure,proximity,steps,orientation,motion",
    "required": false
   }],
   "tags": ["sensors"]
  }},
  "/v1/health/records": {"get": {
   "summary": "Read-only steps, sleep or heart-rate source records (maximum 100)",
   "operationId": "getHealthRecords",
   "responses": {
    "200": {"description": "Read-only steps, sleep or heart-rate source records (maximum 100)"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "parameters": [
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "type",
     "description": "steps, sleep, heart_rate",
     "required": false
    },
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "since",
     "description": "ISO-8601 UTC",
     "required": false
    },
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "until",
     "description": "ISO-8601 UTC",
     "required": false
    }
   ],
   "tags": ["health_connect"]
  }},
  "/v1/captures/{id}": {
   "get": {
    "summary": "One kept capture: from memory, or from its phone file after memory let it go",
    "operationId": "getCapturesId",
    "responses": {
     "200": {"description": "the capture's details (as in the list) and data_base64, or raw=1 bytes"},
     "401": {"description": "unauthorized"},
     "413": {
      "description": "payload_too_large",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "404": {
      "description": "not_found",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     }
    },
    "parameters": [
     {
      "schema": {"type": "string"},
      "in": "path",
      "name": "id",
      "required": true
     },
     {
      "schema": {"type": "integer"},
      "in": "query",
      "name": "raw",
      "description": "1 = the bytes, details in X-Bridgit-* headers",
      "required": false
     }
    ],
    "tags": ["captures"]
   },
   "delete": {
    "summary": "Forget a capture: drops the memory copy and deletes its phone file (uploads can't be recalled)",
    "operationId": "deleteCapturesId",
    "responses": {
     "200": {"description": "deleted"},
     "401": {"description": "unauthorized"},
     "404": {
      "description": "not_found",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     }
    },
    "parameters": [{
     "schema": {"type": "string"},
     "in": "path",
     "name": "id",
     "required": true
    }],
    "tags": ["captures"]
   }
  },
  "/v1/screen/grant": {
   "post": {
    "summary": "Request owner-approved MediaProjection screen access",
    "requestBody": {"content": {"application/json": {"schema": {
     "type": "object",
     "properties": {"duration_seconds": {
      "description": "0=once, 3600=one hour, 57600=sixteen hours",
      "type": "integer"
     }},
     "required": []
    }}}},
    "operationId": "postScreenGrant",
    "responses": {
     "200": {"description": "Request owner-approved MediaProjection screen access"},
     "422": {
      "description": "invalid_parameter",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "401": {"description": "unauthorized"}
    },
    "parameters": [{
     "schema": {"type": "string"},
     "in": "header",
     "name": "Idempotency-Key",
     "description": "Any UUID; a repeat within 24 h returns the first result"
    }],
    "tags": ["screen_share"]
   },
   "delete": {
    "summary": "End your screen-sharing grant",
    "operationId": "deleteScreenGrant",
    "responses": {
     "200": {"description": "End your screen-sharing grant"},
     "422": {
      "description": "invalid_parameter",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "401": {"description": "unauthorized"}
    },
    "tags": ["screen_share"]
   }
  },
  "/v1/samples": {"get": {
   "summary": "Complete interaction samples for every kind (notice, question, html, text): the POST /v1/interactions body, the reply and the answer it produces (JSON)",
   "operationId": "getSamples",
   "responses": {
    "200": {"description": "api_revision, conventions, samples[id, kind, title, summary, request, answer, events, notes, page?, calls?]"},
    "401": {"description": "unauthorized"},
    "404": {
     "description": "not_found",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    }
   },
   "parameters": [
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "id",
     "description": "One sample, e.g. html-step",
     "required": false
    },
    {
     "schema": {
      "type": "string",
      "enum": [
       "notice",
       "question",
       "html",
       "text"
      ]
     },
     "in": "query",
     "name": "kind",
     "description": "Only samples of this kind",
     "required": false
    }
   ],
   "tags": ["status"]
  }},
  "/v1/adb/grant": {"post": {
   "summary": "Give Bridgit every useful permission and access through ADB (agents with Agent Super Powers)",
   "requestBody": {"content": {"application/json": {"schema": {
    "type": "object",
    "properties": {"only": {
     "description": "Grant keys to run (default all); see grants in /v1/adb/status",
     "type": "array"
    }},
    "required": []
   }}}},
   "operationId": "postAdbGrant",
   "responses": {
    "200": {"description": "results[], grants[key, title, granted]"},
    "401": {"description": "unauthorized"},
    "403": {
     "description": "capability_disabled, forbidden",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "503": {
     "description": "service_start_blocked",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    }
   },
   "tags": ["adb"]
  }},
  "/v1/tools/bridgit": {"get": {
   "summary": "The `bridgit` command-line helper (Python, no secrets inside)",
   "security": [],
   "operationId": "getToolsBridgit",
   "responses": {
    "200": {"description": "text/x-python"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    }
   },
   "tags": ["status"]
  }},
  "/v1/listen/clip/{id}": {"get": {
   "summary": "The audio after a wake word, when the owner set that wake word to send it (kept in memory 10 minutes unless you chose longer with POST /v1/captures/storage; also GET /v1/captures/{id})",
   "operationId": "getListenClipId",
   "responses": {
    "200": {"description": "heard_at, duration_seconds, format (wav), sample_rate_hz, size_bytes, data_base64 (or raw=1 bytes)"},
    "401": {"description": "unauthorized"},
    "404": {
     "description": "not_found",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    }
   },
   "parameters": [{
    "schema": {"type": "string"},
    "in": "path",
    "name": "id",
    "required": true
   }],
   "tags": ["wakewords"]
  }},
  "/v1/phone/status": {"get": {
   "summary": "Battery, network, screen and sound status, with as_of",
   "operationId": "getPhoneStatus",
   "responses": {
    "200": {"description": "Battery, network, screen and sound status, with as_of"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "tags": ["phone"]
  }},
  "/v1/phone/sound": {"post": {
   "summary": "Change ringer or volume",
   "requestBody": {"content": {"application/json": {"schema": {
    "type": "object",
    "properties": {
     "volume": {
      "description": "media/ring/alarm percentages, 0\u2013100",
      "type": "object"
     },
     "duration_minutes": {
      "description": "Optional timed restoration, 1\u20131440 minutes; null leaves the change in place",
      "type": "integer"
     },
     "ringer_mode": {
      "description": "normal, vibrate or silent",
      "type": "string"
     }
    },
    "required": []
   }}}},
   "operationId": "postPhoneSound",
   "responses": {
    "200": {"description": "Change ringer or volume"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "parameters": [{
    "schema": {"type": "string"},
    "in": "header",
    "name": "Idempotency-Key",
    "description": "Any UUID; a repeat within 24 h returns the first result"
   }],
   "tags": ["controls"]
  }},
  "/v1/phone/power": {"post": {
   "summary": "Turn battery saver on or off (needs a one-time USB grant, see /phone/battery controls) or set the screen timeout, with optional restoration",
   "requestBody": {"content": {"application/json": {"schema": {
    "type": "object",
    "properties": {
     "screen_timeout_seconds": {
      "description": "15\u20131800",
      "type": "integer"
     },
     "battery_saver": {
      "description": "true turns battery saver on; Android keeps it off while charging",
      "type": "boolean"
     },
     "duration_minutes": {
      "description": "Optional timed restoration, 1\u20131440 minutes; null leaves the change in place",
      "type": "integer"
     }
    },
    "required": []
   }}}},
   "operationId": "postPhonePower",
   "responses": {
    "200": {"description": "Turn battery saver on or off (needs a one-time USB grant, see /phone/battery controls) or set the screen timeout, with optional restoration"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "parameters": [{
    "schema": {"type": "string"},
    "in": "header",
    "name": "Idempotency-Key",
    "description": "Any UUID; a repeat within 24 h returns the first result"
   }],
   "tags": ["controls"]
  }},
  "/v1/schedule": {
   "post": {
    "summary": "Hand the phone an action manifest once: any action it can take (any /v1 call you're allowed, plus download, play, show, send and delete of saved files), each with its own schedule. The owner approves each new manifest once on the phone; then it runs by itself and results arrive as schedule.* events",
    "requestBody": {"content": {"application/json": {"schema": {
     "type": "object",
     "properties": {
      "manifest": {
       "description": "{timezone?, actions:[{id, name?, when, do, save_as?, send_to?}]} (see GET /v1/guide → schedule)",
       "type": "object"
      },
      "poll_minutes": {
       "description": "With url: how often to check, 15-1440 (default 60)",
       "type": "integer"
      },
      "url": {
       "description": "Instead of manifest: a public https:// URL the phone polls for the manifest (ETag honoured)",
       "type": "string"
      }
     },
     "required": []
    }}}},
    "operationId": "postSchedule",
    "responses": {
     "200": {"description": "status (awaiting_owner, or active when identical to the running manifest), digest, actions[{id, summary}]"},
     "422": {
      "description": "invalid_parameter",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "401": {"description": "unauthorized"},
     "403": {
      "description": "capability_disabled, agent_not_allowed",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     }
    },
    "parameters": [{
     "schema": {"type": "string"},
     "in": "header",
     "name": "Idempotency-Key",
     "description": "Any UUID; a repeat within 24 h returns the first result"
    }],
    "tags": ["schedule"]
   },
   "get": {
    "summary": "Your manifest: what's approved, what's waiting for the owner, each action's next run and last result, and your saved files",
    "operationId": "getSchedule",
    "responses": {
     "200": {"description": "status (none, awaiting_owner, active, paused), timezone, source{url, poll_minutes, last_poll, last_error}, active{digest, actions[{id, summary, next_at, runs, last_status, last_error}]}, pending{digest, actions}, assets[]"},
     "422": {
      "description": "invalid_parameter",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "401": {"description": "unauthorized"}
    },
    "tags": ["schedule"]
   },
   "delete": {
    "summary": "Remove your manifest (approved and waiting) and, unless keep_assets=true, your saved files",
    "operationId": "deleteSchedule",
    "responses": {
     "200": {"description": "removed"},
     "422": {
      "description": "invalid_parameter",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "401": {"description": "unauthorized"}
    },
    "parameters": [{
     "schema": {"type": "boolean"},
     "in": "query",
     "name": "keep_assets",
     "description": "Keep saved files (default false)",
     "required": false
    }],
    "tags": ["schedule"]
   }
  },
  "/v1/schedule/pause": {"post": {
   "summary": "Pause or resume your approved actions",
   "requestBody": {"content": {"application/json": {"schema": {
    "type": "object",
    "properties": {"paused": {
     "description": "true pauses, false resumes",
     "type": "boolean"
    }},
    "required": ["paused"]
   }}}},
   "operationId": "postSchedulePause",
   "responses": {
    "200": {"description": "paused"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"},
    "404": {
     "description": "not_found",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    }
   },
   "tags": ["schedule"]
  }},
  "/v1/ocr": {"post": {
   "summary": "Recognize Latin-script text locally; no image upload",
   "requestBody": {"content": {"application/json": {"schema": {
    "type": "object",
    "properties": {
     "data_base64": {
      "description": "Image bytes instead of gallery_id",
      "type": "string"
     },
     "gallery_id": {
      "description": "Accessible gallery image (also requires gallery grant)",
      "type": "integer"
     }
    },
    "required": []
   }}}},
   "operationId": "postOcr",
   "responses": {
    "200": {"description": "Recognize Latin-script text locally; no image upload"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "parameters": [{
    "schema": {"type": "string"},
    "in": "header",
    "name": "Idempotency-Key",
    "description": "Any UUID; a repeat within 24 h returns the first result"
   }],
   "tags": ["ocr"]
  }},
  "/v1/me": {"post": {
   "summary": "Tell the owner which model you are and what runs you; shown on your agent card (AGT-16)",
   "requestBody": {"content": {"application/json": {"schema": {
    "type": "object",
    "properties": {
     "harness": {
      "description": "The program running you, e.g. Claude Code, Codex CLI, a Python script (1-40 chars)",
      "type": "string"
     },
     "model": {
      "description": "Your model, as exact as you know it, e.g. claude-opus-5-5 or gpt-6.1 (1-60 chars)",
      "type": "string"
     }
    },
    "required": ["model"]
   }}}},
   "operationId": "postMe",
   "responses": {
    "200": {"description": "agent, model, harness"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "tags": ["status"]
  }},
  "/v1/files/{id}": {
   "get": {
    "summary": "Read your selected transfer bytes",
    "operationId": "getFilesId",
    "responses": {
     "200": {"description": "Read your selected transfer bytes"},
     "422": {
      "description": "invalid_parameter",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "401": {"description": "unauthorized"}
    },
    "parameters": [{
     "schema": {"type": "string"},
     "in": "path",
     "name": "id",
     "required": true
    }],
    "tags": ["files"]
   },
   "delete": {
    "summary": "Delete your transfer",
    "operationId": "deleteFilesId",
    "responses": {
     "200": {"description": "Delete your transfer"},
     "422": {
      "description": "invalid_parameter",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "401": {"description": "unauthorized"}
    },
    "parameters": [{
     "schema": {"type": "string"},
     "in": "path",
     "name": "id",
     "required": true
    }],
    "tags": ["files"]
   }
  },
  "/v1/guide": {"get": {
   "summary": "This guide, generated live (Markdown)",
   "operationId": "getGuide",
   "responses": {
    "200": {"description": "text/markdown"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "tags": ["status"]
  }},
  "/v1/phone/undo": {"post": {
   "summary": "Restore pending timed phone changes, preserving subsequent manual changes",
   "operationId": "postPhoneUndo",
   "responses": {
    "200": {"description": "Restore pending timed phone changes, preserving subsequent manual changes"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "parameters": [{
    "schema": {"type": "string"},
    "in": "header",
    "name": "Idempotency-Key",
    "description": "Any UUID; a repeat within 24 h returns the first result"
   }],
   "tags": ["controls"]
  }},
  "/v1/tools/bridget": {"get": {
   "summary": "Deprecated: the old address of GET /v1/tools/bridgit, same helper",
   "security": [],
   "operationId": "getToolsBridget",
   "responses": {
    "200": {"description": "text/x-python"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    }
   },
   "tags": ["status"]
  }},
  "/v1/outbound/{id}": {"get": {
   "summary": "One outbound entry with its previews",
   "operationId": "getOutboundId",
   "responses": {
    "200": {"description": "the entry"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"},
    "404": {
     "description": "not_found",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    }
   },
   "parameters": [{
    "schema": {"type": "string"},
    "in": "path",
    "name": "id",
    "required": true
   }],
   "tags": ["outbound"]
  }},
  "/v1/mcp": {"post": {
   "summary": "Model Context Protocol (Streamable HTTP, JSON replies): every endpoint you can use is an MCP tool",
   "requestBody": {"content": {"application/json": {"schema": {
    "type": "object",
    "properties": {
     "method": {
      "description": "initialize, tools/list, tools/call, ping",
      "type": "string"
     },
     "id": {
      "description": "Request id",
      "type": "integer"
     },
     "jsonrpc": {
      "description": "\"2.0\"",
      "type": "string"
     },
     "params": {
      "description": "For tools/call: {name, arguments}",
      "type": "object"
     }
    },
    "required": [
     "jsonrpc",
     "method"
    ]
   }}}},
   "operationId": "postMcp",
   "responses": {
    "200": {"description": "JSON-RPC result"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "tags": ["status"]
  }},
  "/v1/shares/{id}": {
   "get": {
    "summary": "Read your selected transfer bytes",
    "operationId": "getSharesId",
    "responses": {
     "200": {"description": "Read your selected transfer bytes"},
     "422": {
      "description": "invalid_parameter",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "401": {"description": "unauthorized"}
    },
    "parameters": [{
     "schema": {"type": "string"},
     "in": "path",
     "name": "id",
     "required": true
    }],
    "tags": ["shares"]
   },
   "delete": {
    "summary": "Delete your transfer",
    "operationId": "deleteSharesId",
    "responses": {
     "200": {"description": "Delete your transfer"},
     "422": {
      "description": "invalid_parameter",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "401": {"description": "unauthorized"}
    },
    "parameters": [{
     "schema": {"type": "string"},
     "in": "path",
     "name": "id",
     "required": true
    }],
    "tags": ["shares"]
   }
  },
  "/v1/gallery/photo/{id}": {"get": {
   "summary": "One gallery image, sized for you",
   "operationId": "getGalleryPhotoId",
   "responses": {
    "200": {"description": "taken_at, width_px, height_px, format, size_bytes, data_base64"},
    "401": {"description": "unauthorized"},
    "413": {
     "description": "payload_too_large",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "403": {
     "description": "capability_disabled, permission_denied",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "404": {
     "description": "photo_not_found",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    }
   },
   "parameters": [
    {
     "schema": {"type": "string"},
     "in": "path",
     "name": "id",
     "required": true
    },
    {
     "schema": {
      "type": "string",
      "enum": [
       "agent",
       "thumb",
       "large",
       "original"
      ]
     },
     "in": "query",
     "name": "size",
     "description": "Preset: agent (1568 px, q85), thumb (512, q75), large (2560, q90), original",
     "required": false
    },
    {
     "schema": {"type": "integer"},
     "in": "query",
     "name": "max_edge_px",
     "description": "Long edge limit, 64-20000; overrides the preset",
     "required": false
    },
    {
     "schema": {"type": "integer"},
     "in": "query",
     "name": "max_width_px",
     "description": "Width limit, 64-20000",
     "required": false
    },
    {
     "schema": {"type": "integer"},
     "in": "query",
     "name": "quality",
     "description": "JPEG quality 40-100",
     "required": false
    },
    {
     "schema": {"type": "integer"},
     "in": "query",
     "name": "raw",
     "description": "1 = return the image bytes, details in X-Bridgit-* headers",
     "required": false
    }
   ],
   "tags": ["gallery"]
  }},
  "/v1/listen": {"get": {
   "summary": "Wake words: whether the phone is listening, and the wake words the owner gave you (CAP-47)",
   "operationId": "getListen",
   "responses": {
    "200": {"description": "enabled, state (off|listening|hearing|paused), reason, muted_until, model (ready|not_downloaded|downloading|failed), model_name, max_seconds, wake_words[{phrase, send_clip}]. Each hit arrives as a listen.heard event: wake_word, transcript, heard_at, ended_by (pause|max_seconds|no_speech|interrupted), duration_seconds, recogniser, clip_id, capture {capture_id, stored, url, memory_until, file}"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "tags": ["wakewords"]
  }},
  "/v1/screen/share/capture": {"post": {
   "summary": "Capture a JPEG using your active owner-approved grant",
   "operationId": "postScreenShareCapture",
   "responses": {
    "200": {"description": "Capture a JPEG using your active owner-approved grant"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "parameters": [{
    "schema": {"type": "string"},
    "in": "header",
    "name": "Idempotency-Key",
    "description": "Any UUID; a repeat within 24 h returns the first result"
   }],
   "tags": ["screen_share"]
  }},
  "/v1/owner/email": {
   "post": {
    "summary": "Give the owner's email address: bridgit.cc emails them a link, and tapping it verifies the address (the same address gets email alerts). Works during and after the 24 hours; not once an address is verified (the owner changes it on the phone)",
    "requestBody": {"content": {"application/json": {"schema": {
     "type": "object",
     "properties": {"email": {
      "description": "The owner's email address",
      "type": "string"
     }},
     "required": ["email"]
    }}}},
    "operationId": "postOwnerEmail",
    "responses": {
     "200": {"description": "status, state (pending), email (masked), next (what to tell the owner)"},
     "422": {
      "description": "invalid_parameter",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "401": {"description": "unauthorized"},
     "502": {
      "description": "upstream_failed",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "429": {
      "description": "rate_limited",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "409": {
      "description": "conflict",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     }
    },
    "tags": ["status"]
   },
   "get": {
    "summary": "Whether the owner has verified their email. Bridgit works for 24 hours from the first agent call; after that every other endpoint answers email_required until they do",
    "operationId": "getOwnerEmail",
    "responses": {
     "200": {"description": "status (verified, grace or required), state (none, pending or confirmed), email (masked, e.g. w***@gmail.com, or null), grace_ends_at (ISO time, or null before the first call), hours_left, required_after_hours (24), how"},
     "422": {
      "description": "invalid_parameter",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "401": {"description": "unauthorized"}
    },
    "tags": ["status"]
   }
  },
  "/v1/schedule/run/{id}": {"post": {
   "summary": "Run one approved action now, outside its timetable (its 'after' chain doesn't follow)",
   "operationId": "postScheduleRunId",
   "responses": {
    "200": {"description": "action_id, status (ok or failed), result{runs, last_status, last_error}"},
    "401": {"description": "unauthorized"},
    "403": {
     "description": "capability_disabled",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "404": {
     "description": "not_found",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    }
   },
   "parameters": [{
    "schema": {"type": "string"},
    "in": "path",
    "name": "id",
    "required": true
   }],
   "tags": ["schedule"]
  }},
  "/v1/gallery/video/{id}": {"get": {
   "summary": "Accessible video raw, or a JPEG frame",
   "operationId": "getGalleryVideoId",
   "responses": {
    "200": {"description": "Accessible video raw, or a JPEG frame"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "parameters": [
    {
     "schema": {"type": "string"},
     "in": "path",
     "name": "id",
     "required": true
    },
    {
     "schema": {"type": "number"},
     "in": "query",
     "name": "frame_at_s",
     "description": "Optional frame position in seconds",
     "required": false
    }
   ],
   "tags": ["gallery_video"]
  }},
  "/v1/adb/shell": {"post": {
   "summary": "Run a shell command as Android's shell user (agents with Agent Super Powers)",
   "requestBody": {"content": {"application/json": {"schema": {
    "type": "object",
    "properties": {
     "timeout_seconds": {
      "description": "1-120, default 30",
      "type": "integer"
     },
     "command": {
      "description": "Shell command, 1-8000 characters",
      "type": "string"
     }
    },
    "required": ["command"]
   }}}},
   "operationId": "postAdbShell",
   "responses": {
    "200": {"description": "exit_code, output, truncated, timed_out"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"},
    "403": {
     "description": "capability_disabled, forbidden",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "503": {
     "description": "service_start_blocked",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    }
   },
   "tags": ["adb"]
  }},
  "/v1/camera/arm": {"post": {
   "summary": "Open the camera ahead of a photo, so your next snapshot fires in about 0.3 s",
   "requestBody": {"content": {"application/json": {"schema": {
    "type": "object",
    "properties": {
     "seconds": {
      "description": "How long to keep it ready, 1-10 (default 10). It closes after your next snapshot, at the end of this time, or when the owner pauses Bridgit",
      "type": "integer"
     },
     "camera": {
      "description": "rear (default) or front: the camera your next snapshot will use",
      "type": "string",
      "enum": [
       "rear",
       "front"
      ]
     }
    },
    "required": []
   }}}},
   "operationId": "postCameraArm",
   "responses": {
    "200": {"description": "camera, armed, seconds, armed_until, settle_ms (exposure needs this long after the camera opens; a snapshot sent sooner waits out the rest); the next snapshot says warm: true"},
    "401": {"description": "unauthorized"},
    "403": {
     "description": "capability_disabled, permission_denied, notifications_required",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "503": {
     "description": "service_start_blocked",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "409": {
     "description": "device_locked, sensor_busy",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    }
   },
   "tags": ["camera"]
  }},
  "/v1/demo": {"get": {
   "summary": "The demo to offer right after pairing: a five-minute first-run tour run from cards on the phone, then a menu of more demos picked by a few questions (Markdown)",
   "operationId": "getDemo",
   "responses": {
    "200": {"description": "text/markdown"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "tags": ["status"]
  }},
  "/v1/callback/test": {"post": {
   "summary": "Send a signed test event to the callback URL the owner set for you (EVT-05/06)",
   "operationId": "postCallbackTest",
   "responses": {
    "200": {"description": "delivered, http_status, host"},
    "401": {"description": "unauthorized"},
    "502": {
     "description": "callback_failed",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "404": {
     "description": "not_found",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    }
   },
   "tags": ["interactions"]
  }},
  "/v1/events": {"get": {
   "summary": "Your events, oldest first: answers, closes, expiries, switch changes. Repeated phone answers emit interaction.answered with resubmission=true and previous_answer; agents decide whether to accept the change. An answer given after the question expired comes as interaction.answered with late=true. action.executed: one of your HTML cards ran Bridgit.act (interaction_id, method, path, status, ok, error)",
   "operationId": "getEvents",
   "responses": {
    "200": {"description": "events[id, type, at, data], next_cursor"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"},
    "429": {
     "description": "too_many_waits",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    }
   },
   "parameters": [
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "since",
     "description": "next_cursor from the last call; omit for the last 50",
     "required": false
    },
    {
     "schema": {"type": "integer"},
     "in": "query",
     "name": "wait",
     "description": "With since: hold up to 55 s for a new event",
     "required": false
    },
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "types",
     "description": "Comma list, e.g. interaction.answered",
     "required": false
    }
   ],
   "tags": ["interactions"]
  }},
  "/v1/shares": {"get": {
   "summary": "Your shares transfers, retained 30 days on the phone",
   "operationId": "getShares",
   "responses": {
    "200": {"description": "Your shares transfers, retained 30 days on the phone"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "tags": ["shares"]
  }},
  "/v1/screen/grants": {"get": {
   "summary": "Your screen requests and active grant",
   "operationId": "getScreenGrants",
   "responses": {
    "200": {"description": "Your screen requests and active grant"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "tags": ["screen_share"]
  }},
  "/v1/feedback": {
   "post": {
    "summary": "File a bug report or feature request yourself (any agent; images only in Bridgit Fixer Mode). Send every bug and every feature request, however small, even if you doubt we can or will do it: we'd rather triage too many than miss one",
    "requestBody": {"content": {"application/json": {"schema": {
     "type": "object",
     "properties": {
      "images": {
       "description": "Fixer Mode only: up to 5 {\"data_base64\"} images",
       "type": "array"
      },
      "kind": {
       "description": "bug or feature",
       "type": "string",
       "enum": [
        "bug",
        "feature"
       ]
      },
      "agent_info": {
       "description": "About you, sent with the report to the Bridgit team: e.g. {\"harness\":\"Claude Code\",\"harness_version\":\"2.3.1\",\"model\":\"Claude Opus 5.5\"} (up to 20 short string, number or boolean fields)",
       "type": "object"
      },
      "description": {
       "description": "What happened, up to 10,000 characters",
       "type": "string"
      },
      "no_autofix": {
       "description": "true = leave it for a person",
       "type": "boolean"
      }
     },
     "required": [
      "kind",
      "description"
     ]
    }}}},
    "operationId": "postFeedback",
    "responses": {
     "200": {"description": "id (use in URLs), ref and number (the team-wide number, e.g. A0042; null until the phone sends it to the Bridgit team, then GET url shows it), status, sent_to_team, url (check back with GET), followup_url, team_api {base_url, key_endpoint, docs}"},
     "422": {
      "description": "invalid_parameter",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "401": {"description": "unauthorized"},
     "403": {
      "description": "forbidden",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "429": {
      "description": "rate_limited",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     }
    },
    "parameters": [{
     "schema": {"type": "string"},
     "in": "header",
     "name": "Idempotency-Key",
     "description": "Any UUID; a repeat within 24 h returns the first result"
    }],
    "tags": ["feedback"]
   },
   "get": {
    "summary": "Bug reports and feature requests: the ones you filed, or every report for agents in Bridgit Fixer Mode",
    "operationId": "getFeedback",
    "responses": {
     "200": {"description": "reports[id (this phone's id, used in URLs), ref (the team-wide number, e.g. M0042 from the owner, A0042 from an agent; null until sent to the Bridgit team), number (same as ref), team_id, kind, status, first_line, created_at, updated_at, no_autofix, image_count, filed_by, sent_to_team]"},
     "422": {
      "description": "invalid_parameter",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "401": {"description": "unauthorized"},
     "403": {
      "description": "forbidden",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "429": {
      "description": "too_many_waits",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     }
    },
    "parameters": [
     {
      "schema": {"type": "boolean"},
      "in": "query",
      "name": "mine",
      "description": "Fixer Mode agents: true = only reports you filed (other agents always get only their own)",
      "required": false
     },
     {
      "schema": {"type": "string"},
      "in": "query",
      "name": "status",
      "description": "new, seen, in_progress, fixed, wont_fix, duplicate, confirmed, reopened",
      "required": false
     },
     {
      "schema": {
       "type": "string",
       "enum": [
        "bug",
        "feature"
       ]
      },
      "in": "query",
      "name": "kind",
      "description": "bug or feature",
      "required": false
     },
     {
      "schema": {"type": "string"},
      "in": "query",
      "name": "since",
      "description": "ISO time: only reports updated after it",
      "required": false
     },
     {
      "schema": {"type": "integer"},
      "in": "query",
      "name": "wait",
      "description": "With since: hold up to this many seconds (max 55) for a new or changed report",
      "required": false
     },
     {
      "schema": {"type": "integer"},
      "in": "query",
      "name": "limit",
      "description": "1-100, default 50",
      "required": false
     }
    ],
    "tags": ["feedback"]
   }
  },
  "/v1/health": {"get": {
   "summary": "Is Bridgit up, and which agent you are",
   "operationId": "getHealth",
   "responses": {
    "200": {"description": "status, app, app_version, mcp (this API's MCP server, /v1/mcp), agent_control (the second MCP server /mcp and /v2 routes for the control tools), agent, listener_uptime_seconds, battery_level, charging, bind_address, port"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "tags": ["status"]
  }},
  "/v1/log/stats": {"get": {
   "summary": "Counts, errors and p50/p95 time per agent and endpoint",
   "operationId": "getLogStats",
   "responses": {
    "200": {"description": "by_agent[], by_endpoint[]"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "parameters": [{
    "schema": {"type": "string"},
    "in": "query",
    "name": "since",
    "description": "Log id or ISO time; default the last 24 h",
    "required": false
   }],
   "tags": ["log"]
  }},
  "/v1/tour": {
   "get": {
    "summary": "Your running City tour, if the owner started one with you (D30)",
    "operationId": "getTour",
    "responses": {
     "200": {"description": "tour{tour_id, kinds, interval_s, started_at, ticks, last_tick_at, distance_m, photos_sent, brief} or null"},
     "422": {
      "description": "invalid_parameter",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "401": {"description": "unauthorized"}
    },
    "tags": ["tour"]
   },
   "delete": {
    "summary": "End your City tour",
    "operationId": "deleteTour",
    "responses": {
     "200": {"description": "ended"},
     "401": {"description": "unauthorized"},
     "404": {
      "description": "not_found",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     }
    },
    "parameters": [{
     "schema": {"type": "string"},
     "in": "query",
     "name": "tour_id",
     "description": "Only end this tour (it must be yours and still running)",
     "required": false
    }],
    "tags": ["tour"]
   }
  },
  "/v1/watches/{id}": {
   "get": {
    "summary": "One running watch: its spec, the last 10 checks with Jev's answers, and the last state sent",
    "operationId": "getWatchesId",
    "responses": {
     "200": {"description": "watch_id, label, ..., spec, recent_checks [{at, readings, answers, matched, model} or {at, error, message}], last_state"},
     "401": {"description": "unauthorized"},
     "404": {
      "description": "not_found",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     }
    },
    "parameters": [{
     "schema": {"type": "string"},
     "in": "path",
     "name": "id",
     "required": true
    }],
    "tags": ["watches"]
   },
   "delete": {
    "summary": "Stop a watch (you get a watch.ended event with reason deleted)",
    "operationId": "deleteWatchesId",
    "responses": {
     "200": {"description": "deleted: the watch_id"},
     "401": {"description": "unauthorized"},
     "404": {
      "description": "not_found",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     }
    },
    "parameters": [{
     "schema": {"type": "string"},
     "in": "path",
     "name": "id",
     "required": true
    }],
    "tags": ["watches"]
   }
  },
  "/v1/speaker/play": {"post": {
   "summary": "Play audio on the phone's speaker: send audio/* bytes as the body, or {\"url\"} (public https)",
   "requestBody": {"content": {"application/json": {"schema": {
    "type": "object",
    "properties": {"url": {
     "description": "https:// audio file (MP3, M4A, OGG, WAV, FLAC), up to 25 MB",
     "type": "string"
    }},
    "required": []
   }}}},
   "operationId": "postSpeakerPlay",
   "responses": {
    "200": {"description": "play_id, position, status (playing, queued or silenced)"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"},
    "413": {
     "description": "payload_too_large",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "403": {
     "description": "capability_disabled, notifications_required",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "404": {
     "description": "not_found",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "429": {
     "description": "rate_limited",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    }
   },
   "parameters": [
    {
     "schema": {
      "type": "string",
      "enum": [
       "after_current",
       "now",
       "queue"
      ]
     },
     "in": "query",
     "name": "replace",
     "description": "after_current (default: replace what's queued from you), now, or queue",
     "required": false
    },
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "tour_id",
     "description": "Narration for your running City tour",
     "required": false
    },
    {
     "schema": {"type": "boolean"},
     "in": "query",
     "name": "urgent",
     "description": "Jump the queue (answers to questions)",
     "required": false
    },
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "text",
     "description": "Caption shown on the phone while it plays",
     "required": false
    },
    {
     "schema": {"type": "string"},
     "in": "header",
     "name": "Idempotency-Key",
     "description": "Any UUID; a repeat within 24 h returns the first result"
    }
   ],
   "tags": ["speaker"]
  }},
  "/v1/schedule/assets": {"get": {
   "summary": "Files your actions saved (downloads and kept results), up to 100 / 100 MB, kept 30 days",
   "operationId": "getScheduleAssets",
   "responses": {
    "200": {"description": "assets[{name, mime, size, sha256, created_at, by}]"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "tags": ["schedule"]
  }},
  "/v1/feedback/{id}/status": {"post": {
   "summary": "Move a report: in_progress, fixed, wont_fix or duplicate (agents in Bridgit Fixer Mode; FBK-11a)",
   "requestBody": {"content": {"application/json": {"schema": {
    "type": "object",
    "properties": {
     "note": {
      "description": "Short note shown to the owner, e.g. \"Fix in PR #412\" (500 chars)",
      "type": "string"
     },
     "status": {
      "description": "in_progress, fixed, wont_fix or duplicate",
      "type": "string"
     }
    },
    "required": ["status"]
   }}}},
   "operationId": "postFeedbackIdStatus",
   "responses": {
    "200": {"description": "the report summary"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"},
    "403": {
     "description": "forbidden",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "404": {
     "description": "not_found",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    }
   },
   "parameters": [
    {
     "schema": {"type": "string"},
     "in": "path",
     "name": "id",
     "required": true
    },
    {
     "schema": {"type": "string"},
     "in": "header",
     "name": "Idempotency-Key",
     "description": "Any UUID; a repeat within 24 h returns the first result"
    }
   ],
   "tags": ["feedback"]
  }},
  "/v1/phone/ring": {
   "post": {
    "summary": "Ring and vibrate within Android sound restrictions",
    "requestBody": {"content": {"application/json": {"schema": {
     "type": "object",
     "properties": {"duration_seconds": {
      "description": "1\u201360, default 15",
      "type": "integer"
     }},
     "required": []
    }}}},
    "operationId": "postPhoneRing",
    "responses": {
     "200": {"description": "Ring and vibrate within Android sound restrictions"},
     "422": {
      "description": "invalid_parameter",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "401": {"description": "unauthorized"}
    },
    "parameters": [{
     "schema": {"type": "string"},
     "in": "header",
     "name": "Idempotency-Key",
     "description": "Any UUID; a repeat within 24 h returns the first result"
    }],
    "tags": ["ring"]
   },
   "delete": {
    "summary": "Stop ringing and vibration",
    "operationId": "deletePhoneRing",
    "responses": {
     "200": {"description": "Stop ringing and vibration"},
     "422": {
      "description": "invalid_parameter",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "401": {"description": "unauthorized"}
    },
    "tags": ["ring"]
   }
  },
  "/v1/adb/status": {"get": {
   "summary": "ADB setup progress: developer options, wireless debugging, paired, grants",
   "operationId": "getAdbStatus",
   "responses": {
    "200": {"description": "developer_options, usb_debugging, wireless_debugging, paired, connected, shell_switch, ready, blocked_reason, grants[key, title, granted]"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "tags": ["adb"]
  }},
  "/v1/captures/storage": {
   "post": {
    "summary": "Choose where your captures go, in any combination: memory, phone files, upload; and how long memory keeps them (within the owner's limits)",
    "requestBody": {"content": {"application/json": {"schema": {
     "type": "object",
     "properties": {
      "keep_minutes": {
       "description": "How long memory keeps them, 1 to the owner's limit (default 10, owner limit 1440 unless changed)",
       "type": "integer"
      },
      "upload_url": {
       "description": "Where uploads go (POST, the capture as the body, X-Bridgit-Capture-Id/Kind/Agent/Captured-At headers). Tailnet always; public HTTPS when the owner allows internet callbacks. Needed with upload",
       "type": "string"
      },
      "upload_headers": {
       "description": "Up to 8 extra headers for the upload, e.g. {\"Authorization\": \"Bearer ...\"}; never shown back",
       "type": "object"
      },
      "kinds": {
       "description": "Only these kinds: camera, screen, mic, wakewords, sounds; null = all",
       "type": "array"
      },
      "store": {
       "description": "Any of memory, files, upload; [] = only return captures; null = back to the defaults (clips in memory, the rest only returned)",
       "type": "array"
      }
     },
     "required": ["store"]
    }}}},
    "operationId": "postCapturesStorage",
    "responses": {
     "200": {"description": "as GET /v1/captures/storage"},
     "422": {
      "description": "invalid_parameter",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "401": {"description": "unauthorized"},
     "403": {
      "description": "forbidden",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     }
    },
    "parameters": [{
     "schema": {"type": "string"},
     "in": "header",
     "name": "Idempotency-Key",
     "description": "Any UUID; a repeat within 24 h returns the first result"
    }],
    "tags": ["captures"]
   },
   "get": {
    "summary": "Where your captures go: your choice and what the owner allows (SEC-13)",
    "operationId": "getCapturesStorage",
    "responses": {
     "200": {"description": "yours {store, kinds, upload_url, upload_headers (names only), keep_minutes}, effective {<kind>: {store, keep_minutes}}, owner {agent_files, agent_upload, max_keep_minutes, any_agent_can_fetch, owner_files, owner_upload}, destinations, kinds"},
     "422": {
      "description": "invalid_parameter",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "401": {"description": "unauthorized"}
    },
    "tags": ["captures"]
   }
  },
  "/v1/changes": {"get": {
   "summary": "What's new in the API since a revision you know (API-14)",
   "operationId": "getChanges",
   "responses": {
    "200": {"description": "api_revision, app_version, changes[revision, app_version, date, items[what, endpoint]], links"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "parameters": [{
    "schema": {"type": "integer"},
    "in": "query",
    "name": "since",
    "description": "The API revision you last read about; 0 or absent = everything",
    "required": false
   }],
   "tags": ["status"]
  }},
  "/v1/location": {"get": {
   "summary": "Where the phone is now, with altitude, speed, heading and the compass",
   "operationId": "getLocation",
   "responses": {
    "200": {"description": "latitude, longitude, altitude_m, accuracy_m, vertical_accuracy_m, speed_mps, bearing_deg, fix_time, age_s, precision, compass{azimuth_deg, direction, pitch_deg, roll_deg}"},
    "401": {"description": "unauthorized"},
    "403": {
     "description": "capability_disabled, permission_denied, notifications_required",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "503": {
     "description": "service_start_blocked",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "504": {
     "description": "capture_timeout",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    }
   },
   "parameters": [
    {
     "schema": {"type": "boolean"},
     "in": "query",
     "name": "fresh",
     "description": "true (default): a new fix, up to 15 s; false: the last known one at once",
     "required": false
    },
    {
     "schema": {
      "type": "string",
      "enum": [
       "high",
       "balanced"
      ]
     },
     "in": "query",
     "name": "accuracy",
     "description": "high (GPS, default) or balanced",
     "required": false
    },
    {
     "schema": {"type": "boolean"},
     "in": "query",
     "name": "compass",
     "description": "Include the compass (default true)",
     "required": false
    }
   ],
   "tags": ["location"]
  }},
  "/v1/mic/record": {"post": {
   "summary": "Record an audio clip",
   "requestBody": {"content": {"application/json": {"schema": {
    "type": "object",
    "properties": {
     "transcribe": {
      "description": "Use only Android on-device recognition; no cloud fallback",
      "type": "boolean"
     },
     "duration_seconds": {
      "description": "Whole seconds, 1-120",
      "type": "integer"
     },
     "return_audio": {
      "description": "true by default; false requires transcribe=true",
      "type": "boolean"
     },
     "language": {
      "description": "Optional offline language, e.g. en-US",
      "type": "string"
     },
     "store": {
      "description": "Keep this capture too: any of memory (fetch it later from GET /v1/captures/{id}), files (a copy in the phone's Downloads/Bridgit), upload (POSTed to your upload_url). [] or \"none\" = only return it. Default: your POST /v1/captures/storage choice, else only returned",
      "type": "array"
     }
    },
    "required": ["duration_seconds"]
   }}}},
   "operationId": "postMicRecord",
   "responses": {
    "200": {"description": "recorded_at, duration_seconds, format (m4a), sample_rate_hz, size_bytes, data_base64; capture {capture_id, stored, url, memory_until, file} when kept"},
    "401": {"description": "unauthorized"},
    "403": {
     "description": "capability_disabled, permission_denied, notifications_required",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "503": {
     "description": "service_start_blocked",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "504": {
     "description": "capture_timeout",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "409": {
     "description": "sensor_busy",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    }
   },
   "parameters": [{
    "schema": {"type": "string"},
    "in": "header",
    "name": "Idempotency-Key",
    "description": "Any UUID; a repeat within 24 h returns the first result"
   }],
   "tags": ["mic"]
  }},
  "/v1/phone/context": {"get": {
   "summary": "Screen and lock context; likely=in_use or unknown, with the rule",
   "operationId": "getPhoneContext",
   "responses": {
    "200": {"description": "Screen and lock context; likely=in_use or unknown, with the rule"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "tags": ["phone"]
  }},
  "/v1/clipboard/{id}": {"get": {
   "summary": "Your clipboard request: pending, copied, denied or expired",
   "operationId": "getClipboardId",
   "responses": {
    "200": {"description": "Your clipboard request: pending, copied, denied or expired"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "parameters": [{
    "schema": {"type": "string"},
    "in": "path",
    "name": "id",
    "required": true
   }],
   "tags": ["clipboard"]
  }},
  "/v1/gallery/videos/recent": {"get": {
   "summary": "Accessible videos and metadata",
   "operationId": "getGalleryVideosRecent",
   "responses": {
    "200": {"description": "Accessible videos and metadata"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "parameters": [{
    "schema": {"type": "integer"},
    "in": "query",
    "name": "limit",
    "description": "1\u2013100, default 20",
    "required": false
   }],
   "tags": ["gallery_video"]
  }},
  "/v1/speaker": {
   "get": {
    "summary": "What's playing, and your queued sounds",
    "operationId": "getSpeaker",
    "responses": {
     "200": {"description": "playing{play_id, agent, text} (yours only, else null), busy (someone else's sound is playing), paused, queued[], quiet"},
     "422": {
      "description": "invalid_parameter",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "401": {"description": "unauthorized"}
    },
    "tags": ["speaker"]
   },
   "delete": {
    "summary": "Stop your audio and clear your queue",
    "operationId": "deleteSpeaker",
    "responses": {
     "200": {"description": "stopped"},
     "422": {
      "description": "invalid_parameter",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "401": {"description": "unauthorized"}
    },
    "tags": ["speaker"]
   }
  },
  "/v1/interactions/{id}": {
   "get": {
    "summary": "One of your interactions; with wait, holds until the owner answers or closes it",
    "operationId": "getInteractionsId",
    "responses": {
     "200": {"description": "kind, status, answer{button, values} (html cards: answer{button: null, values: {}, data: what the page sent}), answered_at, closed_at"},
     "401": {"description": "unauthorized"},
     "404": {
      "description": "not_found",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "429": {
      "description": "too_many_waits",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     }
    },
    "parameters": [
     {
      "schema": {"type": "string"},
      "in": "path",
      "name": "id",
      "required": true
     },
     {
      "schema": {"type": "integer"},
      "in": "query",
      "name": "wait",
      "description": "Hold up to this many seconds (max 55) for the answer",
      "required": false
     }
    ],
    "tags": ["interactions"]
   },
   "delete": {
    "summary": "Cancel one of your interactions",
    "operationId": "deleteInteractionsId",
    "responses": {
     "200": {"description": "the interaction"},
     "401": {"description": "unauthorized"},
     "404": {
      "description": "not_found",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     }
    },
    "parameters": [{
     "schema": {"type": "string"},
     "in": "path",
     "name": "id",
     "required": true
    }],
    "tags": ["interactions"]
   }
  },
  "/v1/phone/dnd": {"post": {
   "summary": "Set Do Not Disturb, with optional restoration",
   "requestBody": {"content": {"application/json": {"schema": {
    "type": "object",
    "properties": {
     "mode": {
      "description": "off, priority, alarms or none (none mutes alarms)",
      "type": "string"
     },
     "duration_minutes": {
      "description": "Optional timed restoration, 1\u20131440 minutes; null leaves the change in place",
      "type": "integer"
     }
    },
    "required": ["mode"]
   }}}},
   "operationId": "postPhoneDnd",
   "responses": {
    "200": {"description": "Set Do Not Disturb, with optional restoration"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "parameters": [{
    "schema": {"type": "string"},
    "in": "header",
    "name": "Idempotency-Key",
    "description": "Any UUID; a repeat within 24 h returns the first result"
   }],
   "tags": ["controls"]
  }},
  "/v1/adb/setup": {"get": {
   "summary": "How to help the owner turn on ADB for Bridgit, and what to do once it's on (Markdown)",
   "security": [],
   "operationId": "getAdbSetup",
   "responses": {
    "200": {"description": "text/markdown"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    }
   },
   "tags": ["adb"]
  }},
  "/v1/feedback/{id}/followup": {"post": {
   "summary": "Follow up on a report you filed: a note (\"still happens on 1.7.2\"), and once it's marked fixed, won't fix or duplicate, outcome works (closes it) or still_broken (reopens it)",
   "requestBody": {"content": {"application/json": {"schema": {
    "type": "object",
    "properties": {
     "note": {
      "description": "What you see now (500 chars); needed when there's no outcome",
      "type": "string"
     },
     "outcome": {
      "description": "works or still_broken: the owner's Confirm / Still broken, allowed once the report is fixed, wont_fix or duplicate",
      "type": "string",
      "enum": [
       "works",
       "still_broken"
      ]
     }
    },
    "required": []
   }}}},
   "operationId": "postFeedbackIdFollowup",
   "responses": {
    "200": {"description": "the report summary"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"},
    "404": {
     "description": "not_found",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "429": {
     "description": "rate_limited",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    }
   },
   "parameters": [
    {
     "schema": {"type": "string"},
     "in": "path",
     "name": "id",
     "required": true
    },
    {
     "schema": {"type": "string"},
     "in": "header",
     "name": "Idempotency-Key",
     "description": "Any UUID; a repeat within 24 h returns the first result"
    }
   ],
   "tags": ["feedback"]
  }},
  "/v1/downloads/{id}": {
   "get": {
    "summary": "Read your selected transfer bytes",
    "operationId": "getDownloadsId",
    "responses": {
     "200": {"description": "Read your selected transfer bytes"},
     "422": {
      "description": "invalid_parameter",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "401": {"description": "unauthorized"}
    },
    "parameters": [{
     "schema": {"type": "string"},
     "in": "path",
     "name": "id",
     "required": true
    }],
    "tags": ["downloads"]
   },
   "delete": {
    "summary": "Delete your transfer",
    "operationId": "deleteDownloadsId",
    "responses": {
     "200": {"description": "Delete your transfer"},
     "422": {
      "description": "invalid_parameter",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "401": {"description": "unauthorized"}
    },
    "parameters": [{
     "schema": {"type": "string"},
     "in": "path",
     "name": "id",
     "required": true
    }],
    "tags": ["downloads"]
   }
  },
  "/v1/log/{id}": {"get": {
   "summary": "One log entry",
   "operationId": "getLogId",
   "responses": {
    "200": {"description": "the entry"},
    "401": {"description": "unauthorized"},
    "404": {
     "description": "not_found",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    }
   },
   "parameters": [{
    "schema": {"type": "string"},
    "in": "path",
    "name": "id",
    "required": true
   }],
   "tags": ["log"]
  }},
  "/v1/audit": {"get": {
   "summary": "Deprecated alias of /v1/log?channel=audit (removed in v3)",
   "operationId": "getAudit",
   "responses": {
    "200": {"description": "entries[] (same shape as /v1/log)"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "parameters": [{
    "schema": {"type": "integer"},
    "in": "query",
    "name": "limit",
    "description": "1-500, default 50",
    "required": false
   }],
   "tags": ["log"]
  }},
  "/v1/captures": {"get": {
   "summary": "Your kept captures (photos, screenshots, recordings, clips), newest first: where each is and until when",
   "operationId": "getCaptures",
   "responses": {
    "200": {"description": "captures[id, kind, agent_id, mime, size_bytes, captured_at, in_memory, memory_until, file, upload {agent|owner: pending|sent|failed: why}, url, meta]"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "parameters": [
    {
     "schema": {
      "type": "string",
      "enum": [
       "camera",
       "screen",
       "mic",
       "wakewords",
       "sounds"
      ]
     },
     "in": "query",
     "name": "kind",
     "description": "Only this kind",
     "required": false
    },
    {
     "schema": {"type": "integer"},
     "in": "query",
     "name": "limit",
     "description": "1-200, default 50",
     "required": false
    }
   ],
   "tags": ["captures"]
  }},
  "/v1/openapi.json": {"get": {
   "summary": "OpenAPI 3.1 description of every endpoint",
   "operationId": "getOpenapiJson",
   "responses": {
    "200": {"description": "application/json"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "tags": ["status"]
  }},
  "/v1/sounds/clip/{id}": {"get": {
   "summary": "The audio of a sound (up to 10 s, from just before it started), when the owner lets sounds send audio (kept in memory 10 minutes unless you chose longer with POST /v1/captures/storage; also GET /v1/captures/{id})",
   "operationId": "getSoundsClipId",
   "responses": {
    "200": {"description": "heard_at, duration_seconds, format (wav), sample_rate_hz, size_bytes, data_base64 (or raw=1 bytes)"},
    "401": {"description": "unauthorized"},
    "404": {
     "description": "not_found",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    }
   },
   "parameters": [{
    "schema": {"type": "string"},
    "in": "path",
    "name": "id",
    "required": true
   }],
   "tags": ["sounds"]
  }},
  "/v1/speaker/say": {"post": {
   "summary": "Read text aloud on the phone (its own text-to-speech)",
   "requestBody": {"content": {"application/json": {"schema": {
    "type": "object",
    "properties": {
     "tour_id": {
      "description": "Narration for your City tour",
      "type": "string"
     },
     "rate": {
      "description": "0.5-2, default 1",
      "type": "number"
     },
     "replace": {
      "description": "after_current (default), now, or queue",
      "type": "string"
     },
     "language": {
      "description": "e.g. en-GB, de-DE",
      "type": "string"
     },
     "text": {
      "description": "Up to 4,000 characters",
      "type": "string"
     },
     "pitch": {
      "description": "0.5-2, default 1",
      "type": "number"
     },
     "urgent": {
      "description": "Jump the queue",
      "type": "boolean"
     }
    },
    "required": ["text"]
   }}}},
   "operationId": "postSpeakerSay",
   "responses": {
    "200": {"description": "play_id, position, status (playing, queued, or silenced: the phone is on silent, Do Not Disturb or in a call, so it won't be heard)"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"},
    "403": {
     "description": "capability_disabled",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "404": {
     "description": "not_found",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "429": {
     "description": "rate_limited",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    }
   },
   "parameters": [{
    "schema": {"type": "string"},
    "in": "header",
    "name": "Idempotency-Key",
    "description": "Any UUID; a repeat within 24 h returns the first result"
   }],
   "tags": ["speaker"]
  }},
  "/v1/camera/video": {"post": {
   "summary": "Record an MP4, returned raw (HTTP: 40 MB maximum; MCP: 6 MB, may stop early)",
   "requestBody": {"content": {"application/json": {"schema": {
    "type": "object",
    "properties": {
     "duration_seconds": {
      "description": "1\u201330, default 10",
      "type": "integer"
     },
     "audio": {
      "description": "false by default; true also requires microphone grant",
      "type": "boolean"
     },
     "camera": {
      "description": "rear or front",
      "type": "string"
     },
     "resolution": {
      "description": "720p or 1080p",
      "type": "string"
     }
    },
    "required": []
   }}}},
   "operationId": "postCameraVideo",
   "responses": {
    "200": {"description": "Record an MP4, returned raw (HTTP: 40 MB maximum; MCP: 6 MB, may stop early)"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "parameters": [{
    "schema": {"type": "string"},
    "in": "header",
    "name": "Idempotency-Key",
    "description": "Any UUID; a repeat within 24 h returns the first result"
   }],
   "tags": ["video"]
  }},
  "/v1/phone/brightness": {"post": {
   "summary": "Set brightness or automatic brightness",
   "requestBody": {"content": {"application/json": {"schema": {
    "type": "object",
    "properties": {
     "auto": {
      "description": "true enables automatic brightness",
      "type": "boolean"
     },
     "duration_minutes": {
      "description": "Optional timed restoration, 1\u20131440 minutes; null leaves the change in place",
      "type": "integer"
     },
     "level": {
      "description": "0\u20131",
      "type": "number"
     }
    },
    "required": []
   }}}},
   "operationId": "postPhoneBrightness",
   "responses": {
    "200": {"description": "Set brightness or automatic brightness"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "parameters": [{
    "schema": {"type": "string"},
    "in": "header",
    "name": "Idempotency-Key",
    "description": "Any UUID; a repeat within 24 h returns the first result"
   }],
   "tags": ["controls"]
  }},
  "/v1/log/export": {"get": {
   "summary": "Every matching entry as JSONL or CSV",
   "operationId": "getLogExport",
   "responses": {
    "200": {"description": "application/x-ndjson or text/csv"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "parameters": [
    {
     "schema": {
      "type": "string",
      "enum": [
       "jsonl",
       "csv"
      ]
     },
     "in": "query",
     "name": "format",
     "description": "jsonl (default) or csv",
     "required": false
    },
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "channel",
     "description": "Comma list of audit, diagnostic, agent",
     "required": false
    },
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "agent",
     "description": "Agent name or id; `me` for you; `bridgit` for Bridgit's own entries",
     "required": false
    },
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "kind",
     "description": "request, setting, agent, pairing, service, note, \u2026",
     "required": false
    },
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "endpoint",
     "description": "Endpoint prefix, e.g. /v1/camera",
     "required": false
    },
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "result",
     "description": "ok, error, or an error code",
     "required": false
    },
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "level",
     "description": "Minimum level: debug, info, warn, error",
     "required": false
    },
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "since",
     "description": "Log id or ISO time (exclusive id)",
     "required": false
    },
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "until",
     "description": "Log id or ISO time",
     "required": false
    },
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "q",
     "description": "Text in message or endpoint",
     "required": false
    }
   ],
   "tags": ["log"]
  }},
  "/v1/judgment": {"post": {
   "summary": "Ask Jev (TypeSafe) typed questions about a state you send; get typed answers with calibrated probabilities, and the phone runs the conditional actions whose conditions held",
   "requestBody": {"content": {"application/json": {"schema": {
    "type": "object",
    "properties": {
     "questions": {
      "description": "1-50 typed questions, {id: {type: choice|noul|..., instructions, criteria?}}, as https://docs.typesafe.ai/primitives",
      "type": "object"
     },
     "state": {
      "description": "What the questions are about: text or JSON, up to about 512 KB. Text only: no images, audio or video (send a transcript)",
      "type": "string|object|array"
     },
     "actions": {
      "description": "Up to 10 rules, bridgit-actions/1: {id, when: condition or 1-5 conditions (all must hold), do: action}. Condition: {answer, choice, min_confidence?} or {answer, min?, max?} for a probability. Action: {type: notice, title, text?} (a card from you), {type: speak, text} or {type: log, message}; plain text only, no links",
      "type": "array"
     }
    },
    "required": [
     "state",
     "questions"
    ]
   }}}},
   "operationId": "postJudgment",
   "responses": {
    "200": {"description": "model, answers {id: {type, choice+confidence | noul}}, usage, cost_usd, elapsed_ms, actions_schema (bridgit-actions/1), actions [{id, type, reason, ran, error?}] (only rules whose conditions held), skipped [{id, reason}]. When Jev fails you get an error and no action runs"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"},
    "413": {
     "description": "payload_too_large",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "502": {
     "description": "upstream_failed",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "503": {
     "description": "team_unavailable",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "429": {
     "description": "rate_limited",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    }
   },
   "tags": ["judgment"]
  }},
  "/v1/outbound/summary": {"get": {
   "summary": "Analysis of what left the phone, in one call: a plain-language headline, totals, trends by hour or day, the biggest destinations, agents and calls, destinations first seen in the window, failures, and for each destination the data categories, purposes and agents it received",
   "operationId": "getOutboundSummary",
   "responses": {
    "200": {"description": "headline (\"Since 00:00 today: 7 calls sent 4.9 KB to 3 destinations: ...\"), window{since, until, bucket}, totals{calls, failed, bytes_sent, bytes_received, categories[], destinations, agents}, by_destination[{service, host, calls, failed, bytes, categories[], purposes[], agents[], first_at, last_at, new}], by_category[{category, destinations[], agents[]}], by_agent[{agent, destinations[]}], by_purpose[], by_day[], by_time[], biggest{destinations[], agents[], calls[]}, new_destinations[{host, first_at, categories[]}], failures{count, by_destination[], by_error[], recent[]}, recording{on, changed_at, changed_by}, scope, coverage"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "parameters": [
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "since",
     "description": "Outbound id (exclusive) or ISO time",
     "required": false
    },
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "until",
     "description": "Outbound id or ISO time",
     "required": false
    },
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "destination",
     "description": "Text in the host or service name, e.g. met.no, jev, relay",
     "required": false
    },
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "agent",
     "description": "Comma list of agent names or ids; me; phone or owner for calls nobody's agent caused",
     "required": false
    },
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "category",
     "description": "Comma list of data categories, any of them, e.g. location_1km,image,install_id",
     "required": false
    },
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "method",
     "description": "GET, POST, SEND (relay frames)\u2026",
     "required": false
    },
    {
     "schema": {
      "type": "string",
      "enum": [
       "ok",
       "error"
      ]
     },
     "in": "query",
     "name": "result",
     "description": "ok or error",
     "required": false
    },
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "q",
     "description": "Text in the purpose, path or sent preview",
     "required": false
    },
    {
     "schema": {
      "type": "string",
      "enum": [
       "today",
       "24h",
       "7d",
       "30d"
      ]
     },
     "in": "query",
     "name": "period",
     "description": "today, 24h, 7d or 30d (default 30d; since overrides it)",
     "required": false
    },
    {
     "schema": {
      "type": "string",
      "enum": [
       "hour",
       "day"
      ]
     },
     "in": "query",
     "name": "bucket",
     "description": "Trend step: hour or day (default hour for windows up to 48 h)",
     "required": false
    }
   ],
   "tags": ["outbound"]
  }},
  "/v1/feedback/team-key": {"get": {
   "summary": "Your own key for the Bridgit team's feedback backend: file reports, check their status and verify fixes there directly, even when this phone is down (FBK-15)",
   "operationId": "getFeedbackTeamKey",
   "responses": {
    "200": {"description": "base_url, key (bgk_...), agent_id, role, docs, how_to"},
    "401": {"description": "unauthorized"},
    "403": {
     "description": "capability_disabled, forbidden",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "503": {
     "description": "team_unavailable",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "429": {
     "description": "rate_limited",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    }
   },
   "parameters": [{
    "schema": {"type": "boolean"},
    "in": "query",
    "name": "rotate",
    "description": "true = make a new key; the old one stops working",
    "required": false
   }],
   "tags": ["feedback"]
  }},
  "/v1/log": {
   "post": {
    "summary": "Write a note to the agent channel",
    "requestBody": {"content": {"application/json": {"schema": {
     "type": "object",
     "properties": {
      "data": {
       "description": "Up to 4 KB of JSON",
       "type": "object"
      },
      "level": {
       "description": "debug, info (default), warn, error",
       "type": "string"
      },
      "message": {
       "description": "Up to 1 KB",
       "type": "string"
      }
     },
     "required": ["message"]
    }}}},
    "operationId": "postLog",
    "responses": {
     "200": {"description": "id"},
     "422": {
      "description": "invalid_parameter",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "401": {"description": "unauthorized"},
     "429": {
      "description": "rate_limited",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     }
    },
    "parameters": [{
     "schema": {"type": "string"},
     "in": "header",
     "name": "Idempotency-Key",
     "description": "Any UUID; a repeat within 24 h returns the first result"
    }],
    "tags": ["log"]
   },
   "get": {
    "summary": "Read the log; with order=asc&since=<id>&wait=55 it follows new entries",
    "operationId": "getLog",
    "responses": {
     "200": {"description": "entries[], next_cursor, latest_id"},
     "422": {
      "description": "invalid_parameter",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "401": {"description": "unauthorized"},
     "429": {
      "description": "too_many_waits",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     }
    },
    "parameters": [
     {
      "schema": {"type": "string"},
      "in": "query",
      "name": "channel",
      "description": "Comma list of audit, diagnostic, agent",
      "required": false
     },
     {
      "schema": {"type": "string"},
      "in": "query",
      "name": "agent",
      "description": "Agent name or id; `me` for you; `bridgit` for Bridgit's own entries",
      "required": false
     },
     {
      "schema": {"type": "string"},
      "in": "query",
      "name": "kind",
      "description": "request, setting, agent, pairing, service, note, \u2026",
      "required": false
     },
     {
      "schema": {"type": "string"},
      "in": "query",
      "name": "endpoint",
      "description": "Endpoint prefix, e.g. /v1/camera",
      "required": false
     },
     {
      "schema": {"type": "string"},
      "in": "query",
      "name": "result",
      "description": "ok, error, or an error code",
      "required": false
     },
     {
      "schema": {"type": "string"},
      "in": "query",
      "name": "level",
      "description": "Minimum level: debug, info, warn, error",
      "required": false
     },
     {
      "schema": {"type": "string"},
      "in": "query",
      "name": "since",
      "description": "Log id or ISO time (exclusive id)",
      "required": false
     },
     {
      "schema": {"type": "string"},
      "in": "query",
      "name": "until",
      "description": "Log id or ISO time",
      "required": false
     },
     {
      "schema": {"type": "string"},
      "in": "query",
      "name": "q",
      "description": "Text in message or endpoint",
      "required": false
     },
     {
      "schema": {"type": "integer"},
      "in": "query",
      "name": "limit",
      "description": "1-500, default 100",
      "required": false
     },
     {
      "schema": {
       "type": "string",
       "enum": [
        "desc",
        "asc"
       ]
      },
      "in": "query",
      "name": "order",
      "description": "desc (default) or asc",
      "required": false
     },
     {
      "schema": {"type": "string"},
      "in": "query",
      "name": "cursor",
      "description": "next_cursor from the previous page",
      "required": false
     },
     {
      "schema": {"type": "integer"},
      "in": "query",
      "name": "wait",
      "description": "Tail mode: hold up to this many seconds (max 55) for a new entry",
      "required": false
     }
    ],
    "tags": ["log"]
   }
  },
  "/v1/phone/battery": {"get": {
   "summary": "Full battery report: percent, status, plug type, health, temperature, voltage, cycles, current, time to full, battery saver, which power settings agents may change, and the battery.* events",
   "operationId": "getPhoneBattery",
   "responses": {
    "200": {"description": "Full battery report: percent, status, plug type, health, temperature, voltage, cycles, current, time to full, battery saver, which power settings agents may change, and the battery.* events"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "tags": ["phone"]
  }},
  "/v1/downloads": {"get": {
   "summary": "Your downloads transfers, retained 30 days on the phone",
   "operationId": "getDownloads",
   "responses": {
    "200": {"description": "Your downloads transfers, retained 30 days on the phone"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "tags": ["downloads"]
  }},
  "/v1/outbound": {"get": {
   "summary": "Every call this phone made to a server off the device: destination, purpose, which agent caused it, the data categories sent, bytes, status, time, and a redacted preview of what was sent and received",
   "operationId": "getOutbound",
   "responses": {
    "200": {"description": "entries[id, at, destination{host, service}, method, path, purpose, agent, agent_id, categories[], bytes_sent, bytes_received, status, ok, error, duration_ms, query, headers (secrets redacted), sent_sha256, sent{type, preview}, received{type, preview}], next_cursor, latest_id, recording{on, changed_at, changed_by, note}, scope{sees: own|all}, coverage{recorded[], not_recorded[]}"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "parameters": [
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "since",
     "description": "Outbound id (exclusive) or ISO time",
     "required": false
    },
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "until",
     "description": "Outbound id or ISO time",
     "required": false
    },
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "destination",
     "description": "Text in the host or service name, e.g. met.no, jev, relay",
     "required": false
    },
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "agent",
     "description": "Comma list of agent names or ids; me; phone or owner for calls nobody's agent caused",
     "required": false
    },
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "category",
     "description": "Comma list of data categories, any of them, e.g. location_1km,image,install_id",
     "required": false
    },
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "method",
     "description": "GET, POST, SEND (relay frames)\u2026",
     "required": false
    },
    {
     "schema": {
      "type": "string",
      "enum": [
       "ok",
       "error"
      ]
     },
     "in": "query",
     "name": "result",
     "description": "ok or error",
     "required": false
    },
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "q",
     "description": "Text in the purpose, path or sent preview",
     "required": false
    },
    {
     "schema": {
      "type": "string",
      "enum": [
       "today",
       "24h",
       "7d",
       "30d"
      ]
     },
     "in": "query",
     "name": "period",
     "description": "today, 24h, 7d or 30d (since overrides it)",
     "required": false
    },
    {
     "schema": {"type": "integer"},
     "in": "query",
     "name": "limit",
     "description": "1-500, default 100",
     "required": false
    },
    {
     "schema": {
      "type": "string",
      "enum": [
       "desc",
       "asc"
      ]
     },
     "in": "query",
     "name": "order",
     "description": "desc (default) or asc",
     "required": false
    },
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "cursor",
     "description": "next_cursor from the previous page",
     "required": false
    },
    {
     "schema": {"type": "boolean"},
     "in": "query",
     "name": "bodies",
     "description": "false leaves out the sent/received previews (default true)",
     "required": false
    }
   ],
   "tags": ["outbound"]
  }},
  "/v1/gallery/recent": {"get": {
   "summary": "Newest gallery images (metadata only)",
   "operationId": "getGalleryRecent",
   "responses": {
    "200": {"description": "access_mode, photos[id, taken_at, width_px, height_px, size_bytes, mime, album]"},
    "401": {"description": "unauthorized"},
    "403": {
     "description": "capability_disabled, permission_denied",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    }
   },
   "parameters": [
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "type",
     "description": "any, photo or screenshot",
     "required": false
    },
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "album",
     "description": "Exact album name",
     "required": false
    },
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "since",
     "description": "ISO-8601 UTC added-at lower bound",
     "required": false
    },
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "until",
     "description": "ISO-8601 UTC upper bound",
     "required": false
    },
    {
     "schema": {"type": "integer"},
     "in": "query",
     "name": "limit",
     "description": "1-100, default 20",
     "required": false
    }
   ],
   "tags": ["gallery"]
  }},
  "/v1/capabilities": {"get": {
   "summary": "What's switched on and ready, and why not",
   "operationId": "getCapabilities",
   "responses": {
    "200": {"description": "per capability: title, enabled (the phone switch), ready (the device can do it), agent_allowed (the owner lets you use it), blocked_reason, details. Usable only when agent_allowed, enabled and ready are all true. enabled false means the owner's switch is off; blocked_reason names other known causes (agent_not_allowed, a missing Android permission, no_hardware) and can be null. Also notifications, callback {set, host}, listener"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "tags": ["status"]
  }},
  "/v1/notifications": {"get": {
   "summary": "Up to 100 active notification texts since service connected; RAM only",
   "operationId": "getNotifications",
   "responses": {
    "200": {"description": "Up to 100 active notification texts since service connected; RAM only"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "tags": ["notifications"]
  }},
  "/v1/usage": {"get": {
   "summary": "App foreground time from Android usage buckets (maximum seven days)",
   "operationId": "getUsage",
   "responses": {
    "200": {"description": "App foreground time from Android usage buckets (maximum seven days)"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "parameters": [
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "since",
     "description": "ISO-8601 UTC",
     "required": false
    },
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "until",
     "description": "ISO-8601 UTC",
     "required": false
    }
   ],
   "tags": ["usage"]
  }},
  "/v1/schedule/assets/{name}": {
   "get": {
    "summary": "One saved file's bytes, e.g. a photo a scheduled action took",
    "operationId": "getScheduleAssetsName",
    "responses": {
     "200": {"description": "The raw bytes with their Content-Type"},
     "401": {"description": "unauthorized"},
     "404": {
      "description": "not_found",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     }
    },
    "parameters": [{
     "schema": {"type": "string"},
     "in": "path",
     "name": "name",
     "required": true
    }],
    "tags": ["schedule"]
   },
   "delete": {
    "summary": "Delete one saved file",
    "operationId": "deleteScheduleAssetsName",
    "responses": {
     "200": {"description": "deleted"},
     "401": {"description": "unauthorized"},
     "404": {
      "description": "not_found",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     }
    },
    "parameters": [{
     "schema": {"type": "string"},
     "in": "path",
     "name": "name",
     "required": true
    }],
    "tags": ["schedule"]
   }
  },
  "/v1/text/stream": {"post": {
   "summary": "Add text to your live text panel (an interaction of kind text); it scrolls on the phone as it arrives",
   "requestBody": {"content": {"application/json": {"schema": {
    "type": "object",
    "properties": {
     "interaction_id": {
      "description": "The panel's interaction_id",
      "type": "string"
     },
     "done": {
      "description": "true: the stream is finished; the panel stays until the owner closes it",
      "type": "boolean"
     },
     "append": {
      "description": "Text to add, up to 16 KB per call (the panel keeps the last 200 KB)",
      "type": "string"
     }
    },
    "required": ["interaction_id"]
   }}}},
   "operationId": "postTextStream",
   "responses": {
    "200": {"description": "interaction_id, length, status"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"},
    "404": {
     "description": "not_found",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "429": {
     "description": "rate_limited",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "409": {
     "description": "conflict",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    }
   },
   "tags": ["interactions"]
  }},
  "/v1/tour/photo/{n}": {"get": {
   "summary": "A photo the owner took with Take photo on your tour (n from tour.photo), sized for you",
   "operationId": "getTourPhotoN",
   "responses": {
    "200": {"description": "taken_at, width_px, height_px, format, size_bytes, data_base64"},
    "401": {"description": "unauthorized"},
    "413": {
     "description": "payload_too_large",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "404": {
     "description": "not_found, photo_not_found",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    }
   },
   "parameters": [
    {
     "schema": {"type": "string"},
     "in": "path",
     "name": "n",
     "required": true
    },
    {
     "schema": {
      "type": "string",
      "enum": [
       "agent",
       "thumb",
       "large",
       "original"
      ]
     },
     "in": "query",
     "name": "size",
     "description": "Preset: agent (1568 px, q85), thumb (512, q75), large (2560, q90), original",
     "required": false
    },
    {
     "schema": {"type": "integer"},
     "in": "query",
     "name": "max_edge_px",
     "description": "Long edge limit, 64-20000; overrides the preset",
     "required": false
    },
    {
     "schema": {"type": "integer"},
     "in": "query",
     "name": "max_width_px",
     "description": "Width limit, 64-20000",
     "required": false
    },
    {
     "schema": {"type": "integer"},
     "in": "query",
     "name": "quality",
     "description": "JPEG quality 40-100",
     "required": false
    },
    {
     "schema": {"type": "integer"},
     "in": "query",
     "name": "raw",
     "description": "1 = return the image bytes, details in X-Bridgit-* headers",
     "required": false
    }
   ],
   "tags": ["tour"]
  }},
  "/v1/image/last": {"get": {
   "summary": "The newest image of a type; with since and wait, waits for the next one",
   "operationId": "getImageLast",
   "responses": {
    "200": {"description": "id, type, taken_at, added_at, album, width_px, height_px, size_bytes, data_base64"},
    "401": {"description": "unauthorized"},
    "403": {
     "description": "capability_disabled, permission_denied",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "404": {
     "description": "photo_not_found",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "429": {
     "description": "too_many_waits",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    }
   },
   "parameters": [
    {
     "schema": {
      "type": "string",
      "enum": [
       "any",
       "screenshot",
       "photo"
      ]
     },
     "in": "query",
     "name": "type",
     "description": "any (default), screenshot or photo",
     "required": false
    },
    {
     "schema": {"type": "string"},
     "in": "query",
     "name": "since",
     "description": "ISO time or gallery id: only an image added after it",
     "required": false
    },
    {
     "schema": {"type": "integer"},
     "in": "query",
     "name": "wait",
     "description": "With since: hold up to this many seconds (max 55) for a new image",
     "required": false
    },
    {
     "schema": {
      "type": "string",
      "enum": [
       "agent",
       "thumb",
       "large",
       "original"
      ]
     },
     "in": "query",
     "name": "size",
     "description": "Preset: agent (1568 px, q85), thumb (512, q75), large (2560, q90), original",
     "required": false
    },
    {
     "schema": {"type": "integer"},
     "in": "query",
     "name": "max_edge_px",
     "description": "Long edge limit, 64-20000; overrides the preset",
     "required": false
    },
    {
     "schema": {"type": "integer"},
     "in": "query",
     "name": "max_width_px",
     "description": "Width limit, 64-20000",
     "required": false
    },
    {
     "schema": {"type": "integer"},
     "in": "query",
     "name": "quality",
     "description": "JPEG quality 40-100",
     "required": false
    },
    {
     "schema": {"type": "integer"},
     "in": "query",
     "name": "raw",
     "description": "1 = return the image bytes, details in X-Bridgit-* headers",
     "required": false
    }
   ],
   "tags": ["gallery"]
  }},
  "/v1/screen/capture": {"post": {
   "summary": "What's on the owner's screen right now (D17, no prompt once they've turned it on)",
   "requestBody": {"content": {"application/json": {"schema": {
    "type": "object",
    "properties": {
     "mode": {
      "description": "private (default): taken in memory, never put in the gallery",
      "type": "string",
      "enum": ["private"]
     },
     "store": {
      "description": "Keep this capture too: any of memory (fetch it later from GET /v1/captures/{id}), files (a copy in the phone's Downloads/Bridgit), upload (POSTed to your upload_url). [] or \"none\" = only return it. Default: your POST /v1/captures/storage choice, else only returned",
      "type": "array"
     }
    },
    "required": []
   }}}},
   "operationId": "postScreenCapture",
   "responses": {
    "200": {"description": "captured_at, width_px, height_px, format, size_bytes, mode, data_base64 (or raw=1 bytes); capture {capture_id, stored, url, memory_until, file} when kept (X-Bridgit-Capture-Id with raw=1)"},
    "422": {
     "description": "not_supported",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"},
    "413": {
     "description": "payload_too_large",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "403": {
     "description": "capability_disabled, access_needed, notifications_required",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "503": {
     "description": "service_start_blocked",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "504": {
     "description": "capture_timeout",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "429": {
     "description": "rate_limited",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "409": {
     "description": "device_locked, sensor_busy",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    }
   },
   "parameters": [
    {
     "schema": {
      "type": "string",
      "enum": [
       "agent",
       "thumb",
       "large",
       "original"
      ]
     },
     "in": "query",
     "name": "size",
     "description": "Preset: agent (1568 px, q85), thumb (512, q75), large (2560, q90), original",
     "required": false
    },
    {
     "schema": {"type": "integer"},
     "in": "query",
     "name": "max_edge_px",
     "description": "Long edge limit, 64-20000; overrides the preset",
     "required": false
    },
    {
     "schema": {"type": "integer"},
     "in": "query",
     "name": "max_width_px",
     "description": "Width limit, 64-20000",
     "required": false
    },
    {
     "schema": {"type": "integer"},
     "in": "query",
     "name": "quality",
     "description": "JPEG quality 40-100",
     "required": false
    },
    {
     "schema": {"type": "integer"},
     "in": "query",
     "name": "raw",
     "description": "1 = return the image bytes, details in X-Bridgit-* headers",
     "required": false
    },
    {
     "schema": {"type": "string"},
     "in": "header",
     "name": "Idempotency-Key",
     "description": "Any UUID; a repeat within 24 h returns the first result"
    }
   ],
   "tags": ["screen"]
  }},
  "/v1/sounds": {"get": {
   "summary": "Listen for any sounds: whether the phone tells you when the room gets loud (8.23)",
   "operationId": "getSounds",
   "responses": {
    "200": {"description": "enabled, for_you, state (off|listening|paused), reason, sensitivity (quiet|normal|loud), send_clip, cooldown_seconds, max_seconds. Each sound arrives as a sound.heard event: heard_at, duration_seconds, peak_dbfs, mean_dbfs, sensitivity, clip_id, capture {capture_id, stored, url, memory_until, file}"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "tags": ["sounds"]
  }},
  "/v1/files": {
   "post": {
    "summary": "Receive a file on the phone (25 MB maximum)",
    "requestBody": {"content": {"application/json": {"schema": {
     "type": "object",
     "properties": {
      "data_base64": {
       "description": "File bytes; or send raw body with ?name=...",
       "type": "string"
      },
      "mime": {
       "description": "MIME type",
       "type": "string"
      },
      "name": {
       "description": "Filename, no path",
       "type": "string"
      }
     },
     "required": ["name"]
    }}}},
    "operationId": "postFiles",
    "responses": {
     "200": {"description": "Receive a file on the phone (25 MB maximum)"},
     "422": {
      "description": "invalid_parameter",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "401": {"description": "unauthorized"}
    },
    "parameters": [
     {
      "schema": {"type": "string"},
      "in": "query",
      "name": "filename",
      "description": "Filename for raw-body uploads (or name= for HTTP compatibility)",
      "required": false
     },
     {
      "schema": {"type": "string"},
      "in": "header",
      "name": "Idempotency-Key",
      "description": "Any UUID; a repeat within 24 h returns the first result"
     }
    ],
    "tags": ["files"]
   },
   "get": {
    "summary": "Your files transfers, retained 30 days on the phone",
    "operationId": "getFiles",
    "responses": {
     "200": {"description": "Your files transfers, retained 30 days on the phone"},
     "422": {
      "description": "invalid_parameter",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "401": {"description": "unauthorized"}
    },
    "tags": ["files"]
   }
  },
  "/v1/weather": {"get": {
   "summary": "Weather where the phone is (or at a lat/lon you give): conditions now, the next hours and the next 24 hours, from MET Norway. Schedule it like any call: {\"do\":{\"call\":\"GET /v1/weather\"}}",
   "operationId": "getWeather",
   "responses": {
    "200": {"description": "location{latitude, longitude, from (phone or request), rounded_to_decimals}, now{time, temperature_c, symbol, summary, precipitation_mm, precipitation_period, wind_speed_mps, wind_from_deg, wind_from, humidity_pct, cloud_pct, pressure_hpa}, next_hours[{time, temperature_c, symbol, summary, precipitation_mm, wind_speed_mps}], next_12_hours{symbol, summary}, next_24_hours{min_temperature_c, max_temperature_c, precipitation_mm}, forecast_updated_at, fetched_at, expires_at, cached, stale, source, attribution"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"},
    "403": {
     "description": "capability_disabled, agent_not_allowed, permission_denied, access_needed, notifications_required",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "502": {
     "description": "upstream_failed",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "504": {
     "description": "capture_timeout",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    }
   },
   "parameters": [
    {
     "schema": {"type": "number"},
     "in": "query",
     "name": "lat",
     "description": "Latitude. With lon: weather there, and no location access is needed",
     "required": false
    },
    {
     "schema": {"type": "number"},
     "in": "query",
     "name": "lon",
     "description": "Longitude, with lat",
     "required": false
    },
    {
     "schema": {"type": "integer"},
     "in": "query",
     "name": "hours",
     "description": "Hourly forecast points after now, 0-48 (default 6)",
     "required": false
    }
   ],
   "tags": ["weather"]
  }},
  "/v1/watches": {
   "post": {
    "summary": "Call me back when ...: the phone reads the data you pick (location, motion, ...) on an interval, asks Jev (or Clef) your question about the last few readings, and calls you back when the answer matches",
    "requestBody": {"content": {"application/json": {"schema": {
     "type": "object",
     "properties": {
      "interval_s": {
       "description": "Seconds between readings, 30-3600 (default 60). A watch keeps the phone awake and reads location each time, so pick the longest interval and expiry that work. Phone-wide limit: 240 Jev checks an hour (50 on an install the Bridgit team couldn't attest). A still, unplugged phone may pause checks until it wakes",
       "type": "integer"
      },
      "question": {
       "description": "A yes/no question in words, e.g. \"Is the phone on a bicycle?\". You're called back when Jev's probability of yes reaches min_probability. Send this or questions",
       "type": "string"
      },
      "data": {
       "description": "What to read each time (default [\"location\", \"motion\"]): location (with speed), motion (2 s accelerometer burst), steps, light, pressure, proximity, battery, device (screen, lock, headphones, network). location needs the location permission, the sensors ones the sensors permission",
       "type": "array"
      },
      "expires_in_s": {
       "description": "Stop after this long, up to 86400 (default 7200)",
       "type": "integer"
      },
      "questions": {
       "description": "Instead of question: 1-10 typed questions, {id: {type: choice|noul, instructions, criteria?}}, as https://docs.typesafe.ai/primitives",
       "type": "object"
      },
      "label": {
       "description": "A short name for logs and lists (default: the question)",
       "type": "string"
      },
      "min_readings": {
       "description": "Readings to collect before the first question (default 3, at most window)",
       "type": "integer"
      },
      "callback_url": {
       "description": "Where to POST the result, as well as your registered callback and /v1/events. Same rules as callbacks: a tailnet address, or https on the internet if the owner allows internet callbacks. Signed with the callback_secret in the reply",
       "type": "string"
      },
      "cooldown_s": {
       "description": "With repeat: seconds between callbacks (default 600)",
       "type": "integer"
      },
      "repeat": {
       "description": "false (default): one callback, then the watch ends. true: keep watching, at most one callback per cooldown_s",
       "type": "boolean"
      },
      "min_probability": {
       "description": "With question: how likely yes must be, 0-1 (default 0.8)",
       "type": "number"
      },
      "context": {
       "description": "Anything Jev should know, up to 2000 characters (\"the owner commutes by bike\")",
       "type": "string"
      },
      "model": {
       "description": "Decision model: jev (default, TypeSafe; best on reasoning about text) or clef (Cloudflare Clef-omni). Both share the phone's hourly limit",
       "type": "string",
       "enum": [
        "jev",
        "clef"
       ]
      },
      "window": {
       "description": "How many recent readings Jev sees, 1-20 (default 5)",
       "type": "integer"
      },
      "callback_when": {
       "description": "With questions: the answer that calls you back, 1-5 conditions that must all hold: {answer, min?, max?} on a noul probability, or {answer, choice, min_confidence?} (default 0.8) on a choice. Jev's confidence is not the probability: 0.67 likely is about 0.34 confident",
       "type": "object|array"
      }
     },
     "required": []
    }}}},
    "operationId": "postWatches",
    "responses": {
     "200": {"description": "201: watch_id, label, created_at, expires_at, spec, callback_secret (only with callback_url; shown once), first_check_in_s, delivery. Each match is a watch.matched event {watch_id, label, question, answers, callback_when, model, checked_at, match, state (the readings Jev saw)}; the end is watch.ended {watch_id, reason: matched|expired|deleted|access_revoked|budget|rejected|failing, message, checks, matches}"},
     "422": {
      "description": "invalid_parameter",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "401": {"description": "unauthorized"},
     "403": {
      "description": "agent_not_allowed, capability_disabled",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "503": {
      "description": "team_unavailable",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "429": {
      "description": "too_many_open, rate_limited",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     }
    },
    "tags": ["watches"]
   },
   "get": {
    "summary": "Your running watches, with their last check",
    "operationId": "getWatches",
    "responses": {
     "200": {"description": "watches [{watch_id, label, created_at, expires_at, interval_s, data, checks, matches, last_match_at, readings_held, last_check}]"},
     "422": {
      "description": "invalid_parameter",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "401": {"description": "unauthorized"}
    },
    "tags": ["watches"]
   }
  },
  "/v1/interactions": {
   "post": {
    "summary": "Send the owner a notice, a question (buttons, text reply, choice, links), an HTML card or a live text panel. Prefer a native question for simple choices, normal priority and no speech. Sending isn't seeing or answering: wait with GET /v1/interactions/{id}?wait=55 (or one /v1/events loop for several)",
    "requestBody": {"content": {"application/json": {"schema": {
     "type": "object",
     "properties": {
      "image": {
       "description": "{\"gallery_id\"} or {\"data_base64\"}, up to 2 MB",
       "type": "object"
      },
      "expires_in_seconds": {
       "description": "60 to 604800, default 86400. After it, waits return expired and you get interaction.expired, but a question stays on the owner's phone and they can still answer it late (interaction.answered with late=true)",
       "type": "integer"
      },
      "stack": {
       "description": "kind=html: 1-32 letters, digits, - or _. Your cards with the same stack id form one stack the owner swipes through (drag left = next, right = previous) with \"n of m\" and a peek of the next card; each card keeps its own id, wait and answer. Up to 10 cards per stack id; an open stack counts as one of your 5 open questions. Leave it out for a single card, which is never swipeable. Don't rely on horizontal scrolling inside a stacked card. Wait on GET /v1/events?types=interaction.answered rather than one wait per card",
       "type": "string"
      },
      "controls": {
       "description": "Question: 1-6 of {type: button|text|choice|link, id, label, style?, placeholder?, options?, url?, package?}. Notice: links only",
       "type": "array"
      },
      "stack_index": {
       "description": "kind=html with stack: position 0-9 (default: after the cards already posted)",
       "type": "integer"
      },
      "kind": {
       "description": "notice (one-way), question, html (a card you draw; answer comes from Bridgit.respond) or text (a live text panel you stream into with /v1/text/stream)",
       "type": "string",
       "enum": [
        "notice",
        "question",
        "html",
        "text"
       ]
      },
      "html": {
       "description": "kind=html: the card's HTML, up to 256 KB. Runs offline: no network, only data:image/* images; call Bridgit.respond(value) once per question view (up to 16 KB) to answer; value is a JSON string or a plain object/array, which is serialized for you. window.Bridget is the same object (the only name on 1.6.269 and older). After persistence, bridgit:answered lets the card show its confirmation; the trusted Back to questions control reloads the question for resubmission. Bridgit.act({method, path, query?, body?}) runs one of your own endpoints on the phone right away, as you, with your grants and the owner's switches, e.g. await Bridgit.act({path:'/v1/flashlight', body:{on:true, auto_off_seconds:1}}) resolves to {ok, status, body}; you get an action.executed event for each call, so it works while you're offline. A single card can't be swiped: show progress as text (\"Step 2 of 5\"), not swipe or segment bars. Complete pages: GET /v1/samples",
       "type": "string"
      },
      "speak": {
       "description": "Read it aloud on the phone",
       "type": "boolean"
      },
      "text": {
       "description": "Up to 2,000 characters",
       "type": "string"
      },
      "title": {
       "description": "Up to 80 characters",
       "type": "string"
      },
      "priority": {
       "description": "normal or urgent",
       "type": "string",
       "enum": [
        "normal",
        "urgent"
       ]
      },
      "swipe_answer": {
       "description": "kind=html with stack: {\"left\": label, \"right\": label} (1-20 characters each). While the card waits, a swipe answers it and moves on: answer.data = {\"swipe\": \"left\"|\"right\", \"label\": ...}. Bridgit shows both labels under the card",
       "type": "object"
      }
     },
     "required": [
      "kind",
      "title"
     ]
    }}}},
    "operationId": "postInteractions",
    "responses": {
     "200": {"description": "interaction_id, status, expires_at, display {shown_as: full_screen|bridgit_open|notification, full_screen, missing?: [open_on_arrival, display_over_other_apps], fix?}. When full_screen is false and missing is set, only a notification was shown; pass fix on to the owner"},
     "422": {
      "description": "invalid_parameter",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "401": {"description": "unauthorized"},
     "413": {
      "description": "payload_too_large",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "403": {
      "description": "capability_disabled, notifications_required",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "404": {
      "description": "photo_not_found",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "429": {
      "description": "too_many_open",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     }
    },
    "parameters": [{
     "schema": {"type": "string"},
     "in": "header",
     "name": "Idempotency-Key",
     "description": "Any UUID; a repeat within 24 h returns the first result"
    }],
    "tags": ["interactions"]
   },
   "get": {
    "summary": "Your interactions, newest first",
    "operationId": "getInteractions",
    "responses": {
     "200": {"description": "interactions[]"},
     "422": {
      "description": "invalid_parameter",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "401": {"description": "unauthorized"}
    },
    "parameters": [
     {
      "schema": {"type": "string"},
      "in": "query",
      "name": "status",
      "description": "pending, seen, answered, dismissed, expired or cancelled",
      "required": false
     },
     {
      "schema": {"type": "integer"},
      "in": "query",
      "name": "limit",
      "description": "1-100, default 50",
      "required": false
     }
    ],
    "tags": ["interactions"]
   }
  },
  "/v1/flashlight": {
   "post": {
    "summary": "Set torch with mandatory auto-off",
    "requestBody": {"content": {"application/json": {"schema": {
     "type": "object",
     "properties": {
      "auto_off_seconds": {
       "description": "1\u2013600, default 60",
       "type": "integer"
      },
      "on": {
       "description": "true or false",
       "type": "boolean"
      }
     },
     "required": ["on"]
    }}}},
    "operationId": "postFlashlight",
    "responses": {
     "200": {"description": "Set torch with mandatory auto-off"},
     "422": {
      "description": "invalid_parameter",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "401": {"description": "unauthorized"}
    },
    "parameters": [{
     "schema": {"type": "string"},
     "in": "header",
     "name": "Idempotency-Key",
     "description": "Any UUID; a repeat within 24 h returns the first result"
    }],
    "tags": ["flashlight"]
   },
   "get": {
    "summary": "Whether the torch is on",
    "operationId": "getFlashlight",
    "responses": {
     "200": {"description": "Whether the torch is on"},
     "422": {
      "description": "invalid_parameter",
      "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
     },
     "401": {"description": "unauthorized"}
    },
    "tags": ["flashlight"]
   }
  },
  "/v1/clipboard": {"post": {
   "summary": "Queue a five-minute owner approval; never copies until owner taps Copy",
   "requestBody": {"content": {"application/json": {"schema": {
    "type": "object",
    "properties": {"text": {
     "description": "1\u201310000 characters",
     "type": "string"
    }},
    "required": ["text"]
   }}}},
   "operationId": "postClipboard",
   "responses": {
    "200": {"description": "Queue a five-minute owner approval; never copies until owner taps Copy"},
    "422": {
     "description": "invalid_parameter",
     "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
    },
    "401": {"description": "unauthorized"}
   },
   "parameters": [{
    "schema": {"type": "string"},
    "in": "header",
    "name": "Idempotency-Key",
    "description": "Any UUID; a repeat within 24 h returns the first result"
   }],
   "tags": ["clipboard"]
  }}
 },
 "info": {
  "x-learn": "https://bridgit.cc/learn/index.json",
  "description": "The owner's phone, for their AI agents. Tailscale only; one key per agent; everything logged.",
  "x-api-revision": 39,
  "title": "Bridgit",
  "version": "1.8.0"
 }
}
