{
  "openapi": "3.1.1",
  "info": {
    "title": "Eto API",
    "version": "1.0.0",
    "summary": "Etsy marketplace data, listing creation, orders, finance and product research behind one REST API and one key.",
    "description": "Every request carries an Eto API key in the `X-Eto-API-Key` header, or an OAuth 2.1 bearer token from the \"log in with Eto\" flow. Both resolve to the same account and are accepted on every operation.\n\nOperations tagged with a category that reads or writes shop data need that Etsy shop connected to your Eto account: call `GET /api/v1/stores` first and use the `shop_id` values it returns.\n\nRate limits are 2 requests per second and 5,000 per day, counted per account. On a 429, wait the number of seconds in `Retry-After`.\n\nFailures use one body shape, `{\"error\": {\"code\", \"status\", \"message\", \"hint\", \"docs\"}}`; branch on `code`, whose full set is the `ErrorCode` enum in this document.\n\nThe same API is available as MCP tools at https://mcp.eto.tools/mcp, one tool per operationId. Human documentation: https://eto.tools/dev/docs/",
    "contact": {
      "name": "Eto support",
      "url": "https://eto.tools/contact/",
      "email": "support@eto.tools"
    },
    "termsOfService": "https://eto.tools/terms-of-service/"
  },
  "externalDocs": {
    "description": "The full reference, including the llms.txt index",
    "url": "https://eto.tools/dev/docs/"
  },
  "servers": [
    {
      "url": "https://eto.tools",
      "description": "Production. The only environment."
    }
  ],
  "security": [
    {
      "EtoApiKey": []
    },
    {
      "EtoBearer": []
    }
  ],
  "tags": [
    {
      "name": "Listing Builder",
      "description": "Create a complete Etsy listing from one JSON payload, and fetch the category schema and store profiles it needs.",
      "externalDocs": {
        "url": "https://eto.tools/dev/docs/listing-builder.md"
      }
    },
    {
      "name": "Search",
      "description": "Search active Etsy listings across the marketplace.",
      "externalDocs": {
        "url": "https://eto.tools/dev/docs/search.md"
      }
    },
    {
      "name": "Listings",
      "description": "Read and edit single listings: detail, images, inventory, reviews.",
      "externalDocs": {
        "url": "https://eto.tools/dev/docs/listings.md"
      }
    },
    {
      "name": "Shops",
      "description": "Public shop lookups: details, sections, reviews, production partners.",
      "externalDocs": {
        "url": "https://eto.tools/dev/docs/shops.md"
      }
    },
    {
      "name": "Store Management",
      "description": "Create and edit listings inside a shop you own.",
      "externalDocs": {
        "url": "https://eto.tools/dev/docs/store-management.md"
      }
    },
    {
      "name": "Finance",
      "description": "Eto’s own revenue, fee, refund and profit figures for a connected store.",
      "externalDocs": {
        "url": "https://eto.tools/dev/docs/finance.md"
      }
    },
    {
      "name": "Images & Media",
      "description": "Listing images, videos and digital files.",
      "externalDocs": {
        "url": "https://eto.tools/dev/docs/images-and-media.md"
      }
    },
    {
      "name": "Listing Properties",
      "description": "Category attributes on a listing.",
      "externalDocs": {
        "url": "https://eto.tools/dev/docs/listing-properties.md"
      }
    },
    {
      "name": "Shipping",
      "description": "Shipping profiles, destinations, upgrades and carriers.",
      "externalDocs": {
        "url": "https://eto.tools/dev/docs/shipping.md"
      }
    },
    {
      "name": "Categories",
      "description": "The Etsy taxonomy and the properties each category allows.",
      "externalDocs": {
        "url": "https://eto.tools/dev/docs/categories.md"
      }
    },
    {
      "name": "User",
      "description": "The authenticated Etsy user and the shops they own.",
      "externalDocs": {
        "url": "https://eto.tools/dev/docs/user.md"
      }
    },
    {
      "name": "Shop Policies",
      "description": "Return policies, shop sections and listing requirements.",
      "externalDocs": {
        "url": "https://eto.tools/dev/docs/shop-policies.md"
      }
    },
    {
      "name": "Orders",
      "description": "Receipts and fulfilment, both Eto’s synced copy and the live Etsy passthrough.",
      "externalDocs": {
        "url": "https://eto.tools/dev/docs/orders.md"
      }
    },
    {
      "name": "Finances",
      "description": "Raw Etsy ledger data: transactions, payments, sales.",
      "externalDocs": {
        "url": "https://eto.tools/dev/docs/finances.md"
      }
    },
    {
      "name": "Analytics",
      "description": "Shop traffic statistics.",
      "externalDocs": {
        "url": "https://eto.tools/dev/docs/analytics.md"
      }
    },
    {
      "name": "Stores",
      "description": "The Etsy stores connected to your Eto account.",
      "externalDocs": {
        "url": "https://eto.tools/dev/docs/stores.md"
      }
    },
    {
      "name": "Research",
      "description": "Product research: demand signals and AI ranking for a keyword.",
      "externalDocs": {
        "url": "https://eto.tools/dev/docs/research.md"
      }
    },
    {
      "name": "AI Studio",
      "description": "Generate listing titles, descriptions and images, and analyse product photos.",
      "externalDocs": {
        "url": "https://eto.tools/dev/docs/ai-studio.md"
      }
    },
    {
      "name": "Webhooks",
      "description": "Inspect and re-send the order events Eto pushes to your server.",
      "externalDocs": {
        "url": "https://eto.tools/dev/docs/webhooks.md"
      }
    }
  ],
  "paths": {
    "/api/v1/categories/{category_id}/listing-schema": {
      "get": {
        "operationId": "listing_schema",
        "summary": "Get category listing schema",
        "description": "Returns the full schema for creating a listing in a specific Etsy category. Includes required fields, category-specific attributes with valid values, variation properties, and constraints. Cache this response — categories change rarely.\n\nAuthentication: API key only. Reads or writes data Eto holds for your own account.\n\nFull documentation: https://eto.tools/dev/docs/listing-builder/listing-schema.md",
        "tags": [
          "Listing Builder"
        ],
        "parameters": [
          {
            "name": "category_id",
            "in": "path",
            "required": true,
            "description": "Etsy taxonomy/category ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": "{\"category_id\": 2078, \"required_fields\": {...}, \"category_attributes\": [...], \"variation_properties\": [...]}"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/listing-builder/listing-schema.md"
        },
        "x-eto-slug": "listing-schema",
        "x-eto-auth": "api_key",
        "x-eto-mcp-tool": "listing_schema",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/categories/2078/listing-schema\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/categories/2078/listing-schema\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/categories/2078/listing-schema\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/listings/create": {
      "post": {
        "operationId": "listing_create",
        "summary": "Create a listing",
        "description": "Create a complete Etsy listing with a single JSON payload. Handles title, description, images (URLs or eto-upload:// tokens from POST /api/v1/uploads), variations, pricing, tags, materials, personalization, and multi-shop publishing. ETO handles all Etsy API complexity: variation property ordering, Cartesian product completion, price_on_property detection, SKU truncation, image ordering, and inventory updates.\n\nstate=\"draft\"   → saves to ETO only. No Etsy API calls. Returns immediately.\nstate=\"publish\" → saves to ETO and creates a draft listing on Etsy. Blocking: the request holds open until Etsy has accepted the listing and all images/videos/files are attached (typically 5–15s per shop). Returns the final results inline.\nstate=\"active\"  → same as publish + activates each listing on Etsy. Costs $0.20 USD per listing per shop.\n\nYou can only publish to Etsy shops connected to your ETO account. Use GET /api/v1/stores to list them.\n\nFor backwards compatibility, the response still includes job_id and poll_url so existing clients that poll GET /api/v1/listings/create/{job_id} continue to work — the job will be in \"completed\" state on the first poll.\n\nValidation errors (400 VALIDATION_FAILED):\n  • images[N].url / digital_files[N].url / videos[N].url — \"Uploaded file is no longer available on the server. Re-upload via POST /api/v1/uploads and use the new url.\"\n    Fires when the eto-upload:// path no longer resolves on disk. Re-upload and retry.\n  • shops[N].shop_section_id — \"Section X not found in shop Y.\"\n    Fires when the section ID does not belong to the shop. Call GET /api/v1/stores/{shop_id}/shop-sections/live to fetch the current sections.\n\nAll preflight validation runs before any ETO row or Etsy draft is created — a 400 means nothing was persisted and retrying with a fixed payload is safe.\n\nAuthentication: API key only. Reads or writes data Eto holds for your own account.\n\nFull documentation: https://eto.tools/dev/docs/listing-builder/listing-create.md",
        "tags": [
          "Listing Builder"
        ],
        "responses": {
          "200": {
            "description": "The listing job result. See the example for the full shape.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": "# state=\"draft\" — 201 Created\n{\n  \"listing_pk\": 1173,\n  \"status\": \"draft\",\n  \"message\": \"Listing saved as draft in ETO. Open it in the ETO dashboard to review and publish.\",\n  \"dashboard_url\": \"/dashboard/single-research/1173/\"\n}\n\n# state=\"publish\" or \"active\" — 200 OK, synchronous\n{\n  \"job_id\": \"lcj_aDzKwnFW5sYHewZaPTduRw\",\n  \"listing_pk\": 1173,\n  \"status\": \"completed\",\n  \"poll_url\": \"/api/v1/listings/create/lcj_aDzKwnFW5sYHewZaPTduRw\",\n  \"dashboard_url\": \"/dashboard/single-research/1173/\",\n  \"shops_count\": 1,\n  \"results\": [\n    {\n      \"shop_id\": \"53081804\",\n      \"status\": \"ok\",\n      \"listing_id\": 4489813117,\n      \"listing_url\": \"https://www.etsy.com/listing/4489813117\",\n      \"currency_code\": \"GBP\",\n      \"price\": 24.99,\n      \"images\": [\n        {\"listing_image_id\": 5523110099001, \"url_fullxfull\": \"https://i.etsystatic.com/...\", \"rank\": 1},\n        {\"listing_image_id\": 5523110099002, \"url_fullxfull\": \"https://i.etsystatic.com/...\", \"rank\": 2}\n      ],\n      \"videos\": []\n    }\n  ]\n}\n\n# For state=\"active\", each succeeded shop also includes:\n#   \"activated\": true, \"activation_cost_usd\": 0.20\n\n# On per-shop failure (other shops may still succeed):\n#   {\"shop_id\": \"...\", \"status\": \"error\", \"error\": \"<reason>\", \"etsy_status\": 400, \"details\": {...}}"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/listing-builder/listing-create.md"
        },
        "x-eto-slug": "listing-create",
        "x-eto-auth": "api_key",
        "x-eto-mcp-tool": "listing_create",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST -H \"X-Eto-API-Key: eto_your_key\" -H \"Content-Type: application/json\" \\\n  \"https://eto.tools/api/v1/listings/create\" \\\n  -d '{\n  \"state\": \"draft\",\n  \"shops\": [{\"shop_id\": 12345678, \"shipping_profile_id\": 111222, \"return_policy_id\": 333444, \"price\": 24.99}],\n  \"listing\": {\n    \"title\": \"Custom Leather Wallet - Personalized Gift for Him\",\n    \"description\": \"Handmade genuine leather wallet with optional monogram...\",\n    \"listing_type\": \"physical\",\n    \"taxonomy_id\": 2078,\n    \"price\": 24.99,\n    \"quantity\": 50,\n    \"who_made\": \"i_did\",\n    \"when_made\": \"2020_2026\",\n    \"tags\": [\"leather wallet\", \"personalized gift\", \"groomsmen gift\"],\n    \"materials\": [\"leather\", \"thread\"],\n    \"sku\": \"WALLET-CUSTOM-001\",\n    \"item_weight\": 4.5,\n    \"item_weight_unit\": \"oz\"\n  },\n  \"images\": [\n    {\"url\": \"https://example.com/wallet-front.jpg\", \"rank\": 1},\n    {\"url\": \"https://example.com/wallet-back.jpg\", \"rank\": 2}\n  ],\n  \"variations\": {\n    \"properties\": [\n      {\"property_id\": 200, \"name\": \"Color\", \"values\": [\"Black\", \"Brown\", \"Tan\"]}\n    ],\n    \"offerings\": [\n      {\"color\": \"Black\", \"price\": 24.99, \"quantity\": 50, \"sku\": \"W-BLK\"},\n      {\"color\": \"Brown\", \"price\": 24.99, \"quantity\": 50, \"sku\": \"W-BRN\"},\n      {\"color\": \"Tan\", \"price\": 27.99, \"quantity\": 30, \"sku\": \"W-TAN\"}\n    ],\n    \"variation_images\": {\"property\": \"color\", \"mapping\": {\"Black\": 0, \"Brown\": 1}}\n  }\n}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/listings/create\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\npayload = {\n    \"state\": \"draft\",\n    \"shops\": [\n        {\n            \"shop_id\": 12345678,\n            \"shipping_profile_id\": 111222,\n            \"return_policy_id\": 333444,\n            \"price\": 24.99\n        }\n    ],\n    \"listing\": {\n        \"title\": \"Custom Leather Wallet - Personalized Gift for Him\",\n        \"description\": \"Handmade genuine leather wallet with optional monogram...\",\n        \"listing_type\": \"physical\",\n        \"taxonomy_id\": 2078,\n        \"price\": 24.99,\n        \"quantity\": 50,\n        \"who_made\": \"i_did\",\n        \"when_made\": \"2020_2026\",\n        \"tags\": [\n            \"leather wallet\",\n            \"personalized gift\",\n            \"groomsmen gift\"\n        ],\n        \"materials\": [\n            \"leather\",\n            \"thread\"\n        ],\n        \"sku\": \"WALLET-CUSTOM-001\",\n        \"item_weight\": 4.5,\n        \"item_weight_unit\": \"oz\"\n    },\n    \"images\": [\n        {\n            \"url\": \"https://example.com/wallet-front.jpg\",\n            \"rank\": 1\n        },\n        {\n            \"url\": \"https://example.com/wallet-back.jpg\",\n            \"rank\": 2\n        }\n    ],\n    \"variations\": {\n        \"properties\": [\n            {\n                \"property_id\": 200,\n                \"name\": \"Color\",\n                \"values\": [\n                    \"Black\",\n                    \"Brown\",\n                    \"Tan\"\n                ]\n            }\n        ],\n        \"offerings\": [\n            {\n                \"color\": \"Black\",\n                \"price\": 24.99,\n                \"quantity\": 50,\n                \"sku\": \"W-BLK\"\n            },\n            {\n                \"color\": \"Brown\",\n                \"price\": 24.99,\n                \"quantity\": 50,\n                \"sku\": \"W-BRN\"\n            },\n            {\n                \"color\": \"Tan\",\n                \"price\": 27.99,\n                \"quantity\": 30,\n                \"sku\": \"W-TAN\"\n            }\n        ],\n        \"variation_images\": {\n            \"property\": \"color\",\n            \"mapping\": {\n                \"Black\": 0,\n                \"Brown\": 1\n            }\n        }\n    }\n}\n\nresponse = requests.post(url, headers=headers, json=payload, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/listings/create\";\nconst payload = {\n  \"state\": \"draft\",\n  \"shops\": [\n    {\n      \"shop_id\": 12345678,\n      \"shipping_profile_id\": 111222,\n      \"return_policy_id\": 333444,\n      \"price\": 24.99\n    }\n  ],\n  \"listing\": {\n    \"title\": \"Custom Leather Wallet - Personalized Gift for Him\",\n    \"description\": \"Handmade genuine leather wallet with optional monogram...\",\n    \"listing_type\": \"physical\",\n    \"taxonomy_id\": 2078,\n    \"price\": 24.99,\n    \"quantity\": 50,\n    \"who_made\": \"i_did\",\n    \"when_made\": \"2020_2026\",\n    \"tags\": [\n      \"leather wallet\",\n      \"personalized gift\",\n      \"groomsmen gift\"\n    ],\n    \"materials\": [\n      \"leather\",\n      \"thread\"\n    ],\n    \"sku\": \"WALLET-CUSTOM-001\",\n    \"item_weight\": 4.5,\n    \"item_weight_unit\": \"oz\"\n  },\n  \"images\": [\n    {\n      \"url\": \"https://example.com/wallet-front.jpg\",\n      \"rank\": 1\n    },\n    {\n      \"url\": \"https://example.com/wallet-back.jpg\",\n      \"rank\": 2\n    }\n  ],\n  \"variations\": {\n    \"properties\": [\n      {\n        \"property_id\": 200,\n        \"name\": \"Color\",\n        \"values\": [\n          \"Black\",\n          \"Brown\",\n          \"Tan\"\n        ]\n      }\n    ],\n    \"offerings\": [\n      {\n        \"color\": \"Black\",\n        \"price\": 24.99,\n        \"quantity\": 50,\n        \"sku\": \"W-BLK\"\n      },\n      {\n        \"color\": \"Brown\",\n        \"price\": 24.99,\n        \"quantity\": 50,\n        \"sku\": \"W-BRN\"\n      },\n      {\n        \"color\": \"Tan\",\n        \"price\": 27.99,\n        \"quantity\": 30,\n        \"sku\": \"W-TAN\"\n      }\n    ],\n    \"variation_images\": {\n      \"property\": \"color\",\n      \"mapping\": {\n        \"Black\": 0,\n        \"Brown\": 1\n      }\n    }\n  }\n};\n\nconst response = await fetch(url, {\n  method: \"POST\",\n  body: JSON.stringify(payload),\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n    \"Content-Type\": \"application/json\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Fields are given in dotted path form, which describes the nested JSON body. The example below is the authoritative shape.\n\n- `state` (string): \"draft\" saves to ETO only (instant, zero Etsy calls). \"publish\" saves to ETO and creates a draft listing on Etsy (blocking, 5–15s per shop). \"active\" same as publish + activates on Etsy (blocking, costs $0.20 USD per listing per shop).\n- `shops[].shop_id` (integer, required): The unique positive non-zero numeric ID for an Etsy Shop. Must be connected to your ETO account. Use GET /api/v1/stores to list connected shops. Constraints: >= 1.\n- `shops[].price` (number): Per-shop price override in the shop's native currency. If omitted, uses listing.price. Constraints: >= 0.20.\n- `shops[].shipping_profile_id` (integer): The numeric ID of the shipping profile associated with the listing. Required when listing_type is physical. Get the latest IDs from GET /api/v1/stores/{shop_id}/shipping-profiles/live. Constraints: >= 1.\n- `shops[].return_policy_id` (integer): The numeric ID of the return policy. Required for physical listings. Get the latest IDs from GET /api/v1/stores/{shop_id}/return-policies/live. Constraints: >= 1.\n- `shops[].processing_profile_id` (integer): The numeric ID of the processing/readiness state profile. Controls processing time display on the listing. Get the latest IDs from GET /api/v1/stores/{shop_id}/processing-profiles/live. Constraints: >= 1.\n- `shops[].shop_section_id` (integer): The numeric ID of the shop section to organize the listing under. Get the latest IDs from GET /api/v1/stores/{shop_id}/shop-sections/live. Constraints: >= 1.\n- `shops[].production_partner_ids` (array): An array of unique IDs of production partners for this listing. Get IDs from POST /api/v1/stores/{shop_id}/sync.\n- `listing.title` (string, required): The listing's title string. Valid title strings contain only letters, numbers, punctuation marks, mathematical symbols, whitespace characters, ™, ©, and ®. You can only use the %, :, & and + characters once each. Constraints: max 140 chars.\n- `listing.description` (string, required): A description string of the product for sale in the listing. Newlines are rendered by Etsy. HTML tags are stripped.\n- `listing.listing_type` (string, required): An enumerated type string that indicates whether the listing is a physical product or a digital download.\n- `listing.taxonomy_id` (integer, required): The numerical taxonomy ID of the listing. Use GET /api/v1/categories/{id}/listing-schema to find valid IDs and discover required category attributes and variation properties. Constraints: >= 1.\n- `listing.price` (number): The positive non-zero price of the product. Required unless variations define per-variant prices. Note: The price is the minimum possible price. Variation offerings can set different prices per combination. Constraints: >= 0.20.\n- `listing.quantity` (integer): The positive non-zero number of products available for purchase. Required unless variations define per-variant quantities. Note: For variation listings, this is overridden by per-offering quantities. Constraints: 1-999.\n- `listing.who_made` (string): An enumerated string indicating who made the product. Helps buyers locate the listing under the Handmade heading. Requires 'is_supply' and 'when_made'.\n- `listing.when_made` (string): An enumerated string for the era in which the maker made the product in this listing. Helps buyers locate the listing under the Vintage heading. Requires 'is_supply' and 'who_made'.\n- `listing.tags` (array): A list of tag strings for the listing. Valid tag strings contain only letters, numbers, whitespace characters, -, ', ™, ©, and ®. Default value is null. Constraints: max 13 items, each max 20 chars.\n- `listing.materials` (array): A list of material strings for materials used in the product. Valid materials strings contain only letters, numbers, and whitespace characters. Default value is null. Constraints: max 13 items.\n- `listing.styles` (array): An array of style strings for this listing, each of which is free-form text string such as \"Formal\", or \"Steampunk\". Valid style strings contain only letters, numbers, and whitespace characters. Default value is null. Constraints: max 2 items.\n- `listing.sku` (string): Optional internal identifier. First 32 characters are sent to Etsy (Etsy's limit). The full SKU (up to 512 chars) is stored in ETO for order fulfillment and can be retrieved via the ETO API. Constraints: max 512 chars (32 to Etsy).\n- `listing.is_supply` (boolean): When true, tags the listing as a supply product, else indicates that it's a finished product. Helps buyers locate the listing under the Supplies heading. Requires 'who_made' and 'when_made'.\n- `listing.is_customizable` (boolean): When true, a buyer may contact the seller for a customized order. The default value is true when a shop accepts custom orders. Does not apply to shops that do not accept custom orders.\n- `listing.is_taxable` (boolean): When true, applicable shop tax rates apply to this listing at checkout.\n- `listing.should_auto_renew` (boolean): When true, renews a listing for four months upon expiration.\n- `listing.item_weight` (number): The numeric weight of the product measured in units set in 'item_weight_unit'. Default value is null. If set, the value must be greater than 0. Constraints: > 0.\n- `listing.item_weight_unit` (string): A string defining the units used to measure the weight of the product. Default value is null.\n- `listing.item_length` (number): The numeric length of the product measured in units set in 'item_dimensions_unit'. Default value is null. If set, the value must be greater than 0. Constraints: > 0.\n- `listing.item_width` (number): The numeric width of the product measured in units set in 'item_dimensions_unit'. Default value is null. If set, the value must be greater than 0. Constraints: > 0.\n- `listing.item_height` (number): The numeric height of the product measured in units set in 'item_dimensions_unit'. Default value is null. If set, the value must be greater than 0. Constraints: > 0.\n- `listing.item_dimensions_unit` (string): A string defining the units used to measure the dimensions of the product. Default value is null.\n- `listing.processing_min` (integer): The minimum number of days required to process this listing. Default value is null.\n- `listing.processing_max` (integer): The maximum number of days required to process this listing. Default value is null.\n- `images[].url` (string, required): A publicly accessible URL to the image file. ETO downloads the image server-side and uploads it to Etsy. Supported formats: JPG, PNG, GIF. Max 100MB per image. Constraints: min 1, max 10 images.\n- `images[].rank` (integer): Position in the listing image gallery. Rank 1 is the primary/leftmost photo shown to buyers. If omitted, images are ordered by their position in the array. Constraints: 1-10.\n- `digital_files[].url` (string): A publicly accessible URL to the digital file. Required for listing_type=digital. ETO downloads the file server-side and uploads it to Etsy. Max 100MB per file. Supported types: .bmp, .doc, .gif, .jpeg, .jpg, .mobi, .mov, .mp3, .mpeg, .pdf, .png, .psp, .rtf, .stl, .txt, .zip, .ePUB, .iBook. Constraints: min 1, max 5 files (for digital listings).\n- `digital_files[].name` (string): The display name for the digital file shown to buyers after purchase. Letters, numbers, periods, hyphens, and underscores only. No spaces or parentheses. Constraints: 3-70 chars.\n- `videos[].url` (string): A publicly accessible URL to the video file. ETO downloads the video server-side and uploads it to Etsy. MP4 or MOV format, max 15 seconds, no audio. Max 100MB. Constraints: max 1 video per listing.\n- `personalization.enabled` (boolean): When true, enables personalization for this listing. ETO uses the modern Etsy personalization API to set this up after listing creation.\n- `personalization.is_required` (boolean): When true, the buyer must enter personalization text before purchasing. Only applies when personalization.enabled is true.\n- `personalization.instructions` (string): Instructions shown to the buyer at checkout describing what personalization to enter (e.g. 'Enter up to 10 characters for monogram'). Only applies when personalization.enabled is true. Constraints: max 256 chars.\n- `personalization.max_chars` (integer): The maximum character count for the buyer's personalization message. Only applies when personalization.enabled is true. Constraints: 1-1024.\n- `category_attributes` (object): Category-specific listing attributes. Keys are property_id strings. Values are objects with value_ids, values, and optional scale_id. Use GET /api/v1/categories/{id}/listing-schema to discover which attributes exist, which are required, and their valid values for a given category.\n- `category_attributes.{property_id}.value_ids` (array): The Etsy value IDs for the selected attribute values. Get valid IDs from the listing-schema endpoint possible_values array.\n- `category_attributes.{property_id}.values` (array): Human-readable attribute value strings corresponding to each value_id.\n- `category_attributes.{property_id}.scale_id` (integer): Scale ID for properties that use scales (e.g. alpha sizing). Get valid scale IDs from the listing-schema endpoint scales array.\n- `variations.properties` (array): Array of variation property definitions. Etsy allows at most 2 variation properties per listing. Use GET /api/v1/categories/{id}/listing-schema variation_properties to discover available properties for the chosen category. Constraints: max 2 items.\n- `variations.properties[].property_id` (integer, required): The Etsy property ID from the listing-schema variation_properties (e.g. 200 for Primary color, 100 for Size, 513 for Style).\n- `variations.properties[].name` (string, required): Human-readable property name (e.g. 'Color', 'Size'). This name (lowercased) is used as the key in each offering to specify the value.\n- `variations.properties[].scale_id` (integer): Scale ID for sized properties (e.g. Alpha sizing: XS, S, M, L, XL). Get valid scale IDs from the listing-schema endpoint.\n- `variations.properties[].values` (array, required): All possible values for this property (e.g. ['Black', 'Brown', 'Tan'] for Color). Parentheses characters () are not allowed in values.\n- `variations.offerings` (array): Array of offerings, one per variation combination. Each offering uses the lowercased property name as a key to specify which value it represents. ETO auto-detects which properties affect price/quantity and builds the Etsy inventory payload accordingly.\n- `variations.offerings[].{property_name}` (string, required): The value for this property in this offering. The key is the lowercased property name (e.g. 'color': 'Black', 'size': 'S'). Must match one of the values listed in variations.properties[].values.\n- `variations.offerings[].price` (number): Price for this specific variation combination. If all offerings have the same price, ETO automatically tells Etsy that price does not vary by property. If prices differ, ETO detects which property causes the difference. Constraints: >= 0.20.\n- `variations.offerings[].quantity` (integer): Stock quantity for this specific variation combination. Set to 0 along with enabled=false to create the combination but hide it from the listing. Constraints: 0-999.\n- `variations.offerings[].sku` (string): Per-variant SKU identifier. First 32 characters are sent to Etsy, full SKU (up to 512 chars) is stored in ETO. Must be unique across all offerings if provided. Constraints: max 512 chars (32 to Etsy).\n- `variations.offerings[].enabled` (boolean): When false, the offering is created but hidden from the listing. Etsy receives is_enabled=false and quantity=0. Useful for pre-creating combinations that are temporarily out of stock.\n- `variations.offerings[].processing_profile_id` (integer): Per-variant processing/readiness profile ID. If different values are set across offerings, ETO automatically sets readiness_state_on_property. If omitted, the shop-level processing_profile_id applies. Constraints: >= 1.\n- `variations.variation_images.property` (string): The name of the variation property whose values should be linked to specific listing images (e.g. 'color'). Only one property can have variation images per listing (Etsy constraint). Case-insensitive match against variations.properties[].name.\n- `variations.variation_images.mapping` (object): Maps property values to image indices. Keys are value names (e.g. 'Black'), values are 0-based indices into the images[] array. Example: {\"Black\": 0, \"Brown\": 1, \"Tan\": 2}. If a value references an out-of-bounds index, validation returns an error.",
                "additionalProperties": true
              },
              "examples": {
                "default": {
                  "summary": "A complete request body",
                  "value": {
                    "state": "draft",
                    "shops": [
                      {
                        "shop_id": 12345678,
                        "shipping_profile_id": 111222,
                        "return_policy_id": 333444,
                        "price": 24.99
                      }
                    ],
                    "listing": {
                      "title": "Custom Leather Wallet - Personalized Gift for Him",
                      "description": "Handmade genuine leather wallet with optional monogram...",
                      "listing_type": "physical",
                      "taxonomy_id": 2078,
                      "price": 24.99,
                      "quantity": 50,
                      "who_made": "i_did",
                      "when_made": "2020_2026",
                      "tags": [
                        "leather wallet",
                        "personalized gift",
                        "groomsmen gift"
                      ],
                      "materials": [
                        "leather",
                        "thread"
                      ],
                      "sku": "WALLET-CUSTOM-001",
                      "item_weight": 4.5,
                      "item_weight_unit": "oz"
                    },
                    "images": [
                      {
                        "url": "https://example.com/wallet-front.jpg",
                        "rank": 1
                      },
                      {
                        "url": "https://example.com/wallet-back.jpg",
                        "rank": 2
                      }
                    ],
                    "variations": {
                      "properties": [
                        {
                          "property_id": 200,
                          "name": "Color",
                          "values": [
                            "Black",
                            "Brown",
                            "Tan"
                          ]
                        }
                      ],
                      "offerings": [
                        {
                          "color": "Black",
                          "price": 24.99,
                          "quantity": 50,
                          "sku": "W-BLK"
                        },
                        {
                          "color": "Brown",
                          "price": 24.99,
                          "quantity": 50,
                          "sku": "W-BRN"
                        },
                        {
                          "color": "Tan",
                          "price": 27.99,
                          "quantity": 30,
                          "sku": "W-TAN"
                        }
                      ],
                      "variation_images": {
                        "property": "color",
                        "mapping": {
                          "Black": 0,
                          "Brown": 1
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/listings/create/{job_id}": {
      "get": {
        "operationId": "listing_create_status",
        "summary": "Poll listing creation job status",
        "description": "Returns the status and results of a listing-create job. Since publish/active now execute synchronously on the web, jobs are normally in \"completed\" state by the time any poll lands. This endpoint remains available for backwards compatibility and for clients that prefer the job-polling pattern. Returns per-shop results when the job completes, including listing IDs, Etsy URLs, and any per-shop warnings.\n\nAuthentication: API key only. Reads or writes data Eto holds for your own account.\n\nFull documentation: https://eto.tools/dev/docs/listing-builder/listing-create-status.md",
        "tags": [
          "Listing Builder"
        ],
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "description": "The job_id returned by POST /api/v1/listings/create",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": "{\n  \"job_id\": \"lcj_aDzKwnFW5sYHewZaPTduRw\",\n  \"status\": \"completed\",\n  \"created_at\": \"2026-04-16T21:07:20.963219+00:00\",\n  \"completed_at\": \"2026-04-16T21:07:28.245564+00:00\",\n  \"results\": [\n    {\n      \"shop_id\": \"53081804\",\n      \"status\": \"ok\",\n      \"listing_id\": 4489813117,\n      \"listing_url\": \"https://www.etsy.com/listing/4489813117\",\n      \"currency_code\": \"GBP\",\n      \"price\": 24.99,\n      \"images\": [\n        {\"listing_image_id\": 5523110099001, \"url_fullxfull\": \"https://i.etsystatic.com/...\", \"rank\": 1}\n      ],\n      \"videos\": [],\n      \"warnings\": [\n        {\"code\": \"recovery_update_failed\", \"fields\": [\"shop_section_id\"], \"reason\": \"Etsy rejected the section update\"}\n      ]\n    }\n  ]\n}\n\n# Terminal statuses: \"completed\" | \"failed\"\n# On job-level failure: response also includes \"error_message\": \"<reason>\""
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/listing-builder/listing-create-status.md"
        },
        "x-eto-slug": "listing-create-status",
        "x-eto-auth": "api_key",
        "x-eto-mcp-tool": "listing_create_status",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/listings/create/lcj_abc123def456\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/listings/create/lcj_abc123def456\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/listings/create/lcj_abc123def456\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/stores/{shop_id}/details": {
      "get": {
        "operationId": "store_details_cached",
        "summary": "Get cached store details (zero Etsy calls)",
        "description": "Returns all cached data for a connected store: shop details, shipping profiles, shop sections. No Etsy API calls are made. Return policies, processing profiles, and production partners return null (not cached locally). Use POST /sync to fetch those.\n\nAuthentication: API key only. Reads or writes data Eto holds for your own account.\n\nFull documentation: https://eto.tools/dev/docs/listing-builder/store-details-cached.md",
        "tags": [
          "Listing Builder"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your connected Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "shop_id": "12345678",
                      "shop_name": "MyShop",
                      "currency_code": "USD",
                      "shipping_from_country_iso": "US",
                      "listing_active_count": 142,
                      "review_average": 4.8,
                      "review_count": 523,
                      "is_vacation": false,
                      "url": "https://www.etsy.com/shop/MyShop",
                      "last_synced_at": "2026-04-10T14:30:00Z",
                      "shipping_profiles": [
                        {
                          "shipping_profile_id": 111222,
                          "title": "Standard Shipping",
                          "min_processing_days": 1,
                          "max_processing_days": 3,
                          "primary_cost": "5.99",
                          "currency_code": "USD"
                        }
                      ],
                      "shop_sections": [
                        {
                          "shop_section_id": 44556,
                          "title": "New Arrivals",
                          "rank": 1,
                          "active_listing_count": 15
                        }
                      ],
                      "return_policies": null,
                      "processing_profiles": null,
                      "production_partners": null
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/listing-builder/store-details-cached.md"
        },
        "x-eto-slug": "store-details-cached",
        "x-eto-auth": "api_key",
        "x-eto-mcp-tool": "store_details_cached",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/stores/12345678/details\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/stores/12345678/details\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/stores/12345678/details\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/stores/{shop_id}/sync": {
      "post": {
        "operationId": "store_sync",
        "summary": "Sync store data from Etsy",
        "description": "Triggers a fresh pull from Etsy API for all store data (details, shipping profiles, sections, return policies, processing profiles, production partners). Caches what can be cached and returns the complete updated dataset. Costs ~5 Etsy API calls.\n\nAuthentication: API key only. Reads or writes data Eto holds for your own account.\n\nFull documentation: https://eto.tools/dev/docs/listing-builder/store-sync.md",
        "tags": [
          "Listing Builder"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your connected Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "shop_id": "12345678",
                      "shop_name": "MyShop",
                      "currency_code": "USD",
                      "last_synced_at": "2026-04-12T16:45:00Z",
                      "shipping_profiles": [
                        {
                          "shipping_profile_id": 111222,
                          "title": "Standard Shipping",
                          "min_processing_days": 1,
                          "max_processing_days": 3,
                          "primary_cost": "5.99",
                          "currency_code": "USD"
                        }
                      ],
                      "shop_sections": [
                        {
                          "shop_section_id": 44556,
                          "title": "New Arrivals",
                          "rank": 1,
                          "active_listing_count": 15
                        }
                      ],
                      "return_policies": [
                        {
                          "return_policy_id": 333444,
                          "accepts_returns": true,
                          "accepts_exchanges": true,
                          "return_deadline": 30
                        }
                      ],
                      "processing_profiles": [
                        {
                          "readiness_state_id": 555666,
                          "readiness_state": "ready_to_ship",
                          "min_processing_days": 1,
                          "max_processing_days": 3,
                          "processing_days_display_label": "1-3 business days"
                        }
                      ],
                      "production_partners": [
                        {
                          "production_partner_id": 999,
                          "partner_name": "PrintCo",
                          "location": "USA"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/listing-builder/store-sync.md"
        },
        "x-eto-slug": "store-sync",
        "x-eto-auth": "api_key",
        "x-eto-mcp-tool": "store_sync",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/stores/12345678/sync\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/stores/12345678/sync\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.post(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/stores/12345678/sync\";\n\nconst response = await fetch(url, {\n  method: \"POST\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/uploads": {
      "post": {
        "operationId": "file_upload",
        "summary": "Upload a file (image, video, or digital file)",
        "description": "Upload a local file to ETO for use in listing creation. Returns an eto-upload:// URL that you can use in images[].url, digital_files[].url, or videos[].url when calling POST /api/v1/listings/create. This is the way to use local files instead of remote URLs.\n\nSend as multipart/form-data with a \"file\" field and optional \"type\" field.\n\nAuthentication: API key only. Reads or writes data Eto holds for your own account.\n\nFull documentation: https://eto.tools/dev/docs/listing-builder/file-upload.md",
        "tags": [
          "Listing Builder"
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "url": "eto-upload:///path/to/uploaded/file.jpg",
                      "filename": "my_product_photo.jpg",
                      "size": 102400,
                      "content_type": "image/jpeg",
                      "type": "image",
                      "note": "Use this url value in images[].url when calling POST /api/v1/listings/create."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/listing-builder/file-upload.md"
        },
        "x-eto-slug": "file-upload",
        "x-eto-auth": "api_key",
        "x-eto-mcp-tool": "file_upload",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST -H \"X-Eto-API-Key: eto_your_key\" \\\n  -F \"file=@my_product_photo.jpg\" \\\n  -F \"type=image\" \\\n  \"https://eto.tools/api/v1/uploads\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/uploads\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\nfiles = {\"file\": open(\"my_product_photo.jpg\", \"rb\")}\ndata = {\"type\": \"image\"}\n\nresponse = requests.post(url, headers=headers, files=files, data=data, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/uploads\";\nconst form = new FormData();\nform.append(\"file\", fileInput.files[0]);\nform.append(\"type\", \"image\");\n\nconst response = await fetch(url, {\n  method: \"POST\",\n  body: form,\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "file": {
                    "type": "string",
                    "contentEncoding": "binary",
                    "description": "max 100MB"
                  },
                  "type": {
                    "type": "string",
                    "enum": [
                      "image",
                      "video",
                      "digital"
                    ],
                    "default": "image"
                  }
                },
                "required": [
                  "file"
                ]
              }
            }
          }
        }
      }
    },
    "/api/v1/listings/search": {
      "get": {
        "operationId": "listings_search",
        "summary": "Search active Etsy listings",
        "description": "Search for active listings on Etsy by keyword. Returns paginated results with listing details.\n\nAuthentication: API key only. Reads public marketplace data, so no store needs to be connected.\n\nProxied to the Etsy API at `/v3/application/listings/active`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/search/listings-search.md",
        "tags": [
          "Search"
        ],
        "parameters": [
          {
            "name": "keywords",
            "in": "query",
            "required": true,
            "description": "Search keywords",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Number of results (max 100)",
            "schema": {
              "type": "integer",
              "default": 25
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Pagination offset",
            "schema": {
              "type": "integer",
              "default": 0
            }
          },
          {
            "name": "sort_on",
            "in": "query",
            "required": false,
            "description": "Sort field: created, price, score",
            "schema": {
              "type": "string",
              "default": "created"
            }
          },
          {
            "name": "sort_order",
            "in": "query",
            "required": false,
            "description": "Sort order: asc, desc",
            "schema": {
              "type": "string",
              "default": "desc"
            }
          },
          {
            "name": "min_price",
            "in": "query",
            "required": false,
            "description": "Minimum price filter",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "max_price",
            "in": "query",
            "required": false,
            "description": "Maximum price filter",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "category_id",
            "in": "query",
            "required": false,
            "description": "Filter by product category ID (get IDs from /categories)",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": "{\"count\": 1000, \"results\": [{\"listing_id\": 123, \"title\": \"...\", \"price\": {\"amount\": 2999, \"divisor\": 100, \"currency_code\": \"USD\"}, ...}]}"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/search/listings-search.md"
        },
        "x-eto-slug": "listings-search",
        "x-eto-auth": "public",
        "x-eto-mcp-tool": "listings_search",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/listings/search?keywords=leather+wallet&limit=10\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/listings/search?keywords=leather+wallet&limit=10\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/listings/search?keywords=leather+wallet&limit=10\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/listings/{listing_id}": {
      "get": {
        "operationId": "listing_detail",
        "summary": "Get listing details",
        "description": "Retrieve detailed information about a specific listing including title, description, price, tags, materials, and more.\n\nAuthentication: API key only. Reads public marketplace data, so no store needs to be connected.\n\nProxied to the Etsy API at `/v3/application/listings/{listing_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/listings/listing-detail.md",
        "tags": [
          "Listings"
        ],
        "parameters": [
          {
            "name": "listing_id",
            "in": "path",
            "required": true,
            "description": "The Etsy listing ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "includes",
            "in": "query",
            "required": false,
            "description": "Comma-separated associations to include: Images, Shop, User, Translations, Inventory, Videos",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/listings/listing-detail.md"
        },
        "x-eto-slug": "listing-detail",
        "x-eto-auth": "public",
        "x-eto-mcp-tool": "listing_detail",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/listings/1234567890?includes=Images,Shop\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/listings/1234567890?includes=Images,Shop\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/listings/1234567890?includes=Images,Shop\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      },
      "delete": {
        "operationId": "listing_delete",
        "summary": "Delete a listing",
        "description": "Permanently delete a listing you own. This action cannot be undone.\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/listings/{listing_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/listings/listing-delete.md",
        "tags": [
          "Listings"
        ],
        "parameters": [
          {
            "name": "listing_id",
            "in": "path",
            "required": true,
            "description": "The Etsy listing ID to delete",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/listings/listing-delete.md"
        },
        "x-eto-slug": "listing-delete",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "listing_delete",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/listings/1234567890\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/listings/1234567890\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.delete(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/listings/1234567890\";\n\nconst response = await fetch(url, {\n  method: \"DELETE\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/listings/{listing_id}/images": {
      "get": {
        "operationId": "listing_images",
        "summary": "Get listing images",
        "description": "Retrieve all images for a specific listing.\n\nAuthentication: API key only. Reads public marketplace data, so no store needs to be connected.\n\nProxied to the Etsy API at `/v3/application/listings/{listing_id}/images`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/listings/listing-images.md",
        "tags": [
          "Listings"
        ],
        "parameters": [
          {
            "name": "listing_id",
            "in": "path",
            "required": true,
            "description": "The Etsy listing ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/listings/listing-images.md"
        },
        "x-eto-slug": "listing-images",
        "x-eto-auth": "public",
        "x-eto-mcp-tool": "listing_images",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/listings/1234567890/images\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/listings/1234567890/images\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/listings/1234567890/images\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/listings/{listing_id}/reviews": {
      "get": {
        "operationId": "listing_reviews",
        "summary": "Get listing reviews",
        "description": "Retrieve reviews for a specific listing.\n\nAuthentication: API key only. Reads public marketplace data, so no store needs to be connected.\n\nProxied to the Etsy API at `/v3/application/listings/{listing_id}/reviews`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/listings/listing-reviews.md",
        "tags": [
          "Listings"
        ],
        "parameters": [
          {
            "name": "listing_id",
            "in": "path",
            "required": true,
            "description": "The Etsy listing ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Number of reviews (max 100)",
            "schema": {
              "type": "integer",
              "default": 25
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Pagination offset",
            "schema": {
              "type": "integer",
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/listings/listing-reviews.md"
        },
        "x-eto-slug": "listing-reviews",
        "x-eto-auth": "public",
        "x-eto-mcp-tool": "listing_reviews",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/listings/1234567890/reviews?limit=5\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/listings/1234567890/reviews?limit=5\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/listings/1234567890/reviews?limit=5\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/listings/{listing_id}/inventory": {
      "get": {
        "operationId": "listing_inventory_get",
        "summary": "Get listing inventory",
        "description": "Retrieve inventory data (stock levels, variations, pricing) for a listing.\n\nAuthentication: API key only. Reads public marketplace data, so no store needs to be connected.\n\nProxied to the Etsy API at `/v3/application/listings/{listing_id}/inventory`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/listings/listing-inventory-get.md",
        "tags": [
          "Listings"
        ],
        "parameters": [
          {
            "name": "listing_id",
            "in": "path",
            "required": true,
            "description": "The Etsy listing ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/listings/listing-inventory-get.md"
        },
        "x-eto-slug": "listing-inventory-get",
        "x-eto-auth": "public",
        "x-eto-mcp-tool": "listing_inventory_get",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/listings/1234567890/inventory\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/listings/1234567890/inventory\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/listings/1234567890/inventory\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      },
      "put": {
        "operationId": "listing_inventory_update",
        "summary": "Update listing inventory",
        "description": "Update inventory, pricing, and variations for a listing you own.\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/listings/{listing_id}/inventory`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/listings/listing-inventory-update.md",
        "tags": [
          "Listings"
        ],
        "parameters": [
          {
            "name": "listing_id",
            "in": "path",
            "required": true,
            "description": "The Etsy listing ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/listings/listing-inventory-update.md"
        },
        "x-eto-slug": "listing-inventory-update",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "listing_inventory_update",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X PUT -H \"X-Eto-API-Key: eto_your_key\" -H \"Content-Type: application/json\" -d '{\"products\": [...]}' \"https://eto.tools/api/v1/listings/1234567890/inventory\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/listings/1234567890/inventory\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\npayload = \"{\\\"products\\\": [...]}\"\n\nresponse = requests.put(url, headers=headers, data=payload, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/listings/1234567890/inventory\";\nconst payload = \"{\\\"products\\\": [...]}\";\n\nconst response = await fetch(url, {\n  method: \"PUT\",\n  body: payload,\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n    \"Content-Type\": \"application/json\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/listings/{listing_id}/videos": {
      "get": {
        "operationId": "listing_videos",
        "summary": "Get listing videos",
        "description": "Retrieve all videos for a specific listing.\n\nAuthentication: API key only. Reads public marketplace data, so no store needs to be connected.\n\nProxied to the Etsy API at `/v3/application/listings/{listing_id}/videos`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/listings/listing-videos.md",
        "tags": [
          "Listings"
        ],
        "parameters": [
          {
            "name": "listing_id",
            "in": "path",
            "required": true,
            "description": "The Etsy listing ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/listings/listing-videos.md"
        },
        "x-eto-slug": "listing-videos",
        "x-eto-auth": "public",
        "x-eto-mcp-tool": "listing_videos",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/listings/1234567890/videos\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/listings/1234567890/videos\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/listings/1234567890/videos\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/listings/{listing_id}/personalization": {
      "get": {
        "operationId": "listing_personalization_get",
        "summary": "Manage listing personalization",
        "description": "Get, create, or delete personalization questions for a listing.\nGET returns {personalization_questions: [...]} with up to 5 questions.\nPOST replaces all questions. DELETE removes personalization entirely.\nQuestion types: text_input, dropdown, unlabeled_upload, labeled_upload.\nMax 1 file-upload question per listing. See the Listing Builder guide for full field constraints.\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/listings/{listing_id}/personalization`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/listings/listing-personalization.md",
        "tags": [
          "Listings"
        ],
        "parameters": [
          {
            "name": "listing_id",
            "in": "path",
            "required": true,
            "description": "The Etsy listing ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/listings/listing-personalization.md"
        },
        "x-eto-slug": "listing-personalization",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "listing_personalization_get",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/listings/1234567890/personalization\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/listings/1234567890/personalization\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/listings/1234567890/personalization\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      },
      "post": {
        "operationId": "listing_personalization_post",
        "summary": "Manage listing personalization",
        "description": "Get, create, or delete personalization questions for a listing.\nGET returns {personalization_questions: [...]} with up to 5 questions.\nPOST replaces all questions. DELETE removes personalization entirely.\nQuestion types: text_input, dropdown, unlabeled_upload, labeled_upload.\nMax 1 file-upload question per listing. See the Listing Builder guide for full field constraints.\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/listings/{listing_id}/personalization`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/listings/listing-personalization.md",
        "tags": [
          "Listings"
        ],
        "parameters": [
          {
            "name": "listing_id",
            "in": "path",
            "required": true,
            "description": "The Etsy listing ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/listings/listing-personalization.md"
        },
        "x-eto-slug": "listing-personalization",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "listing_personalization_post",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \"https://eto.tools/api/v1/listings/1234567890/personalization\" \\\n  -H \"X-Eto-API-Key: eto_your_key\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/listings/1234567890/personalization\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.post(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/listings/1234567890/personalization\";\n\nconst response = await fetch(url, {\n  method: \"POST\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      },
      "delete": {
        "operationId": "listing_personalization_delete",
        "summary": "Manage listing personalization",
        "description": "Get, create, or delete personalization questions for a listing.\nGET returns {personalization_questions: [...]} with up to 5 questions.\nPOST replaces all questions. DELETE removes personalization entirely.\nQuestion types: text_input, dropdown, unlabeled_upload, labeled_upload.\nMax 1 file-upload question per listing. See the Listing Builder guide for full field constraints.\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/listings/{listing_id}/personalization`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/listings/listing-personalization.md",
        "tags": [
          "Listings"
        ],
        "parameters": [
          {
            "name": "listing_id",
            "in": "path",
            "required": true,
            "description": "The Etsy listing ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/listings/listing-personalization.md"
        },
        "x-eto-slug": "listing-personalization",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "listing_personalization_delete",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \"https://eto.tools/api/v1/listings/1234567890/personalization\" \\\n  -H \"X-Eto-API-Key: eto_your_key\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/listings/1234567890/personalization\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.delete(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/listings/1234567890/personalization\";\n\nconst response = await fetch(url, {\n  method: \"DELETE\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/listings/batch": {
      "get": {
        "operationId": "listings_batch",
        "summary": "Batch get listings",
        "description": "Retrieve multiple listings in a single request.\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/listings/batch`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/listings/listings-batch.md",
        "tags": [
          "Listings"
        ],
        "parameters": [
          {
            "name": "listing_ids",
            "in": "query",
            "required": true,
            "description": "Comma-separated listing IDs",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "includes",
            "in": "query",
            "required": false,
            "description": "Comma-separated associations: Images, Shop, User, Inventory",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/listings/listings-batch.md"
        },
        "x-eto-slug": "listings-batch",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "listings_batch",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/listings/batch?listing_ids=123,456,789\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/listings/batch?listing_ids=123,456,789\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/listings/batch?listing_ids=123,456,789\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/listings/{listing_id}/products/{product_id}/offerings/{offering_id}": {
      "get": {
        "operationId": "listing_offering",
        "summary": "Get a listing offering",
        "description": "Get pricing and availability for a specific product variation offering. Etsy docs: \"Listing Offering\".\n\nAuthentication: API key only. Reads public marketplace data, so no store needs to be connected.\n\nProxied to the Etsy API at `/v3/application/listings/{listing_id}/products/{product_id}/offerings/{offering_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/listings/listing-offering.md",
        "tags": [
          "Listings"
        ],
        "parameters": [
          {
            "name": "listing_id",
            "in": "path",
            "required": true,
            "description": "The listing ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "product_id",
            "in": "path",
            "required": true,
            "description": "The product variant ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "offering_id",
            "in": "path",
            "required": true,
            "description": "The offering ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/listings/listing-offering.md"
        },
        "x-eto-slug": "listing-offering",
        "x-eto-auth": "public",
        "x-eto-mcp-tool": "listing_offering",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/listings/1234567890/products/555666777/offerings/888999000\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/listings/1234567890/products/555666777/offerings/888999000\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/listings/1234567890/products/555666777/offerings/888999000\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/listings/{listing_id}/inventory/products/{product_id}": {
      "get": {
        "operationId": "listing_product",
        "summary": "Get a product variant",
        "description": "Get a specific product variant (size/color combination) and its offerings. Etsy docs: \"Listing Product\".\n\nAuthentication: API key only. Reads public marketplace data, so no store needs to be connected.\n\nProxied to the Etsy API at `/v3/application/listings/{listing_id}/inventory/products/{product_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/listings/listing-product.md",
        "tags": [
          "Listings"
        ],
        "parameters": [
          {
            "name": "listing_id",
            "in": "path",
            "required": true,
            "description": "The listing ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "product_id",
            "in": "path",
            "required": true,
            "description": "The product variant ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/listings/listing-product.md"
        },
        "x-eto-slug": "listing-product",
        "x-eto-auth": "public",
        "x-eto-mcp-tool": "listing_product",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/listings/1234567890/inventory/products/555666777\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/listings/1234567890/inventory/products/555666777\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/listings/1234567890/inventory/products/555666777\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}": {
      "get": {
        "operationId": "shop_detail",
        "summary": "Get shop details",
        "description": "Retrieve detailed information about a shop including name, description, ratings, and listing counts.\n\nAuthentication: API key only. Reads public marketplace data, so no store needs to be connected.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shops/shop-detail.md",
        "tags": [
          "Shops"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "The Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shops/shop-detail.md"
        },
        "x-eto-slug": "shop-detail",
        "x-eto-auth": "public",
        "x-eto-mcp-tool": "shop_detail",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      },
      "put": {
        "operationId": "shop_update",
        "summary": "Update shop details",
        "description": "Update your shop's title, announcement, or other settings. Etsy docs: \"Update Shop\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shops/shop-update.md",
        "tags": [
          "Shops"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shops/shop-update.md"
        },
        "x-eto-slug": "shop-update",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "shop_update",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X PUT -H \"X-Eto-API-Key: eto_your_key\" -H \"Content-Type: application/json\" -d '{\"title\": \"My Shop Name\"}' \"https://eto.tools/api/v1/shops/12345678\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\npayload = {\n    \"title\": \"My Shop Name\"\n}\n\nresponse = requests.put(url, headers=headers, json=payload, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678\";\nconst payload = {\n  \"title\": \"My Shop Name\"\n};\n\nconst response = await fetch(url, {\n  method: \"PUT\",\n  body: JSON.stringify(payload),\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n    \"Content-Type\": \"application/json\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/reviews": {
      "get": {
        "operationId": "shop_reviews",
        "summary": "Get shop reviews",
        "description": "Retrieve reviews for a specific shop.\n\nAuthentication: API key only. Reads public marketplace data, so no store needs to be connected.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/reviews`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shops/shop-reviews.md",
        "tags": [
          "Shops"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "The Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Number of reviews (max 100)",
            "schema": {
              "type": "integer",
              "default": 25
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Pagination offset",
            "schema": {
              "type": "integer",
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shops/shop-reviews.md"
        },
        "x-eto-slug": "shop-reviews",
        "x-eto-auth": "public",
        "x-eto-mcp-tool": "shop_reviews",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/reviews?limit=5\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/reviews?limit=5\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/reviews?limit=5\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/sections": {
      "get": {
        "operationId": "shop_sections_get",
        "summary": "Get shop sections",
        "description": "Retrieve product sections for a shop.\n\nAuthentication: API key only. Reads public marketplace data, so no store needs to be connected.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/sections`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shops/shop-sections-get.md",
        "tags": [
          "Shops"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "The Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shops/shop-sections-get.md"
        },
        "x-eto-slug": "shop-sections-get",
        "x-eto-auth": "public",
        "x-eto-mcp-tool": "shop_sections_get",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/sections\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/sections\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/sections\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      },
      "post": {
        "operationId": "shop_sections_create",
        "summary": "Create shop section",
        "description": "Create a new product section in your shop.\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/sections`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shops/shop-sections-create.md",
        "tags": [
          "Shops"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shops/shop-sections-create.md"
        },
        "x-eto-slug": "shop-sections-create",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "shop_sections_create",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST -H \"X-Eto-API-Key: eto_your_key\" -H \"Content-Type: application/json\" -d '{\"title\": \"New Section\"}' \"https://eto.tools/api/v1/shops/12345678/sections\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/sections\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\npayload = {\n    \"title\": \"New Section\"\n}\n\nresponse = requests.post(url, headers=headers, json=payload, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/sections\";\nconst payload = {\n  \"title\": \"New Section\"\n};\n\nconst response = await fetch(url, {\n  method: \"POST\",\n  body: JSON.stringify(payload),\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n    \"Content-Type\": \"application/json\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "description": "Section title"
                  }
                },
                "required": [
                  "title"
                ]
              },
              "examples": {
                "default": {
                  "summary": "A complete request body",
                  "value": {
                    "title": "New Section"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/shops": {
      "get": {
        "operationId": "shop_search",
        "summary": "Search shops",
        "description": "Search for Etsy shops by name. Etsy docs: \"Find Shops\".\n\nAuthentication: API key only. Reads public marketplace data, so no store needs to be connected.\n\nProxied to the Etsy API at `/v3/application/shops`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shops/shop-search.md",
        "tags": [
          "Shops"
        ],
        "parameters": [
          {
            "name": "shop_name",
            "in": "query",
            "required": true,
            "description": "Shop name to search for",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Number of results (max 100)",
            "schema": {
              "type": "integer",
              "default": 25
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Pagination offset",
            "schema": {
              "type": "integer",
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shops/shop-search.md"
        },
        "x-eto-slug": "shop-search",
        "x-eto-auth": "public",
        "x-eto-mcp-tool": "shop_search",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops?shop_name=handmade&limit=5\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops?shop_name=handmade&limit=5\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops?shop_name=handmade&limit=5\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/sections/{section_id}": {
      "get": {
        "operationId": "shop_section_detail_get",
        "summary": "Get, update, or delete a section",
        "description": "Manage a specific shop section. Etsy docs: \"Shop Section\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/sections/{section_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shops/shop-section-detail.md",
        "tags": [
          "Shops"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "section_id",
            "in": "path",
            "required": true,
            "description": "The section ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shops/shop-section-detail.md"
        },
        "x-eto-slug": "shop-section-detail",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "shop_section_detail_get",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/sections/12345\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/sections/12345\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/sections/12345\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      },
      "put": {
        "operationId": "shop_section_detail_put",
        "summary": "Get, update, or delete a section",
        "description": "Manage a specific shop section. Etsy docs: \"Shop Section\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/sections/{section_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shops/shop-section-detail.md",
        "tags": [
          "Shops"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "section_id",
            "in": "path",
            "required": true,
            "description": "The section ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shops/shop-section-detail.md"
        },
        "x-eto-slug": "shop-section-detail",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "shop_section_detail_put",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X PUT \"https://eto.tools/api/v1/shops/12345678/sections/1\" \\\n  -H \"X-Eto-API-Key: eto_your_key\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/sections/1\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.put(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/sections/1\";\n\nconst response = await fetch(url, {\n  method: \"PUT\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      },
      "delete": {
        "operationId": "shop_section_detail_delete",
        "summary": "Get, update, or delete a section",
        "description": "Manage a specific shop section. Etsy docs: \"Shop Section\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/sections/{section_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shops/shop-section-detail.md",
        "tags": [
          "Shops"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "section_id",
            "in": "path",
            "required": true,
            "description": "The section ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shops/shop-section-detail.md"
        },
        "x-eto-slug": "shop-section-detail",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "shop_section_detail_delete",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \"https://eto.tools/api/v1/shops/12345678/sections/1\" \\\n  -H \"X-Eto-API-Key: eto_your_key\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/sections/1\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.delete(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/sections/1\";\n\nconst response = await fetch(url, {\n  method: \"DELETE\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/section-listings": {
      "get": {
        "operationId": "section_listings",
        "summary": "Get listings by section",
        "description": "Get all listings organized by shop section. Etsy docs: \"Listings By Section\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/shop-sections/listings`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shops/section-listings.md",
        "tags": [
          "Shops"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shops/section-listings.md"
        },
        "x-eto-slug": "section-listings",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "section_listings",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/section-listings\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/section-listings\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/section-listings\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/listings": {
      "get": {
        "operationId": "shop_listings_get",
        "summary": "List or create shop listings",
        "description": "GET: Retrieve your shop listings. POST: Create a new draft listing.\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/listings`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/store-management/shop-listings.md",
        "tags": [
          "Store Management"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Number of listings (max 100)",
            "schema": {
              "type": "integer",
              "default": 25
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Pagination offset",
            "schema": {
              "type": "integer",
              "default": 0
            }
          },
          {
            "name": "state",
            "in": "query",
            "required": false,
            "description": "Listing state: active, draft, inactive",
            "schema": {
              "type": "string",
              "default": "active"
            }
          },
          {
            "name": "sort_on",
            "in": "query",
            "required": false,
            "description": "Sort field",
            "schema": {
              "type": "string",
              "default": "created"
            }
          },
          {
            "name": "sort_order",
            "in": "query",
            "required": false,
            "description": "Sort direction",
            "schema": {
              "type": "string",
              "default": "desc"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/store-management/shop-listings.md"
        },
        "x-eto-slug": "shop-listings",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "shop_listings_get",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/listings?limit=10&state=active\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/listings?limit=10&state=active\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/listings?limit=10&state=active\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      },
      "post": {
        "operationId": "shop_listings_post",
        "summary": "List or create shop listings",
        "description": "GET: Retrieve your shop listings. POST: Create a new draft listing.\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/listings`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/store-management/shop-listings.md",
        "tags": [
          "Store Management"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Number of listings (max 100)",
            "schema": {
              "type": "integer",
              "default": 25
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Pagination offset",
            "schema": {
              "type": "integer",
              "default": 0
            }
          },
          {
            "name": "state",
            "in": "query",
            "required": false,
            "description": "Listing state: active, draft, inactive",
            "schema": {
              "type": "string",
              "default": "active"
            }
          },
          {
            "name": "sort_on",
            "in": "query",
            "required": false,
            "description": "Sort field",
            "schema": {
              "type": "string",
              "default": "created"
            }
          },
          {
            "name": "sort_order",
            "in": "query",
            "required": false,
            "description": "Sort direction",
            "schema": {
              "type": "string",
              "default": "desc"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/store-management/shop-listings.md"
        },
        "x-eto-slug": "shop-listings",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "shop_listings_post",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \"https://eto.tools/api/v1/shops/12345678/listings\" \\\n  -H \"X-Eto-API-Key: eto_your_key\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/listings\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\nparams = {\n    \"limit\": 25,\n    \"offset\": 0\n}\n\nresponse = requests.post(url, headers=headers, params=params, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/listings\";\n\nconst response = await fetch(url, {\n  method: \"POST\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/listings/{listing_id}": {
      "patch": {
        "operationId": "shop_listing_update",
        "summary": "Update a listing",
        "description": "Update properties of a listing you own.\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/listings/{listing_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/store-management/shop-listing-update.md",
        "tags": [
          "Store Management"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "listing_id",
            "in": "path",
            "required": true,
            "description": "The listing ID to update",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/store-management/shop-listing-update.md"
        },
        "x-eto-slug": "shop-listing-update",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "shop_listing_update",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X PATCH -H \"X-Eto-API-Key: eto_your_key\" -H \"Content-Type: application/json\" -d '{\"title\": \"Updated Title\"}' \"https://eto.tools/api/v1/shops/12345678/listings/1234567890\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/listings/1234567890\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\npayload = {\n    \"title\": \"Updated Title\"\n}\n\nresponse = requests.patch(url, headers=headers, json=payload, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/listings/1234567890\";\nconst payload = {\n  \"title\": \"Updated Title\"\n};\n\nconst response = await fetch(url, {\n  method: \"PATCH\",\n  body: JSON.stringify(payload),\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n    \"Content-Type\": \"application/json\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/listings/active": {
      "get": {
        "operationId": "shop_active_listings",
        "summary": "Get active listings only",
        "description": "Get only active (live) listings for your shop. Etsy docs: \"Active Listings By Shop\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/listings/active`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/store-management/shop-active-listings.md",
        "tags": [
          "Store Management"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Number of results (max 100)",
            "schema": {
              "type": "integer",
              "default": 25
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Pagination offset",
            "schema": {
              "type": "integer",
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/store-management/shop-active-listings.md"
        },
        "x-eto-slug": "shop-active-listings",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "shop_active_listings",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/listings/active?limit=10\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/listings/active?limit=10\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/listings/active?limit=10\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/listings/featured": {
      "get": {
        "operationId": "shop_featured_listings",
        "summary": "Get featured listings",
        "description": "Get listings featured on your shop's homepage. Etsy docs: \"Featured Listings By Shop\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/listings/featured`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/store-management/shop-featured-listings.md",
        "tags": [
          "Store Management"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Number of results (max 100)",
            "schema": {
              "type": "integer",
              "default": 25
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Pagination offset",
            "schema": {
              "type": "integer",
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/store-management/shop-featured-listings.md"
        },
        "x-eto-slug": "shop-featured-listings",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "shop_featured_listings",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/listings/featured?limit=5\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/listings/featured?limit=5\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/listings/featured?limit=5\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/listings/{listing_id}/translations/{language}": {
      "get": {
        "operationId": "listing_translation_get",
        "summary": "Manage listing translations",
        "description": "Get, create, or update a listing translation for a specific language. Etsy docs: \"Listing Translation\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/listings/{listing_id}/translations/{language}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/store-management/listing-translation.md",
        "tags": [
          "Store Management"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "listing_id",
            "in": "path",
            "required": true,
            "description": "The listing ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "language",
            "in": "path",
            "required": true,
            "description": "Language code (e.g. \"fr\", \"de\", \"es\")",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/store-management/listing-translation.md"
        },
        "x-eto-slug": "listing-translation",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "listing_translation_get",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/translations/fr\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/translations/fr\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/translations/fr\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      },
      "post": {
        "operationId": "listing_translation_post",
        "summary": "Manage listing translations",
        "description": "Get, create, or update a listing translation for a specific language. Etsy docs: \"Listing Translation\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/listings/{listing_id}/translations/{language}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/store-management/listing-translation.md",
        "tags": [
          "Store Management"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "listing_id",
            "in": "path",
            "required": true,
            "description": "The listing ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "language",
            "in": "path",
            "required": true,
            "description": "Language code (e.g. \"fr\", \"de\", \"es\")",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/store-management/listing-translation.md"
        },
        "x-eto-slug": "listing-translation",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "listing_translation_post",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/translations/fr\" \\\n  -H \"X-Eto-API-Key: eto_your_key\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/translations/fr\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.post(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/translations/fr\";\n\nconst response = await fetch(url, {\n  method: \"POST\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      },
      "put": {
        "operationId": "listing_translation_put",
        "summary": "Manage listing translations",
        "description": "Get, create, or update a listing translation for a specific language. Etsy docs: \"Listing Translation\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/listings/{listing_id}/translations/{language}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/store-management/listing-translation.md",
        "tags": [
          "Store Management"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "listing_id",
            "in": "path",
            "required": true,
            "description": "The listing ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "language",
            "in": "path",
            "required": true,
            "description": "Language code (e.g. \"fr\", \"de\", \"es\")",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/store-management/listing-translation.md"
        },
        "x-eto-slug": "listing-translation",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "listing_translation_put",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X PUT \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/translations/fr\" \\\n  -H \"X-Eto-API-Key: eto_your_key\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/translations/fr\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.put(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/translations/fr\";\n\nconst response = await fetch(url, {\n  method: \"PUT\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/finance/{shop_id}": {
      "get": {
        "operationId": "finance",
        "summary": "Get all finance metrics",
        "description": "Returns every financial metric for a store over a date range. Zero Etsy API calls — reads directly from the Eto database. Instant.\n\n━━━ WHAT YOU GET BACK (always returned) ━━━\n\nshop_id — the store\nshop_name — store display name\ncurrency — e.g. \"GBP\", \"USD\"\nstart / end — the range you requested\nbalance_cents — current store balance (latest ledger entry, not range-scoped)\npaid_out_cents — total deposited to bank in this range\nsales_count — number of sales\ngross_sales_cents — raw sale revenue before any deductions\nsales_cents — display sales value (gross - refunds - cancelled + remitted tax)\nfees_cents — total Etsy fees charged (negative number)\nads_cents — total ad spend (negative number)\nrefund_cents — total refunded to buyers\ncancelled_cents — total cancelled order amounts\nrecoup_cents — Etsy recovering money from your balance\nremitted_tax_cents — sales tax / VAT remitted by Etsy (negative)\ngross_profit_cents — profit before COGS (gross + fees + ads + tax)\ncogs_cents — cost of goods sold (from your item costs in Eto)\nnet_profit_cents — gross profit minus COGS\n\nAll amounts in cents. Divide by 100 for display. Negative = money out.\n\n━━━ HOW TO PICK THE DATE WINDOW ━━━\n\nEASIEST — pass `period`: today, yesterday, last_7_days, last_30_days, this_month, last_month.\n  The server resolves it in the shop timezone (override with `timezone`). No timestamps, no math.\nSpecific days — pass `start_date` / `end_date` as \"YYYY-MM-DD\" (inclusive).\nAdvanced — pass raw `start` / `end` unix seconds (range is [start, end), max 366 days).\nThe response echoes back a `range` object (exact start/end unix, start_local/end_local ISO,\ntimezone, label) AND the current server time — so you never compute or guess dates, and never\nneed a separate \"what time is it\" call. If the user means THEIR calendar day, pass their timezone.\nAny store — use any shop_id connected to your Eto account (GET /api/v1/stores to list them).\n\n━━━ BREAKDOWNS (optional) ━━━\n\nAdd &breakdown= to get detailed sub-breakdowns. Combine with commas.\n\nbreakdown=fees — returns breakdown.fees with:\n  listing, listing_credits, transaction, transaction_credits,\n  processing, processing_credits, shipping, shipping_credits,\n  vat_on_fees, vat_on_fees_credits, regulatory, regulatory_credits,\n  other, total\n\nbreakdown=ads — returns breakdown.ads with:\n  etsy_ads, offsite_ads, offsite_ads_credits, subscription, total\n\nbreakdown=sales — returns breakdown.sales with:\n  gross_sales_cents, refund_cents, cancelled_cents,\n  remitted_tax: { sales_tax, sales_tax_credits, vat_ep, vat_ep_credits, total }\n\nbreakdown=gross — same as sales (alias)\n\nbreakdown=profit — returns both breakdown.gross_profit and breakdown.net_profit:\n  gross_profit: { gross_sales_cents, fees_cents, ads_cents, remitted_tax_cents, total }\n  net_profit: { gross_profit_cents, cogs_cents, total }\n\nCombine: &breakdown=fees,ads,profit returns all three at once.\nOmit entirely to get just the top-level numbers.\n\n━━━ WHAT HAS BREAKDOWNS vs WHAT DOESN'T ━━━\n\nHAS breakdown: fees, ads, sales/gross, profit\nNO breakdown: balance_cents, paid_out_cents, sales_count, refund_cents,\n  cancelled_cents, recoup_cents, cogs_cents, remitted_tax_cents\n  (some of these appear inside the sales or profit breakdown instead)\n\n━━━ HOURLY BREAKDOWN (optional, single-day only) ━━━\n\nAdd &hourly=true to get a per-hour breakdown alongside the day summary.\nOnly works when your range is 24 hours or less (single day).\nIf your range is longer than 24h, hourly returns null with a note.\n\nWhat you get: an \"hourly\" array with one object per hour, from hour 0\n(midnight) up to the hour containing your end time.\n\nEach hour object contains:\n  hour — 0-23 (the hour index)\n  hour_start — unix timestamp of this hour's start\n  hour_end — unix timestamp of this hour's end\n  entry_count — number of ledger entries in this hour\n  sales_count — number of sales\n  gross_sales_cents — raw revenue for this hour\n  sales_cents — display sales (gross - refunds - cancelled + tax)\n  fees_cents — Etsy fees charged this hour\n  ads_cents — ad spend this hour\n  remitted_tax_cents — tax remitted this hour\n  refund_cents — refunds this hour\n  cancelled_cents — cancellations this hour\n  recoup_cents — Etsy recoupments this hour\n  gross_profit_cents — profit before COGS\n  cogs_cents — cost of goods sold this hour\n  net_profit_cents — profit after COGS\n  paid_out_cents — payouts this hour\n\nCombine with breakdowns: &hourly=true&breakdown=fees,ads works fine.\nThe hourly array gives per-hour summary metrics.\nThe breakdown object gives sub-category detail for the FULL day.\n\nTurn it off: just omit &hourly (default is off). No penalty for not using it.\nMulti-day range: hourly is ignored (returns null + hourly_note explaining why).\n\nAuthentication: API key only. Reads or writes data Eto holds for your own account.\n\nFull documentation: https://eto.tools/dev/docs/finance/finance.md",
        "tags": [
          "Finance"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID (from GET /api/v1/stores)",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "period",
            "in": "query",
            "required": false,
            "description": "EASIEST — a named window the server resolves for you, no timestamps: today, yesterday, last_7_days, last_30_days, this_month, last_month.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "start_date",
            "in": "query",
            "required": false,
            "description": "Calendar day \"YYYY-MM-DD\" (inclusive). Use with end_date for a custom range.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "end_date",
            "in": "query",
            "required": false,
            "description": "Calendar day \"YYYY-MM-DD\" (inclusive). Defaults to start_date (single day).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "timezone",
            "in": "query",
            "required": false,
            "description": "IANA timezone for resolving period/dates (e.g. \"Europe/London\", \"America/New_York\"). Defaults to the shop's local timezone. Pass the USER's timezone (e.g. Europe/Helsinki) if they mean their own calendar day.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "start",
            "in": "query",
            "required": false,
            "description": "Advanced: raw range start as unix seconds (inclusive). Prefer period/start_date.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "end",
            "in": "query",
            "required": false,
            "description": "Advanced: raw range end as unix seconds (exclusive, max 366 days). Prefer period/start_date.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "breakdown",
            "in": "query",
            "required": false,
            "description": "Comma-separated breakdowns to include: fees, ads, sales, gross, profit. Omit for top-level numbers only.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "hourly",
            "in": "query",
            "required": false,
            "description": "Set to \"true\" to get per-hour metrics. Only works for single-day queries (range ≤ 24h). Returns array of 24 hour objects. Default: off.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": "// ── Response WITHOUT breakdown ──\n{\n  \"shop_id\": \"12345678\",\n  \"shop_name\": \"My Etsy Shop\",\n  \"currency\": \"GBP\",\n  \"start\": 1716508800,\n  \"end\": 1717113600,\n  \"balance_cents\": 125430,\n  \"paid_out_cents\": 90000,\n  \"sales_count\": 15,\n  \"gross_sales_cents\": 125000,\n  \"sales_cents\": 120000,\n  \"fees_cents\": -15000,\n  \"ads_cents\": -5000,\n  \"refund_cents\": 8000,\n  \"cancelled_cents\": 2000,\n  \"recoup_cents\": 0,\n  \"remitted_tax_cents\": -3000,\n  \"gross_profit_cents\": 102000,\n  \"cogs_cents\": 30000,\n  \"net_profit_cents\": 72000\n}\n\n// ── Response WITH breakdown=fees,ads,sales,profit ──\n{\n  \"shop_id\": \"12345678\",\n  \"shop_name\": \"My Etsy Shop\",\n  \"currency\": \"GBP\",\n  \"start\": 1716508800,\n  \"end\": 1717113600,\n  \"balance_cents\": 125430,\n  \"paid_out_cents\": 90000,\n  \"sales_count\": 15,\n  \"gross_sales_cents\": 125000,\n  \"sales_cents\": 120000,\n  \"fees_cents\": -15000,\n  \"ads_cents\": -5000,\n  \"refund_cents\": 8000,\n  \"cancelled_cents\": 2000,\n  \"recoup_cents\": 0,\n  \"remitted_tax_cents\": -3000,\n  \"gross_profit_cents\": 102000,\n  \"cogs_cents\": 30000,\n  \"net_profit_cents\": 72000,\n  \"breakdown\": {\n    \"fees\": {\n      \"listing\": -400,\n      \"listing_credits\": 40,\n      \"transaction\": -8125,\n      \"transaction_credits\": 325,\n      \"processing\": -4800,\n      \"processing_credits\": 192,\n      \"shipping\": -650,\n      \"shipping_credits\": 0,\n      \"vat_on_fees\": -1200,\n      \"vat_on_fees_credits\": 0,\n      \"regulatory\": -500,\n      \"regulatory_credits\": 0,\n      \"other\": 0,\n      \"total\": -15118\n    },\n    \"ads\": {\n      \"etsy_ads\": -3000,\n      \"offsite_ads\": -1500,\n      \"offsite_ads_credits\": 0,\n      \"subscription\": -999,\n      \"total\": -5499\n    },\n    \"sales\": {\n      \"gross_sales_cents\": 125000,\n      \"refund_cents\": 8000,\n      \"cancelled_cents\": 2000,\n      \"remitted_tax\": {\n        \"sales_tax\": -2000,\n        \"sales_tax_credits\": 200,\n        \"vat_ep\": -1200,\n        \"vat_ep_credits\": 0,\n        \"total\": -3000\n      }\n    },\n    \"gross_profit\": {\n      \"gross_sales_cents\": 125000,\n      \"fees_cents\": -15000,\n      \"ads_cents\": -5000,\n      \"remitted_tax_cents\": -3000,\n      \"total\": 102000\n    },\n    \"net_profit\": {\n      \"gross_profit_cents\": 102000,\n      \"cogs_cents\": 30000,\n      \"total\": 72000\n    }\n  }\n}\n\n// ── Response WITH hourly=true (single day) ──\n{\n  \"shop_id\": \"12345678\",\n  \"shop_name\": \"My Etsy Shop\",\n  \"currency\": \"GBP\",\n  \"start\": 1716508800,\n  \"end\": 1716595200,\n  \"balance_cents\": 125430,\n  \"paid_out_cents\": 12000,\n  \"sales_count\": 5,\n  \"gross_sales_cents\": 45000,\n  \"sales_cents\": 43500,\n  \"fees_cents\": -5400,\n  \"ads_cents\": -1200,\n  \"refund_cents\": 1500,\n  \"cancelled_cents\": 0,\n  \"recoup_cents\": 0,\n  \"remitted_tax_cents\": 0,\n  \"gross_profit_cents\": 38400,\n  \"cogs_cents\": 10000,\n  \"net_profit_cents\": 28400,\n  \"hourly\": [\n    {\n      \"hour\": 0,\n      \"hour_start\": 1716508800,\n      \"hour_end\": 1716512400,\n      \"entry_count\": 0,\n      \"sales_count\": 0,\n      \"gross_sales_cents\": 0,\n      \"sales_cents\": 0,\n      \"fees_cents\": 0,\n      \"ads_cents\": 0,\n      \"remitted_tax_cents\": 0,\n      \"refund_cents\": 0,\n      \"cancelled_cents\": 0,\n      \"recoup_cents\": 0,\n      \"gross_profit_cents\": 0,\n      \"cogs_cents\": 0,\n      \"net_profit_cents\": 0,\n      \"paid_out_cents\": 0\n    },\n    { \"hour\": 1, \"...\" : \"...\" },\n    { \"hour\": 2, \"...\" : \"...\" },\n    \"... (hours 3-8 omitted for brevity) ...\",\n    {\n      \"hour\": 9,\n      \"hour_start\": 1716541200,\n      \"hour_end\": 1716544800,\n      \"entry_count\": 4,\n      \"sales_count\": 2,\n      \"gross_sales_cents\": 18000,\n      \"sales_cents\": 18000,\n      \"fees_cents\": -2160,\n      \"ads_cents\": -600,\n      \"remitted_tax_cents\": 0,\n      \"refund_cents\": 0,\n      \"cancelled_cents\": 0,\n      \"recoup_cents\": 0,\n      \"gross_profit_cents\": 15240,\n      \"cogs_cents\": 4000,\n      \"net_profit_cents\": 11240,\n      \"paid_out_cents\": 0\n    },\n    \"... (hours 10-23) ...\"\n  ]\n}"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/finance/finance.md"
        },
        "x-eto-slug": "finance",
        "x-eto-auth": "api_key",
        "x-eto-mcp-tool": "finance",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "# ── All metrics for a period (no breakdown) ──\ncurl -H \"X-Eto-API-Key: eto_your_key\" \\\n  \"https://eto.tools/api/v1/finance/12345678?start=1716508800&end=1717113600\"\n\n# ── All metrics for a single day ──\ncurl -H \"X-Eto-API-Key: eto_your_key\" \\\n  \"https://eto.tools/api/v1/finance/12345678?start=1716508800&end=1716595200\"\n\n# ── All metrics + fee breakdown ──\ncurl -H \"X-Eto-API-Key: eto_your_key\" \\\n  \"https://eto.tools/api/v1/finance/12345678?start=1716508800&end=1717113600&breakdown=fees\"\n\n# ── All metrics + ads breakdown ──\ncurl -H \"X-Eto-API-Key: eto_your_key\" \\\n  \"https://eto.tools/api/v1/finance/12345678?start=1716508800&end=1717113600&breakdown=ads\"\n\n# ── All metrics + profit breakdown (shows gross + net) ──\ncurl -H \"X-Eto-API-Key: eto_your_key\" \\\n  \"https://eto.tools/api/v1/finance/12345678?start=1716508800&end=1717113600&breakdown=profit\"\n\n# ── All metrics + sales/tax breakdown ──\ncurl -H \"X-Eto-API-Key: eto_your_key\" \\\n  \"https://eto.tools/api/v1/finance/12345678?start=1716508800&end=1717113600&breakdown=sales\"\n\n# ── All metrics + EVERY breakdown combined ──\ncurl -H \"X-Eto-API-Key: eto_your_key\" \\\n  \"https://eto.tools/api/v1/finance/12345678?start=1716508800&end=1717113600&breakdown=fees,ads,sales,profit\"\n\n# ── Single day + fee and ads breakdown ──\ncurl -H \"X-Eto-API-Key: eto_your_key\" \\\n  \"https://eto.tools/api/v1/finance/12345678?start=1716508800&end=1716595200&breakdown=fees,ads\"\n\n# ── Single day + hourly breakdown (per-hour metrics) ──\ncurl -H \"X-Eto-API-Key: eto_your_key\" \\\n  \"https://eto.tools/api/v1/finance/12345678?start=1716508800&end=1716595200&hourly=true\"\n\n# ── Single day + hourly + fee breakdown (combine both) ──\ncurl -H \"X-Eto-API-Key: eto_your_key\" \\\n  \"https://eto.tools/api/v1/finance/12345678?start=1716508800&end=1716595200&hourly=true&breakdown=fees\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/finance/12345678?start=1716508800&end=1717113600\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/finance/12345678?start=1716508800&end=1717113600\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/finance/{shop_id}/sync": {
      "post": {
        "operationId": "finance_sync",
        "summary": "Re-fetch finance data from Etsy",
        "description": "Re-fetches ledger data from the Etsy API and saves it to the Eto database. After syncing, GET /finance/{shop_id} returns the updated numbers.\n\n━━━ MODES ━━━\n\nEASIEST — send { \"period\": \"today\" } (or yesterday/last_7_days/last_30_days/this_month/last_month), or { \"date\": \"2026-06-01\" }, or { \"start_date\": \"...\", \"end_date\": \"...\" }. The server resolves the window (shop timezone, override with \"timezone\") and re-fetches it — no unix math. Single day → day mode, multi-day → range mode. The response echoes a `range` object with the exact window + server time.\n\n1. Incremental — send empty body or {}.\n   Fetches only new entries since last sync. Fast, safe to call often.\n   Use for: keeping data fresh on a schedule (e.g. every 15 min).\n   Returns: new_entries, total_fetched, affected_days.\n\n2. Single day — send { \"day_start\": unix_ts }.\n   Re-fetches ALL entries for that day. Replaces stale data.\n   Optionally include day_end (defaults to day_start + 86399).\n   Use for: a day that looks wrong or incomplete.\n   Returns: day_start, day_end, new_entries, total_fetched.\n\n3. Date range — send { \"start\": unix_ts, \"end\": unix_ts }.\n   Deletes existing entries in the range, re-fetches from Etsy, recomputes summaries.\n   Use for: full reconciliation of a period. Heaviest mode.\n   Returns: start, end, deleted_stale, new_entries.\n\n━━━ WHAT YOU GET BACK ━━━\n\nsuccess — true if sync completed\nmode — \"incremental\", \"day\", or \"range\"\nnew_entries — number of new ledger entries saved\ntotal_fetched — total entries fetched from Etsy (incremental + day modes)\naffected_days — list of day timestamps that had changes (incremental mode only)\ndeleted_stale — entries deleted before re-fetch (range mode only)\nday_start / day_end — the day that was synced (day mode only)\nstart / end — the range that was synced (range mode only)\n\n━━━ NOTES ━━━\n\nThis is the ONLY finance endpoint that makes Etsy API calls.\nCounts toward your Eto rate limit AND Etsy API cost billing.\nIf the store's OAuth token expired, returns STORE_TOKEN_EXPIRED.\nIf Etsy's API is down, returns UPSTREAM_ERROR with detail.\n\nAuthentication: API key only. Reads or writes data Eto holds for your own account.\n\nFull documentation: https://eto.tools/dev/docs/finance/finance-sync.md",
        "tags": [
          "Finance"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": "// ── Incremental ──\n{\n  \"success\": true,\n  \"mode\": \"incremental\",\n  \"new_entries\": 12,\n  \"total_fetched\": 15,\n  \"affected_days\": [1716508800, 1716595200]\n}\n\n// ── Single day ──\n{\n  \"success\": true,\n  \"mode\": \"day\",\n  \"day_start\": 1716508800,\n  \"day_end\": 1716595199,\n  \"new_entries\": 22,\n  \"total_fetched\": 22\n}\n\n// ── Date range ──\n{\n  \"success\": true,\n  \"mode\": \"range\",\n  \"start\": 1716508800,\n  \"end\": 1717113600,\n  \"deleted_stale\": 145,\n  \"new_entries\": 152\n}"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/finance/finance-sync.md"
        },
        "x-eto-slug": "finance-sync",
        "x-eto-auth": "api_key",
        "x-eto-mcp-tool": "finance_sync",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "# ── Incremental sync (get latest entries) ──\ncurl -X POST -H \"X-Eto-API-Key: eto_your_key\" \\\n  \"https://eto.tools/api/v1/finance/12345678/sync\"\n\n# ── Re-fetch a single day ──\ncurl -X POST -H \"X-Eto-API-Key: eto_your_key\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"day_start\": 1716508800}' \\\n  \"https://eto.tools/api/v1/finance/12345678/sync\"\n\n# ── Re-fetch a single day with explicit end ──\ncurl -X POST -H \"X-Eto-API-Key: eto_your_key\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"day_start\": 1716508800, \"day_end\": 1716595199}' \\\n  \"https://eto.tools/api/v1/finance/12345678/sync\"\n\n# ── Re-fetch an entire date range ──\ncurl -X POST -H \"X-Eto-API-Key: eto_your_key\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"start\": 1716508800, \"end\": 1717113600}' \\\n  \"https://eto.tools/api/v1/finance/12345678/sync\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/finance/12345678/sync\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.post(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/finance/12345678/sync\";\n\nconst response = await fetch(url, {\n  method: \"POST\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "period": {
                    "type": "string",
                    "description": "EASIEST — resolve a window server-side and re-fetch it: today, yesterday, last_7_days, last_30_days, this_month, last_month. No timestamps."
                  },
                  "date": {
                    "type": "string",
                    "description": "Re-fetch one calendar day \"YYYY-MM-DD\" (resolved in the shop/timezone)."
                  },
                  "start_date": {
                    "type": "string",
                    "description": "Range mode — first day \"YYYY-MM-DD\" (inclusive)."
                  },
                  "end_date": {
                    "type": "string",
                    "description": "Range mode — last day \"YYYY-MM-DD\" (inclusive)."
                  },
                  "timezone": {
                    "type": "string",
                    "description": "IANA timezone for resolving period/date (default: shop timezone)."
                  },
                  "day_start": {
                    "type": "integer",
                    "description": "Advanced single-day mode — unix timestamp of the day start."
                  },
                  "day_end": {
                    "type": "integer",
                    "description": "Advanced single-day mode — unix timestamp of the day end (default: day_start + 86399)."
                  },
                  "start": {
                    "type": "integer",
                    "description": "Advanced range mode — start of range to re-fetch (unix seconds)."
                  },
                  "end": {
                    "type": "integer",
                    "description": "Advanced range mode — end of range to re-fetch (unix seconds)."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/finance/software-expenses": {
      "get": {
        "operationId": "finance_software_expenses",
        "summary": "Get logged software expenses (subscriptions)",
        "description": "Returns the software expenses you logged on the Finance dashboard — the subscriptions under Finance → Settings → Subscriptions (Canva, Printify, Eto, …) — and exactly what they cost inside a date window. The same numbers as the dashboard's \"Software Expense\" card and its breakdown. Zero Etsy API calls — reads from the Eto database. Instant.\n\nThese are ACCOUNT-level, not per shop, so they are NOT included in GET /finance/{shop_id}. To get profit after software, subtract total_cents from the shop's net_profit_cents.\n\n━━━ WHAT YOU GET BACK (always returned) ━━━\n\nstart / end — the resolved window (unix seconds)\nrange — exact window: timezone, local-ISO bounds, label, server time\ncurrency — the currency total_cents is in: your common currency from Finance settings, else the single currency all subscriptions share, else null (mixed)\ncommon_currency — the common currency configured in Finance → Settings, or null\ntotal_cents — everything charged inside the window, converted to `currency`\ntotals_by_currency — { \"USD\": 2598, \"GBP\": 999 } raw sums per native currency\ncharge_count — number of individual charges inside the window\nsubscription_count — number of subscriptions logged (all of them, not just active in window)\nsubscriptions[] — one entry per logged subscription:\n  id, name, amount_cents, currency, frequency (weekly | biweekly | monthly | onetime), start_date (YYYY-MM-DD), conversion_rate (native → common), amount_converted_cents, charges_in_range, total_in_range_cents (converted), next_charge_date (YYYY-MM-DD or null), issue (only present when the entry is broken and never bills — e.g. missing amount/date)\nscope — reminder that these are account-level costs, not per shop\nwarnings[] — caveats, e.g. mixed currencies with no common currency set\nhint — only when nothing is logged yet, with where to add subscriptions\n\nAll amounts are COSTS (money out) returned as POSITIVE cents. Divide by 100 for display.\n\n━━━ HOW CHARGES ARE COUNTED ━━━\n\nEach subscription bills from its start_date on its schedule: weekly every 7 days, biweekly every 14, monthly on the same day each month (clamped to shorter months — the 31st bills on the 30th/28th), onetime exactly once on start_date. A charge is counted when its calendar date falls inside the window. So \"this month\" for a $12.99 monthly subscription started on the 15th is 1299 cents; \"last_7_days\" may be 0 if the billing day is not in that week. Identical to the dashboard.\n\n━━━ HOW TO PICK THE DATE WINDOW ━━━\n\nEASIEST — pass period=this_month (the default), today, yesterday, last_7_days, last_30_days or last_month. Or start_date=YYYY-MM-DD & end_date=YYYY-MM-DD (inclusive calendar days). Add timezone=Europe/London to resolve the window in a specific zone — the default is your primary connected shop's timezone, else UTC. Raw unix start/end are accepted too (max 366 days). The response echoes the resolved window in `range`, so you never have to guess which days were counted.\n\n━━━ OPTIONAL ━━━\n\ninclude=charges — also return charges[]: every individual charge inside the window (date, subscription_id, name, frequency, amount_cents, currency, converted_cents), sorted by date. charges_truncated is true if the list was cut at 2,000 entries (totals are always complete).\n\n━━━ NOTES ━━━\n\nRead-only. Subscriptions are added and edited on the Finance dashboard (eto.tools/dashboard/finances → Settings → Subscriptions).\nOnly YOUR account's subscriptions are ever returned — there is no id to look up.\nAn empty subscriptions[] with total_cents 0 is a valid answer: nothing is logged yet (the response carries a hint saying so).\n\nAuthentication: API key only. Reads or writes data Eto holds for your own account.\n\nFull documentation: https://eto.tools/dev/docs/finance/finance-software-expenses.md",
        "tags": [
          "Finance"
        ],
        "parameters": [
          {
            "name": "period",
            "in": "query",
            "required": false,
            "description": "EASIEST — today, yesterday, last_7_days, last_30_days, this_month, last_month. Resolved server-side. Default: this_month.",
            "schema": {
              "type": "string",
              "default": "this_month"
            }
          },
          {
            "name": "start_date",
            "in": "query",
            "required": false,
            "description": "First calendar day \"YYYY-MM-DD\" (inclusive).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "end_date",
            "in": "query",
            "required": false,
            "description": "Last calendar day \"YYYY-MM-DD\" (inclusive). Defaults to start_date.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "timezone",
            "in": "query",
            "required": false,
            "description": "IANA timezone used to resolve period/dates into calendar days (default: your primary connected shop's timezone, else UTC).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "include",
            "in": "query",
            "required": false,
            "description": "Set to \"charges\" to also list every individual charge in the window.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "start",
            "in": "query",
            "required": false,
            "description": "Advanced — unix timestamp, range start (inclusive). Prefer period/start_date.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "end",
            "in": "query",
            "required": false,
            "description": "Advanced — unix timestamp, range end (exclusive). Prefer period/end_date.",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": "{\n  \"start\": 1785542400,\n  \"end\": 1788220800,\n  \"range\": {\n    \"start\": 1785542400,\n    \"end\": 1788220800,\n    \"start_local\": \"2026-08-01T00:00:00+01:00\",\n    \"end_local\": \"2026-09-01T00:00:00+01:00\",\n    \"timezone\": \"Europe/London\",\n    \"label\": \"this month (month-to-date)\",\n    \"server_now_unix\": 1787788800,\n    \"server_now_utc\": \"2026-08-23T00:00:00+00:00\"\n  },\n  \"currency\": \"GBP\",\n  \"common_currency\": \"GBP\",\n  \"total_cents\": 2325,\n  \"totals_by_currency\": { \"USD\": 1299, \"GBP\": 1299 },\n  \"charge_count\": 2,\n  \"subscription_count\": 3,\n  \"subscriptions\": [\n    {\n      \"id\": \"sub_1753000000000_ab12\",\n      \"name\": \"Eto\",\n      \"amount_cents\": 1299,\n      \"currency\": \"GBP\",\n      \"frequency\": \"monthly\",\n      \"start_date\": \"2026-03-05\",\n      \"conversion_rate\": 1.0,\n      \"amount_converted_cents\": 1299,\n      \"charges_in_range\": 1,\n      \"total_in_range_cents\": 1299,\n      \"next_charge_date\": \"2026-09-05\"\n    },\n    {\n      \"id\": \"sub_1751000000000_cd34\",\n      \"name\": \"Canva Pro\",\n      \"amount_cents\": 1299,\n      \"currency\": \"USD\",\n      \"frequency\": \"monthly\",\n      \"start_date\": \"2026-01-15\",\n      \"conversion_rate\": 0.79,\n      \"amount_converted_cents\": 1026,\n      \"charges_in_range\": 1,\n      \"total_in_range_cents\": 1026,\n      \"next_charge_date\": \"2026-09-15\"\n    },\n    {\n      \"id\": \"sub_1749000000000_ef56\",\n      \"name\": \"Printify Premium\",\n      \"amount_cents\": 2499,\n      \"currency\": \"USD\",\n      \"frequency\": \"monthly\",\n      \"start_date\": \"2026-08-28\",\n      \"conversion_rate\": 0.79,\n      \"amount_converted_cents\": 1974,\n      \"charges_in_range\": 0,\n      \"total_in_range_cents\": 0,\n      \"next_charge_date\": \"2026-08-28\"\n    }\n  ],\n  \"scope\": {\n    \"level\": \"account\",\n    \"note\": \"Software expenses are logged per Eto account, not per shop, so they are NOT part of GET /api/v1/finance/{shop_id}. All amounts are costs (money out) returned as positive cents; subtract total_cents from a shop's net_profit_cents to get profit after software.\",\n    \"manage_at\": \"https://eto.tools/dashboard/finances (Settings → Subscriptions)\"\n  },\n  \"warnings\": []\n}\n\n// ── With include=charges (extra keys) ──\n{\n  \"...\": \"...\",\n  \"charges\": [\n    { \"date\": \"2026-08-05\", \"subscription_id\": \"sub_1753000000000_ab12\", \"name\": \"Eto\", \"frequency\": \"monthly\", \"amount_cents\": 1299, \"currency\": \"GBP\", \"converted_cents\": 1299 },\n    { \"date\": \"2026-08-15\", \"subscription_id\": \"sub_1751000000000_cd34\", \"name\": \"Canva Pro\", \"frequency\": \"monthly\", \"amount_cents\": 1299, \"currency\": \"USD\", \"converted_cents\": 1026 }\n  ],\n  \"charges_truncated\": false\n}\n\n// ── Nothing logged yet ──\n{\n  \"...\": \"...\",\n  \"currency\": null,\n  \"total_cents\": 0,\n  \"subscription_count\": 0,\n  \"subscriptions\": [],\n  \"hint\": \"No software expenses are logged yet. Add them at eto.tools/dashboard/finances → Settings → Subscriptions and they will appear here.\"\n}"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/finance/finance-software-expenses.md"
        },
        "x-eto-slug": "finance-software-expenses",
        "x-eto-auth": "api_key",
        "x-eto-mcp-tool": "finance_software_expenses",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "# ── This month (default) ──\ncurl -H \"X-Eto-API-Key: eto_your_key\" \\\n  \"https://eto.tools/api/v1/finance/software-expenses\"\n\n# ── Last month ──\ncurl -H \"X-Eto-API-Key: eto_your_key\" \\\n  \"https://eto.tools/api/v1/finance/software-expenses?period=last_month\"\n\n# ── A specific window, in your own timezone ──\ncurl -H \"X-Eto-API-Key: eto_your_key\" \\\n  \"https://eto.tools/api/v1/finance/software-expenses?start_date=2026-07-01&end_date=2026-07-31&timezone=Europe/London\"\n\n# ── This month + every individual charge ──\ncurl -H \"X-Eto-API-Key: eto_your_key\" \\\n  \"https://eto.tools/api/v1/finance/software-expenses?period=this_month&include=charges\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/finance/software-expenses\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/finance/software-expenses\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/listings/{listing_id}/images": {
      "post": {
        "operationId": "listing_image_upload",
        "summary": "Upload listing image",
        "description": "Upload an image to a listing. Send as multipart/form-data with the image in the \"image\" field.\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/listings/{listing_id}/images`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/images-and-media/listing-image-upload.md",
        "tags": [
          "Images & Media"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "listing_id",
            "in": "path",
            "required": true,
            "description": "The listing ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/images-and-media/listing-image-upload.md"
        },
        "x-eto-slug": "listing-image-upload",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "listing_image_upload",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST -H \"X-Eto-API-Key: eto_your_key\" -F \"image=@photo.jpg\" -F \"rank=1\" \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/images\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/images\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\nfiles = {\"image\": open(\"photo.jpg\", \"rb\")}\ndata = {\"rank\": \"1\"}\n\nresponse = requests.post(url, headers=headers, files=files, data=data, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/images\";\nconst form = new FormData();\nform.append(\"image\", fileInput.files[0]);\nform.append(\"rank\", \"1\");\n\nconst response = await fetch(url, {\n  method: \"POST\",\n  body: form,\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "image": {
                    "type": "string",
                    "contentEncoding": "binary"
                  },
                  "rank": {
                    "type": "integer"
                  }
                },
                "required": [
                  "image"
                ]
              }
            }
          }
        }
      }
    },
    "/api/v1/shops/{shop_id}/listings/{listing_id}/images/{image_id}": {
      "delete": {
        "operationId": "listing_image_delete",
        "summary": "Delete listing image",
        "description": "Remove an image from a listing.\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/listings/{listing_id}/images/{image_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/images-and-media/listing-image-delete.md",
        "tags": [
          "Images & Media"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "listing_id",
            "in": "path",
            "required": true,
            "description": "The listing ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "image_id",
            "in": "path",
            "required": true,
            "description": "The image ID to delete",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/images-and-media/listing-image-delete.md"
        },
        "x-eto-slug": "listing-image-delete",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "listing_image_delete",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/images/987654321\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/images/987654321\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.delete(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/images/987654321\";\n\nconst response = await fetch(url, {\n  method: \"DELETE\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/listings/{listing_id}/videos": {
      "post": {
        "operationId": "listing_video_upload",
        "summary": "Upload listing video",
        "description": "Upload a video to a listing.\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/listings/{listing_id}/videos`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/images-and-media/listing-video-upload.md",
        "tags": [
          "Images & Media"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "listing_id",
            "in": "path",
            "required": true,
            "description": "The listing ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/images-and-media/listing-video-upload.md"
        },
        "x-eto-slug": "listing-video-upload",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "listing_video_upload",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST -H \"X-Eto-API-Key: eto_your_key\" -F \"video=@clip.mp4\" \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/videos\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/videos\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\nfiles = {\"video\": open(\"clip.mp4\", \"rb\")}\n\nresponse = requests.post(url, headers=headers, files=files, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/videos\";\nconst form = new FormData();\nform.append(\"video\", fileInput.files[0]);\n\nconst response = await fetch(url, {\n  method: \"POST\",\n  body: form,\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "video": {
                    "type": "string",
                    "contentEncoding": "binary"
                  }
                },
                "required": [
                  "video"
                ]
              }
            }
          }
        }
      }
    },
    "/api/v1/shops/{shop_id}/listings/{listing_id}/videos/{video_id}": {
      "delete": {
        "operationId": "listing_video_delete",
        "summary": "Delete listing video",
        "description": "Remove a video from a listing.\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/listings/{listing_id}/videos/{video_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/images-and-media/listing-video-delete.md",
        "tags": [
          "Images & Media"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "listing_id",
            "in": "path",
            "required": true,
            "description": "The listing ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "video_id",
            "in": "path",
            "required": true,
            "description": "The video ID to delete",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/images-and-media/listing-video-delete.md"
        },
        "x-eto-slug": "listing-video-delete",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "listing_video_delete",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/videos/987654321\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/videos/987654321\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.delete(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/videos/987654321\";\n\nconst response = await fetch(url, {\n  method: \"DELETE\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/listings/{listing_id}/variation-images": {
      "get": {
        "operationId": "listing_variation_images_get",
        "summary": "Manage variation images",
        "description": "Get or upload images for listing variations.\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/listings/{listing_id}/variation-images`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/images-and-media/listing-variation-images.md",
        "tags": [
          "Images & Media"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "listing_id",
            "in": "path",
            "required": true,
            "description": "The listing ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/images-and-media/listing-variation-images.md"
        },
        "x-eto-slug": "listing-variation-images",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "listing_variation_images_get",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/variation-images\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/variation-images\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/variation-images\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      },
      "post": {
        "operationId": "listing_variation_images_post",
        "summary": "Manage variation images",
        "description": "Get or upload images for listing variations.\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/listings/{listing_id}/variation-images`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/images-and-media/listing-variation-images.md",
        "tags": [
          "Images & Media"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "listing_id",
            "in": "path",
            "required": true,
            "description": "The listing ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/images-and-media/listing-variation-images.md"
        },
        "x-eto-slug": "listing-variation-images",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "listing_variation_images_post",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/variation-images\" \\\n  -H \"X-Eto-API-Key: eto_your_key\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/variation-images\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.post(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/variation-images\";\n\nconst response = await fetch(url, {\n  method: \"POST\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/listings/{listing_id}/files": {
      "get": {
        "operationId": "listing_file_upload_get",
        "summary": "List or upload digital files",
        "description": "GET: List all digital files for a listing. POST: Upload a new digital file. Etsy docs: \"Listing Files\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/listings/{listing_id}/files`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/images-and-media/listing-file-upload.md",
        "tags": [
          "Images & Media"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "listing_id",
            "in": "path",
            "required": true,
            "description": "The listing ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/images-and-media/listing-file-upload.md"
        },
        "x-eto-slug": "listing-file-upload",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "listing_file_upload_get",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/files\" \\\n  -H \"X-Eto-API-Key: eto_your_key\" \\\n  -F \"file=@/path/to/photo.jpg\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/files\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\nfiles = {\"file\": open(\"/path/to/photo.jpg\", \"rb\")}\n\nresponse = requests.get(url, headers=headers, files=files, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/files\";\nconst form = new FormData();\nform.append(\"file\", fileInput.files[0]);\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  body: form,\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      },
      "post": {
        "operationId": "listing_file_upload_post",
        "summary": "List or upload digital files",
        "description": "GET: List all digital files for a listing. POST: Upload a new digital file. Etsy docs: \"Listing Files\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/listings/{listing_id}/files`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/images-and-media/listing-file-upload.md",
        "tags": [
          "Images & Media"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "listing_id",
            "in": "path",
            "required": true,
            "description": "The listing ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/images-and-media/listing-file-upload.md"
        },
        "x-eto-slug": "listing-file-upload",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "listing_file_upload_post",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST -H \"X-Eto-API-Key: eto_your_key\" -F \"file=@design.pdf\" \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/files\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/files\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\nfiles = {\"file\": open(\"design.pdf\", \"rb\")}\n\nresponse = requests.post(url, headers=headers, files=files, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/files\";\nconst form = new FormData();\nform.append(\"file\", fileInput.files[0]);\n\nconst response = await fetch(url, {\n  method: \"POST\",\n  body: form,\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "file": {
                    "type": "string",
                    "contentEncoding": "binary"
                  },
                  "name": {
                    "type": "string"
                  }
                },
                "required": [
                  "file"
                ]
              }
            }
          }
        }
      }
    },
    "/api/v1/shops/{shop_id}/listings/{listing_id}/files/{file_id}": {
      "get": {
        "operationId": "listing_file_detail_get",
        "summary": "Get or delete a digital file",
        "description": "Get details for or delete a specific digital file. Etsy docs: \"Listing File\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/listings/{listing_id}/files/{file_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/images-and-media/listing-file-detail.md",
        "tags": [
          "Images & Media"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "listing_id",
            "in": "path",
            "required": true,
            "description": "The listing ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "file_id",
            "in": "path",
            "required": true,
            "description": "The file ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/images-and-media/listing-file-detail.md"
        },
        "x-eto-slug": "listing-file-detail",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "listing_file_detail_get",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/files/987654321\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/files/987654321\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/files/987654321\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      },
      "delete": {
        "operationId": "listing_file_detail_delete",
        "summary": "Get or delete a digital file",
        "description": "Get details for or delete a specific digital file. Etsy docs: \"Listing File\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/listings/{listing_id}/files/{file_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/images-and-media/listing-file-detail.md",
        "tags": [
          "Images & Media"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "listing_id",
            "in": "path",
            "required": true,
            "description": "The listing ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "file_id",
            "in": "path",
            "required": true,
            "description": "The file ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/images-and-media/listing-file-detail.md"
        },
        "x-eto-slug": "listing-file-detail",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "listing_file_detail_delete",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/files/1\" \\\n  -H \"X-Eto-API-Key: eto_your_key\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/files/1\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.delete(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/files/1\";\n\nconst response = await fetch(url, {\n  method: \"DELETE\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/listings/{listing_id}/images/{image_id}": {
      "get": {
        "operationId": "listing_image_detail",
        "summary": "Get a single image",
        "description": "Get details for a specific listing image. Etsy docs: \"Listing Image\".\n\nAuthentication: API key only. Reads public marketplace data, so no store needs to be connected.\n\nProxied to the Etsy API at `/v3/application/listings/{listing_id}/images/{image_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/images-and-media/listing-image-detail.md",
        "tags": [
          "Images & Media"
        ],
        "parameters": [
          {
            "name": "listing_id",
            "in": "path",
            "required": true,
            "description": "The listing ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "image_id",
            "in": "path",
            "required": true,
            "description": "The image ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/images-and-media/listing-image-detail.md"
        },
        "x-eto-slug": "listing-image-detail",
        "x-eto-auth": "public",
        "x-eto-mcp-tool": "listing_image_detail",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/listings/1234567890/images/987654321\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/listings/1234567890/images/987654321\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/listings/1234567890/images/987654321\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/listings/{listing_id}/videos/{video_id}": {
      "get": {
        "operationId": "listing_video_detail",
        "summary": "Get a single video",
        "description": "Get details for a specific listing video. Etsy docs: \"Listing Video\".\n\nAuthentication: API key only. Reads public marketplace data, so no store needs to be connected.\n\nProxied to the Etsy API at `/v3/application/listings/{listing_id}/videos/{video_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/images-and-media/listing-video-detail.md",
        "tags": [
          "Images & Media"
        ],
        "parameters": [
          {
            "name": "listing_id",
            "in": "path",
            "required": true,
            "description": "The listing ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "video_id",
            "in": "path",
            "required": true,
            "description": "The video ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/images-and-media/listing-video-detail.md"
        },
        "x-eto-slug": "listing-video-detail",
        "x-eto-auth": "public",
        "x-eto-mcp-tool": "listing_video_detail",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/listings/1234567890/videos/987654321\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/listings/1234567890/videos/987654321\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/listings/1234567890/videos/987654321\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/listings/{listing_id}/properties/{property_id}": {
      "get": {
        "operationId": "listing_property_get",
        "summary": "Get or update listing property",
        "description": "Manage specific properties (like color, size) for a listing.\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/listings/{listing_id}/properties/{property_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/listing-properties/listing-property.md",
        "tags": [
          "Listing Properties"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "listing_id",
            "in": "path",
            "required": true,
            "description": "The listing ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "property_id",
            "in": "path",
            "required": true,
            "description": "The property ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/listing-properties/listing-property.md"
        },
        "x-eto-slug": "listing-property",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "listing_property_get",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/properties/200\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/properties/200\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/properties/200\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      },
      "put": {
        "operationId": "listing_property_put",
        "summary": "Get or update listing property",
        "description": "Manage specific properties (like color, size) for a listing.\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/listings/{listing_id}/properties/{property_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/listing-properties/listing-property.md",
        "tags": [
          "Listing Properties"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "listing_id",
            "in": "path",
            "required": true,
            "description": "The listing ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "property_id",
            "in": "path",
            "required": true,
            "description": "The property ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/listing-properties/listing-property.md"
        },
        "x-eto-slug": "listing-property",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "listing_property_put",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X PUT \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/properties/200\" \\\n  -H \"X-Eto-API-Key: eto_your_key\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/properties/200\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.put(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/properties/200\";\n\nconst response = await fetch(url, {\n  method: \"PUT\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      },
      "delete": {
        "operationId": "listing_property_delete",
        "summary": "Delete a listing property",
        "description": "Remove a property value from your listing. Etsy docs: \"Delete Listing Property\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/listings/{listing_id}/properties/{property_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/listing-properties/listing-property-delete.md",
        "tags": [
          "Listing Properties"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "listing_id",
            "in": "path",
            "required": true,
            "description": "The listing ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "property_id",
            "in": "path",
            "required": true,
            "description": "The property ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/listing-properties/listing-property-delete.md"
        },
        "x-eto-slug": "listing-property-delete",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "listing_property_delete",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/properties/200\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/properties/200\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.delete(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/properties/200\";\n\nconst response = await fetch(url, {\n  method: \"DELETE\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/listings/{listing_id}/properties/{property_id}": {
      "get": {
        "operationId": "listing_property_public",
        "summary": "Get a listing property (public)",
        "description": "Get a specific property value for any listing. Etsy docs: \"Listing Property\".\n\nAuthentication: API key only. Reads public marketplace data, so no store needs to be connected.\n\nProxied to the Etsy API at `/v3/application/listings/{listing_id}/properties/{property_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/listing-properties/listing-property-public.md",
        "tags": [
          "Listing Properties"
        ],
        "parameters": [
          {
            "name": "listing_id",
            "in": "path",
            "required": true,
            "description": "The listing ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "property_id",
            "in": "path",
            "required": true,
            "description": "The property ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/listing-properties/listing-property-public.md"
        },
        "x-eto-slug": "listing-property-public",
        "x-eto-auth": "public",
        "x-eto-mcp-tool": "listing_property_public",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/listings/1234567890/properties/200\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/listings/1234567890/properties/200\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/listings/1234567890/properties/200\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/listings/{listing_id}/properties": {
      "get": {
        "operationId": "listing_properties_all",
        "summary": "Get all listing properties",
        "description": "Get all properties for one of your listings. Etsy docs: \"Listing Properties\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/listings/{listing_id}/properties`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/listing-properties/listing-properties-all.md",
        "tags": [
          "Listing Properties"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "listing_id",
            "in": "path",
            "required": true,
            "description": "The listing ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/listing-properties/listing-properties-all.md"
        },
        "x-eto-slug": "listing-properties-all",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "listing_properties_all",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/properties\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/properties\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/properties\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/shipping-profiles": {
      "get": {
        "operationId": "shipping_profiles_get",
        "summary": "List or create shipping profiles",
        "description": "GET: List all shipping profiles for your shop. POST: Create a new shipping profile.\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/shipping-profiles`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shipping/shipping-profiles.md",
        "tags": [
          "Shipping"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shipping/shipping-profiles.md"
        },
        "x-eto-slug": "shipping-profiles",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "shipping_profiles_get",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/shipping-profiles\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/shipping-profiles\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/shipping-profiles\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      },
      "post": {
        "operationId": "shipping_profiles_post",
        "summary": "List or create shipping profiles",
        "description": "GET: List all shipping profiles for your shop. POST: Create a new shipping profile.\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/shipping-profiles`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shipping/shipping-profiles.md",
        "tags": [
          "Shipping"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shipping/shipping-profiles.md"
        },
        "x-eto-slug": "shipping-profiles",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "shipping_profiles_post",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \"https://eto.tools/api/v1/shops/12345678/shipping-profiles\" \\\n  -H \"X-Eto-API-Key: eto_your_key\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/shipping-profiles\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.post(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/shipping-profiles\";\n\nconst response = await fetch(url, {\n  method: \"POST\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/shipping-profiles/{profile_id}": {
      "put": {
        "operationId": "shipping_profile_detail_put",
        "summary": "Update or delete shipping profile",
        "description": "Update or delete a specific shipping profile.\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/shipping-profiles/{profile_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shipping/shipping-profile-detail.md",
        "tags": [
          "Shipping"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "profile_id",
            "in": "path",
            "required": true,
            "description": "The shipping profile ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shipping/shipping-profile-detail.md"
        },
        "x-eto-slug": "shipping-profile-detail",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "shipping_profile_detail_put",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X PUT -H \"X-Eto-API-Key: eto_your_key\" -H \"Content-Type: application/json\" -d '{\"title\": \"Updated\"}' \"https://eto.tools/api/v1/shops/12345678/shipping-profiles/111222333\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/shipping-profiles/111222333\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\npayload = {\n    \"title\": \"Updated\"\n}\n\nresponse = requests.put(url, headers=headers, json=payload, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/shipping-profiles/111222333\";\nconst payload = {\n  \"title\": \"Updated\"\n};\n\nconst response = await fetch(url, {\n  method: \"PUT\",\n  body: JSON.stringify(payload),\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n    \"Content-Type\": \"application/json\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      },
      "delete": {
        "operationId": "shipping_profile_detail_delete",
        "summary": "Update or delete shipping profile",
        "description": "Update or delete a specific shipping profile.\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/shipping-profiles/{profile_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shipping/shipping-profile-detail.md",
        "tags": [
          "Shipping"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "profile_id",
            "in": "path",
            "required": true,
            "description": "The shipping profile ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shipping/shipping-profile-detail.md"
        },
        "x-eto-slug": "shipping-profile-detail",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "shipping_profile_detail_delete",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \"https://eto.tools/api/v1/shops/12345678/shipping-profiles/1\" \\\n  -H \"X-Eto-API-Key: eto_your_key\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/shipping-profiles/1\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.delete(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/shipping-profiles/1\";\n\nconst response = await fetch(url, {\n  method: \"DELETE\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/shipping-profiles/{profile_id}/destinations": {
      "get": {
        "operationId": "shipping_destinations_get",
        "summary": "List or add shipping destinations",
        "description": "Get or add destination countries/regions for a shipping profile. Etsy docs: \"Shipping Profile Destinations\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/shipping-profiles/{profile_id}/destinations`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shipping/shipping-destinations.md",
        "tags": [
          "Shipping"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "profile_id",
            "in": "path",
            "required": true,
            "description": "The shipping profile ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shipping/shipping-destinations.md"
        },
        "x-eto-slug": "shipping-destinations",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "shipping_destinations_get",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/shipping-profiles/111222333/destinations\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/shipping-profiles/111222333/destinations\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/shipping-profiles/111222333/destinations\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      },
      "post": {
        "operationId": "shipping_destinations_post",
        "summary": "List or add shipping destinations",
        "description": "Get or add destination countries/regions for a shipping profile. Etsy docs: \"Shipping Profile Destinations\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/shipping-profiles/{profile_id}/destinations`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shipping/shipping-destinations.md",
        "tags": [
          "Shipping"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "profile_id",
            "in": "path",
            "required": true,
            "description": "The shipping profile ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shipping/shipping-destinations.md"
        },
        "x-eto-slug": "shipping-destinations",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "shipping_destinations_post",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \"https://eto.tools/api/v1/shops/12345678/shipping-profiles/1/destinations\" \\\n  -H \"X-Eto-API-Key: eto_your_key\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/shipping-profiles/1/destinations\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.post(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/shipping-profiles/1/destinations\";\n\nconst response = await fetch(url, {\n  method: \"POST\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/shipping-profiles/{profile_id}/destinations/{destination_id}": {
      "put": {
        "operationId": "shipping_destination_detail_put",
        "summary": "Update or delete a shipping destination",
        "description": "Manage a specific shipping destination. Etsy docs: \"Shipping Profile Destination\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/shipping-profiles/{profile_id}/destinations/{destination_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shipping/shipping-destination-detail.md",
        "tags": [
          "Shipping"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "profile_id",
            "in": "path",
            "required": true,
            "description": "The shipping profile ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "destination_id",
            "in": "path",
            "required": true,
            "description": "The destination ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shipping/shipping-destination-detail.md"
        },
        "x-eto-slug": "shipping-destination-detail",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "shipping_destination_detail_put",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X PUT -H \"X-Eto-API-Key: eto_your_key\" -H \"Content-Type: application/json\" -d '{\"primary_cost\": 500}' \"https://eto.tools/api/v1/shops/12345678/shipping-profiles/111222333/destinations/77777\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/shipping-profiles/111222333/destinations/77777\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\npayload = {\n    \"primary_cost\": 500\n}\n\nresponse = requests.put(url, headers=headers, json=payload, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/shipping-profiles/111222333/destinations/77777\";\nconst payload = {\n  \"primary_cost\": 500\n};\n\nconst response = await fetch(url, {\n  method: \"PUT\",\n  body: JSON.stringify(payload),\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n    \"Content-Type\": \"application/json\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      },
      "delete": {
        "operationId": "shipping_destination_detail_delete",
        "summary": "Update or delete a shipping destination",
        "description": "Manage a specific shipping destination. Etsy docs: \"Shipping Profile Destination\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/shipping-profiles/{profile_id}/destinations/{destination_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shipping/shipping-destination-detail.md",
        "tags": [
          "Shipping"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "profile_id",
            "in": "path",
            "required": true,
            "description": "The shipping profile ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "destination_id",
            "in": "path",
            "required": true,
            "description": "The destination ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shipping/shipping-destination-detail.md"
        },
        "x-eto-slug": "shipping-destination-detail",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "shipping_destination_detail_delete",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \"https://eto.tools/api/v1/shops/12345678/shipping-profiles/1/destinations/1\" \\\n  -H \"X-Eto-API-Key: eto_your_key\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/shipping-profiles/1/destinations/1\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.delete(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/shipping-profiles/1/destinations/1\";\n\nconst response = await fetch(url, {\n  method: \"DELETE\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/shipping-profiles/{profile_id}/upgrades": {
      "get": {
        "operationId": "shipping_upgrades_get",
        "summary": "List or add shipping upgrades",
        "description": "Get or add shipping speed upgrades (e.g. express, priority). Etsy docs: \"Shipping Profile Upgrades\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/shipping-profiles/{profile_id}/upgrades`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shipping/shipping-upgrades.md",
        "tags": [
          "Shipping"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "profile_id",
            "in": "path",
            "required": true,
            "description": "The shipping profile ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shipping/shipping-upgrades.md"
        },
        "x-eto-slug": "shipping-upgrades",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "shipping_upgrades_get",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/shipping-profiles/111222333/upgrades\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/shipping-profiles/111222333/upgrades\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/shipping-profiles/111222333/upgrades\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      },
      "post": {
        "operationId": "shipping_upgrades_post",
        "summary": "List or add shipping upgrades",
        "description": "Get or add shipping speed upgrades (e.g. express, priority). Etsy docs: \"Shipping Profile Upgrades\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/shipping-profiles/{profile_id}/upgrades`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shipping/shipping-upgrades.md",
        "tags": [
          "Shipping"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "profile_id",
            "in": "path",
            "required": true,
            "description": "The shipping profile ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shipping/shipping-upgrades.md"
        },
        "x-eto-slug": "shipping-upgrades",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "shipping_upgrades_post",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \"https://eto.tools/api/v1/shops/12345678/shipping-profiles/1/upgrades\" \\\n  -H \"X-Eto-API-Key: eto_your_key\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/shipping-profiles/1/upgrades\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.post(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/shipping-profiles/1/upgrades\";\n\nconst response = await fetch(url, {\n  method: \"POST\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/shipping-profiles/{profile_id}/upgrades/{upgrade_id}": {
      "get": {
        "operationId": "shipping_upgrade_detail_get",
        "summary": "Get, update, or delete a shipping upgrade",
        "description": "Manage a specific shipping speed upgrade. Etsy docs: \"Shipping Profile Upgrade\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/shipping-profiles/{profile_id}/upgrades/{upgrade_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shipping/shipping-upgrade-detail.md",
        "tags": [
          "Shipping"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "profile_id",
            "in": "path",
            "required": true,
            "description": "The shipping profile ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "upgrade_id",
            "in": "path",
            "required": true,
            "description": "The upgrade ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shipping/shipping-upgrade-detail.md"
        },
        "x-eto-slug": "shipping-upgrade-detail",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "shipping_upgrade_detail_get",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/shipping-profiles/111222333/upgrades/88888\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/shipping-profiles/111222333/upgrades/88888\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/shipping-profiles/111222333/upgrades/88888\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      },
      "put": {
        "operationId": "shipping_upgrade_detail_put",
        "summary": "Get, update, or delete a shipping upgrade",
        "description": "Manage a specific shipping speed upgrade. Etsy docs: \"Shipping Profile Upgrade\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/shipping-profiles/{profile_id}/upgrades/{upgrade_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shipping/shipping-upgrade-detail.md",
        "tags": [
          "Shipping"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "profile_id",
            "in": "path",
            "required": true,
            "description": "The shipping profile ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "upgrade_id",
            "in": "path",
            "required": true,
            "description": "The upgrade ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shipping/shipping-upgrade-detail.md"
        },
        "x-eto-slug": "shipping-upgrade-detail",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "shipping_upgrade_detail_put",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X PUT \"https://eto.tools/api/v1/shops/12345678/shipping-profiles/1/upgrades/1\" \\\n  -H \"X-Eto-API-Key: eto_your_key\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/shipping-profiles/1/upgrades/1\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.put(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/shipping-profiles/1/upgrades/1\";\n\nconst response = await fetch(url, {\n  method: \"PUT\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      },
      "delete": {
        "operationId": "shipping_upgrade_detail_delete",
        "summary": "Get, update, or delete a shipping upgrade",
        "description": "Manage a specific shipping speed upgrade. Etsy docs: \"Shipping Profile Upgrade\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/shipping-profiles/{profile_id}/upgrades/{upgrade_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shipping/shipping-upgrade-detail.md",
        "tags": [
          "Shipping"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "profile_id",
            "in": "path",
            "required": true,
            "description": "The shipping profile ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "upgrade_id",
            "in": "path",
            "required": true,
            "description": "The upgrade ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shipping/shipping-upgrade-detail.md"
        },
        "x-eto-slug": "shipping-upgrade-detail",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "shipping_upgrade_detail_delete",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \"https://eto.tools/api/v1/shops/12345678/shipping-profiles/1/upgrades/1\" \\\n  -H \"X-Eto-API-Key: eto_your_key\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/shipping-profiles/1/upgrades/1\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.delete(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/shipping-profiles/1/upgrades/1\";\n\nconst response = await fetch(url, {\n  method: \"DELETE\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shipping-carriers": {
      "get": {
        "operationId": "shipping_carriers",
        "summary": "Get shipping carriers",
        "description": "List all available shipping carriers (USPS, FedEx, DHL, etc.). Etsy docs: \"Shipping Carriers\".\n\nAuthentication: API key only. Reads public marketplace data, so no store needs to be connected.\n\nProxied to the Etsy API at `/v3/application/shipping-carriers`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shipping/shipping-carriers.md",
        "tags": [
          "Shipping"
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shipping/shipping-carriers.md"
        },
        "x-eto-slug": "shipping-carriers",
        "x-eto-auth": "public",
        "x-eto-mcp-tool": "shipping_carriers",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shipping-carriers\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shipping-carriers\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shipping-carriers\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/categories": {
      "get": {
        "operationId": "categories",
        "summary": "Get product categories",
        "description": "Get the full product category tree (e.g. Jewelry, Clothing, Home Decor). Use category IDs when creating listings to place them in the right section. Etsy docs: \"Seller Taxonomy Nodes\".\n\nAuthentication: API key only. Reads public marketplace data, so no store needs to be connected.\n\nProxied to the Etsy API at `/v3/application/seller-taxonomy/nodes`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/categories/categories.md",
        "tags": [
          "Categories"
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/categories/categories.md"
        },
        "x-eto-slug": "categories",
        "x-eto-auth": "public",
        "x-eto-mcp-tool": "categories",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/categories\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/categories\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/categories\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/categories/{category_id}/properties": {
      "get": {
        "operationId": "category_properties",
        "summary": "Get category properties",
        "description": "Get the required and optional fields for a category — like size, color, or material options that buyers can filter by. Etsy docs: \"Taxonomy Node Properties\".\n\nAuthentication: API key only. Reads public marketplace data, so no store needs to be connected.\n\nProxied to the Etsy API at `/v3/application/seller-taxonomy/nodes/{category_id}/properties`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/categories/category-properties.md",
        "tags": [
          "Categories"
        ],
        "parameters": [
          {
            "name": "category_id",
            "in": "path",
            "required": true,
            "description": "The category ID (from /categories)",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/categories/category-properties.md"
        },
        "x-eto-slug": "category-properties",
        "x-eto-auth": "public",
        "x-eto-mcp-tool": "category_properties",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/categories/1/properties\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/categories/1/properties\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/categories/1/properties\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/buyer-categories": {
      "get": {
        "operationId": "buyer_categories",
        "summary": "Get buyer categories",
        "description": "Get the category tree from a buyer's perspective — how shoppers browse Etsy. Etsy docs: \"Buyer Taxonomy Nodes\".\n\nAuthentication: API key only. Reads public marketplace data, so no store needs to be connected.\n\nProxied to the Etsy API at `/v3/application/buyer-taxonomy/nodes`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/categories/buyer-categories.md",
        "tags": [
          "Categories"
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/categories/buyer-categories.md"
        },
        "x-eto-slug": "buyer-categories",
        "x-eto-auth": "public",
        "x-eto-mcp-tool": "buyer_categories",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/buyer-categories\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/buyer-categories\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/buyer-categories\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/buyer-categories/{category_id}/properties": {
      "get": {
        "operationId": "buyer_category_properties",
        "summary": "Get buyer category properties",
        "description": "Get filterable properties for a buyer category. Etsy docs: \"Buyer Taxonomy Properties\".\n\nAuthentication: API key only. Reads public marketplace data, so no store needs to be connected.\n\nProxied to the Etsy API at `/v3/application/buyer-taxonomy/nodes/{category_id}/properties`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/categories/buyer-category-properties.md",
        "tags": [
          "Categories"
        ],
        "parameters": [
          {
            "name": "category_id",
            "in": "path",
            "required": true,
            "description": "The buyer category ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/categories/buyer-category-properties.md"
        },
        "x-eto-slug": "buyer-category-properties",
        "x-eto-auth": "public",
        "x-eto-mcp-tool": "buyer_category_properties",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/buyer-categories/1/properties\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/buyer-categories/1/properties\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/buyer-categories/1/properties\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/users/me": {
      "get": {
        "operationId": "users_me",
        "summary": "Get current user",
        "description": "Retrieve the Etsy user profile for the authenticated store.\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/users/me`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/user/users-me.md",
        "tags": [
          "User"
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/user/users-me.md"
        },
        "x-eto-slug": "users-me",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "users_me",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/users/me\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/users/me\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/users/me\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/users/{user_id}/shops": {
      "get": {
        "operationId": "user_shops",
        "summary": "Get user shops",
        "description": "List shops owned by a specific user.\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/users/{user_id}/shops`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/user/user-shops.md",
        "tags": [
          "User"
        ],
        "parameters": [
          {
            "name": "user_id",
            "in": "path",
            "required": true,
            "description": "The Etsy user ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/user/user-shops.md"
        },
        "x-eto-slug": "user-shops",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "user_shops",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/users/123456789/shops\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/users/123456789/shops\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/users/123456789/shops\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/users/{user_id}": {
      "get": {
        "operationId": "user_profile",
        "summary": "Get user profile",
        "description": "Get a user's Etsy profile by ID. Etsy docs: \"Get User\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/users/{user_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/user/user-profile.md",
        "tags": [
          "User"
        ],
        "parameters": [
          {
            "name": "user_id",
            "in": "path",
            "required": true,
            "description": "The Etsy user ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/user/user-profile.md"
        },
        "x-eto-slug": "user-profile",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "user_profile",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/users/123456789\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/users/123456789\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/users/123456789\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/return-policies": {
      "get": {
        "operationId": "shop_return_policies",
        "summary": "Get return policies",
        "description": "Retrieve return policy details for your shop.\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/policies/return`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shop-policies/shop-return-policies.md",
        "tags": [
          "Shop Policies"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shop-policies/shop-return-policies.md"
        },
        "x-eto-slug": "shop-return-policies",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "shop_return_policies",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/return-policies\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/return-policies\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/return-policies\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      },
      "post": {
        "operationId": "return_policy_create",
        "summary": "Create return policy",
        "description": "Create a new return policy for your shop. Etsy docs: \"Create Return Policy\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/policies/return`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shop-policies/return-policy-create.md",
        "tags": [
          "Shop Policies"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shop-policies/return-policy-create.md"
        },
        "x-eto-slug": "return-policy-create",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "return_policy_create",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST -H \"X-Eto-API-Key: eto_your_key\" -H \"Content-Type: application/json\" -d '{\"accepts_returns\": true, \"return_deadline\": 30}' \"https://eto.tools/api/v1/shops/12345678/return-policies\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/return-policies\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\npayload = {\n    \"accepts_returns\": True,\n    \"return_deadline\": 30\n}\n\nresponse = requests.post(url, headers=headers, json=payload, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/return-policies\";\nconst payload = {\n  \"accepts_returns\": true,\n  \"return_deadline\": 30\n};\n\nconst response = await fetch(url, {\n  method: \"POST\",\n  body: JSON.stringify(payload),\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n    \"Content-Type\": \"application/json\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/production-partners": {
      "get": {
        "operationId": "shop_production_partners",
        "summary": "Get production partners",
        "description": "List production partners (e.g. print-on-demand services) for your shop.\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/production-partners`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shop-policies/shop-production-partners.md",
        "tags": [
          "Shop Policies"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shop-policies/shop-production-partners.md"
        },
        "x-eto-slug": "shop-production-partners",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "shop_production_partners",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/production-partners\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/production-partners\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/production-partners\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/listing-requirements": {
      "get": {
        "operationId": "shop_listing_requirements_get",
        "summary": "Listing requirements",
        "description": "Get or create listing readiness requirements — the checklist items a listing must complete before going live. Etsy docs: \"Readiness State Definitions\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/readiness-state-definitions`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shop-policies/shop-listing-requirements.md",
        "tags": [
          "Shop Policies"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shop-policies/shop-listing-requirements.md"
        },
        "x-eto-slug": "shop-listing-requirements",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "shop_listing_requirements_get",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/listing-requirements\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/listing-requirements\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/listing-requirements\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      },
      "post": {
        "operationId": "shop_listing_requirements_post",
        "summary": "Listing requirements",
        "description": "Get or create listing readiness requirements — the checklist items a listing must complete before going live. Etsy docs: \"Readiness State Definitions\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/readiness-state-definitions`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shop-policies/shop-listing-requirements.md",
        "tags": [
          "Shop Policies"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shop-policies/shop-listing-requirements.md"
        },
        "x-eto-slug": "shop-listing-requirements",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "shop_listing_requirements_post",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \"https://eto.tools/api/v1/shops/12345678/listing-requirements\" \\\n  -H \"X-Eto-API-Key: eto_your_key\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/listing-requirements\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.post(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/listing-requirements\";\n\nconst response = await fetch(url, {\n  method: \"POST\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/return-policies/{policy_id}": {
      "get": {
        "operationId": "return_policy_detail_get",
        "summary": "Get, update, or delete a return policy",
        "description": "Manage a specific return policy. Etsy docs: \"Shop Return Policy\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/policies/return/{policy_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shop-policies/return-policy-detail.md",
        "tags": [
          "Shop Policies"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "policy_id",
            "in": "path",
            "required": true,
            "description": "The return policy ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shop-policies/return-policy-detail.md"
        },
        "x-eto-slug": "return-policy-detail",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "return_policy_detail_get",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/return-policies/54321\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/return-policies/54321\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/return-policies/54321\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      },
      "put": {
        "operationId": "return_policy_detail_put",
        "summary": "Get, update, or delete a return policy",
        "description": "Manage a specific return policy. Etsy docs: \"Shop Return Policy\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/policies/return/{policy_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shop-policies/return-policy-detail.md",
        "tags": [
          "Shop Policies"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "policy_id",
            "in": "path",
            "required": true,
            "description": "The return policy ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shop-policies/return-policy-detail.md"
        },
        "x-eto-slug": "return-policy-detail",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "return_policy_detail_put",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X PUT \"https://eto.tools/api/v1/shops/12345678/return-policies/1\" \\\n  -H \"X-Eto-API-Key: eto_your_key\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/return-policies/1\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.put(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/return-policies/1\";\n\nconst response = await fetch(url, {\n  method: \"PUT\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      },
      "delete": {
        "operationId": "return_policy_detail_delete",
        "summary": "Get, update, or delete a return policy",
        "description": "Manage a specific return policy. Etsy docs: \"Shop Return Policy\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/policies/return/{policy_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shop-policies/return-policy-detail.md",
        "tags": [
          "Shop Policies"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "policy_id",
            "in": "path",
            "required": true,
            "description": "The return policy ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shop-policies/return-policy-detail.md"
        },
        "x-eto-slug": "return-policy-detail",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "return_policy_detail_delete",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \"https://eto.tools/api/v1/shops/12345678/return-policies/1\" \\\n  -H \"X-Eto-API-Key: eto_your_key\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/return-policies/1\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.delete(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/return-policies/1\";\n\nconst response = await fetch(url, {\n  method: \"DELETE\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/return-policies/consolidate": {
      "post": {
        "operationId": "return_policy_consolidate",
        "summary": "Consolidate return policies",
        "description": "Merge multiple return policies into one. Etsy docs: \"Consolidate Return Policies\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/policies/return/consolidate`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shop-policies/return-policy-consolidate.md",
        "tags": [
          "Shop Policies"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shop-policies/return-policy-consolidate.md"
        },
        "x-eto-slug": "return-policy-consolidate",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "return_policy_consolidate",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/return-policies/consolidate\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/return-policies/consolidate\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.post(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/return-policies/consolidate\";\n\nconst response = await fetch(url, {\n  method: \"POST\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/return-policies/{policy_id}/listings": {
      "get": {
        "operationId": "return_policy_listings",
        "summary": "Get listings with a return policy",
        "description": "Get all listings that use a specific return policy. Etsy docs: \"Listings By Return Policy\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/policies/return/{policy_id}/listings`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shop-policies/return-policy-listings.md",
        "tags": [
          "Shop Policies"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "policy_id",
            "in": "path",
            "required": true,
            "description": "The return policy ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shop-policies/return-policy-listings.md"
        },
        "x-eto-slug": "return-policy-listings",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "return_policy_listings",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/return-policies/54321/listings\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/return-policies/54321/listings\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/return-policies/54321/listings\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/holiday-preferences": {
      "get": {
        "operationId": "shop_holidays",
        "summary": "Get holiday preferences",
        "description": "Get your shop's holiday settings (when you're on vacation). Etsy docs: \"Holiday Preferences\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/holiday-preferences`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shop-policies/shop-holidays.md",
        "tags": [
          "Shop Policies"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shop-policies/shop-holidays.md"
        },
        "x-eto-slug": "shop-holidays",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "shop_holidays",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/holiday-preferences\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/holiday-preferences\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/holiday-preferences\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/holiday-preferences/{holiday_id}": {
      "put": {
        "operationId": "shop_holiday_update",
        "summary": "Update a holiday preference",
        "description": "Update vacation/holiday settings. Etsy docs: \"Update Holiday Preferences\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/holiday-preferences/{holiday_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shop-policies/shop-holiday-update.md",
        "tags": [
          "Shop Policies"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "holiday_id",
            "in": "path",
            "required": true,
            "description": "The holiday ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shop-policies/shop-holiday-update.md"
        },
        "x-eto-slug": "shop-holiday-update",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "shop_holiday_update",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X PUT -H \"X-Eto-API-Key: eto_your_key\" -H \"Content-Type: application/json\" -d '{\"is_working\": false}' \"https://eto.tools/api/v1/shops/12345678/holiday-preferences/1\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/holiday-preferences/1\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\npayload = {\n    \"is_working\": False\n}\n\nresponse = requests.put(url, headers=headers, json=payload, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/holiday-preferences/1\";\nconst payload = {\n  \"is_working\": false\n};\n\nconst response = await fetch(url, {\n  method: \"PUT\",\n  body: JSON.stringify(payload),\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n    \"Content-Type\": \"application/json\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/listing-requirements/{requirement_id}": {
      "get": {
        "operationId": "listing_requirement_detail_get",
        "summary": "Get, update, or delete a listing requirement",
        "description": "Manage a specific listing readiness requirement. Etsy docs: \"Readiness State Definition\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/readiness-state-definitions/{requirement_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shop-policies/listing-requirement-detail.md",
        "tags": [
          "Shop Policies"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "requirement_id",
            "in": "path",
            "required": true,
            "description": "The requirement ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shop-policies/listing-requirement-detail.md"
        },
        "x-eto-slug": "listing-requirement-detail",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "listing_requirement_detail_get",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/listing-requirements/99999\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/listing-requirements/99999\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/listing-requirements/99999\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      },
      "put": {
        "operationId": "listing_requirement_detail_put",
        "summary": "Get, update, or delete a listing requirement",
        "description": "Manage a specific listing readiness requirement. Etsy docs: \"Readiness State Definition\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/readiness-state-definitions/{requirement_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shop-policies/listing-requirement-detail.md",
        "tags": [
          "Shop Policies"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "requirement_id",
            "in": "path",
            "required": true,
            "description": "The requirement ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shop-policies/listing-requirement-detail.md"
        },
        "x-eto-slug": "listing-requirement-detail",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "listing_requirement_detail_put",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X PUT \"https://eto.tools/api/v1/shops/12345678/listing-requirements/1\" \\\n  -H \"X-Eto-API-Key: eto_your_key\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/listing-requirements/1\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.put(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/listing-requirements/1\";\n\nconst response = await fetch(url, {\n  method: \"PUT\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      },
      "delete": {
        "operationId": "listing_requirement_detail_delete",
        "summary": "Get, update, or delete a listing requirement",
        "description": "Manage a specific listing readiness requirement. Etsy docs: \"Readiness State Definition\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/readiness-state-definitions/{requirement_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/shop-policies/listing-requirement-detail.md",
        "tags": [
          "Shop Policies"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "requirement_id",
            "in": "path",
            "required": true,
            "description": "The requirement ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shop-policies/listing-requirement-detail.md"
        },
        "x-eto-slug": "listing-requirement-detail",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "listing_requirement_detail_delete",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X DELETE \"https://eto.tools/api/v1/shops/12345678/listing-requirements/1\" \\\n  -H \"X-Eto-API-Key: eto_your_key\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/listing-requirements/1\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.delete(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/listing-requirements/1\";\n\nconst response = await fetch(url, {\n  method: \"DELETE\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/stores/{shop_id}/shipping-profiles/live": {
      "get": {
        "operationId": "shipping_profiles_live",
        "summary": "Get current shipping profiles (live, no cache)",
        "description": "Returns this shop's shipping profiles RIGHT NOW — fetched live from Etsy on every call, never from the local cache. Use this when you need the absolute latest IDs to put into shops[].shipping_profile_id when calling POST /api/v1/listings/create.\n\nOne Etsy API call per request. Response is a flat list — pick the shipping_profile_id you want.\n\nAuthentication: API key only. Reads or writes data Eto holds for your own account.\n\nFull documentation: https://eto.tools/dev/docs/shop-policies/shipping-profiles-live.md",
        "tags": [
          "Shop Policies"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your connected Etsy shop ID. Get the list from GET /api/v1/stores.",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "shop_id": "12345678",
                      "fetched_at": "2026-04-19T14:30:00Z",
                      "count": 2,
                      "shipping_profiles": [
                        {
                          "shipping_profile_id": 291257702631,
                          "title": "Standard Shipping",
                          "min_processing_days": 1,
                          "max_processing_days": 3,
                          "processing_days_display_label": "1-3 business days",
                          "origin_country_iso": "US",
                          "origin_postal_code": "10001",
                          "profile_type": "manual",
                          "domestic_handling_fee": 0.0,
                          "international_handling_fee": 0.0
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shop-policies/shipping-profiles-live.md"
        },
        "x-eto-slug": "shipping-profiles-live",
        "x-eto-auth": "api_key",
        "x-eto-mcp-tool": "shipping_profiles_live",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/stores/12345678/shipping-profiles/live\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/stores/12345678/shipping-profiles/live\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/stores/12345678/shipping-profiles/live\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/stores/{shop_id}/return-policies/live": {
      "get": {
        "operationId": "return_policies_live",
        "summary": "Get current return policies (live, no cache)",
        "description": "Returns this shop's return policies RIGHT NOW — fetched live from Etsy on every call. No cache, no staleness. Use this to get the return_policy_id to plug into shops[].return_policy_id when calling POST /api/v1/listings/create.\n\nOne Etsy API call per request.\n\nAuthentication: API key only. Reads or writes data Eto holds for your own account.\n\nFull documentation: https://eto.tools/dev/docs/shop-policies/return-policies-live.md",
        "tags": [
          "Shop Policies"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your connected Etsy shop ID.",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "shop_id": "12345678",
                      "fetched_at": "2026-04-19T14:30:00Z",
                      "count": 1,
                      "return_policies": [
                        {
                          "return_policy_id": 1435074483195,
                          "accepts_returns": true,
                          "accepts_exchanges": true,
                          "return_deadline": 30
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shop-policies/return-policies-live.md"
        },
        "x-eto-slug": "return-policies-live",
        "x-eto-auth": "api_key",
        "x-eto-mcp-tool": "return_policies_live",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/stores/12345678/return-policies/live\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/stores/12345678/return-policies/live\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/stores/12345678/return-policies/live\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/stores/{shop_id}/processing-profiles/live": {
      "get": {
        "operationId": "processing_profiles_live",
        "summary": "Get current processing profiles (live, no cache)",
        "description": "Returns this shop's processing profiles (Etsy \"readiness state definitions\") RIGHT NOW — fetched live from Etsy on every call. No cache. Use this to get the processing_profile_id (a.k.a. readiness_state_id) for shops[].processing_profile_id when calling POST /api/v1/listings/create.\n\nOne Etsy API call per request.\n\nAuthentication: API key only. Reads or writes data Eto holds for your own account.\n\nFull documentation: https://eto.tools/dev/docs/shop-policies/processing-profiles-live.md",
        "tags": [
          "Shop Policies"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your connected Etsy shop ID.",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "shop_id": "12345678",
                      "fetched_at": "2026-04-19T14:30:00Z",
                      "count": 1,
                      "processing_profiles": [
                        {
                          "readiness_state_id": 1456101932490,
                          "readiness_state": "ready_to_ship",
                          "min_processing_days": 1,
                          "max_processing_days": 3,
                          "processing_days_display_label": "1-3 business days"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shop-policies/processing-profiles-live.md"
        },
        "x-eto-slug": "processing-profiles-live",
        "x-eto-auth": "api_key",
        "x-eto-mcp-tool": "processing_profiles_live",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/stores/12345678/processing-profiles/live\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/stores/12345678/processing-profiles/live\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/stores/12345678/processing-profiles/live\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/stores/{shop_id}/shop-sections/live": {
      "get": {
        "operationId": "shop_sections_live",
        "summary": "Get current shop sections (live, no cache)",
        "description": "Returns this shop's sections RIGHT NOW — fetched live from Etsy on every call. No cache. Use this to get the shop_section_id to plug into shops[].shop_section_id when calling POST /api/v1/listings/create.\n\nOne Etsy API call per request.\n\nAuthentication: API key only. Reads or writes data Eto holds for your own account.\n\nFull documentation: https://eto.tools/dev/docs/shop-policies/shop-sections-live.md",
        "tags": [
          "Shop Policies"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your connected Etsy shop ID.",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "shop_id": "12345678",
                      "fetched_at": "2026-04-19T14:30:00Z",
                      "count": 2,
                      "shop_sections": [
                        {
                          "shop_section_id": 56909368,
                          "title": "New Arrivals",
                          "rank": 1,
                          "user_id": 99887766,
                          "active_listing_count": 15
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/shop-policies/shop-sections-live.md"
        },
        "x-eto-slug": "shop-sections-live",
        "x-eto-auth": "api_key",
        "x-eto-mcp-tool": "shop_sections_live",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/stores/12345678/shop-sections/live\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/stores/12345678/shop-sections/live\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/stores/12345678/shop-sections/live\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/orders": {
      "get": {
        "operationId": "shop_orders",
        "summary": "List shop orders",
        "description": "Get all orders for your shop. Supports filtering by date and pagination. Etsy docs: \"Shop Receipts\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/receipts`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/orders/shop-orders.md",
        "tags": [
          "Orders"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Number of orders (max 100)",
            "schema": {
              "type": "integer",
              "default": 25
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Pagination offset",
            "schema": {
              "type": "integer",
              "default": 0
            }
          },
          {
            "name": "min_created",
            "in": "query",
            "required": false,
            "description": "Earliest order date (unix seconds)",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "max_created",
            "in": "query",
            "required": false,
            "description": "Latest order date (unix seconds)",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "sort_on",
            "in": "query",
            "required": false,
            "description": "Sort field",
            "schema": {
              "type": "string",
              "default": "created"
            }
          },
          {
            "name": "sort_order",
            "in": "query",
            "required": false,
            "description": "Sort direction",
            "schema": {
              "type": "string",
              "default": "desc"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/orders/shop-orders.md"
        },
        "x-eto-slug": "shop-orders",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "shop_orders",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/orders?limit=10\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/orders?limit=10\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/orders?limit=10\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/orders/{order_id}": {
      "get": {
        "operationId": "shop_order_detail",
        "summary": "Get order details",
        "description": "Get full details for a specific order including items, shipping, and payment info. Etsy docs: \"Shop Receipt by ID\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/receipts/{order_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/orders/shop-order-detail.md",
        "tags": [
          "Orders"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "order_id",
            "in": "path",
            "required": true,
            "description": "The order ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/orders/shop-order-detail.md"
        },
        "x-eto-slug": "shop-order-detail",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "shop_order_detail",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/orders/3344556677\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/orders/3344556677\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/orders/3344556677\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/orders/{order_id}/tracking": {
      "post": {
        "operationId": "shop_order_tracking",
        "summary": "Update order tracking",
        "description": "Add or update tracking information for an order so the buyer can track their shipment. Etsy docs: \"Receipt Tracking\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/receipts/{order_id}/tracking`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/orders/shop-order-tracking.md",
        "tags": [
          "Orders"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "order_id",
            "in": "path",
            "required": true,
            "description": "The order ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/orders/shop-order-tracking.md"
        },
        "x-eto-slug": "shop-order-tracking",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "shop_order_tracking",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST -H \"X-Eto-API-Key: eto_your_key\" -H \"Content-Type: application/json\" -d '{\"tracking_code\": \"1Z999AA10123456784\", \"carrier_name\": \"ups\"}' \"https://eto.tools/api/v1/shops/12345678/orders/3344556677/tracking\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/orders/3344556677/tracking\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\npayload = {\n    \"tracking_code\": \"1Z999AA10123456784\",\n    \"carrier_name\": \"ups\"\n}\n\nresponse = requests.post(url, headers=headers, json=payload, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/orders/3344556677/tracking\";\nconst payload = {\n  \"tracking_code\": \"1Z999AA10123456784\",\n  \"carrier_name\": \"ups\"\n};\n\nconst response = await fetch(url, {\n  method: \"POST\",\n  body: JSON.stringify(payload),\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n    \"Content-Type\": \"application/json\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "tracking_code": {
                    "type": "string",
                    "description": "Tracking number"
                  },
                  "carrier_name": {
                    "type": "string",
                    "description": "Shipping carrier name"
                  }
                },
                "required": [
                  "tracking_code",
                  "carrier_name"
                ]
              },
              "examples": {
                "default": {
                  "summary": "A complete request body",
                  "value": {
                    "tracking_code": "1Z999AA10123456784",
                    "carrier_name": "ups"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/shops/{shop_id}/orders/{order_id}/update": {
      "put": {
        "operationId": "order_update",
        "summary": "Update an order",
        "description": "Update order details like notes or status. Etsy docs: \"Update Shop Receipt\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/receipts/{order_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/orders/order-update.md",
        "tags": [
          "Orders"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "order_id",
            "in": "path",
            "required": true,
            "description": "The order ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/orders/order-update.md"
        },
        "x-eto-slug": "order-update",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "order_update",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X PUT -H \"X-Eto-API-Key: eto_your_key\" -H \"Content-Type: application/json\" -d '{\"was_shipped\": true}' \"https://eto.tools/api/v1/shops/12345678/orders/3344556677/update\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/orders/3344556677/update\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\npayload = {\n    \"was_shipped\": True\n}\n\nresponse = requests.put(url, headers=headers, json=payload, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/orders/3344556677/update\";\nconst payload = {\n  \"was_shipped\": true\n};\n\nconst response = await fetch(url, {\n  method: \"PUT\",\n  body: JSON.stringify(payload),\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n    \"Content-Type\": \"application/json\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/orders/{order_id}/listings": {
      "get": {
        "operationId": "order_listings",
        "summary": "Get listings in an order",
        "description": "Get the listings that were purchased in a specific order. Etsy docs: \"Listings By Receipt\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/receipts/{order_id}/listings`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/orders/order-listings.md",
        "tags": [
          "Orders"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "order_id",
            "in": "path",
            "required": true,
            "description": "The order ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/orders/order-listings.md"
        },
        "x-eto-slug": "order-listings",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "order_listings",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/orders/3344556677/listings\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/orders/3344556677/listings\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/orders/3344556677/listings\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/orders/{order_id}/payments": {
      "get": {
        "operationId": "order_payments",
        "summary": "Get order payments",
        "description": "Get payment details for a specific order. Etsy docs: \"Payment By Receipt ID\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/receipts/{order_id}/payments`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/orders/order-payments.md",
        "tags": [
          "Orders"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "order_id",
            "in": "path",
            "required": true,
            "description": "The order ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/orders/order-payments.md"
        },
        "x-eto-slug": "order-payments",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "order_payments",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/orders/3344556677/payments\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/orders/3344556677/payments\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/orders/3344556677/payments\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/orders/{shop_id}": {
      "get": {
        "operationId": "orders_list",
        "summary": "List orders for a store",
        "description": "List receipts/orders for a connected store (newest first by default — so for \"my latest order\" just call this, no date filter). Triggers a background sync so data stays fresh. To filter by date, pass a friendly `period` or `start_date`/`end_date` (resolved server-side in the shop timezone) — do NOT compute unix timestamps. Every order includes `created_iso` (UTC) and `created_local` (shop/your timezone), and the response carries `server_now_utc` + `timezone`, so you never mis-read a raw timestamp or think an order is \"in the future\".\n\nAuthentication: API key only. Reads or writes data Eto holds for your own account.\n\nFull documentation: https://eto.tools/dev/docs/orders/orders-list.md",
        "tags": [
          "Orders"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Connected shop id",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size (default 25)",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Pagination offset",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "period",
            "in": "query",
            "required": false,
            "description": "Friendly date filter: today, yesterday, last_7_days, last_30_days, this_month, last_month.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "start_date",
            "in": "query",
            "required": false,
            "description": "Filter from this calendar day \"YYYY-MM-DD\" (inclusive).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "end_date",
            "in": "query",
            "required": false,
            "description": "Filter to this calendar day \"YYYY-MM-DD\" (inclusive).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "timezone",
            "in": "query",
            "required": false,
            "description": "IANA tz for resolving period/dates + formatting created_local (default: shop tz).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "min_created",
            "in": "query",
            "required": false,
            "description": "Advanced: unix lower bound on order creation. Prefer period/start_date.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "max_created",
            "in": "query",
            "required": false,
            "description": "Advanced: unix upper bound on order creation. Prefer period/end_date.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "sort_on",
            "in": "query",
            "required": false,
            "description": "Sort field (default \"created\")",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort_order",
            "in": "query",
            "required": false,
            "description": "asc or desc (default desc)",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/orders/orders-list.md"
        },
        "x-eto-slug": "orders-list",
        "x-eto-auth": "api_key",
        "x-eto-mcp-tool": "orders_list",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \"https://eto.tools/api/v1/orders/12345678?limit=25&offset=0\" \\\n  -H \"X-Eto-API-Key: eto_your_key\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/orders/12345678\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\nparams = {\n    \"limit\": 25,\n    \"offset\": 0\n}\n\nresponse = requests.get(url, headers=headers, params=params, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/orders/12345678?limit=25&offset=0\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/orders/{shop_id}/{receipt_id}": {
      "get": {
        "operationId": "order_detail",
        "summary": "Get one order",
        "description": "Get a single order (receipt) with its transactions for a connected store. Also returns a `profit` object = THIS order's own profit: gross_profit_cents (its gross sale minus its OWN fees, incl remitted tax), fees_cents, fees_breakdown, cogs_cents, net_profit_cents. This is the answer to \"profit for this product/order\" — it does NOT subtract shop-wide ad spend or other orders' refunds/cancellations. (profit is null until a finance_sync has run.)\n\nAuthentication: API key only. Reads or writes data Eto holds for your own account.\n\nFull documentation: https://eto.tools/dev/docs/orders/order-detail.md",
        "tags": [
          "Orders"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Connected shop id",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "receipt_id",
            "in": "path",
            "required": true,
            "description": "Etsy receipt id",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/orders/order-detail.md"
        },
        "x-eto-slug": "order-detail",
        "x-eto-auth": "api_key",
        "x-eto-mcp-tool": "order_detail",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \"https://eto.tools/api/v1/orders/12345678/987654321\" \\\n  -H \"X-Eto-API-Key: eto_your_key\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/orders/12345678/987654321\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/orders/12345678/987654321\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/orders/{shop_id}/sync": {
      "post": {
        "operationId": "orders_sync",
        "summary": "Sync orders from Etsy",
        "description": "Force a fresh sync of orders for a connected store from Etsy.\n\nAuthentication: API key only. Reads or writes data Eto holds for your own account.\n\nFull documentation: https://eto.tools/dev/docs/orders/orders-sync.md",
        "tags": [
          "Orders"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Connected shop id",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/orders/orders-sync.md"
        },
        "x-eto-slug": "orders-sync",
        "x-eto-auth": "api_key",
        "x-eto-mcp-tool": "orders_sync",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \"https://eto.tools/api/v1/orders/12345678/sync\" \\\n  -H \"X-Eto-API-Key: eto_your_key\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/orders/12345678/sync\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.post(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/orders/12345678/sync\";\n\nconst response = await fetch(url, {\n  method: \"POST\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/finance/transactions": {
      "get": {
        "operationId": "shop_finance_transactions",
        "summary": "Get financial transactions",
        "description": "Get all financial transactions — charges, fees, refunds, and deposits. This is your shop's payment ledger. Etsy docs: \"Payment Account Ledger Entries\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/payment-account/ledger-entries`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/finances/shop-finance-transactions.md",
        "tags": [
          "Finances"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "min_created",
            "in": "query",
            "required": false,
            "description": "Earliest date (unix seconds)",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "max_created",
            "in": "query",
            "required": false,
            "description": "Latest date (unix seconds)",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Number of results (max 100)",
            "schema": {
              "type": "integer",
              "default": 25
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Pagination offset",
            "schema": {
              "type": "integer",
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/finances/shop-finance-transactions.md"
        },
        "x-eto-slug": "shop-finance-transactions",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "shop_finance_transactions",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/finance/transactions?limit=10\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/finance/transactions?limit=10\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/finance/transactions?limit=10\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/finance/payments": {
      "get": {
        "operationId": "shop_finance_payments",
        "summary": "Get payment details",
        "description": "Get detailed payment info for specific financial transactions. Etsy docs: \"Ledger Entry Payments\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/payment-account/ledger-entries/payments`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/finances/shop-finance-payments.md",
        "tags": [
          "Finances"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "transaction_ids",
            "in": "query",
            "required": true,
            "description": "Comma-separated transaction IDs",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/finances/shop-finance-payments.md"
        },
        "x-eto-slug": "shop-finance-payments",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "shop_finance_payments",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/finance/payments?transaction_ids=123,456\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/finance/payments?transaction_ids=123,456\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/finance/payments?transaction_ids=123,456\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/finance/sales": {
      "get": {
        "operationId": "shop_finance_sales",
        "summary": "Get sales history",
        "description": "Get individual sale records — each item sold, its price, and the buyer. Etsy docs: \"Shop Transactions\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/transactions`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/finances/shop-finance-sales.md",
        "tags": [
          "Finances"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Number of sales (max 100)",
            "schema": {
              "type": "integer",
              "default": 25
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Pagination offset",
            "schema": {
              "type": "integer",
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/finances/shop-finance-sales.md"
        },
        "x-eto-slug": "shop-finance-sales",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "shop_finance_sales",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/finance/sales?limit=10\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/finance/sales?limit=10\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/finance/sales?limit=10\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/listings/{listing_id}/sales": {
      "get": {
        "operationId": "listing_sales",
        "summary": "Get sales for a listing",
        "description": "Get all sale transactions for a specific listing. Etsy docs: \"Transactions By Listing\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/listings/{listing_id}/transactions`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/finances/listing-sales.md",
        "tags": [
          "Finances"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "listing_id",
            "in": "path",
            "required": true,
            "description": "The listing ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/finances/listing-sales.md"
        },
        "x-eto-slug": "listing-sales",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "listing_sales",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/sales\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/sales\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/listings/1234567890/sales\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/orders/{order_id}/transactions": {
      "get": {
        "operationId": "order_transactions",
        "summary": "Get transactions for an order",
        "description": "Get individual sale items within a specific order. Etsy docs: \"Transactions By Receipt\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/receipts/{order_id}/transactions`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/finances/order-transactions.md",
        "tags": [
          "Finances"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "order_id",
            "in": "path",
            "required": true,
            "description": "The order ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/finances/order-transactions.md"
        },
        "x-eto-slug": "order-transactions",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "order_transactions",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/orders/3344556677/transactions\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/orders/3344556677/transactions\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/orders/3344556677/transactions\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/finance/sales/{transaction_id}": {
      "get": {
        "operationId": "single_transaction",
        "summary": "Get a single sale",
        "description": "Get details for one specific sale transaction. Etsy docs: \"Shop Receipt Transaction\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/transactions/{transaction_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/finances/single-transaction.md",
        "tags": [
          "Finances"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "transaction_id",
            "in": "path",
            "required": true,
            "description": "The transaction ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/finances/single-transaction.md"
        },
        "x-eto-slug": "single-transaction",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "single_transaction",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/finance/sales/4455667788\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/finance/sales/4455667788\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/finance/sales/4455667788\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/finance/transactions/{entry_id}": {
      "get": {
        "operationId": "single_ledger_entry",
        "summary": "Get a single financial transaction",
        "description": "Get details for one ledger entry. Etsy docs: \"Ledger Entry\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/payment-account/ledger-entries/{entry_id}`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/finances/single-ledger-entry.md",
        "tags": [
          "Finances"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "entry_id",
            "in": "path",
            "required": true,
            "description": "The ledger entry ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/finances/single-ledger-entry.md"
        },
        "x-eto-slug": "single-ledger-entry",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "single_ledger_entry",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/finance/transactions/9988776655\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/finance/transactions/9988776655\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/finance/transactions/9988776655\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/finance/all-payments": {
      "get": {
        "operationId": "shop_all_payments",
        "summary": "Get all payments",
        "description": "Get all payment records for your shop. Etsy docs: \"Shop Payments\".\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nProxied to the Etsy API at `/v3/application/shops/{shop_id}/payments`; fields Etsy returns are passed through untouched.\n\nFull documentation: https://eto.tools/dev/docs/finances/shop-all-payments.md",
        "tags": [
          "Finances"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "502": {
            "$ref": "#/components/responses/Error502"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/finances/shop-all-payments.md"
        },
        "x-eto-slug": "shop-all-payments",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "shop_all_payments",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/finance/all-payments\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/finance/all-payments\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/finance/all-payments\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/shops/{shop_id}/stats/traffic": {
      "get": {
        "operationId": "shop_traffic_stats",
        "summary": "Shop views & favorites (lifetime)",
        "description": "Lifetime VIEWS and FAVORITES aggregated across your active listings, plus a top-listings-by-views leaderboard, total, and average. NOTE: Etsy's public API does not expose day-by-day traffic (Stats are dashboard-only), so these are cumulative figures, not per-day. No date range needed.\n\nAuthentication: API key plus a connected store. Eto uses that store’s Etsy token, so the shop_id must belong to a store connected to your Eto account or the call answers 403 STORE_NOT_CONNECTED.\n\nFull documentation: https://eto.tools/dev/docs/analytics/shop-traffic-stats.md",
        "tags": [
          "Analytics"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Your Etsy shop ID",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "403": {
            "$ref": "#/components/responses/Error403"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          },
          "503": {
            "$ref": "#/components/responses/Error503"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/analytics/shop-traffic-stats.md"
        },
        "x-eto-slug": "shop-traffic-stats",
        "x-eto-auth": "oauth_owner",
        "x-eto-mcp-tool": "shop_traffic_stats",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -H \"X-Eto-API-Key: eto_your_key\" \"https://eto.tools/api/v1/shops/12345678/stats/traffic\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/shops/12345678/stats/traffic\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/shops/12345678/stats/traffic\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/stores": {
      "get": {
        "operationId": "stores_list",
        "summary": "List connected stores",
        "description": "List every Etsy store connected to your Eto account, with shop_id, name and basic status. Start here: the shop_id values are what every shop-scoped endpoint needs. `token_valid` false means the store is connected but its Etsy authorisation has lapsed, so shop-scoped calls will answer STORE_TOKEN_EXPIRED until it is reconnected. Verified against developer_api/views_stores.py.\n\nAuthentication: API key only. Reads or writes data Eto holds for your own account.\n\nFull documentation: https://eto.tools/dev/docs/stores/stores-list.md",
        "tags": [
          "Stores"
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "stores": [
                        {
                          "shop_id": "12345678",
                          "shop_name": "MyShop",
                          "is_connected": true,
                          "token_valid": true,
                          "connected_at": "2026-04-19T14:30:00+00:00"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/stores/stores-list.md"
        },
        "x-eto-slug": "stores-list",
        "x-eto-auth": "api_key",
        "x-eto-mcp-tool": "stores_list",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \"https://eto.tools/api/v1/stores\" \\\n  -H \"X-Eto-API-Key: eto_your_key\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/stores\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/stores\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/stores/{shop_id}": {
      "get": {
        "operationId": "store_detail",
        "summary": "Get a connected store",
        "description": "Get details for a single connected store you own.\n\nAuthentication: API key only. Reads or writes data Eto holds for your own account.\n\nFull documentation: https://eto.tools/dev/docs/stores/store-detail.md",
        "tags": [
          "Stores"
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "description": "Eto/Etsy shop id from /api/v1/stores",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/stores/store-detail.md"
        },
        "x-eto-slug": "store-detail",
        "x-eto-auth": "api_key",
        "x-eto-mcp-tool": "store_detail",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \"https://eto.tools/api/v1/stores/12345678\" \\\n  -H \"X-Eto-API-Key: eto_your_key\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/stores/12345678\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.get(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/stores/12345678\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/product-hunt": {
      "post": {
        "operationId": "product_hunt",
        "summary": "Run product research (Product Hunt)",
        "description": "Run the full Eto Product Hunt for a keyword — the exact same engine as the Product Hunt page: search Etsy -> POPULAR-NOW detection -> demand (units sold/24h) -> AI ranking.\n\nTHREE modes:\n  1. SEARCH = THE DEFAULT. Use this ANY time the user names a topic to research (\"research t-shirts, 100 products, optimized\"). Pass ONLY \"keyword\" + \"amount\" (+ optional \"max_listing_age\", \"optimized\", \"full_details\"). Eto does the whole pipeline and returns ranked products with real demand.\n  2. \"listing_ids\": ONLY when you ALREADY have specific Etsy listing ids to score.\n  3. \"listings\": ONLY when you already have full listing objects (Eto just adds demand).\n\nCRITICAL: for a topic search, do NOT first call listings_search and then pass its listing_ids here. That bypasses popular-now detection and demand comes back EMPTY (null). Just call SEARCH mode with the keyword and let Eto do it.\n\ndemand_24h (units sold in last 24h) is the popularity signal — only populated via the real pipeline (SEARCH mode, or popular listings). With \"optimized\" true, results are AI-ranked by opportunity and carry ai_score + ai_reason; otherwise sorted by demand. Send native JSON types (optimized true, not \"true\"); stringified values are tolerated. Note: Etsy calls may be billed against your plan usage.\n\nAuthentication: API key only. Reads or writes data Eto holds for your own account.\n\nFull documentation: https://eto.tools/dev/docs/research/product-hunt.md",
        "tags": [
          "Research"
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/research/product-hunt.md"
        },
        "x-eto-slug": "product-hunt",
        "x-eto-auth": "api_key",
        "x-eto-mcp-tool": "product_hunt",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \"https://eto.tools/api/v1/product-hunt\" \\\n  -H \"X-Eto-API-Key: eto_your_key\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"keyword\": \"leather wallet\"\n}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/product-hunt\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\npayload = {\n    \"keyword\": \"leather wallet\"\n}\n\nresponse = requests.post(url, headers=headers, json=payload, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/product-hunt\";\nconst payload = {\n  \"keyword\": \"leather wallet\"\n};\n\nconst response = await fetch(url, {\n  method: \"POST\",\n  body: JSON.stringify(payload),\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n    \"Content-Type\": \"application/json\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "keyword": {
                    "type": "string",
                    "description": "Search term / keyword (max 200 chars)."
                  },
                  "amount": {
                    "type": "integer",
                    "description": "SEARCH mode: how many products to fetch & rank (1-8000, default 50). Large amounts take longer — demand extraction is heavy."
                  },
                  "max_listing_age": {
                    "type": "integer",
                    "description": "SEARCH mode: only listings created within the last N months (0 or omit = no limit, max 60)."
                  },
                  "optimized": {
                    "type": "boolean",
                    "description": "SEARCH mode: AI-powered filtering & ranking. When true, results carry ai_score + ai_reason and full_details is ignored."
                  },
                  "full_details": {
                    "type": "boolean",
                    "description": "SEARCH mode (only when optimized is false): true returns full per-listing details; false returns listing_id + demand only (lightest)."
                  },
                  "listing_ids": {
                    "type": "array",
                    "items": {},
                    "description": "Array of Etsy listing ids (integers). Use instead of a keyword search."
                  },
                  "listings": {
                    "type": "array",
                    "items": {},
                    "description": "Array of listing objects you already have. Eto just adds demand."
                  }
                },
                "required": [
                  "keyword"
                ]
              },
              "examples": {
                "default": {
                  "summary": "A complete request body",
                  "value": {
                    "keyword": "leather wallet"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/ai/chat": {
      "post": {
        "operationId": "ai_chat",
        "summary": "AI chat",
        "description": "Free-form AI chat using your configured Gemini credentials. Requires AI credentials configured in Eto settings.\n\nAuthentication: API key only. Reads or writes data Eto holds for your own account.\n\nFull documentation: https://eto.tools/dev/docs/ai-studio/ai-chat.md",
        "tags": [
          "AI Studio"
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/ai-studio/ai-chat.md"
        },
        "x-eto-slug": "ai-chat",
        "x-eto-auth": "api_key",
        "x-eto-mcp-tool": "ai_chat",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \"https://eto.tools/api/v1/ai/chat\" \\\n  -H \"X-Eto-API-Key: eto_your_key\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"message\": \"Suggest three tag ideas for a leather wallet listing.\"\n}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/ai/chat\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\npayload = {\n    \"message\": \"Suggest three tag ideas for a leather wallet listing.\"\n}\n\nresponse = requests.post(url, headers=headers, json=payload, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/ai/chat\";\nconst payload = {\n  \"message\": \"Suggest three tag ideas for a leather wallet listing.\"\n};\n\nconst response = await fetch(url, {\n  method: \"POST\",\n  body: JSON.stringify(payload),\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n    \"Content-Type\": \"application/json\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "message": {
                    "type": "string",
                    "description": "The user message / prompt"
                  },
                  "context": {
                    "type": "object",
                    "description": "Optional context object merged into the prompt"
                  }
                },
                "required": [
                  "message"
                ]
              },
              "examples": {
                "default": {
                  "summary": "A complete request body",
                  "value": {
                    "message": "Suggest three tag ideas for a leather wallet listing."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/ai/generate-title": {
      "post": {
        "operationId": "ai_generate_title",
        "summary": "AI: generate a listing title",
        "description": "Generate an Etsy listing title for a keyword.\n\nAuthentication: API key only. Reads or writes data Eto holds for your own account.\n\nFull documentation: https://eto.tools/dev/docs/ai-studio/ai-generate-title.md",
        "tags": [
          "AI Studio"
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/ai-studio/ai-generate-title.md"
        },
        "x-eto-slug": "ai-generate-title",
        "x-eto-auth": "api_key",
        "x-eto-mcp-tool": "ai_generate_title",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \"https://eto.tools/api/v1/ai/generate-title\" \\\n  -H \"X-Eto-API-Key: eto_your_key\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"keyword\": \"leather wallet\"\n}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/ai/generate-title\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\npayload = {\n    \"keyword\": \"leather wallet\"\n}\n\nresponse = requests.post(url, headers=headers, json=payload, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/ai/generate-title\";\nconst payload = {\n  \"keyword\": \"leather wallet\"\n};\n\nconst response = await fetch(url, {\n  method: \"POST\",\n  body: JSON.stringify(payload),\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n    \"Content-Type\": \"application/json\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "keyword": {
                    "type": "string",
                    "description": "Target keyword"
                  },
                  "product_description": {
                    "type": "string",
                    "description": "Optional product description for context"
                  },
                  "style": {
                    "type": "string",
                    "description": "Tone/style (default \"professional\")"
                  },
                  "max_length": {
                    "type": "integer",
                    "description": "Max title length (capped at 200, default 140)"
                  }
                },
                "required": [
                  "keyword"
                ]
              },
              "examples": {
                "default": {
                  "summary": "A complete request body",
                  "value": {
                    "keyword": "leather wallet"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/ai/generate-description": {
      "post": {
        "operationId": "ai_generate_description",
        "summary": "AI: generate a listing description",
        "description": "Generate an Etsy listing description. Provide at least one of \"keyword\" or \"title\".\n\nAuthentication: API key only. Reads or writes data Eto holds for your own account.\n\nFull documentation: https://eto.tools/dev/docs/ai-studio/ai-generate-description.md",
        "tags": [
          "AI Studio"
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/ai-studio/ai-generate-description.md"
        },
        "x-eto-slug": "ai-generate-description",
        "x-eto-auth": "api_key",
        "x-eto-mcp-tool": "ai_generate_description",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \"https://eto.tools/api/v1/ai/generate-description\" \\\n  -H \"X-Eto-API-Key: eto_your_key\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/ai/generate-description\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.post(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/ai/generate-description\";\n\nconst response = await fetch(url, {\n  method: \"POST\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "keyword": {
                    "type": "string",
                    "description": "Target keyword (keyword or title required)"
                  },
                  "title": {
                    "type": "string",
                    "description": "Listing title (keyword or title required)"
                  },
                  "features": {
                    "type": "array",
                    "items": {},
                    "description": "Array of product feature strings"
                  },
                  "tone": {
                    "type": "string",
                    "description": "Tone (default \"professional\")"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/ai/generate-image": {
      "post": {
        "operationId": "ai_generate_image",
        "summary": "AI: generate an image (async)",
        "description": "Start an AI image generation job from a text prompt. Returns a job_id; poll ai_generate_image_status for the result.\n\nAuthentication: API key only. Reads or writes data Eto holds for your own account.\n\nFull documentation: https://eto.tools/dev/docs/ai-studio/ai-generate-image.md",
        "tags": [
          "AI Studio"
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/ai-studio/ai-generate-image.md"
        },
        "x-eto-slug": "ai-generate-image",
        "x-eto-auth": "api_key",
        "x-eto-mcp-tool": "ai_generate_image",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \"https://eto.tools/api/v1/ai/generate-image\" \\\n  -H \"X-Eto-API-Key: eto_your_key\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"prompt\": \"A leather wallet on a walnut desk, soft daylight\"\n}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/ai/generate-image\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\npayload = {\n    \"prompt\": \"A leather wallet on a walnut desk, soft daylight\"\n}\n\nresponse = requests.post(url, headers=headers, json=payload, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/ai/generate-image\";\nconst payload = {\n  \"prompt\": \"A leather wallet on a walnut desk, soft daylight\"\n};\n\nconst response = await fetch(url, {\n  method: \"POST\",\n  body: JSON.stringify(payload),\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n    \"Content-Type\": \"application/json\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "prompt": {
                    "type": "string",
                    "description": "Image prompt"
                  }
                },
                "required": [
                  "prompt"
                ]
              },
              "examples": {
                "default": {
                  "summary": "A complete request body",
                  "value": {
                    "prompt": "A leather wallet on a walnut desk, soft daylight"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/ai/generate-image/status": {
      "get": {
        "operationId": "ai_generate_image_status",
        "summary": "AI: image generation status",
        "description": "Poll the status/result of an AI image generation job.\n\nAuthentication: API key only. Reads or writes data Eto holds for your own account.\n\nFull documentation: https://eto.tools/dev/docs/ai-studio/ai-generate-image-status.md",
        "tags": [
          "AI Studio"
        ],
        "parameters": [
          {
            "name": "job_id",
            "in": "query",
            "required": true,
            "description": "Job id returned by ai_generate_image",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/ai-studio/ai-generate-image-status.md"
        },
        "x-eto-slug": "ai-generate-image-status",
        "x-eto-auth": "api_key",
        "x-eto-mcp-tool": "ai_generate_image_status",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \"https://eto.tools/api/v1/ai/generate-image/status?job_id=job_9f2c41d8\" \\\n  -H \"X-Eto-API-Key: eto_your_key\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/ai/generate-image/status\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\nparams = {\n    \"job_id\": \"job_9f2c41d8\"\n}\n\nresponse = requests.get(url, headers=headers, params=params, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/ai/generate-image/status?job_id=job_9f2c41d8\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/ai/analyze-image": {
      "post": {
        "operationId": "ai_analyze_image",
        "summary": "AI: analyze a product image",
        "description": "Analyze a product image and return a description suitable for an Etsy listing.\n\nAuthentication: API key only. Reads or writes data Eto holds for your own account.\n\nFull documentation: https://eto.tools/dev/docs/ai-studio/ai-analyze-image.md",
        "tags": [
          "AI Studio"
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/ai-studio/ai-analyze-image.md"
        },
        "x-eto-slug": "ai-analyze-image",
        "x-eto-auth": "api_key",
        "x-eto-mcp-tool": "ai_analyze_image",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \"https://eto.tools/api/v1/ai/analyze-image\" \\\n  -H \"X-Eto-API-Key: eto_your_key\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n  \"image\": {}\n}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/ai/analyze-image\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\npayload = {\n    \"image\": {}\n}\n\nresponse = requests.post(url, headers=headers, json=payload, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/ai/analyze-image\";\nconst payload = {\n  \"image\": {}\n};\n\nconst response = await fetch(url, {\n  method: \"POST\",\n  body: JSON.stringify(payload),\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n    \"Content-Type\": \"application/json\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "image": {
                    "type": "object",
                    "description": "Object with \"data\" (base64) and \"mimeType\" (e.g. image/png)"
                  },
                  "prompt": {
                    "type": "string",
                    "description": "Optional instruction (default describes the product image)"
                  }
                },
                "required": [
                  "image"
                ]
              },
              "examples": {
                "default": {
                  "summary": "A complete request body",
                  "value": {
                    "image": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/webhooks/deliveries": {
      "get": {
        "operationId": "webhooks_deliveries",
        "summary": "List webhook deliveries",
        "description": "List recent outbound webhook deliveries from your Eto account, newest first. Pass `id` to fetch one delivery on its own, which is the only form that includes the full payload Eto sent. Verified against developer_api/webhook_views.py.\n\nAuthentication: API key only. Reads or writes data Eto holds for your own account.\n\nFull documentation: https://eto.tools/dev/docs/webhooks/webhooks-deliveries.md",
        "tags": [
          "Webhooks"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": false,
            "description": "Fetch this one delivery instead of a page, including its full payload. Ids come from the `deliveries[].id` field of a list call.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only deliveries in this state. Any other value is ignored.",
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "success",
                "failed"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size. Values above 100 are clamped. Constraints: max 100.",
            "schema": {
              "type": "integer",
              "default": 25,
              "description": "max 100"
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Pagination offset.",
            "schema": {
              "type": "integer",
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "success": true,
                      "total": 128,
                      "limit": 25,
                      "offset": 0,
                      "deliveries": [
                        {
                          "id": 8842,
                          "event_type": "order.paid",
                          "status": "success",
                          "response_status_code": 200
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/webhooks/webhooks-deliveries.md"
        },
        "x-eto-slug": "webhooks-deliveries",
        "x-eto-auth": "api_key",
        "x-eto-mcp-tool": "webhooks_deliveries",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X GET \"https://eto.tools/api/v1/webhooks/deliveries?id=1&status=pending\" \\\n  -H \"X-Eto-API-Key: eto_your_key\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/webhooks/deliveries\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\nparams = {\n    \"id\": 1,\n    \"status\": \"pending\"\n}\n\nresponse = requests.get(url, headers=headers, params=params, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/webhooks/deliveries?id=1&status=pending\";\n\nconst response = await fetch(url, {\n  method: \"GET\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    },
    "/api/v1/webhooks/deliveries/{delivery_id}/retry": {
      "post": {
        "operationId": "webhook_delivery_retry",
        "summary": "Re-send one webhook delivery",
        "description": "Re-deliver exactly one past webhook delivery — the single delivery_id you pass — to your currently configured URL, and return the new outcome (success, response_status_code, error). It never re-sends anything else. Find delivery ids with GET /api/v1/webhooks/deliveries.\n\nAuthentication: API key only. Reads or writes data Eto holds for your own account.\n\nFull documentation: https://eto.tools/dev/docs/webhooks/webhook-delivery-retry.md",
        "tags": [
          "Webhooks"
        ],
        "parameters": [
          {
            "name": "delivery_id",
            "in": "path",
            "required": true,
            "description": "Id of the delivery to re-send, from GET /api/v1/webhooks/deliveries.",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-RateLimit-Limit-Second": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Second"
              },
              "X-RateLimit-Remaining-Second": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Second"
              },
              "X-RateLimit-Limit-Day": {
                "$ref": "#/components/headers/X-RateLimit-Limit-Day"
              },
              "X-RateLimit-Remaining-Day": {
                "$ref": "#/components/headers/X-RateLimit-Remaining-Day"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error400"
          },
          "401": {
            "$ref": "#/components/responses/Error401"
          },
          "404": {
            "$ref": "#/components/responses/Error404"
          },
          "429": {
            "$ref": "#/components/responses/Error429"
          },
          "500": {
            "$ref": "#/components/responses/Error500"
          }
        },
        "externalDocs": {
          "description": "This endpoint as Markdown",
          "url": "https://eto.tools/dev/docs/webhooks/webhook-delivery-retry.md"
        },
        "x-eto-slug": "webhook-delivery-retry",
        "x-eto-auth": "api_key",
        "x-eto-mcp-tool": "webhook_delivery_retry",
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "curl",
            "source": "curl -X POST \"https://eto.tools/api/v1/webhooks/deliveries/8842/retry\" \\\n  -H \"X-Eto-API-Key: eto_your_key\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import requests\n\nurl = \"https://eto.tools/api/v1/webhooks/deliveries/8842/retry\"\nheaders = {\"X-Eto-API-Key\": \"eto_your_key\"}\n\nresponse = requests.post(url, headers=headers, timeout=120)\nresponse.raise_for_status()\nprint(response.json())"
          },
          {
            "lang": "javascript",
            "label": "JavaScript",
            "source": "const url = \"https://eto.tools/api/v1/webhooks/deliveries/8842/retry\";\n\nconst response = await fetch(url, {\n  method: \"POST\",\n  headers: {\n    \"X-Eto-API-Key\": \"eto_your_key\",\n  },\n});\nif (!response.ok) throw new Error(`Eto API ${response.status}`);\nconst data = await response.json();"
          }
        ]
      }
    }
  },
  "webhooks": {
    "order.paid": {
      "post": {
        "operationId": "webhook_order_paid",
        "summary": "The buyer completed payment for the order.",
        "description": "The buyer completed payment for the order. Eto POSTs this to the URL configured in the API console. Headers: X-Eto-Event, X-Eto-Webhook-Id, X-Eto-Timestamp, X-Eto-Signature. De-duplicate on X-Eto-Webhook-Id and answer 2xx quickly; a non-2xx is retried.",
        "tags": [
          "Webhooks"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "event",
                  "event_id",
                  "sent_at",
                  "shop",
                  "order"
                ],
                "properties": {
                  "event": {
                    "type": "string",
                    "const": "order.paid"
                  },
                  "event_description": {
                    "type": "string"
                  },
                  "event_id": {
                    "type": "string",
                    "description": "Unique delivery id, e.g. evt_8842."
                  },
                  "source_webhook_id": {
                    "type": "string"
                  },
                  "sent_at": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "shop": {
                    "type": "object",
                    "additionalProperties": true
                  },
                  "order": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Every detail Eto holds for the receipt: buyer, address, amounts, items, shipments."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Delivery accepted. Anything else is retried."
          }
        }
      }
    },
    "order.shipped": {
      "post": {
        "operationId": "webhook_order_shipped",
        "summary": "Shipping information was created, or the order was marked shipped.",
        "description": "Shipping information was created, or the order was marked shipped. Eto POSTs this to the URL configured in the API console. Headers: X-Eto-Event, X-Eto-Webhook-Id, X-Eto-Timestamp, X-Eto-Signature. De-duplicate on X-Eto-Webhook-Id and answer 2xx quickly; a non-2xx is retried.",
        "tags": [
          "Webhooks"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "event",
                  "event_id",
                  "sent_at",
                  "shop",
                  "order"
                ],
                "properties": {
                  "event": {
                    "type": "string",
                    "const": "order.shipped"
                  },
                  "event_description": {
                    "type": "string"
                  },
                  "event_id": {
                    "type": "string",
                    "description": "Unique delivery id, e.g. evt_8842."
                  },
                  "source_webhook_id": {
                    "type": "string"
                  },
                  "sent_at": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "shop": {
                    "type": "object",
                    "additionalProperties": true
                  },
                  "order": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Every detail Eto holds for the receipt: buyer, address, amounts, items, shipments."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Delivery accepted. Anything else is retried."
          }
        }
      }
    },
    "order.canceled": {
      "post": {
        "operationId": "webhook_order_canceled",
        "summary": "The seller canceled the order.",
        "description": "The seller canceled the order. Eto POSTs this to the URL configured in the API console. Headers: X-Eto-Event, X-Eto-Webhook-Id, X-Eto-Timestamp, X-Eto-Signature. De-duplicate on X-Eto-Webhook-Id and answer 2xx quickly; a non-2xx is retried.",
        "tags": [
          "Webhooks"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "event",
                  "event_id",
                  "sent_at",
                  "shop",
                  "order"
                ],
                "properties": {
                  "event": {
                    "type": "string",
                    "const": "order.canceled"
                  },
                  "event_description": {
                    "type": "string"
                  },
                  "event_id": {
                    "type": "string",
                    "description": "Unique delivery id, e.g. evt_8842."
                  },
                  "source_webhook_id": {
                    "type": "string"
                  },
                  "sent_at": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "shop": {
                    "type": "object",
                    "additionalProperties": true
                  },
                  "order": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Every detail Eto holds for the receipt: buyer, address, amounts, items, shipments."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Delivery accepted. Anything else is retried."
          }
        }
      }
    },
    "order.delivered": {
      "post": {
        "operationId": "webhook_order_delivered",
        "summary": "The order was marked delivered.",
        "description": "The order was marked delivered. Eto POSTs this to the URL configured in the API console. Headers: X-Eto-Event, X-Eto-Webhook-Id, X-Eto-Timestamp, X-Eto-Signature. De-duplicate on X-Eto-Webhook-Id and answer 2xx quickly; a non-2xx is retried.",
        "tags": [
          "Webhooks"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "event",
                  "event_id",
                  "sent_at",
                  "shop",
                  "order"
                ],
                "properties": {
                  "event": {
                    "type": "string",
                    "const": "order.delivered"
                  },
                  "event_description": {
                    "type": "string"
                  },
                  "event_id": {
                    "type": "string",
                    "description": "Unique delivery id, e.g. evt_8842."
                  },
                  "source_webhook_id": {
                    "type": "string"
                  },
                  "sent_at": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "shop": {
                    "type": "object",
                    "additionalProperties": true
                  },
                  "order": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Every detail Eto holds for the receipt: buyer, address, amounts, items, shipments."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Delivery accepted. Anything else is retried."
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Error": {
        "type": "object",
        "description": "Every failure answers with this shape. Branch on `error.code`; the message and hint are written for people and may be reworded.",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "status",
              "message"
            ],
            "properties": {
              "code": {
                "$ref": "#/components/schemas/ErrorCode"
              },
              "status": {
                "type": "integer",
                "description": "Repeats the HTTP status."
              },
              "message": {
                "type": "string",
                "description": "One sentence for a person."
              },
              "hint": {
                "type": "string",
                "description": "What to do about it."
              },
              "docs": {
                "type": "string",
                "format": "uri",
                "description": "Link to the relevant documentation section."
              },
              "fields": {
                "type": "object",
                "description": "VALIDATION_FAILED only: the per-field problems.",
                "additionalProperties": true
              },
              "upstream": {
                "description": "UPSTREAM_ERROR only: the marketplace’s own response."
              }
            }
          }
        }
      },
      "ErrorCode": {
        "type": "string",
        "description": "Stable, machine-readable error identifier.",
        "enum": [
          "ACTIVATION_COST_WARNING",
          "AGENT_BUSY",
          "AI_CREDENTIALS_MISSING",
          "AI_GENERATION_FAILED",
          "DELIVERY_NOT_FOUND",
          "ENDPOINT_NOT_FOUND",
          "FINANCE_NO_DATA",
          "INVALID_API_KEY",
          "INVALID_REQUEST",
          "JOB_NOT_FOUND",
          "METHOD_NOT_ALLOWED",
          "RATE_LIMIT_DAILY",
          "RATE_LIMIT_SECOND",
          "SESSION_NOT_FOUND",
          "STORE_NOT_CONNECTED",
          "STORE_NOT_OWNED",
          "STORE_TOKEN_EXPIRED",
          "TAXONOMY_INVALID",
          "UPSTREAM_ERROR",
          "VALIDATION_FAILED"
        ]
      }
    },
    "responses": {
      "Error400": {
        "description": "Bad request. Possible codes: `INVALID_REQUEST`, `VALIDATION_FAILED`, `TAXONOMY_INVALID`.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "INVALID_REQUEST": {
                "summary": "Request validation failed.",
                "value": {
                  "error": {
                    "code": "INVALID_REQUEST",
                    "status": 400,
                    "message": "Request validation failed.",
                    "hint": "the specific reason, filled in per request",
                    "docs": "https://eto.tools/dev/docs#errors"
                  }
                }
              },
              "VALIDATION_FAILED": {
                "summary": "Request validation failed.",
                "value": {
                  "error": {
                    "code": "VALIDATION_FAILED",
                    "status": 400,
                    "message": "Request validation failed.",
                    "hint": "Check the fields object for specific issues.",
                    "docs": "https://eto.tools/dev/docs#listing-create"
                  }
                }
              },
              "TAXONOMY_INVALID": {
                "summary": "The provided taxonomy_id is not a valid Etsy category.",
                "value": {
                  "error": {
                    "code": "TAXONOMY_INVALID",
                    "status": 400,
                    "message": "The provided taxonomy_id is not a valid Etsy category.",
                    "hint": "Use GET /api/v1/categories/{id}/listing-schema to find valid categories.",
                    "docs": "https://eto.tools/dev/docs#listing-create"
                  }
                }
              }
            }
          }
        }
      },
      "Error401": {
        "description": "Unauthenticated. Possible codes: `INVALID_API_KEY`.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "INVALID_API_KEY": {
                "summary": "Your API key is missing, invalid, or has been revoked.",
                "value": {
                  "error": {
                    "code": "INVALID_API_KEY",
                    "status": 401,
                    "message": "Your API key is missing, invalid, or has been revoked.",
                    "hint": "Generate a new key in the API console at eto.tools/dashboard/api.",
                    "docs": "https://eto.tools/dev/docs#authentication"
                  }
                }
              }
            }
          }
        }
      },
      "Error403": {
        "description": "Forbidden. Possible codes: `STORE_NOT_CONNECTED`, `AI_CREDENTIALS_MISSING`, `STORE_NOT_OWNED`.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "STORE_NOT_CONNECTED": {
                "summary": "You don't have access to this store.",
                "value": {
                  "error": {
                    "code": "STORE_NOT_CONNECTED",
                    "status": 403,
                    "message": "You don't have access to this store.",
                    "hint": "Connect the store at eto.tools/dashboard first.",
                    "docs": "https://eto.tools/dev/docs#store-connection"
                  }
                }
              },
              "AI_CREDENTIALS_MISSING": {
                "summary": "No AI credentials configured.",
                "value": {
                  "error": {
                    "code": "AI_CREDENTIALS_MISSING",
                    "status": 403,
                    "message": "No AI credentials configured.",
                    "hint": "Add your Gemini API key at eto.tools/settings.",
                    "docs": "https://eto.tools/dev/docs#ai-studio"
                  }
                }
              },
              "STORE_NOT_OWNED": {
                "summary": "One or more shop_ids are not connected to your ETO account.",
                "value": {
                  "error": {
                    "code": "STORE_NOT_OWNED",
                    "status": 403,
                    "message": "One or more shop_ids are not connected to your ETO account.",
                    "hint": "Use GET /api/v1/stores to see your connected shops. Connect new stores at eto.tools/dashboard.",
                    "docs": "https://eto.tools/dev/docs#listing-create"
                  }
                }
              }
            }
          }
        }
      },
      "Error404": {
        "description": "Not found. Possible codes: `ENDPOINT_NOT_FOUND`, `SESSION_NOT_FOUND`, `JOB_NOT_FOUND`, `DELIVERY_NOT_FOUND`, `FINANCE_NO_DATA`.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "ENDPOINT_NOT_FOUND": {
                "summary": "This endpoint doesn't exist.",
                "value": {
                  "error": {
                    "code": "ENDPOINT_NOT_FOUND",
                    "status": 404,
                    "message": "This endpoint doesn't exist.",
                    "hint": "Check the path and method against the docs.",
                    "docs": "https://eto.tools/dev/docs#endpoints"
                  }
                }
              },
              "SESSION_NOT_FOUND": {
                "summary": "Research session not found.",
                "value": {
                  "error": {
                    "code": "SESSION_NOT_FOUND",
                    "status": 404,
                    "message": "Research session not found.",
                    "hint": "Check the session ID.",
                    "docs": "https://eto.tools/dev/docs#product-research"
                  }
                }
              },
              "JOB_NOT_FOUND": {
                "summary": "Listing creation job not found.",
                "value": {
                  "error": {
                    "code": "JOB_NOT_FOUND",
                    "status": 404,
                    "message": "Listing creation job not found.",
                    "hint": "Check the job_id. Jobs expire after 24 hours.",
                    "docs": "https://eto.tools/dev/docs#listing-create"
                  }
                }
              },
              "DELIVERY_NOT_FOUND": {
                "summary": "Webhook delivery not found.",
                "value": {
                  "error": {
                    "code": "DELIVERY_NOT_FOUND",
                    "status": 404,
                    "message": "Webhook delivery not found.",
                    "hint": "Check the delivery id. List recent deliveries with GET /api/v1/webhooks/deliveries.",
                    "docs": "https://eto.tools/dev/docs#webhooks"
                  }
                }
              },
              "FINANCE_NO_DATA": {
                "summary": "No finance data available for this store in the requested range.",
                "value": {
                  "error": {
                    "code": "FINANCE_NO_DATA",
                    "status": 404,
                    "message": "No finance data available for this store in the requested range.",
                    "hint": "Visit the Eto Finance dashboard to sync your store data, or adjust your date range.",
                    "docs": "https://eto.tools/dev/docs#finance"
                  }
                }
              }
            }
          }
        }
      },
      "Error405": {
        "description": "Method not allowed. Possible codes: `METHOD_NOT_ALLOWED`.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "METHOD_NOT_ALLOWED": {
                "summary": "This HTTP method isn't supported on this endpoint.",
                "value": {
                  "error": {
                    "code": "METHOD_NOT_ALLOWED",
                    "status": 405,
                    "message": "This HTTP method isn't supported on this endpoint.",
                    "hint": "Allowed methods: the methods this path accepts",
                    "docs": "https://eto.tools/dev/docs#endpoints"
                  }
                }
              }
            }
          }
        }
      },
      "Error409": {
        "description": "Conflict. Possible codes: `AGENT_BUSY`.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "AGENT_BUSY": {
                "summary": "An agent process is already running for this session.",
                "value": {
                  "error": {
                    "code": "AGENT_BUSY",
                    "status": 409,
                    "message": "An agent process is already running for this session.",
                    "hint": "Wait for it to complete or cancel it.",
                    "docs": "https://eto.tools/dev/docs#product-research"
                  }
                }
              }
            }
          }
        }
      },
      "Error429": {
        "description": "Rate limited. Possible codes: `RATE_LIMIT_SECOND`, `RATE_LIMIT_DAILY`.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "RATE_LIMIT_SECOND": {
                "summary": "Rate limit exceeded (2 requests/second).",
                "value": {
                  "error": {
                    "code": "RATE_LIMIT_SECOND",
                    "status": 429,
                    "message": "Rate limit exceeded (2 requests/second).",
                    "hint": "Wait the number of seconds in the Retry-After headers before retrying.",
                    "docs": "https://eto.tools/dev/docs#rate-limits"
                  }
                }
              },
              "RATE_LIMIT_DAILY": {
                "summary": "Daily request limit reached (5,000/day).",
                "value": {
                  "error": {
                    "code": "RATE_LIMIT_DAILY",
                    "status": 429,
                    "message": "Daily request limit reached (5,000/day).",
                    "hint": "Limit resets at midnight UTC.",
                    "docs": "https://eto.tools/dev/docs#rate-limits"
                  }
                }
              }
            }
          }
        },
        "headers": {
          "Retry-After": {
            "$ref": "#/components/headers/Retry-After"
          }
        }
      },
      "Error500": {
        "description": "Internal error. An unexpected failure. The body still uses the shared error shape.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Error502": {
        "description": "Upstream error. Possible codes: `UPSTREAM_ERROR`, `AI_GENERATION_FAILED`.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "UPSTREAM_ERROR": {
                "summary": "The upstream service returned an error.",
                "value": {
                  "error": {
                    "code": "UPSTREAM_ERROR",
                    "status": 502,
                    "message": "The upstream service returned an error.",
                    "hint": "Check the upstream field for the marketplace’s own response.",
                    "docs": "https://eto.tools/dev/docs#errors"
                  }
                }
              },
              "AI_GENERATION_FAILED": {
                "summary": "Image/text generation failed.",
                "value": {
                  "error": {
                    "code": "AI_GENERATION_FAILED",
                    "status": 502,
                    "message": "Image/text generation failed.",
                    "hint": "the specific reason, filled in per request",
                    "docs": "https://eto.tools/dev/docs#ai-studio"
                  }
                }
              }
            }
          }
        }
      },
      "Error503": {
        "description": "Service unavailable. Possible codes: `STORE_TOKEN_EXPIRED`.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "examples": {
              "STORE_TOKEN_EXPIRED": {
                "summary": "Store authorization has expired.",
                "value": {
                  "error": {
                    "code": "STORE_TOKEN_EXPIRED",
                    "status": 503,
                    "message": "Store authorization has expired.",
                    "hint": "Reconnect your store at eto.tools/dashboard.",
                    "docs": "https://eto.tools/dev/docs#store-connection"
                  }
                }
              }
            }
          }
        }
      }
    },
    "headers": {
      "X-RateLimit-Limit-Second": {
        "description": "The per-second ceiling (always 2).",
        "schema": {
          "type": "integer"
        }
      },
      "X-RateLimit-Remaining-Second": {
        "description": "Requests left in the current second.",
        "schema": {
          "type": "integer"
        }
      },
      "X-RateLimit-Limit-Day": {
        "description": "The daily ceiling (always 5000).",
        "schema": {
          "type": "integer"
        }
      },
      "X-RateLimit-Remaining-Day": {
        "description": "Requests left today. Resets at midnight UTC.",
        "schema": {
          "type": "integer"
        }
      },
      "Retry-After": {
        "description": "On a 429 only: seconds to wait before retrying.",
        "schema": {
          "type": "integer"
        }
      }
    },
    "securitySchemes": {
      "EtoApiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Eto-API-Key",
        "description": "An Eto API key, generated in the API console at https://eto.tools/dashboard/api/. The API is an Enterprise feature."
      },
      "EtoBearer": {
        "type": "http",
        "scheme": "bearer",
        "description": "An OAuth 2.1 access token from the \"log in with Eto\" flow that MCP clients use. Accepted anywhere the API key is."
      }
    }
  }
}