{"openapi":"3.0.3","info":{"title":"HWireline Data Exchange","version":"1.0.0","description":"Partner telemetry API. Authenticate with `Authorization: Bearer hwx_…`. A key only sees customers, pads, and trucks in its grants. Null/blank job context is hidden. `raw_payload` is never returned. Admin UI is not on this hostname. WellScope Stage Share (privilege stageshare, contract wellscope.stageshare/1.0.0) is a live overlay: room LAS, pins, cursors — not /v1/logs or /v1/inbound."},"servers":[{"url":"https://dx.horizontalwireline.ai","description":"Partner HTTPS"}],"tags":[{"name":"meta","description":"Public docs (no API key)"},{"name":"signup","description":"Self-serve sample tenant"},{"name":"catalog","description":"What this key may see"},{"name":"logs","description":"LAS well-log placeholders and file retrieve"},{"name":"telemetry","description":"Time-bounded truck samples"},{"name":"stream","description":"Filtered live SSE"},{"name":"inbound","description":"Partner write sink (admin-granted write privilege)"},{"name":"recommend","description":"Agent product/docs suggestions. Any valid key; not write. Reviewed by hand."},{"name":"admin","description":"Privilege admin. Onboard, notify, roll keys, grants. Mutations email a confirmation code to the acting admin. Super-user console mints this privilege."},{"name":"stageshare","description":"WellScope Stage Share (contract wellscope.stageshare/1.0.0). Live stage overlay: room LAS, pins, pointers. Privilege stageshare, not write. Isolated from /v1/logs and /v1/inbound."}],"paths":{"/openapi.json":{"get":{"tags":["meta"],"summary":"OpenAPI document","security":[],"responses":{"200":{"description":"OpenAPI 3 JSON"}}}},"/llms.txt":{"get":{"tags":["meta"],"summary":"Agent-oriented usage notes","security":[],"responses":{"200":{"description":"text/plain"}}}},"/HWS_DATA_SKILL.md":{"get":{"tags":["meta"],"summary":"HWS_DATA_SKILL v1 — fetch after /skill.json if version changed","security":[],"responses":{"200":{"description":"text/markdown"}}}},"/STAGESHARE_THREAD.md":{"get":{"tags":["meta"],"summary":"Stage Share chat vs depth comments (same POST …/comments). For WellScope units.","security":[],"responses":{"200":{"description":"text/markdown"}}}},"/STAGESHARE_SURVEY.md":{"get":{"tags":["meta"],"summary":"Stage Share directional survey. Prefer survey on POST /rooms; PUT …/survey for a late attach. Ground TVD, 0 = surface.","security":[],"responses":{"200":{"description":"text/markdown"}}}},"/STAGESHARE_UPLINK.md":{"get":{"tags":["meta"],"summary":"Stage Share Pi uplink. Pointer heartbeat keeps LIVE on surface/standby. live_tail is the CCLR lead past the last LAS flush. EcoDrive does not count.","security":[],"responses":{"200":{"description":"text/markdown"}}}},"/STAGESHARE_LOGS.md":{"get":{"tags":["meta"],"summary":"Stage Share LAS promote, Sync inventory, PUT resend, inject reprocessed files.","security":[],"responses":{"200":{"description":"text/markdown"}}}},"/skill.json":{"get":{"tags":["meta"],"summary":"HWS_DATA_SKILL version index — GET this at the start of every task","security":[],"responses":{"200":{"description":"JSON skill index"}}}},"/signup":{"post":{"tags":["signup"],"summary":"Mint a sample-tenant API key (shown once)","security":[],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["name","email"],"properties":{"name":{"type":"string"},"email":{"type":"string","format":"email"}}}}}},"responses":{"201":{"description":"plaintext key plus Sample catalog scope"},"400":{"description":"invalid name or email"},"409":{"description":"email already registered — use /recover"}}}},"/recover":{"post":{"tags":["signup"],"summary":"Email a one-hour recovery link (does not include the API key)","security":[],"responses":{"200":{"description":"Always ok; sends mail only if the email exists"}}}},"/recover/confirm":{"post":{"tags":["signup"],"summary":"Consume a recovery token and mint a replacement key","security":[],"responses":{"200":{"description":"plaintext key shown once"},"400":{"description":"invalid or expired token"}}}},"/v1/openapi.json":{"get":{"tags":["meta"],"summary":"OpenAPI document (alias)","security":[],"responses":{"200":{"description":"OpenAPI 3 JSON"}}}},"/v1/catalog":{"get":{"tags":["catalog"],"summary":"Customers, pads, wells, trucks in grant","responses":{"200":{"description":"Catalog scoped to this key"},"401":{"description":"Missing or invalid key"},"403":{"description":"No read privilege"}}}},"/v1/logs":{"get":{"tags":["logs"],"summary":"LAS log placeholders in grant (no file bytes)","parameters":[{"name":"customer","in":"query","schema":{"type":"string"}},{"name":"pad","in":"query","schema":{"type":"string"}},{"name":"well","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"{ data: [{ id, filename, customer, pad, well, stage, storage.uri, storage.href, curves, … }] }. Bytes live in object storage; this payload is the placeholder."},"401":{"description":"unauthorized"},"403":{"description":"forbidden or out-of-grant filter"}}}},"/v1/logs/{id}":{"get":{"tags":["logs"],"summary":"One LAS placeholder","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Placeholder; storage.href is the file retrieve URL"},"403":{"description":"forbidden"},"404":{"description":"unknown id"}}}},"/v1/logs/{id}/content":{"get":{"tags":["logs"],"summary":"Retrieve the LAS 2.0 file (demo: from local sample store; prod: object storage)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"text/plain LAS body; Content-Disposition has the filename"},"403":{"description":"forbidden"},"404":{"description":"unknown id"}}}},"/v1/logs/{id}/curves":{"get":{"tags":["logs"],"summary":"Downsampled DEPT/CCL/SPEED/TENS for plotting (peak-preserving)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"max_points","in":"query","schema":{"type":"integer","default":8000},"description":"Cap 200–20000. Collar spikes are kept."}],"responses":{"200":{"description":"{ columns, data: [[dept,ccl,speed,tens], …] }"}}}},"/v1/telemetry/latest":{"get":{"tags":["telemetry"],"summary":"Latest sample per truck (7-day window)","parameters":[{"name":"customer","in":"query","schema":{"type":"string"}},{"name":"pad","in":"query","schema":{"type":"string"}},{"name":"truck","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Projected rows; no raw_payload"},"401":{"description":"unauthorized"},"403":{"description":"forbidden or out-of-grant filter"}}}},"/v1/telemetry":{"get":{"tags":["telemetry"],"summary":"History. from and to are required. Max 7 days.","parameters":[{"name":"from","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":true,"schema":{"type":"string","format":"date-time"}},{"name":"customer","in":"query","schema":{"type":"string"}},{"name":"pad","in":"query","schema":{"type":"string"}},{"name":"truck","in":"query","schema":{"type":"string"}},{"name":"resolution","in":"query","schema":{"type":"string","example":"1m"},"description":"Optional time_bucket. Depth/tension/speed include min/max."},{"name":"cursor","in":"query","schema":{"type":"string"},"description":"Opaque. Pass back the cursor from the previous response verbatim. It encodes (time, truck_number), so do not parse or construct it."}],"responses":{"200":{"description":"Page of samples. cursor is non-null when more rows remain; pass it back unchanged."},"400":{"description":"Invalid window or cursor"},"401":{"description":"unauthorized"},"403":{"description":"Need history privilege, or filter outside grant"},"429":{"description":"Rate limited. Honor Retry-After."}}}},"/v1/stream-tokens":{"post":{"tags":["stream"],"summary":"Mint a short-lived EventSource ticket (never put hwx_ in a URL)","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"customer":{"type":"string"},"pad":{"type":"string"},"truck":{"oneOf":[{"type":"string"},{"type":"integer"}]}}}}}},"responses":{"201":{"description":"{ token, expires_in, stream_url, max_uses }. The ticket is replayable for automatic EventSource reconnects until expires_in elapses or max_uses is reached."},"403":{"description":"Need live privilege, or a customer/pad/truck filter outside your grants. Filters are validated at mint time, so a ticket you receive always resolves to data you may read."},"429":{"description":"Rate limited. Honor Retry-After."}}}},"/v1/inbound":{"post":{"tags":["inbound"],"summary":"Post JSON for HWireline (write privilege). Isolated from truck telemetry.","description":"Two body shapes are accepted. Wrapped: `{ \"topic\", \"payload\" }`. Flat: any JSON object; all keys except `topic` become the payload (`topic` defaults to `inbox`). Privilege `write` is required. Rows land in `dx.inbound_payloads` only — never `truck_telemetry`. Max ~200 KiB. `topic` is 1–128 characters `[A-Za-z0-9._/-]`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"topic":{"type":"string","maxLength":128,"pattern":"^[A-Za-z0-9._/-]{1,128}$","description":"Optional label. Default `inbox`.","example":"well-file"},"payload":{"description":"JSON object or array. Required unless the rest of the body is the payload.","oneOf":[{"type":"object","additionalProperties":true},{"type":"array"}]}}},"examples":{"wrapped":{"summary":"topic + payload (preferred)","value":{"topic":"well-file","payload":{"well":"8H","stage":37,"note":"from partner"}}},"flat":{"summary":"flat object (topic optional, defaults to inbox)","value":{"well":"8H","stage":37,"note":"from partner"}},"array":{"summary":"array payload","value":{"topic":"events","payload":[{"well":"8H"},{"well":"2H"}]}}}}}},"responses":{"201":{"description":"{ id, topic, received_at }","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"topic":{"type":"string"},"received_at":{"type":"string","format":"date-time"}}},"example":{"id":"11111111-1111-4111-8111-111111111111","topic":"well-file","received_at":"2026-08-27T21:00:00.000Z"}}}},"400":{"description":"Invalid topic or payload"},"401":{"description":"unauthorized"},"403":{"description":"Need write privilege (admin-granted; not on sample keys by default)"},"429":{"description":"Rate limited. Honor Retry-After."}}},"get":{"tags":["inbound"],"summary":"List this key's inbound posts","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","default":50}}],"responses":{"200":{"description":"{ data: [{ id, topic, payload, received_at, processed_at }] }"},"403":{"description":"Need write privilege"}}}},"/v1/recommendations":{"post":{"tags":["recommend"],"summary":"Suggest a product or docs change (any valid key, not write)","description":"HWireline reviews by hand. Not every suggestion ships. Not `/v1/inbound`. Sample keys are enough. One concrete suggestion per post.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["message"],"properties":{"message":{"type":"string","minLength":8,"maxLength":8000,"example":"It would be great if you can share LAS files for every completed stage."},"context":{"type":"string","maxLength":8000},"source":{"type":"string","maxLength":128,"example":"Cursor"}}}}}},"responses":{"201":{"description":"{ id, message, status, received_at }"},"400":{"description":"message too short or missing"},"401":{"description":"unauthorized"},"429":{"description":"Rate limited. Honor Retry-After."}}},"get":{"tags":["recommend"],"summary":"List this key's recommendations","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","default":50}}],"responses":{"200":{"description":"{ data: [{ id, message, context, source, status, received_at }] }"},"401":{"description":"unauthorized"}}}},"/v1/admin/intents":{"post":{"tags":["admin"],"summary":"Start an admin mutation; emails a 6-digit code to the acting admin","description":"Requires privilege admin. Payload is stored hashed-code until POST /v1/admin/intents/{id}/confirm. Cannot grant privilege admin. Secret never emailed.","responses":{"202":{"description":"{ id, action, expires_at, mailed }"},"403":{"description":"Need admin privilege"}}}},"/v1/admin/intents/{id}/confirm":{"post":{"tags":["admin"],"summary":"Confirm an admin intent with the emailed 6-digit code","description":"Five wrong tries lock the intent. Onboard and roll_key return plaintext once in the JSON.","responses":{"200":{"description":"{ action, result }"},"400":{"description":"invalid, expired, or locked"}}}},"/v1/admin/users":{"get":{"tags":["admin"],"summary":"List parties and key prefixes (never hashes)","responses":{"200":{"description":"{ users }"},"403":{"description":"Need admin"}}}},"/v1/stream":{"get":{"tags":["stream"],"summary":"SSE stream. Query token= from stream-tokens. Honor Last-Event-ID.","description":"On 401 the ticket expired: mint a new one at /v1/stream-tokens rather than retrying this URL. The terminal `end` event carries { reason, remint }.","parameters":[{"name":"token","in":"query","required":true,"schema":{"type":"string"}}],"security":[],"responses":{"200":{"description":"text/event-stream"},"401":{"description":"Ticket invalid or expired; remint at /v1/stream-tokens"}}}},"/v1/stageshare/rooms":{"post":{"tags":["stageshare"],"summary":"Create a Stage Share room (privilege stageshare, not write)","description":"WellScope Stage Share room. Contract wellscope.stageshare/1.0.0 (header WellScope-Contract and/or body.contract). Same major is adapted; other majors 422 {error:contract_unsupported, accepted:[1.0.0]}. 201 includes contract.accepted. Include survey on this POST to snapshot pad well paths (512 KiB; see /STAGESHARE_SURVEY.md). When mail.sender is dx, DX emails invites from ecodrive_notifications; the unit only forwards addresses. Pointers are well-space (depth_ft, column_id, x_frac) — never css_px. One live room per unit key. Do not post this JSON to /v1/inbound. Room LAS is isolated from /v1/logs.","responses":{"201":{"description":"Room + guest_url + contract.accepted (ss_ shown once)"},"403":{"description":"Need stageshare"},"409":{"description":"live_room_exists"},"422":{"description":"contract_unsupported"}}},"get":{"tags":["stageshare"],"summary":"List this key's rooms (live overlay metadata, not telemetry)","description":"Returns rooms this unit key created. Each room is one shared wireline stage (well, stage, pad, unit_label). Then GET …/rooms/{id}/logs and …/comments. 403 without privilege stageshare. Sample keys do not have it.","responses":{"200":{"description":"{ rooms }"}}}},"/v1/stageshare/sessions":{"post":{"tags":["stageshare"],"summary":"Guest session mint (share_key ss_, no hwx_)","description":"No API key. Invite ss_ keys mint with no body name (identity is the invited email). Room ss_ (cabin Copy) requires { display_name } (2–32 chars, not an email). Optional client_id keeps the same browser from becoming Name (2) on refresh. Returns sst_ for Authorization. Remint on 401 or WS 4401. Never put hwx_ in the guest URL.","security":[],"responses":{"201":{"description":"{ token sst_, ws_url, room }"},"401":{"description":"unknown/revoked"},"410":{"description":"revoked or recording flushed"}}}},"/v1/stageshare/stream":{"get":{"tags":["stageshare"],"summary":"Room overlay WebSocket (primary) or SSE (read-only). Query token=sst_.","description":"Live cursors/presence/comment facade for one room. Not /v1/stream (that is truck telemetry). Pointers are well-space: depth_ft, column_id, x_frac — never css_px, x, or y.","security":[{"shareSession":[]}],"parameters":[{"name":"token","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"WS or text/event-stream"},"429":{"description":"room_full (26th connection)"}}}},"/v1/stageshare/rooms/{id}":{"get":{"tags":["stageshare"],"summary":"Get a room. Operator gets guest_url and guests[]; share_key only with ?reveal=1.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Room (live or recorded)"},"410":{"description":"revoked or recording flushed"}}}},"/v1/stageshare/rooms/{id}/finalize":{"post":{"tags":["stageshare"],"summary":"Freeze a live room. Reasons: new_stage | operator | ttl_live | offline | shutdown (≡ offline). Not revoke.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Frozen room"},"400":{"description":"invalid reason (including revoke)"}}}},"/v1/stageshare/rooms/{id}/revoke":{"post":{"tags":["stageshare"],"summary":"Stop sharing: same as finalize (5-day recorded snapshot, same ss_ link). Hard purge is DELETE.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Revoked"}}}},"/v1/stageshare/rooms/{id}/survey":{"get":{"tags":["stageshare"],"summary":"Directional survey for the guest 2D/3D well-path plot","description":"Ground datum: 0 TVD = surface. { survey } or { survey: null }. Guest sst_ or operator hwx_. Format: GET /STAGESHARE_SURVEY.md.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearer":[]},{"shareSession":[]}],"responses":{"200":{"description":"{ survey }"}}},"put":{"tags":["stageshare"],"summary":"Replace the pad directional survey (Pi / operator)","description":"Privilege stageshare. Compact stations [[md,inc,azm,tvd,vs,ns,ew,dls],…]. Required md,tvd,ns,ew. datum is ground. 512 KiB. Handshake. WS type survey.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"{ survey }"},"400":{"description":"invalid_survey"},"413":{"description":"too_many_wells / too_many_stations"}}},"delete":{"tags":["stageshare"],"summary":"Clear the directional survey","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Cleared"}}}},"/v1/stageshare/rooms/{id}/pointer":{"post":{"tags":["stageshare"],"summary":"HTTP overlay fallback: pointer, leave, or view_hint","description":"Pi heartbeat while the room is live — including surface/standby (negative MD, speed 0). Well-space only: { depth_ft, column_id, x_frac }. Optional live readouts: tension_lbs, speed_ftpm (or view_hint.tool_depth_ft / tension_lbs / speed_ftpm). Optional live_tail: uncommitted samples past the last LAS row (dept_ft + cclr_v, cap 80) so guests plot CCLR before the ~10 ft flush. Operator hwx_ only counts as handshake. DX drops css_px, x, y. See /STAGESHARE_UPLINK.md.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Accepted"}}}},"/v1/stageshare/rooms/{id}/comments":{"get":{"tags":["stageshare"],"summary":"List comments (JSON array). Pi also reads text/column aliases.","description":"JSON array (not {comments:[]}). Chat rows omit depth_ft. Plot notes include depth_ft and column_id (or column), body or text, author, deleted_at. Skip deleted_at.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearer":[]},{"shareSession":[]}],"responses":{"200":{"description":"Array of comments"}}},"post":{"tags":["stageshare"],"summary":"Add a comment (body or text, column_id or column)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearer":[]},{"shareSession":[]}],"responses":{"201":{"description":"Comment"}}}},"/v1/stageshare/rooms/{id}/logs":{"get":{"tags":["stageshare"],"summary":"Room-scoped LAS listing { files }. Isolated from /v1/logs.","description":"Depth-aligned columns the crew is looking at (tally|live|rih|corr|pump|pooh). files[] include id, filename, column_id, col, role, bytes, seq, visible, depth_min_ft, depth_max_ft (depths may be null). Then GET …/logs/{lid}/content (Range ok) or …/curves. Do not merge with GET /v1/logs.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearer":[]},{"shareSession":[]}],"responses":{"200":{"description":"{ files }"}}},"post":{"tags":["stageshare"],"summary":"Create or reuse a room log slot (live slot, or same filename)","description":"Reuses the existing live object, or the newest row with the same filename. Does not clobber a different pass on the same column. 413 {error:too many logs, max:48, count} only when a new slot is required and the room is full. Then PUT …/content or POST …/append. Operator hwx_ or HWireline invite admin (sst_).","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"{ id, filename, column_id, role, bytes, seq, reuse }"},"413":{"description":"too many logs | room too large"}}}},"/v1/stageshare/rooms/{id}/logs/sync":{"post":{"tags":["stageshare"],"summary":"Diff the cabin stage inventory against room LAS","description":"Operator hwx_ + stageshare. Body { columns: [{ column_id, filename, bytes, depth_min_ft, depth_max_ft }] }. Returns matched / stale / missing / extra. Extra is never auto-deleted. Then POST …/logs (filename reuse) and PUT …/content. Live stays append-only. See /STAGESHARE_LOGS.md.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"{ matched, stale, missing, extra }"},"400":{"description":"columns required"},"409":{"description":"room_frozen"}}}},"/v1/stageshare/rooms/{id}/logs/sync/request":{"post":{"tags":["stageshare"],"summary":"Ask the cabin to run Sync","description":"Operator hwx_ or HWireline invite admin. Broadcasts WS sync-needed. 409 cabin_offline if the last Pi handshake is older than 2 minutes (same clock as truck-offline).","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearer":[]},{"shareSession":[]}],"responses":{"200":{"description":"{ ok, status: sync_requested }"},"403":{"description":"forbidden"},"409":{"description":"cabin_offline | room_frozen"}}}},"/v1/stageshare/rooms/{id}/logs/{lid}":{"get":{"tags":["stageshare"],"summary":"One room log plus measured depth span","description":"Operator or guest. Returns the listing row plus span { first_ft, last_ft, min_ft, max_ft, n_rows, bytes, direction } scanned from DEPT. See /STAGESHARE_LOGS.md.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"lid","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearer":[]},{"shareSession":[]}],"responses":{"200":{"description":"log + span"},"404":{"description":"not found"}}},"patch":{"tags":["stageshare"],"summary":"Rename a room log, move it, or toggle visibility","description":"Body { visible } only: guests (sst_) and operators. Applies to live and frozen files. WS log-moved so every viewer matches. Full reassign (filename, column_id or col, role, depth_*) is operator hwx_ or HWireline invite admin; live is 409 cannot_reassign_live. Bytes and storage key stay put (no copy). A displaced occupant is hidden (visible:false), not deleted. Unknown column 400 invalid_column.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"lid","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"{ id, filename, column_id, col, role, bytes, seq, visible, depth_min_ft, depth_max_ft, reuse:false }"},"400":{"description":"invalid_column"},"409":{"description":"cannot_reassign_live"}}},"delete":{"tags":["stageshare"],"summary":"Delete a frozen/reference room log (not the live object)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"lid","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Deleted"},"409":{"description":"cannot_delete_live"}}}},"/v1/stageshare/rooms/{id}/logs/{lid}/promote":{"post":{"tags":["stageshare"],"summary":"Snapshot live LAS into a frozen column on DX (no Pi PUT)","description":"Operator hwx_ only. live_id must be the room live log. Body: column_id (rih|corr|pump|pooh|tally), filename, optional preview/dry_run (no copy), expect_first_ft / expect_last_ft / expect_tol_ft (409 depth_mismatch), content_type, depth_min_ft/depth_max_ft. Response and WS include measured span and moved_comments. Copies live bytes into a frozen slot (reuses the same filename; a different filename keeps the previous occupant visible). Live depth comments in the span move to the dest column. Resets live to bytes=0. 413 at cap 48 if a new slot is required. 409 not_live | depth_mismatch. PUT …/content to resend. See /STAGESHARE_LOGS.md.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"lid","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"{ live, frozen } reused frozen slot (reuse:true)"},"201":{"description":"{ live, frozen } new frozen slot"},"400":{"description":"invalid_column | filename required"},"409":{"description":"not_live | room_frozen | depth_mismatch"},"413":{"description":"too many logs"}}}},"/v1/stageshare/rooms/{id}/sessions":{"get":{"tags":["stageshare"],"summary":"List minted overlay sessions and who is on the WebSocket","description":"Operator hwx_ or guest sst_. Returns { sessions, presence }. sessions are unrevoked sst_ rows (no tokens). presence is who is connected now. Same body on GET …/presence. Stop polling if you only needed this to exist — 404 here was the old gap.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearer":[]},{"shareSession":[]}],"responses":{"200":{"description":"{ sessions, presence }"}}},"post":{"tags":["stageshare"],"summary":"Mint an operator sst_ for the cabin overlay","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"{ token sst_, ws_url, room }"}}}},"/v1/stageshare/rooms/{id}/presence":{"get":{"tags":["stageshare"],"summary":"Alias of GET …/sessions (stops a 404 poll)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearer":[]},{"shareSession":[]}],"responses":{"200":{"description":"{ sessions, presence }"}}}},"/v1/stageshare/rooms/{id}/snapshot":{"get":{"tags":["stageshare"],"summary":"Download a zip of this room's LAS files, comments, and room.json","description":"Works on live or frozen (recorded) rooms. Auth: hwx_ with stageshare, or sst_. Content-Disposition attachment. Recordings last 5 days after finalize or Stop sharing (POST …/revoke), then files are deleted (410). DELETE …/rooms/{id} is the hard purge.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearer":[]},{"shareSession":[]}],"responses":{"200":{"description":"application/zip"}}}},"/v1/stageshare/rooms/{id}/logs/{lid}/content":{"get":{"tags":["stageshare"],"summary":"Room LAS 2.0 bytes (Range ok). Isolated from /v1/logs/{id}/content.","description":"The depth-aligned file for one column in this overlay. Auth: hwx_ with stageshare, or sst_ from a guest session. Do not use partner GET /v1/logs for this.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"lid","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearer":[]},{"shareSession":[]}],"responses":{"200":{"description":"LAS 2.0 body"},"410":{"description":"room gone"}}}},"/v1/stageshare/rooms/{id}/logs/{lid}/curves":{"get":{"tags":["stageshare"],"summary":"Downsampled room LAS series for plotting (peak-preserving CCL)","description":"Plot depth downward. Same idea as /v1/logs/{id}/curves but scoped to this Stage Share room.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"lid","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"bearer":[]},{"shareSession":[]}],"responses":{"200":{"description":"Plot series"}}}}},"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","bearerFormat":"hwx","description":"API key issued in the Tailscale admin console. Prefix hwx_."},"shareSession":{"type":"http","scheme":"bearer","bearerFormat":"sst","description":"Short-lived Stage Share session ticket. Prefix sst_. Never put hwx_ in a guest URL."}}},"security":[{"bearer":[]}]}