{
    "openapi": "3.1.0",
    "info": {
        "title": "ShopKollect shop API",
        "version": "1.0.0",
        "description": "Public API of every ShopKollect shop. Prices are in cents, taxes included. Language: Accept-Language (fr, en, es, ar)."
    },
    "servers": [
        {
            "url": "https://{shop}.shopkollect.com",
            "variables": {
                "shop": {
                    "default": "demo"
                }
            }
        }
    ],
    "components": {
        "securitySchemes": {
            "bearer": {
                "type": "http",
                "scheme": "bearer",
                "description": "Personal token from /api/v1/auth/login or /auth/register"
            }
        }
    },
    "paths": {
        "/.well-known/shopkollect.json": {
            "get": {
                "tags": [
                    "Discovery and shop"
                ],
                "summary": "Shop card: name, logo, colours, languages, currency, modules, API base URL.",
                "responses": {
                    "200": {
                        "description": "OK (JSON, {\"data\": …})"
                    },
                    "422": {
                        "description": "Validation error {\"message\", \"errors\"}"
                    },
                    "429": {
                        "description": "Too many requests"
                    }
                }
            }
        },
        "/api/v1/shop": {
            "get": {
                "tags": [
                    "Discovery and shop"
                ],
                "summary": "Contact details, open / closed state and message, pages (terms, legal notice…).",
                "responses": {
                    "200": {
                        "description": "OK (JSON, {\"data\": …})"
                    },
                    "422": {
                        "description": "Validation error {\"message\", \"errors\"}"
                    },
                    "429": {
                        "description": "Too many requests"
                    }
                }
            }
        },
        "/api/v1/pickup-slots": {
            "get": {
                "tags": [
                    "Discovery and shop"
                ],
                "summary": "Today's pickup times (HH:MM); \"required\" tells whether a time must be chosen.",
                "responses": {
                    "200": {
                        "description": "OK (JSON, {\"data\": …})"
                    },
                    "422": {
                        "description": "Validation error {\"message\", \"errors\"}"
                    },
                    "429": {
                        "description": "Too many requests"
                    }
                }
            }
        },
        "/api/v1/categories": {
            "get": {
                "tags": [
                    "Catalogue"
                ],
                "summary": "Visible categories, with the number of products for sale.",
                "responses": {
                    "200": {
                        "description": "OK (JSON, {\"data\": …})"
                    },
                    "422": {
                        "description": "Validation error {\"message\", \"errors\"}"
                    },
                    "429": {
                        "description": "Too many requests"
                    }
                }
            }
        },
        "/api/v1/products": {
            "get": {
                "tags": [
                    "Catalogue"
                ],
                "summary": "Products for sale: prices incl. tax in cents, sale price, images (320 / 640 / 1024 px), stock, \"composable\".",
                "responses": {
                    "200": {
                        "description": "OK (JSON, {\"data\": …})"
                    },
                    "422": {
                        "description": "Validation error {\"message\", \"errors\"}"
                    },
                    "429": {
                        "description": "Too many requests"
                    }
                },
                "parameters": [
                    {
                        "name": "category",
                        "in": "query",
                        "required": false,
                        "description": "category id or slug",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "q",
                        "in": "query",
                        "required": false,
                        "description": "search (2 characters min.)",
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "sort",
                        "in": "query",
                        "required": false,
                        "description": "position, new, price_asc, price_desc, name",
                        "schema": {
                            "type": "string"
                        }
                    }
                ]
            }
        },
        "/api/v1/products/{slug}": {
            "get": {
                "tags": [
                    "Catalogue"
                ],
                "summary": "Full product: description, allergens, product page URL.",
                "responses": {
                    "200": {
                        "description": "OK (JSON, {\"data\": …})"
                    },
                    "422": {
                        "description": "Validation error {\"message\", \"errors\"}"
                    },
                    "429": {
                        "description": "Too many requests"
                    }
                },
                "parameters": [
                    {
                        "name": "slug",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ]
            }
        },
        "/api/v1/products/{slug}/composition": {
            "get": {
                "tags": [
                    "Catalogue"
                ],
                "summary": "Smart Kiosk journey of the product (pages, options, prices, min / max rules): same definition as the kiosk.",
                "responses": {
                    "200": {
                        "description": "OK (JSON, {\"data\": …})"
                    },
                    "422": {
                        "description": "Validation error {\"message\", \"errors\"}"
                    },
                    "429": {
                        "description": "Too many requests"
                    }
                },
                "parameters": [
                    {
                        "name": "slug",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ]
            }
        },
        "/api/v1/cart/quote": {
            "post": {
                "tags": [
                    "Cart and orders"
                ],
                "summary": "The cart lives in the app: the server returns priced lines (compositions included), the total and per-line errors.",
                "responses": {
                    "200": {
                        "description": "OK (JSON, {\"data\": …})"
                    },
                    "422": {
                        "description": "Validation error {\"message\", \"errors\"}"
                    },
                    "429": {
                        "description": "Too many requests"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "lines": {
                                        "type": "array",
                                        "items": {
                                            "type": "object"
                                        },
                                        "description": "[{product: id or slug, quantity, selection?: {page_id: {option_id: quantity}}}]"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/v1/orders": {
            "post": {
                "tags": [
                    "Cart and orders"
                ],
                "summary": "Places the order (pay on site) → number and tracking token. Same checks as the website: opening hours, stock, pickup time.",
                "responses": {
                    "200": {
                        "description": "OK (JSON, {\"data\": …})"
                    },
                    "422": {
                        "description": "Validation error {\"message\", \"errors\"}"
                    },
                    "429": {
                        "description": "Too many requests"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "lines": {
                                        "type": "array",
                                        "items": {
                                            "type": "object"
                                        },
                                        "description": "[{product: id or slug, quantity, selection?: {page_id: {option_id: quantity}}}]"
                                    },
                                    "name": {
                                        "type": "string"
                                    },
                                    "phone": {
                                        "type": "string"
                                    },
                                    "email": {
                                        "type": "string"
                                    },
                                    "note": {
                                        "type": "string"
                                    },
                                    "pickup_time": {
                                        "type": "string",
                                        "description": "HH:MM, from /pickup-slots"
                                    },
                                    "accept": {
                                        "type": "boolean",
                                        "description": "terms accepted (required)"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/v1/orders/{number}": {
            "get": {
                "tags": [
                    "Cart and orders"
                ],
                "summary": "Tracking: status (new, preparing, ready, collected, cancelled), pickup time, lines. With the tracking token or the customer token.",
                "responses": {
                    "200": {
                        "description": "OK (JSON, {\"data\": …})"
                    },
                    "422": {
                        "description": "Validation error {\"message\", \"errors\"}"
                    },
                    "429": {
                        "description": "Too many requests"
                    }
                },
                "parameters": [
                    {
                        "name": "number",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "token",
                        "in": "query",
                        "required": false,
                        "description": "order tracking token",
                        "schema": {
                            "type": "string"
                        }
                    }
                ]
            }
        },
        "/api/v1/devices": {
            "post": {
                "tags": [
                    "Cart and orders"
                ],
                "summary": "Registers a phone (Firebase token) for \"order ready\" / \"cancelled\" notifications, linked to the tracked orders.",
                "responses": {
                    "200": {
                        "description": "OK (JSON, {\"data\": …})"
                    },
                    "422": {
                        "description": "Validation error {\"message\", \"errors\"}"
                    },
                    "429": {
                        "description": "Too many requests"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "token": {
                                        "type": "string"
                                    },
                                    "platform": {
                                        "type": "string",
                                        "description": "android | ios"
                                    },
                                    "locale": {
                                        "type": "string"
                                    },
                                    "orders": {
                                        "type": "array",
                                        "items": {
                                            "type": "object"
                                        },
                                        "description": "[{number, token}]"
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "delete": {
                "tags": [
                    "Cart and orders"
                ],
                "summary": "Unregisters a phone.",
                "responses": {
                    "200": {
                        "description": "OK (JSON, {\"data\": …})"
                    },
                    "422": {
                        "description": "Validation error {\"message\", \"errors\"}"
                    },
                    "429": {
                        "description": "Too many requests"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "token": {
                                        "type": "string"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/v1/auth/register": {
            "post": {
                "tags": [
                    "Customer account (per shop)"
                ],
                "summary": "Creates the account → personal token (one per device). A customer who already ordered as a guest keeps their history.",
                "responses": {
                    "200": {
                        "description": "OK (JSON, {\"data\": …})"
                    },
                    "422": {
                        "description": "Validation error {\"message\", \"errors\"}"
                    },
                    "429": {
                        "description": "Too many requests"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "name": {
                                        "type": "string"
                                    },
                                    "email": {
                                        "type": "string"
                                    },
                                    "phone": {
                                        "type": "string"
                                    },
                                    "password": {
                                        "type": "string"
                                    },
                                    "newsletter": {
                                        "type": "boolean"
                                    },
                                    "device_name": {
                                        "type": "string"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/v1/auth/login": {
            "post": {
                "tags": [
                    "Customer account (per shop)"
                ],
                "summary": "Login → personal token. 5 attempts per minute.",
                "responses": {
                    "200": {
                        "description": "OK (JSON, {\"data\": …})"
                    },
                    "422": {
                        "description": "Validation error {\"message\", \"errors\"}"
                    },
                    "429": {
                        "description": "Too many requests"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "email": {
                                        "type": "string"
                                    },
                                    "password": {
                                        "type": "string"
                                    },
                                    "device_name": {
                                        "type": "string"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/v1/auth/password": {
            "post": {
                "tags": [
                    "Customer account (per shop)"
                ],
                "summary": "Forgotten password: sends the same e-mail as the website.",
                "responses": {
                    "200": {
                        "description": "OK (JSON, {\"data\": …})"
                    },
                    "422": {
                        "description": "Validation error {\"message\", \"errors\"}"
                    },
                    "429": {
                        "description": "Too many requests"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "email": {
                                        "type": "string"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/v1/auth/token": {
            "delete": {
                "tags": [
                    "Customer account (per shop)"
                ],
                "summary": "Logout: revokes the token used.",
                "responses": {
                    "200": {
                        "description": "OK (JSON, {\"data\": …})"
                    },
                    "422": {
                        "description": "Validation error {\"message\", \"errors\"}"
                    },
                    "429": {
                        "description": "Too many requests"
                    },
                    "401": {
                        "description": "Missing or invalid token"
                    }
                },
                "security": [
                    {
                        "bearer": []
                    }
                ]
            }
        },
        "/api/v1/me": {
            "get": {
                "tags": [
                    "Customer account (per shop)"
                ],
                "summary": "Customer profile.",
                "responses": {
                    "200": {
                        "description": "OK (JSON, {\"data\": …})"
                    },
                    "422": {
                        "description": "Validation error {\"message\", \"errors\"}"
                    },
                    "429": {
                        "description": "Too many requests"
                    },
                    "401": {
                        "description": "Missing or invalid token"
                    }
                },
                "security": [
                    {
                        "bearer": []
                    }
                ]
            },
            "put": {
                "tags": [
                    "Customer account (per shop)"
                ],
                "summary": "Updates name, e-mail, phone, newsletter, language, password.",
                "responses": {
                    "200": {
                        "description": "OK (JSON, {\"data\": …})"
                    },
                    "422": {
                        "description": "Validation error {\"message\", \"errors\"}"
                    },
                    "429": {
                        "description": "Too many requests"
                    },
                    "401": {
                        "description": "Missing or invalid token"
                    }
                },
                "security": [
                    {
                        "bearer": []
                    }
                ]
            },
            "delete": {
                "tags": [
                    "Customer account (per shop)"
                ],
                "summary": "Deletes the account (confirm=true); orders stay with the shop, unlinked from the customer.",
                "responses": {
                    "200": {
                        "description": "OK (JSON, {\"data\": …})"
                    },
                    "422": {
                        "description": "Validation error {\"message\", \"errors\"}"
                    },
                    "429": {
                        "description": "Too many requests"
                    },
                    "401": {
                        "description": "Missing or invalid token"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "confirm": {
                                        "type": "boolean"
                                    }
                                }
                            }
                        }
                    }
                },
                "security": [
                    {
                        "bearer": []
                    }
                ]
            }
        },
        "/api/v1/me/orders": {
            "get": {
                "tags": [
                    "Customer account (per shop)"
                ],
                "summary": "Last 50 orders.",
                "responses": {
                    "200": {
                        "description": "OK (JSON, {\"data\": …})"
                    },
                    "422": {
                        "description": "Validation error {\"message\", \"errors\"}"
                    },
                    "429": {
                        "description": "Too many requests"
                    },
                    "401": {
                        "description": "Missing or invalid token"
                    }
                },
                "security": [
                    {
                        "bearer": []
                    }
                ]
            }
        },
        "/api/v1/me/export": {
            "get": {
                "tags": [
                    "Customer account (per shop)"
                ],
                "summary": "Data export (GDPR), JSON.",
                "responses": {
                    "200": {
                        "description": "OK (JSON, {\"data\": …})"
                    },
                    "422": {
                        "description": "Validation error {\"message\", \"errors\"}"
                    },
                    "429": {
                        "description": "Too many requests"
                    },
                    "401": {
                        "description": "Missing or invalid token"
                    }
                },
                "security": [
                    {
                        "bearer": []
                    }
                ]
            }
        }
    }
}