{
  "openapi": "3.1.0",
  "info": {
    "title": "SoldComps Sold Comps API",
    "version": "1.0.0",
    "summary": "eBay sold comps as JSON: up to 200 completed sales per search, median and quartiles precomputed.",
    "description": "SoldComps is a sold comps API. Sold comps (sold comparables) are recent completed sales of the same item, used to price it from what buyers actually paid rather than asking prices.\n\nOne GET request to /sold returns up to 200 completed eBay sales (eBay US, UK or Germany, last 90 days, newest first) plus stats computed only from clean sales. Lots, for-parts listings, boxes, replicas, cheap accessories and outliers are flagged and left out of the stats but still returned.\n\nBilling is per request, not per result. Plans: Free $0/mo for 100 requests; Starter $5/mo for 1,000 requests; Growth $29/mo for 12,000 requests; Scale $79/mo for 40,000 requests. Pay as you go: $6.00 per 1,000 requests. Every successful search is one request; failed requests are never billed.\n\nGet a free key at https://www.soldcomps.io/signup. Human-readable docs: https://www.soldcomps.io/docs. SoldComps is independent and not affiliated with eBay.",
    "contact": {
      "name": "SoldComps",
      "email": "hello@soldcomps.io",
      "url": "https://www.soldcomps.io"
    }
  },
  "externalDocs": {
    "description": "API documentation",
    "url": "https://www.soldcomps.io/docs"
  },
  "servers": [
    {
      "url": "https://www.soldcomps.io/v1",
      "description": "Production"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Sold comps",
      "description": "Completed eBay sales for a keyword"
    }
  ],
  "paths": {
    "/sold": {
      "get": {
        "operationId": "getSoldComps",
        "tags": [
          "Sold comps"
        ],
        "summary": "Get sold comps for a keyword",
        "description": "Returns up to 200 completed eBay sales matching a keyword, newest first, plus summary stats. One call counts as one request whether it returns 3 sales or 200. A sale is kept only if every number in the query appears in the title as a whole number, quoted phrases appear exactly, and at least 80% of the other words appear; minus words exclude a sale.",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "description": "What you'd type in eBay's search box. Put exact phrases in quotes (\"psa 10\") and exclude words with a minus (-lot).",
            "schema": {
              "type": "string",
              "minLength": 1
            },
            "example": "rolex submariner 126610ln"
          },
          {
            "name": "site",
            "in": "query",
            "description": "eBay site: EBAY_US (ebay.com), EBAY_GB (ebay.co.uk) or EBAY_DE (ebay.de). Prices come back in that site's currency.",
            "schema": {
              "type": "string",
              "enum": [
                "EBAY_US",
                "EBAY_GB",
                "EBAY_DE"
              ],
              "default": "EBAY_US"
            }
          },
          {
            "name": "condition",
            "in": "query",
            "description": "Only sales in this condition. Omit for any condition.",
            "schema": {
              "type": "string",
              "enum": [
                "new",
                "open_box",
                "refurbished",
                "used",
                "for_parts"
              ]
            }
          },
          {
            "name": "min_price",
            "in": "query",
            "description": "Only sales at or above this price, in the site's currency.",
            "schema": {
              "type": "number",
              "minimum": 0
            }
          },
          {
            "name": "max_price",
            "in": "query",
            "description": "Only sales at or below this price, in the site's currency.",
            "schema": {
              "type": "number",
              "minimum": 0
            }
          },
          {
            "name": "buying_format",
            "in": "query",
            "description": "auction, or fixed_price (Buy It Now and Best Offer). Omit for any format.",
            "schema": {
              "type": "string",
              "enum": [
                "auction",
                "fixed_price"
              ]
            }
          },
          {
            "name": "days",
            "in": "query",
            "description": "Look-back window in days.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 90,
              "default": 90
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Sold comps for the query.",
            "headers": {
              "X-Request-Id": {
                "description": "Unique id for this request; quote it when contacting support.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Quota-Remaining": {
                "description": "Requests left in this key's monthly quota.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current one-minute window.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SoldResponse"
                }
              }
            }
          },
          "400": {
            "description": "invalid_param: Bad or missing parameter; error.param names it. Not billed.",
            "headers": {
              "X-Request-Id": {
                "description": "Unique id for this request; quote it when contacting support.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Quota-Remaining": {
                "description": "Requests left in this key's monthly quota.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current one-minute window.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid_param",
                    "param": "q"
                  }
                }
              }
            }
          },
          "401": {
            "description": "unauthorized: Missing or revoked key. Not billed.",
            "headers": {
              "X-Request-Id": {
                "description": "Unique id for this request; quote it when contacting support.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Quota-Remaining": {
                "description": "Requests left in this key's monthly quota.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current one-minute window.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized"
                  }
                }
              }
            }
          },
          "402": {
            "description": "quota_exceeded: Monthly requests used up and no credits left. Not billed.",
            "headers": {
              "X-Request-Id": {
                "description": "Unique id for this request; quote it when contacting support.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Quota-Remaining": {
                "description": "Requests left in this key's monthly quota.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current one-minute window.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "quota_exceeded"
                  }
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: Over your per-minute limit; honor Retry-After. Not billed.",
            "headers": {
              "X-Request-Id": {
                "description": "Unique id for this request; quote it when contacting support.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Quota-Remaining": {
                "description": "Requests left in this key's monthly quota.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current one-minute window.",
                "schema": {
                  "type": "integer"
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited"
                  }
                }
              }
            }
          },
          "502": {
            "description": "upstream_unavailable: eBay didn't answer cleanly; safe to retry with backoff. Not billed.",
            "headers": {
              "X-Request-Id": {
                "description": "Unique id for this request; quote it when contacting support.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Quota-Remaining": {
                "description": "Requests left in this key's monthly quota.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current one-minute window.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "upstream_unavailable"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/usage": {
      "get": {
        "operationId": "getUsage",
        "tags": [
          "Account"
        ],
        "summary": "Requests used and remaining this month",
        "description": "Your plan, requests used and remaining in the current month, when the quota resets, and your per-minute rate limit. Never billed.",
        "responses": {
          "200": {
            "description": "Usage for the calling key",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "plan",
                    "used",
                    "limit",
                    "remaining",
                    "resets_at",
                    "rate_limit_per_minute"
                  ],
                  "properties": {
                    "plan": {
                      "type": "string",
                      "example": "free"
                    },
                    "used": {
                      "type": "integer",
                      "example": 12
                    },
                    "limit": {
                      "type": "integer",
                      "example": 100
                    },
                    "remaining": {
                      "type": "integer",
                      "example": 88
                    },
                    "resets_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "rate_limit_per_minute": {
                      "type": "integer",
                      "example": 30
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key from https://www.soldcomps.io/signup, e.g. sh_live_xxxxxxxx. Send as Authorization: Bearer <key>."
      }
    },
    "schemas": {
      "SoldResponse": {
        "type": "object",
        "required": [
          "query",
          "site",
          "window_days",
          "count",
          "stats",
          "items"
        ],
        "properties": {
          "query": {
            "type": "string",
            "description": "The q you sent"
          },
          "site": {
            "type": "string",
            "enum": [
              "EBAY_US",
              "EBAY_GB",
              "EBAY_DE"
            ]
          },
          "window_days": {
            "type": "integer",
            "description": "Look-back window used, in days"
          },
          "count": {
            "type": "integer",
            "description": "Number of sales in items (max 200)"
          },
          "stats": {
            "$ref": "#/components/schemas/Stats"
          },
          "items": {
            "type": "array",
            "maxItems": 200,
            "items": {
              "$ref": "#/components/schemas/SoldItem"
            }
          }
        }
      },
      "Stats": {
        "type": "object",
        "description": "Computed only from sales with an empty flags array and a known price. Values are null when no sale qualifies.",
        "required": [
          "median",
          "p25",
          "p75",
          "min",
          "max",
          "excluded",
          "currency"
        ],
        "properties": {
          "median": {
            "type": [
              "number",
              "null"
            ],
            "description": "Median sold price"
          },
          "p25": {
            "type": [
              "number",
              "null"
            ],
            "description": "25th percentile sold price"
          },
          "p75": {
            "type": [
              "number",
              "null"
            ],
            "description": "75th percentile sold price"
          },
          "min": {
            "type": [
              "number",
              "null"
            ]
          },
          "max": {
            "type": [
              "number",
              "null"
            ]
          },
          "excluded": {
            "type": "integer",
            "description": "How many sales in items were left out of stats"
          },
          "currency": {
            "type": "string",
            "description": "Currency of all stats values"
          }
        }
      },
      "SoldItem": {
        "type": "object",
        "required": [
          "item_id",
          "title",
          "sold_price",
          "shipping",
          "sold_at",
          "condition",
          "buying_format",
          "best_offer_accepted",
          "best_offer_price_known",
          "url",
          "image",
          "flags"
        ],
        "properties": {
          "item_id": {
            "type": "string",
            "description": "eBay item number"
          },
          "title": {
            "type": "string",
            "description": "Listing title at the time of sale"
          },
          "sold_price": {
            "type": "object",
            "description": "Sale price shown by eBay",
            "required": [
              "value",
              "currency"
            ],
            "properties": {
              "value": {
                "type": "number"
              },
              "currency": {
                "type": "string",
                "description": "ISO 4217 code: USD, GBP or EUR, depending on site"
              }
            }
          },
          "shipping": {
            "type": "object",
            "description": "Shipping the buyer paid",
            "required": [
              "value",
              "currency"
            ],
            "properties": {
              "value": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "0 = free shipping, null = not shown"
              },
              "currency": {
                "type": "string"
              }
            }
          },
          "sold_at": {
            "type": "string",
            "format": "date",
            "description": "Day the item sold, YYYY-MM-DD"
          },
          "condition": {
            "type": "string",
            "description": "eBay's condition label, e.g. \"Pre-Owned\", \"Brand New\", \"New (Other)\", \"Parts Only\""
          },
          "buying_format": {
            "type": "string",
            "enum": [
              "auction",
              "fixed_price"
            ]
          },
          "best_offer_accepted": {
            "type": "boolean",
            "description": "true when the sale was an accepted Best Offer"
          },
          "best_offer_price_known": {
            "type": "boolean",
            "description": "false when the accepted offer amount isn't shown (the list price is returned); these sales are left out of stats"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Link to the eBay listing"
          },
          "image": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "Listing photo URL"
          },
          "flags": {
            "type": "array",
            "description": "Why a sale is left out of stats. Empty = counted. lot: several items sold together; for_parts: broken, untested or for repair; box_only: packaging without the item; replica: described as fake, replica or homage; accessory: a part or add-on far below the typical price; outlier: more than 1.5x the interquartile range from the middle.",
            "items": {
              "type": "string",
              "enum": [
                "lot",
                "for_parts",
                "box_only",
                "replica",
                "accessory",
                "outlier"
              ]
            }
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code"
            ],
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "invalid_param",
                  "unauthorized",
                  "quota_exceeded",
                  "rate_limited",
                  "upstream_unavailable"
                ]
              },
              "param": {
                "type": "string",
                "description": "For invalid_param: the parameter that was bad or missing"
              }
            }
          }
        }
      }
    }
  }
}