{
  "openapi": "3.0.1",
  "info": {
    "title": "eBay Sold Listings Comps AI: Price Checker & Max Buy Price",
    "description": "First 25 comps free. eBay sold listings cleaned into exact-match comps: for-parts, lots, accessories and outliers removed, AI-matched to your item, plus the median and max buy price. Pay per clean comp, junk never charged. Free demo on any plan; live search runs on your own Apify account.",
    "version": "0.3",
    "x-build-id": "dOqigWSpK4QlDRIPY"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/rich_minds~ebay-sold-comps-ai/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-rich_minds-ebay-sold-comps-ai",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/acts/rich_minds~ebay-sold-comps-ai/runs": {
      "post": {
        "operationId": "runs-sync-rich_minds-ebay-sold-comps-ai",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor and returns information about the initiated run in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/runsResponseSchema"
                }
              }
            }
          }
        }
      }
    },
    "/acts/rich_minds~ebay-sold-comps-ai/run-sync": {
      "post": {
        "operationId": "run-sync-rich_minds-ebay-sold-comps-ai",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "inputSchema": {
        "type": "object",
        "required": [
          "sourceMode"
        ],
        "properties": {
          "keywords": {
            "title": "eBay search keywords (1–6)",
            "type": "array",
            "description": "The item you price, one keyword per line, e.g. <code>nintendo switch oled</code> or <code>iphone 13 pro 128gb</code> — one price report each. The live search runs eBay Sold Listings Search on your Apify plan (no Store Actors on your plan? use a dataset). The free demo does not search it; typing a keyword starts the live search.",
            "items": {
              "type": "string"
            }
          },
          "sourceMode": {
            "title": "Where do the sold listings come from?",
            "enum": [
              "actor",
              "dataset",
              "list"
            ],
            "type": "string",
            "description": "<b>Search eBay live</b> for the keywords above (rows billed by eBay Sold Listings Search, capped by <b>Max source spend</b>), clean an existing <b>dataset</b>, or paste a <b>list</b> of sold rows. With nothing to search (<code>{}</code>) the free demo runs on 16 sample sold listings — nothing charged.",
            "default": "actor"
          },
          "minScore": {
            "title": "Minimum match score (0–100)",
            "minimum": 0,
            "maximum": 100,
            "type": "integer",
            "description": "The field that decides what you pay: sales whose match to your item scores below this are rejected and <b>not charged</b>. 70 keeps exact matches; raise it to 85 for only sure ones. Rules cap at 95; 96–100 needs the AI's exact verdict.",
            "default": 70
          },
          "itemDescription": {
            "title": "Your exact item, in words (for the AI)",
            "type": "string",
            "description": "Describe the exact item — model, storage, colour, condition — e.g. <i>iPhone 13 Pro Max 128GB unlocked, working</i>. The AI match check compares every borderline sale with it. Leave empty to match on the keywords only."
          },
          "maxQualified": {
            "title": "Max comps to deliver",
            "minimum": 1,
            "maximum": 10000,
            "type": "integer",
            "description": "Hard cap on the comps pushed and on what <b>this Actor</b> charges: at most this many × $0.01 with AI on (× $0.005 off), e.g. 200 × $0.01 = $2.00. The price report always uses every clean comp. Best matches first.",
            "default": 200
          },
          "maxDiscoveryChargeUsd": {
            "title": "Max source spend (USD)",
            "minimum": 0.01,
            "maximum": 1000,
            "type": "number",
            "description": "Hard cap on what the eBay search may charge your account ($0.004 per sold row, so 1 keyword × 100 rows ≈ $0.40) — $0.50 in the form and for API calls that leave it out. Raise it for more keywords.",
            "default": 0.5
          },
          "enableAi": {
            "title": "AI match check",
            "type": "boolean",
            "description": "Checks every borderline sale against your exact item (verdict, confidence, model / storage / colour), lists the defects the listing admits and writes the report summary. <b>On = $0.01 per AI-checked comp + AI tokens; off = $0.005</b> (rule match only). Clear matches stay at the basic price.",
            "default": true
          },
          "notifyEmail": {
            "title": "E-mail me the price report (optional)",
            "type": "string",
            "description": "After every run with new comps or a price report, the digest (median, band, list and max-buy price per keyword, change vs last run, the new comps with links) is e-mailed here. Schedule the run weekly and it lands in your inbox. Never sent for the free demo."
          },
          "mustInclude": {
            "title": "Must include (every term)",
            "type": "array",
            "description": "Terms every matching title must contain, number-aware: <code>128gb</code> matches \"128 GB\". A sale missing one is capped at score 40 — rejected unless the AI confirms it.",
            "items": {
              "type": "string"
            }
          },
          "mustExclude": {
            "title": "Must exclude (any term)",
            "type": "array",
            "description": "A title with any of these terms is rejected, e.g. <code>max</code>, <code>mini</code>, <code>refurbished</code>.",
            "items": {
              "type": "string"
            }
          },
          "keepConditions": {
            "title": "Conditions to keep",
            "type": "array",
            "description": "Condition buckets that count as comps (from eBay's condition id and the local label). <b>For parts</b> and <b>unknown</b> are off by default.",
            "items": {
              "type": "string",
              "enum": [
                "new",
                "open_box",
                "refurbished",
                "used",
                "parts",
                "unknown"
              ],
              "enumTitles": [
                "New",
                "Open box / new other",
                "Refurbished",
                "Used",
                "For parts / not working",
                "Unknown"
              ]
            },
            "default": [
              "new",
              "open_box",
              "refurbished",
              "used"
            ]
          },
          "lotHandling": {
            "title": "Lots and bundles",
            "enum": [
              "exclude",
              "normalize",
              "include"
            ],
            "type": "string",
            "description": "\"Lot of 3\", \"3x\", \"bundle\", \"Konvolut\": <b>exclude</b> them, <b>normalize</b> (price ÷ lot size — a lot without a number is excluded) or <b>include</b> as sold.",
            "default": "exclude"
          },
          "bestOfferHandling": {
            "title": "Best Offer accepted sales",
            "enum": [
              "excludeFromStats",
              "include",
              "drop"
            ],
            "type": "string",
            "description": "eBay shows the asking price, not the accepted offer, on these. <b>Keep out of the statistics</b> (delivered with <code>priceIsAsking: true</code>), <b>include</b> them anyway, or <b>drop</b> them.",
            "default": "excludeFromStats"
          },
          "outlierIqrK": {
            "title": "Outlier fence (IQR × k)",
            "minimum": 0,
            "maximum": 10,
            "type": "number",
            "description": "Sales outside Q1 − k·IQR … Q3 + k·IQR of their keyword and condition (5+ sales) are rejected free. 1.5 is Tukey's fence; 3 keeps more; 0 turns it off.",
            "default": 1.5
          },
          "targetFlags": {
            "title": "Only comps with these flags (any of)",
            "type": "array",
            "description": "Only deliver comps with at least one of these flags, e.g. <code>below_p25</code> for cheap sales or <code>auction</code> (<code>belowP25</code> works too). The price report still uses every clean comp. An unknown name stops the run with the valid ones.",
            "items": {
              "type": "string"
            }
          },
          "suppressionList": {
            "title": "Exclude list",
            "type": "array",
            "description": "eBay item ids, URLs or seller usernames to never output — skipped before any processing and never charged.",
            "items": {
              "type": "string"
            }
          },
          "ebaySite": {
            "title": "eBay marketplace",
            "enum": [
              "ebay.com",
              "ebay.co.uk",
              "ebay.de",
              "ebay.fr",
              "ebay.it",
              "ebay.es",
              "ebay.ca",
              "ebay.com.au"
            ],
            "type": "string",
            "description": "The eBay site the live search runs on. One currency per report — sales in another currency are rejected free.",
            "default": "ebay.com"
          },
          "daysToScrape": {
            "title": "Sold in the last N days",
            "minimum": 1,
            "maximum": 90,
            "type": "integer",
            "description": "The sold window (1–90 days) — also the window of the sell-through rate (sales per day) in the report.",
            "default": 30
          },
          "maxSoldPerKeyword": {
            "title": "Max sold listings per keyword",
            "minimum": 1,
            "maximum": 1000,
            "type": "integer",
            "description": "How many sold rows the source loads per keyword (its <code>count</code>, $0.004 each on your account). 100 gives a solid median; the spend cap above still applies.",
            "default": 100
          },
          "categoryId": {
            "title": "eBay category id",
            "type": "string",
            "description": "Only sales in this eBay category, e.g. <code>139971</code> (video game consoles). Leave empty for all."
          },
          "minPrice": {
            "title": "Min sold price",
            "minimum": 0,
            "type": "number",
            "description": "Only sales at or above this price (site currency) — the source skips the rest, so you pay for fewer junk rows."
          },
          "maxPrice": {
            "title": "Max sold price",
            "minimum": 0,
            "type": "number",
            "description": "Only sales at or below this price (site currency)."
          },
          "feeRatePct": {
            "title": "Your selling fee (%)",
            "minimum": 0,
            "maximum": 50,
            "type": "number",
            "description": "Your eBay final-value-fee rate for the max-buy-price math: <code>maxBuyPrice = suggestedListPrice × (1 − fee) − shippingCost − targetProfit</code>, all in the site's currency.",
            "default": 13.25
          },
          "shippingCost": {
            "title": "Your shipping cost per sale",
            "minimum": 0,
            "type": "number",
            "description": "What shipping one unit costs you, in the eBay site's currency (USD on ebay.com, GBP on ebay.co.uk, EUR on ebay.de …); subtracted in the max buy price. The 0.1 name <code>shippingCostUsd</code> still works.",
            "default": 0
          },
          "targetProfit": {
            "title": "Target profit per flip",
            "minimum": 0,
            "type": "number",
            "description": "The profit you want per unit, in the eBay site's currency; subtracted in the max buy price. The 0.1 name <code>targetProfitUsd</code> still works.",
            "default": 0
          },
          "llmProvider": {
            "title": "AI model access",
            "enum": [
              "apify",
              "byok"
            ],
            "type": "string",
            "description": "<b>Apify (no keys)</b> — the AI runs through Apify's built-in OpenRouter proxy; tokens are billed to your Apify account at OpenRouter's rates. <b>My own key</b> — use your OpenAI / Anthropic / Gemini / Groq key instead. A free-tier key is rate-limited: expect 1–3 AI checks per run (the borderline comps first, one at a time after a rate limit), the rest keep their rule score; a paid Groq / Gemini key (billing on) assesses every comp.",
            "default": "apify"
          },
          "llmModel": {
            "title": "AI model",
            "type": "string",
            "description": "Leave empty for the default (<code>anthropic/claude-haiku-4.5</code>). Apify mode takes an OpenRouter slug such as <code>openai/gpt-4.1-mini</code>; own-key mode takes <code>provider:model</code>, e.g. <code>anthropic:claude-haiku-4-5-20251001</code>."
          },
          "llmApiKey": {
            "title": "Your API key (own-key mode only)",
            "type": "string",
            "description": "Required when <b>AI model access</b> is <i>My own API key</i>. Stored encrypted by Apify, never logged."
          },
          "aiCandidateMultiplier": {
            "title": "AI candidate pool (× max comps)",
            "minimum": 1,
            "maximum": 5,
            "type": "integer",
            "description": "The AI checks the borderline sales only — rule score 40–90, or a clear match in used / open-box condition (for its defects) — best rule score first, up to this multiple of <b>Max comps to deliver</b>.",
            "default": 2
          },
          "slackWebhookUrl": {
            "title": "Post the price report to Slack (optional)",
            "type": "string",
            "description": "A Slack incoming-webhook URL (<code>https://hooks.slack.com/services/…</code>). After every run the digest (median and change per keyword, the new comps with links) is posted to that channel as a readable message. Never sent for the free demo."
          },
          "discordWebhookUrl": {
            "title": "Post the price report to Discord (optional)",
            "type": "string",
            "description": "A Discord channel webhook URL (<code>https://discord.com/api/webhooks/…</code>, channel settings → Integrations → Webhooks). After every run the digest (median, list and max-buy price per keyword, the new comps with links) is posted to that channel — made for reseller groups. Stored encrypted; never sent for the free demo."
          },
          "alertOnly": {
            "title": "Deal alerts only",
            "type": "boolean",
            "description": "On a schedule: send the e-mail / Slack / Discord digest <b>only</b> when a new sale lands at or under your max buy price, or a keyword's median moved by at least <b>Median move to alert on</b> since the last run — a “buy now” ping instead of a weekly report. The comps and the price report are delivered either way.",
            "default": false
          },
          "alertMedianMovePct": {
            "title": "Median move to alert on (%)",
            "minimum": 0,
            "maximum": 100,
            "type": "number",
            "description": "With <b>Deal alerts only</b>: alert when a keyword's median moved by at least this many percent (up or down) vs the last run.",
            "default": 10
          },
          "webhookUrl": {
            "title": "Webhook URL (optional)",
            "type": "string",
            "description": "New comps are POSTed here as JSON (Zapier, Make, n8n, your database), then one <code>comps.report</code> per keyword. For Google Sheets / Slack you can also use Apify's Integrations tab. Stored encrypted — hook URLs carry their secret in the path."
          },
          "webhookHeaders": {
            "title": "Webhook headers (optional)",
            "type": "object",
            "description": "Extra HTTP headers for the webhook, e.g. <code>{\"Authorization\": \"Bearer …\"}</code>. Stored encrypted by Apify, never logged."
          },
          "webhookBatchSize": {
            "title": "Webhook batch size",
            "minimum": 1,
            "maximum": 500,
            "type": "integer",
            "description": "1 = one POST per comp the moment it is ready. Higher = one POST per N comps.",
            "default": 1
          },
          "dedupeAcrossRuns": {
            "title": "Never charge the same sale twice",
            "type": "boolean",
            "description": "Remembers every comp you were charged for (eBay site + item id, in a key-value store on your account): a weekly run delivers only new sales, while the price report still uses every clean sale in the window.",
            "default": true
          },
          "dedupeStoreName": {
            "title": "Dedupe store name",
            "type": "string",
            "description": "Key-value store used for cross-run memory. Left at the default, the memory is kept per search (source, keywords, eBay site): rewording <code>itemDescription</code> keeps it. Pricing for several clients on one account, type one name per client.",
            "default": "ebay-sold-comps-ai-seen"
          },
          "datasetId": {
            "title": "Dataset",
            "type": "string",
            "description": "Only for <b>dataset</b> mode: a dataset of eBay sold listings (from eBay Sold Listings Search or another eBay sold scraper — <code>price</code>, <code>soldDate</code>, <code>link</code>, <code>id</code> work too)."
          },
          "itemsList": {
            "title": "Sold rows to clean",
            "type": "array",
            "description": "Only for <b>list</b> mode. JSON array of sold listings with at least <code>title</code> and <code>soldPrice</code>; <code>itemId</code>, <code>url</code>, <code>condition</code>, <code>endedAt</code>, <code>keyword</code> and the other README list-mode fields switch on the rest of the output."
          },
          "discoveryActorId": {
            "title": "Source Actor (advanced)",
            "type": "string",
            "description": "Actor used in <b>actor</b> mode. Any Actor whose output has the fields of eBay Sold Listings Search works.",
            "default": "caffein.dev/ebay-sold-listings"
          },
          "discoveryInput": {
            "title": "Raw source input (advanced)",
            "type": "object",
            "description": "Only for <b>actor</b> mode. Extra input merged into the eBay Sold Listings Search call, e.g. <code>{\"itemCondition\": \"used\"}</code>; the fields above win. The live search runs that Store Actor on your Apify plan — if your plan cannot run Store Actors, use <b>dataset</b> mode."
          },
          "maxToProcess": {
            "title": "Max new sales to process",
            "minimum": 1,
            "maximum": 20000,
            "type": "integer",
            "description": "Upper bound on the new sold rows cleaned and matched in one run (controls run time). Default = 3 × max comps."
          }
        }
      },
      "runsResponseSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "actId": {
                "type": "string"
              },
              "userId": {
                "type": "string"
              },
              "startedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "finishedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "status": {
                "type": "string",
                "example": "READY"
              },
              "meta": {
                "type": "object",
                "properties": {
                  "origin": {
                    "type": "string",
                    "example": "API"
                  },
                  "userAgent": {
                    "type": "string"
                  }
                }
              },
              "stats": {
                "type": "object",
                "properties": {
                  "inputBodyLen": {
                    "type": "integer",
                    "example": 2000
                  },
                  "rebootCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "restartCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "resurrectCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "computeUnits": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "options": {
                "type": "object",
                "properties": {
                  "build": {
                    "type": "string",
                    "example": "latest"
                  },
                  "timeoutSecs": {
                    "type": "integer",
                    "example": 300
                  },
                  "memoryMbytes": {
                    "type": "integer",
                    "example": 1024
                  },
                  "diskMbytes": {
                    "type": "integer",
                    "example": 2048
                  }
                }
              },
              "buildId": {
                "type": "string"
              },
              "defaultKeyValueStoreId": {
                "type": "string"
              },
              "defaultDatasetId": {
                "type": "string"
              },
              "defaultRequestQueueId": {
                "type": "string"
              },
              "buildNumber": {
                "type": "string",
                "example": "1.0.0"
              },
              "containerUrl": {
                "type": "string"
              },
              "usage": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "integer",
                    "example": 1
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "usageTotalUsd": {
                "type": "number",
                "example": 0.00005
              },
              "usageUsd": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "number",
                    "example": 0.00005
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}