{
    "openapi": "3.1.0",
    "info": {
        "title": "ScrapeFleet Data API",
        "version": "1.0.0",
        "description": "Public API for ScrapeFleet's maintenance-free, self-healing scrapers. Submit a live run (async, spends credits), poll it, and fetch clean JSON rows — or read a maintained data sample synchronously. Authenticate with an X-API-Key header (create keys at https://scrapefleet.ai/app#settings-profile)."
    },
    "servers": [
        {
            "url": "https://b.scrapefleet.ai"
        }
    ],
    "security": [
        {
            "ApiKeyAuth": []
        }
    ],
    "paths": {
        "/api/v1/scrapers/{slug}": {
            "get": {
                "summary": "Describe a scraper: real output fields + example values",
                "operationId": "describeScraper",
                "parameters": [
                    {
                        "name": "slug",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "ikea"
                            ]
                        },
                        "description": "Scraper slug (see x-scrapers for the catalog)."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Scraper schema"
                    },
                    "401": {
                        "description": "Error",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Error",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/v1/scrapers/{slug}/data": {
            "get": {
                "summary": "Maintained data sample (sync, cheap read — no crawl)",
                "operationId": "getLatestData",
                "parameters": [
                    {
                        "name": "slug",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "ikea"
                            ]
                        },
                        "description": "Scraper slug (see x-scrapers for the catalog)."
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "schema": {
                            "type": "integer",
                            "default": 1
                        }
                    },
                    {
                        "name": "page_size",
                        "in": "query",
                        "schema": {
                            "type": "integer",
                            "default": 50,
                            "minimum": 1,
                            "maximum": 200
                        }
                    },
                    {
                        "name": "source",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "sample",
                                "mine"
                            ],
                            "default": "sample"
                        },
                        "description": "sample: a maintained data sample our monitoring keeps fresh (not a full crawl). mine: the latest run you triggered yourself (your runs execute as your own workspace copy)."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Result rows",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "page": {
                                            "type": "integer"
                                        },
                                        "page_size": {
                                            "type": "integer"
                                        },
                                        "rows": {
                                            "type": "array",
                                            "items": {
                                                "type": "object"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Error",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Error",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/v1/scrapers/{slug}/runs": {
            "post": {
                "summary": "Submit a fresh live run (async, spends credits)",
                "description": "Runs execute as YOUR workspace copy of the scraper: the run, its data (readable via the returned job urls or /data?source=mine) and billing are yours; different customers run concurrently. While one of YOUR runs is already active, repeat submits coalesce onto it (200 with deduplicated=true) instead of starting and billing a second scrape. Pass force=true to launch a new run regardless.",
                "operationId": "submitRun",
                "parameters": [
                    {
                        "name": "slug",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string",
                            "enum": [
                                "ikea"
                            ]
                        },
                        "description": "Scraper slug (see x-scrapers for the catalog)."
                    },
                    {
                        "name": "force",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "boolean",
                            "default": false
                        },
                        "description": "Launch a new run even if one is already active (skips run coalescing)."
                    },
                    {
                        "name": "max_pages",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer",
                            "minimum": 1,
                            "maximum": 500
                        },
                        "description": "Cap the URLs fetched per layer — bounded cost for trials and small refreshes. Omit for a full crawl."
                    },
                    {
                        "name": "wait",
                        "in": "query",
                        "required": false,
                        "schema": {
                            "type": "integer",
                            "minimum": 0,
                            "maximum": 55
                        },
                        "description": "Hold the request up to N seconds; if the run finishes in time you get 200 with the first page of rows inline, otherwise 202 with polling urls. Best combined with max_pages."
                    }
                ],
                "responses": {
                    "202": {
                        "description": "Run queued",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/RunStatus"
                                }
                            }
                        }
                    },
                    "200": {
                        "description": "Coalesced onto an already-active run (deduplicated=true)",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/RunStatus"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Error",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "402": {
                        "description": "Error",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Error",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/v1/runs/{job_id}": {
            "get": {
                "summary": "Run status",
                "operationId": "getRunStatus",
                "parameters": [
                    {
                        "name": "job_id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Job id returned when the run was submitted."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Status",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/RunStatus"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Error",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Error",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/v1/runs/{job_id}/data": {
            "get": {
                "summary": "Result rows of a finished run",
                "operationId": "getRunData",
                "parameters": [
                    {
                        "name": "job_id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Job id returned when the run was submitted."
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "schema": {
                            "type": "integer",
                            "default": 1
                        }
                    },
                    {
                        "name": "page_size",
                        "in": "query",
                        "schema": {
                            "type": "integer",
                            "default": 50,
                            "minimum": 1,
                            "maximum": 200
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Result rows",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "page": {
                                            "type": "integer"
                                        },
                                        "page_size": {
                                            "type": "integer"
                                        },
                                        "rows": {
                                            "type": "array",
                                            "items": {
                                                "type": "object"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "Error",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "Error",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "409": {
                        "description": "Error",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        }
    },
    "components": {
        "securitySchemes": {
            "ApiKeyAuth": {
                "type": "apiKey",
                "in": "header",
                "name": "X-API-Key"
            }
        },
        "schemas": {
            "Error": {
                "type": "object",
                "properties": {
                    "error": {
                        "type": "string"
                    }
                }
            },
            "RunStatus": {
                "type": "object",
                "properties": {
                    "job_id": {
                        "type": "string"
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "queued",
                            "running",
                            "succeeded",
                            "failed"
                        ]
                    },
                    "rows": {
                        "type": "integer",
                        "nullable": true
                    },
                    "data_url": {
                        "type": "string"
                    },
                    "deduplicated": {
                        "type": "boolean",
                        "description": "True when the submit was coalesced onto an already-active run instead of starting a new one."
                    }
                }
            },
            "IkeaRow": {
                "type": "object",
                "properties": {
                    "product_sku": {
                        "type": "string",
                        "description": "IKEA's item number, formatted like 806.194.51",
                        "example": "10455434"
                    },
                    "url": {
                        "type": "string",
                        "format": "uri",
                        "description": "Canonical product page link",
                        "example": "https://www.ikea.com/us/en/p/mittled-led-kitchen-cntrtp-lighting-strip-dimmable-white-10455434/"
                    },
                    "title": {
                        "type": "string",
                        "description": "Product name as listed, often the IKEA item name in caps",
                        "example": "MITTLED"
                    },
                    "image_url": {
                        "type": "string",
                        "format": "uri",
                        "description": "Direct link to the primary product image",
                        "example": "https://www.ikea.com/us/en/images/products/mittled-led-kitchen-cntrtp-lighting-strip-dimmable-white__0869934_pe781529_s5.jpg"
                    },
                    "offer_price": {
                        "type": "string",
                        "description": "Current selling price; blank when item has no active price",
                        "example": "22"
                    },
                    "list_price": {
                        "type": "string",
                        "description": "Reference price before any discount",
                        "example": "22"
                    },
                    "discount": {
                        "type": "string",
                        "description": "Discount amount or percentage; blank when item isn't discounted"
                    },
                    "mpn": {
                        "type": "string",
                        "description": "Manufacturer part number, matches product_sku format",
                        "example": "40353537"
                    },
                    "color": {
                        "type": "string",
                        "description": "Product color; blank when not specified for the item",
                        "example": "white"
                    }
                }
            }
        }
    },
    "x-scrapers": [
        {
            "slug": "ikea",
            "name": "IKEA Product Scraper",
            "description": "Structured JSON for IKEA product listings — SKU, price, discount, color, and images — without touching IKEA's internal endpoints.",
            "landing_page": "https://scrapefleet.ai/scrapers/ikea",
            "row_schema": "#/components/schemas/IkeaRow"
        }
    ]
}
