{
  "openapi": "3.0.1",
  "info": {
    "title": "Grailed Scraper - Listings, Prices, Sellers & Reviews",
    "description": "Scrape Grailed by keyword, category, designer, condition, size or URL. Extract prices and price history, descriptions, measurements, shipping, seller profiles and reviews. Includes change tracking to monitor new, updated and removed listings.",
    "version": "0.1",
    "x-build-id": "e8eXP7Pn7bk0mBeS0"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/abotapi~grailed-marketplace-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-abotapi-grailed-marketplace-scraper",
        "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/abotapi~grailed-marketplace-scraper/runs": {
      "post": {
        "operationId": "runs-sync-abotapi-grailed-marketplace-scraper",
        "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/abotapi~grailed-marketplace-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-abotapi-grailed-marketplace-scraper",
        "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": [
          "mode"
        ],
        "properties": {
          "mode": {
            "title": "Mode",
            "enum": [
              "search",
              "url"
            ],
            "type": "string",
            "description": "How to start the scrape. 'search' runs store searches. 'url' processes the store URLs you paste: a listing URL is fetched as a single listing in full, a category or designer URL is paged like a search, and a seller profile URL reads the seller. The price and ordering filters below apply in BOTH modes; search terms, sellers and the catalogue facets (categories, designers, conditions, sizes) apply in search mode only.",
            "default": "search"
          },
          "searchTerms": {
            "title": "Search terms",
            "type": "array",
            "description": "One or more things to search the marketplace for, for example 'varsity jacket', 'cargo pants', 'band tee'. Each term is scraped as its own scope with the catalogue facets below applied. Search mode ONLY: in URL mode the pasted URLs decide their own scope instead.",
            "items": {
              "type": "string"
            }
          },
          "sellerUsernames": {
            "title": "Seller usernames",
            "type": "array",
            "description": "One or more Grailed usernames to read as sellers. Each produces a seller profile row; turn on the two toggles below to also read the seller's reviews or their on-sale listings. Search mode ONLY: in URL mode, paste seller profile URLs instead.",
            "items": {
              "type": "string"
            }
          },
          "fetchSellerReviews": {
            "title": "Fetch seller reviews",
            "type": "boolean",
            "description": "Read each seller's reviews and emit them as their own rows (rowType 'review'), with the rating, the note, the tags and the listing the review refers to. Each review is a dataset row of its own and is billed as one. Search mode ONLY: it applies to the sellers named above, not to listings found by search or browse.",
            "default": false
          },
          "includeSellerListings": {
            "title": "Also walk each seller's on-sale listings",
            "type": "boolean",
            "description": "After the profile row, walk the seller's on-sale listings through the store's own feed, as normal product rows (the Max items cap applies to them like any other row). Search mode ONLY: it applies to the sellers named above.",
            "default": false
          },
          "categories": {
            "title": "Categories",
            "type": "array",
            "description": "Only browse these categories. Accept a whole section ('tops', 'footwear'), a subcategory name from a category page URL ('long-sleeve-t-shirts'), or the store's own feed path ('tops.short_sleeve_shirts'). A name the store does not serve stops the run with a clear message rather than walking a wider scope. Search mode ONLY: in URL mode the pasted URL decides its own scope.",
            "items": {
              "type": "string"
            }
          },
          "designers": {
            "title": "Designers",
            "type": "array",
            "description": "Only browse these designers, by the name the store itself uses on designer pages and on the rows, for example 'Rick Owens' or 'Our Legacy'. Each name narrows the feed; a name the store does not serve simply matches nothing. Search mode ONLY: in URL mode the pasted URL decides its own scope.",
            "items": {
              "type": "string"
            }
          },
          "conditions": {
            "title": "Conditions",
            "type": "array",
            "description": "Only browse listings in these conditions, as the store grades them: 'new', 'gently used', 'used' or 'worn'. Search mode ONLY: in URL mode the pasted URL decides its own scope.",
            "items": {
              "type": "string"
            }
          },
          "sizes": {
            "title": "Sizes",
            "type": "array",
            "description": "Only browse listings in these sizes, exactly as the store labels them: letter sizes ('s', 'm', 'l', 'xl'), waist sizes ('30', '32'), or 'one size'. Search mode ONLY: in URL mode the pasted URL decides its own scope.",
            "items": {
              "type": "string"
            }
          },
          "urls": {
            "title": "Grailed URLs",
            "type": "array",
            "description": "Paste store listing URLs (https://www.grailed.com/listings/12345678), search page URLs (https://www.grailed.com/shop/search?query=jacket), category URLs (https://www.grailed.com/categories/footwear or https://www.grailed.com/categories/womenswear/tops), designer URLs (https://www.grailed.com/designers/designer-name) or seller profile URLs (https://www.grailed.com/username). Add ?page=3 to any browse URL to start walking from that page. A pasted URL decides its own scope: the price and ordering filters below still narrow browse scopes, while the catalogue facets (categories, designers, conditions, sizes) are search mode only. A pasted listing URL returns that single listing in full.",
            "items": {
              "type": "string"
            }
          },
          "department": {
            "title": "Department",
            "enum": [
              "menswear",
              "womenswear"
            ],
            "type": "string",
            "description": "Which storefront department to read. Applies in BOTH search mode and URL mode: search mode sends it with every request, and in URL mode it fills in only when a pasted URL does not name a department of its own.",
            "default": "menswear"
          },
          "minPriceUsd": {
            "title": "Minimum price (USD)",
            "minimum": 0,
            "type": "integer",
            "description": "Only keep listings whose current ask price is at least this many US dollars. The store applies this at the feed itself, so a filtered run reads a narrowed feed. Applies in BOTH search mode and URL mode (a pasted single-listing URL always returns its listing in full)."
          },
          "maxPriceUsd": {
            "title": "Maximum price (USD)",
            "minimum": 0,
            "type": "integer",
            "description": "Only keep listings whose current ask price is at most this many US dollars. The store applies this at the feed itself, so a filtered run reads a narrowed feed. Applies in BOTH search mode and URL mode (a pasted single-listing URL always returns its listing in full)."
          },
          "sortResultsBy": {
            "title": "Order the returned rows by",
            "enum": [
              "site_order",
              "price_asc",
              "price_desc",
              "newest_first"
            ],
            "type": "string",
            "description": "Arranges the rows this run collected, after they are read. The store serves one ranking of its own; the alternatives are a local tidy up of one run's output, not a catalogue wide ordering. Applies in BOTH search mode and URL mode.",
            "default": "site_order"
          },
          "fetchDetails": {
            "title": "Fetch listing details",
            "type": "boolean",
            "description": "Fetch each listing's own page for the description, the measurement table, the photo set and the deeper seller fields. Slower, and charged once per record. Leave off for a fast crawl: the ask price, the ask history, the condition, the size and the seller's score card are included either way.",
            "default": false
          },
          "maxItems": {
            "title": "Max items",
            "minimum": 0,
            "type": "integer",
            "description": "The single cap on this run: stop after collecting this many records (listings, sellers and reviews together) across all search terms, sellers and URLs. Set 0 for unlimited.",
            "default": 20
          },
          "maxPages": {
            "title": "Max pages per source",
            "minimum": 0,
            "type": "integer",
            "description": "Safety bound on how many feed pages to walk per search term, seller or URL. Leave empty (0) for no page limit: the run then stops at Max items, or at the store's own per-scope page bound, not here. Does not impose a separate cap below Max items.",
            "default": 0
          },
          "resumeFromRunId": {
            "title": "Resume from a previous run",
            "type": "string",
            "description": "Paste a previous run ID or dataset ID to continue a large crawl without returning or charging for records already collected there. Use this after an interrupted or capped run. For recurring monitoring of the same search, use Incremental mode below instead."
          },
          "incrementalMode": {
            "title": "Incremental changes for scheduled runs",
            "type": "boolean",
            "description": "Turn this on for daily or weekly recurring monitoring of the same search, for example a price watch. The first run returns everything matching as NEW. Later runs normally return only NEW, UPDATED and REAPPEARED records. Ask-price moves ARE reported as UPDATED: on a resale marketplace they are the signal, not noise. Turn on Emit unchanged or Emit expired only when you also want those rows returned (and billed). State is kept separately per search, URL, seller and filter setup; use State key to name or deliberately share a monitoring campaign. To continue one specific interrupted run instead, use Resume from a previous run above.",
            "default": false
          },
          "stateKey": {
            "title": "State key (optional, incremental mode only)",
            "type": "string",
            "description": "Optional. Name this monitoring campaign to keep its state stable, or to deliberately share state across differently configured runs. Leave empty to let the actor derive a key automatically from the search terms, URLs, sellers and filters, so two different searches never mix state."
          },
          "emitUnchanged": {
            "title": "Emit unchanged records (incremental mode only)",
            "type": "boolean",
            "description": "Off by default. Turn on to also return records that have not changed since the last run, marked UNCHANGED. This returns, and bills, extra rows you already have, so leave it off unless you specifically want a full snapshot every run.",
            "default": false
          },
          "emitExpired": {
            "title": "Emit expired records (incremental mode only)",
            "type": "boolean",
            "description": "Off by default. Turn on to also return records that were present in a previous run but are no longer found, marked EXPIRED. Only produced once a run has fully scanned the tracked search: not when Max items capped it, not when Resume was used, and not when the run was refused. This returns, and bills, extra synthetic rows, so leave it off unless you need expiry tracking.",
            "default": false
          },
          "mcpConnectors": {
            "title": "Pipe results into your apps (optional)",
            "type": "array",
            "description": "Optionally send results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize one under Apify, Settings, API & Integrations, then select it here. Notion gets a page per record; other connectors get a best-effort write or digest. Each connector receives a condensed summary per record, not the full record; the complete record always stays in the dataset. Leave empty to skip; this never changes the dataset output. Supported: Notion (https://mcp.notion.com/mcp), Linear (https://mcp.linear.app/sse), Airtable (https://mcp.airtable.com/mcp), Apify (https://mcp.apify.com)."
          },
          "notionParentPageUrl": {
            "title": "Notion parent page (Notion connector only)",
            "type": "string",
            "description": "URL or id of the Notion page under which record pages are created. Required to enable the Notion export; ignored by other connectors."
          },
          "maxNotifyListings": {
            "title": "Max items to export per connector",
            "minimum": 1,
            "maximum": 1000,
            "type": "integer",
            "description": "Cap on records written to each connector per run. Does not affect the dataset.",
            "default": 50
          },
          "proxy": {
            "title": "Proxy configuration",
            "type": "object",
            "description": "Leave the default for the cheapest run. Change it only if a run reports that it could not read any results. Prices are quoted in US dollars on every row regardless of the exit country.",
            "default": {
              "useApifyProxy": true
            }
          }
        }
      },
      "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
                  }
                }
              },
              "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}