{
  "openapi": "3.1.0",
  "info": {
    "title": "copy anywhere",
    "version": "1.0.0",
    "summary": "Move text and files between devices with a one-time 6-digit code.",
    "description": "Share text (up to 1 MB) or a file (up to 200 MB) and get a 6-digit code; redeem the code on another device within 2 minutes to get the text or a download link. Each code works once. No accounts. Rate limits per client: 20 shares a minute, 2 uploads at once, 5 wrong codes a minute. Errors are JSON {\"error\": \"...\"}. Use is subject to the Terms of Service shown on the site.",
    "contact": { "name": "Infoneto Ltd", "email": "info@infoneto.com" }
  },
  "servers": [{ "url": "http://copy.cvneto.co.il" }],
  "paths": {
    "/api/text": {
      "post": {
        "operationId": "shareText",
        "summary": "Share text and get a one-time code",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["text"],
                "properties": { "text": { "type": "string", "description": "Up to 1 MB of UTF-8; not empty." } }
              }
            }
          }
        },
        "responses": {
          "200": { "$ref": "#/components/responses/Code" },
          "400": { "$ref": "#/components/responses/Error" },
          "413": { "$ref": "#/components/responses/Error" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "503": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/file": {
      "post": {
        "operationId": "shareFile",
        "summary": "Upload a file and get a one-time code",
        "parameters": [
          {
            "name": "X-Filename",
            "in": "header",
            "required": false,
            "description": "The file's name, URL-encoded (percent-encoded UTF-8).",
            "schema": { "type": "string" }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "The raw file, up to 200 MB. Content-Type must be application/octet-stream.",
          "content": { "application/octet-stream": { "schema": { "type": "string", "format": "binary" } } }
        },
        "responses": {
          "200": { "$ref": "#/components/responses/Code" },
          "400": { "$ref": "#/components/responses/Error" },
          "408": { "$ref": "#/components/responses/Error" },
          "413": { "$ref": "#/components/responses/Error" },
          "415": { "$ref": "#/components/responses/Error" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "503": { "$ref": "#/components/responses/Error" },
          "507": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/redeem": {
      "post": {
        "operationId": "redeemCode",
        "summary": "Redeem a code: get the text, or a download link for the file",
        "description": "A code works once. Wrong or expired codes count toward the 5-a-minute limit.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["code"],
                "properties": { "code": { "type": "string", "pattern": "^[0-9]{6}$" } }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The shared text, or the file's name, size and download link.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "type": "object",
                      "required": ["type", "text"],
                      "properties": { "type": { "const": "text" }, "text": { "type": "string" } }
                    },
                    {
                      "type": "object",
                      "required": ["type", "name", "size", "url"],
                      "properties": {
                        "type": { "const": "file" },
                        "name": { "type": "string" },
                        "size": { "type": "integer", "description": "Bytes." },
                        "url": { "type": "string", "description": "Path of the download, e.g. /api/download/<token>." }
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error" },
          "404": { "$ref": "#/components/responses/Error" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/download/{token}": {
      "get": {
        "operationId": "downloadFile",
        "summary": "Download a redeemed file",
        "description": "Valid until about 10 minutes after the last complete download.",
        "parameters": [{ "name": "token", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }],
        "responses": {
          "200": {
            "description": "The file, with its name in Content-Disposition.",
            "content": { "application/octet-stream": { "schema": { "type": "string", "format": "binary" } } }
          },
          "404": { "$ref": "#/components/responses/Error" }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Code": {
        "type": "object",
        "required": ["code", "expires_in"],
        "properties": {
          "code": { "type": "string", "pattern": "^[0-9]{6}$" },
          "expires_in": { "type": "integer", "description": "Seconds until the code expires (120)." }
        }
      },
      "Error": {
        "type": "object",
        "required": ["error"],
        "properties": { "error": { "type": "string" } }
      }
    },
    "responses": {
      "Code": {
        "description": "The one-time code.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Code" } } }
      },
      "Error": {
        "description": "The request was refused; the reason is in error.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "RateLimited": {
        "description": "A rate limit was hit; Retry-After says how many seconds to wait (absent for the 2-uploads-at-once limit).",
        "headers": { "Retry-After": { "schema": { "type": "integer" } } },
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      }
    }
  }
}
