{
  "openapi": "3.1.0",
  "info": {
    "title": "MyTunnel Share Public API",
    "version": "1.0.0",
    "summary": "Bootstrap HTTP endpoints for peer-to-peer file transfer",
    "description": "Public HTTP API used by browser apps, the Share page, and the Linux/macOS CLI to discover signaling and ICE configuration.\n\n**Important:** File bytes are **not** uploaded over HTTP. After calling `GET /api/v1/share/config.php`, clients connect to the WebSocket (`wsUrl`), join a room, exchange WebRTC offers/answers/ICE, and send file data over a WebRTC DataChannel. See the API tab on `/share.php#api` for the signaling and DataChannel protocol.\n\nOptional short links (`POST /api/v1/share/shorten.php` → `/s/{code}`) store the full destination URL (including optional `#k=` AES key) until room TTL so QR codes and copy/paste stay short.\n\nNo API token is required. The room id is the capability secret.",
    "license": {
      "name": "See project licenses",
      "url": "/licenses.php"
    }
  },
  "servers": [
    {
      "url": "/",
      "description": "Same origin as this Share host"
    }
  ],
  "tags": [
    {
      "name": "Share",
      "description": "Public P2P Share bootstrap"
    }
  ],
  "paths": {
    "/api/v1/share/config.php": {
      "get": {
        "tags": ["Share"],
        "operationId": "getShareConfig",
        "summary": "Get Share client bootstrap config",
        "description": "Returns WebSocket URL, public Share page URL, ICE/TURN servers, chunk size, and room defaults. CORS allows any origin.",
        "responses": {
          "200": {
            "description": "Share is enabled and config is available",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ShareConfig"
                },
                "example": {
                  "ok": true,
                  "enabled": true,
                  "wsUrl": "wss://example.com/ws",
                  "publicUrl": "https://example.com/share.php",
                  "iceServers": [
                    {
                      "urls": "stun:stun.l.google.com:19302"
                    },
                    {
                      "urls": [
                        "turn:203.0.113.10:3478?transport=udp",
                        "turn:203.0.113.10:3478?transport=tcp"
                      ],
                      "username": "1710000000:share",
                      "credential": "base64-hmac"
                    }
                  ],
                  "maxChunkSize": 16384,
                  "roomIdLength": 8,
                  "roomTtlMs": 3600000
                }
              }
            }
          },
          "405": {
            "description": "Method not allowed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Share is disabled on this host",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ShareDisabled"
                }
              }
            }
          }
        }
      },
      "options": {
        "tags": ["Share"],
        "operationId": "optionsShareConfig",
        "summary": "CORS preflight for Share config",
        "responses": {
          "204": {
            "description": "No content; CORS headers allow GET from any origin"
          }
        }
      }
    },
    "/api/v1/share/openapi.php": {
      "get": {
        "tags": ["Share"],
        "operationId": "getShareOpenApi",
        "summary": "Fetch this OpenAPI document (JSON)",
        "description": "Returns the Share OpenAPI 3.1 document with CORS enabled so SDKs can load it from the API base.",
        "responses": {
          "200": {
            "description": "OpenAPI 3.1 JSON document",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          }
        }
      },
      "options": {
        "tags": ["Share"],
        "operationId": "optionsShareOpenApi",
        "summary": "CORS preflight for OpenAPI document",
        "responses": {
          "204": {
            "description": "No content"
          }
        }
      }
    },
    "/download/share-client.php": {
      "get": {
        "tags": ["Share"],
        "operationId": "downloadShareClientZip",
        "summary": "Download portable Linux/macOS Share CLI ZIP",
        "description": "Optional helper package for Node hosts. Installs dependencies on the destination machine and speaks the same WebSocket + WebRTC protocol as the browser. Not required for custom apps that implement the protocol themselves.",
        "responses": {
          "200": {
            "description": "ZIP archive (`tunnel-share-linux.zip`)",
            "content": {
              "application/zip": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "404": {
            "description": "CLI package has not been built on this server"
          }
        }
      },
      "head": {
        "tags": ["Share"],
        "operationId": "headShareClientZip",
        "summary": "Check whether the CLI ZIP is available",
        "responses": {
          "200": {
            "description": "Package exists"
          },
          "404": {
            "description": "Package missing"
          }
        }
      }
    },
    "/openapi/share.openapi.json": {
      "get": {
        "tags": ["Share"],
        "operationId": "getShareOpenApiStatic",
        "summary": "Static OpenAPI document (source of truth)",
        "description": "Static file served from the public web root. Prefer this URL for crawlers and human bookmarks; SDKs may use `/api/v1/share/openapi.php` for CORS.",
        "responses": {
          "200": {
            "description": "OpenAPI 3.1 JSON document",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/share/shorten.php": {
      "post": {
        "tags": ["Share"],
        "operationId": "createShareShortLink",
        "summary": "Create a short Share link",
        "description": "Creates a first-party short URL (`/s/{code}`) for a same-host Share room URL. The full target including optional `#k=` is stored until expiry (room TTL). Rate-limited. CORS allows any origin.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["url"],
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "description": "Full Share URL including fragment when AES key-in-link is used"
                  },
                  "room": {
                    "type": "string",
                    "description": "Optional room id (extracted from url when omitted)"
                  },
                  "ttlMs": {
                    "type": "integer",
                    "description": "Time-to-live in milliseconds (defaults to roomTtlMs)"
                  }
                }
              },
              "example": {
                "url": "https://example.com/share.php?room=Ab3Xk9Qm#k=base64url-key",
                "room": "Ab3Xk9Qm",
                "ttlMs": 3600000
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Short link created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ShortLinkCreated"
                }
              }
            }
          },
          "400": {
            "description": "Invalid URL or host",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "options": {
        "tags": ["Share"],
        "operationId": "optionsShareShorten",
        "summary": "CORS preflight for shorten",
        "responses": {
          "204": {
            "description": "No content"
          }
        }
      }
    },
    "/api/v1/share/shorten-revoke.php": {
      "post": {
        "tags": ["Share"],
        "operationId": "revokeShareShortLinks",
        "summary": "Delete short links for a room",
        "description": "Removes stored short-link rows for a room id (used when the sender revokes the share).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["room"],
                "properties": {
                  "room": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Short links deleted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": { "type": "boolean" },
                    "roomId": { "type": "string" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/s/{code}": {
      "get": {
        "tags": ["Share"],
        "operationId": "resolveShareShortLink",
        "summary": "Resolve a short Share link",
        "description": "Looks up `/s/{code}` and redirects to the stored Share URL. When the target includes `#k=`, an HTML/JS redirect is used so the fragment is preserved.",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9]{6,12}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "HTML redirect page when target includes a fragment"
          },
          "302": {
            "description": "Redirect to Share URL without fragment"
          },
          "404": {
            "description": "Unknown, expired, or revoked code"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ShareConfig": {
        "type": "object",
        "required": [
          "ok",
          "enabled",
          "wsUrl",
          "publicUrl",
          "iceServers",
          "maxChunkSize",
          "roomIdLength",
          "roomTtlMs"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": true
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether P2P Share is enabled on this host"
          },
          "wsUrl": {
            "type": "string",
            "format": "uri",
            "description": "WebSocket signaling URL (typically wss://…/ws). Rooms are created by the first sender join."
          },
          "publicUrl": {
            "type": "string",
            "format": "uri",
            "description": "Public Share page URL used to build receiver links"
          },
          "iceServers": {
            "type": "array",
            "description": "RTCPeerConnection iceServers (STUN and optional TURN with time-limited credentials)",
            "items": {
              "$ref": "#/components/schemas/IceServer"
            }
          },
          "maxChunkSize": {
            "type": "integer",
            "minimum": 4096,
            "maximum": 65536,
            "description": "Recommended max binary chunk size on the DataChannel (bytes)"
          },
          "roomIdLength": {
            "type": "integer",
            "const": 8,
            "description": "Suggested room id length when generating new rooms (valid range is 6–16 alphanumeric)"
          },
          "roomTtlMs": {
            "type": "integer",
            "description": "Room time-to-live in milliseconds"
          }
        }
      },
      "IceServer": {
        "type": "object",
        "required": ["urls"],
        "properties": {
          "urls": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            ]
          },
          "username": {
            "type": "string"
          },
          "credential": {
            "type": "string"
          }
        }
      },
      "ShareDisabled": {
        "type": "object",
        "required": ["ok", "enabled", "error"],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": false
          },
          "enabled": {
            "type": "boolean",
            "const": false
          },
          "error": {
            "type": "string"
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "required": ["ok", "error"],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": false
          },
          "error": {
            "type": "string"
          }
        }
      },
      "ShortLinkCreated": {
        "type": "object",
        "required": ["ok", "code", "shortUrl", "expiresAt", "roomId"],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": true
          },
          "code": {
            "type": "string"
          },
          "shortUrl": {
            "type": "string",
            "format": "uri"
          },
          "expiresAt": {
            "type": "string"
          },
          "roomId": {
            "type": "string"
          }
        }
      }
    }
  },
  "externalDocs": {
    "description": "Human-readable Share API guide (WebSocket + DataChannel)",
    "url": "/share.php#api"
  }
}
