{
    "openapi": "3.1.0",
    "info": {
        "title": "Afflink API",
        "version": "1.0.0",
        "description": "Oeffentliche HTTPS-API fuer das produktive Afflink-System auf primary.adrastea.com."
    },
    "servers": [
        {
            "url": "https://afflink.adrastea.com/api/v1",
            "description": "Produktive Afflink API"
        }
    ],
    "tags": [
        {
            "name": "Public",
            "description": "Oeffentlich lesbare Endpunkte ohne Auth."
        },
        {
            "name": "Products",
            "description": "Produktsuche, Link-Aufloesung und Produktpflege."
        }
    ],
    "components": {
        "securitySchemes": {
            "bearerAuth": {
                "type": "http",
                "scheme": "bearer",
                "bearerFormat": "token"
            }
        },
        "schemas": {
            "Error": {
                "type": "object",
                "required": [
                    "error",
                    "status"
                ],
                "properties": {
                    "error": {
                        "type": "string"
                    },
                    "status": {
                        "type": "integer"
                    }
                }
            },
            "Price": {
                "type": "object",
                "properties": {
                    "amount": {
                        "type": [
                            "number",
                            "null"
                        ]
                    },
                    "currency": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "display": {
                        "type": [
                            "string",
                            "null"
                        ]
                    }
                }
            },
            "Score": {
                "type": "object",
                "properties": {
                    "total": {
                        "type": [
                            "number",
                            "null"
                        ]
                    },
                    "base": {
                        "type": [
                            "number",
                            "null"
                        ]
                    },
                    "keywordScore": {
                        "type": [
                            "number",
                            "null"
                        ]
                    },
                    "rankWeight": {
                        "type": [
                            "number",
                            "null"
                        ]
                    },
                    "asinBonus": {
                        "type": [
                            "number",
                            "null"
                        ]
                    },
                    "sourceBonus": {
                        "type": [
                            "number",
                            "null"
                        ]
                    },
                    "priceMultiplier": {
                        "type": [
                            "number",
                            "null"
                        ]
                    },
                    "baselinePrice": {
                        "type": [
                            "number",
                            "null"
                        ]
                    }
                }
            },
            "Candidate": {
                "type": "object",
                "properties": {
                    "asin": {
                        "type": "string"
                    },
                    "title": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "features": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "detail_page_url": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "price": {
                        "$ref": "#/components/schemas/Price"
                    },
                    "image": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "images": {
                        "type": "object",
                        "additionalProperties": true
                    },
                    "attributes": {
                        "type": "object",
                        "additionalProperties": true
                    },
                    "reviews": {
                        "type": [
                            "array",
                            "object"
                        ]
                    },
                    "rank": {
                        "type": [
                            "integer",
                            "null"
                        ]
                    },
                    "source": {
                        "type": [
                            "string",
                            "null"
                        ]
                    }
                }
            },
            "ScoredCandidate": {
                "type": "object",
                "properties": {
                    "candidate": {
                        "$ref": "#/components/schemas/Candidate"
                    },
                    "score": {
                        "$ref": "#/components/schemas/Score"
                    }
                }
            },
            "ProductRecord": {
                "type": "object",
                "description": "Persistierter Datensatz aus afflink_products.",
                "additionalProperties": true
            },
            "HealthResponse": {
                "type": "object",
                "properties": {
                    "status": {
                        "type": "string"
                    },
                    "time": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "host": {
                        "type": "string"
                    }
                }
            },
            "ApiInfoResponse": {
                "type": "object",
                "properties": {
                    "name": {
                        "type": "string"
                    },
                    "version": {
                        "type": "string"
                    },
                    "docs": {
                        "type": "string"
                    },
                    "openapi": {
                        "type": "string"
                    },
                    "health": {
                        "type": "string"
                    },
                    "auth": {
                        "type": "string"
                    },
                    "endpoints": {
                        "type": "object",
                        "additionalProperties": {
                            "type": "string"
                        }
                    }
                }
            },
            "SearchResponse": {
                "type": "object",
                "properties": {
                    "candidates": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/ScoredCandidate"
                        }
                    },
                    "best_match": {
                        "anyOf": [
                            {
                                "$ref": "#/components/schemas/ScoredCandidate"
                            },
                            {
                                "type": "null"
                            }
                        ]
                    },
                    "keywords": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        }
                    },
                    "expected_asin": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "analysis": {
                        "type": "object",
                        "additionalProperties": true
                    }
                }
            },
            "AddProductResponse": {
                "type": "object",
                "properties": {
                    "product": {
                        "$ref": "#/components/schemas/ProductRecord"
                    },
                    "best_match": {
                        "$ref": "#/components/schemas/ScoredCandidate"
                    },
                    "candidates": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/ScoredCandidate"
                        }
                    },
                    "analysis": {
                        "type": "object",
                        "additionalProperties": true
                    }
                }
            },
            "GetProductLinkResponse": {
                "type": "object",
                "properties": {
                    "product": {
                        "$ref": "#/components/schemas/ProductRecord"
                    },
                    "link": {
                        "type": "string"
                    },
                    "score": {
                        "$ref": "#/components/schemas/Score"
                    }
                }
            },
            "ListProductsResponse": {
                "type": "object",
                "properties": {
                    "products": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/ProductRecord"
                        }
                    }
                }
            },
            "QueueRefreshResponse": {
                "type": "object",
                "properties": {
                    "status": {
                        "type": "string"
                    },
                    "mode": {
                        "type": "string",
                        "enum": [
                            "created",
                            "updated"
                        ]
                    },
                    "asin": {
                        "type": "string"
                    },
                    "project": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "product": {
                        "$ref": "#/components/schemas/ProductRecord"
                    },
                    "best_match": {
                        "anyOf": [
                            {
                                "$ref": "#/components/schemas/ScoredCandidate"
                            },
                            {
                                "type": "null"
                            }
                        ]
                    },
                    "candidates": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/ScoredCandidate"
                        }
                    },
                    "analysis": {
                        "type": "object",
                        "additionalProperties": true
                    }
                }
            },
            "UpdateProductsResponse": {
                "type": "object",
                "properties": {
                    "updates": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/AddProductResponse"
                        }
                    },
                    "limit": {
                        "type": "integer"
                    },
                    "stale_minutes": {
                        "type": "integer"
                    },
                    "priority_minutes": {
                        "type": [
                            "integer",
                            "null"
                        ]
                    },
                    "cooldown": {
                        "type": "object",
                        "additionalProperties": true
                    }
                }
            }
        },
        "responses": {
            "Unauthorized": {
                "description": "Fehlender oder ungueltiger Bearer-Token.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        },
                        "example": {
                            "error": "Nicht autorisiert.",
                            "status": 401
                        }
                    }
                }
            }
        }
    },
    "paths": {
        "/": {
            "get": {
                "tags": [
                    "Public"
                ],
                "summary": "API-Metadaten",
                "responses": {
                    "200": {
                        "description": "API-Info",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ApiInfoResponse"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/health": {
            "get": {
                "tags": [
                    "Public"
                ],
                "summary": "Healthcheck",
                "responses": {
                    "200": {
                        "description": "API ist erreichbar",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/HealthResponse"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/add-product": {
            "post": {
                "tags": [
                    "Products"
                ],
                "summary": "Produkt neu anlegen",
                "security": [
                    {
                        "bearerAuth": []
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "keywords": {
                                        "type": [
                                            "string",
                                            "null"
                                        ]
                                    },
                                    "asin": {
                                        "type": [
                                            "string",
                                            "null"
                                        ]
                                    },
                                    "locale": {
                                        "type": "string",
                                        "default": "de-DE"
                                    },
                                    "notes": {
                                        "type": [
                                            "string",
                                            "null"
                                        ]
                                    },
                                    "title": {
                                        "type": [
                                            "string",
                                            "null"
                                        ]
                                    },
                                    "replacement_mode": {
                                        "type": [
                                            "string",
                                            "null"
                                        ]
                                    },
                                    "replacement_keywords": {
                                        "type": [
                                            "string",
                                            "null"
                                        ]
                                    },
                                    "strict_model_pattern": {
                                        "type": [
                                            "string",
                                            "null"
                                        ]
                                    },
                                    "fallback_asins": {
                                        "type": [
                                            "string",
                                            "array",
                                            "null"
                                        ]
                                    },
                                    "exclude_expected_asin": {
                                        "type": "boolean"
                                    },
                                    "excluded_asins": {
                                        "type": [
                                            "string",
                                            "array",
                                            "null"
                                        ]
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Produkt angelegt",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/AddProductResponse"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        },
        "/search-product": {
            "post": {
                "tags": [
                    "Products"
                ],
                "summary": "Produkt suchen ohne Persistenz",
                "security": [
                    {
                        "bearerAuth": []
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "keywords": {
                                        "type": [
                                            "string",
                                            "null"
                                        ]
                                    },
                                    "asin": {
                                        "type": [
                                            "string",
                                            "null"
                                        ]
                                    },
                                    "pages": {
                                        "type": [
                                            "integer",
                                            "null"
                                        ]
                                    },
                                    "max_results": {
                                        "type": [
                                            "integer",
                                            "null"
                                        ]
                                    },
                                    "title": {
                                        "type": [
                                            "string",
                                            "null"
                                        ]
                                    },
                                    "replacement_mode": {
                                        "type": [
                                            "string",
                                            "null"
                                        ]
                                    },
                                    "replacement_keywords": {
                                        "type": [
                                            "string",
                                            "null"
                                        ]
                                    },
                                    "strict_model_pattern": {
                                        "type": [
                                            "string",
                                            "null"
                                        ]
                                    },
                                    "fallback_asins": {
                                        "type": [
                                            "string",
                                            "array",
                                            "null"
                                        ]
                                    },
                                    "exclude_expected_asin": {
                                        "type": "boolean"
                                    },
                                    "excluded_asins": {
                                        "type": [
                                            "string",
                                            "array",
                                            "null"
                                        ]
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Trefferliste",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/SearchResponse"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        },
        "/get-product-link": {
            "post": {
                "tags": [
                    "Products"
                ],
                "summary": "Besten gespeicherten Affiliate-Link liefern",
                "security": [
                    {
                        "bearerAuth": []
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "keywords": {
                                        "type": [
                                            "string",
                                            "null"
                                        ]
                                    },
                                    "asin": {
                                        "type": [
                                            "string",
                                            "null"
                                        ]
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Gefundener Affiliate-Link",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/GetProductLinkResponse"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        },
        "/list-products": {
            "get": {
                "tags": [
                    "Products"
                ],
                "summary": "Produkte listen",
                "security": [
                    {
                        "bearerAuth": []
                    }
                ],
                "parameters": [
                    {
                        "name": "limit",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "offset",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "active",
                        "in": "query",
                        "schema": {
                            "type": "integer",
                            "enum": [
                                0,
                                1
                            ]
                        }
                    },
                    {
                        "name": "search",
                        "in": "query",
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Produktliste",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ListProductsResponse"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        },
        "/inspect-product": {
            "get": {
                "tags": [
                    "Products"
                ],
                "summary": "Produkt per ID laden",
                "security": [
                    {
                        "bearerAuth": []
                    }
                ],
                "parameters": [
                    {
                        "name": "id",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Produktdatensatz",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ProductRecord"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        },
        "/queue-refresh": {
            "post": {
                "tags": [
                    "Products"
                ],
                "summary": "Zentralen Refresh anstossen",
                "description": "Fuehrt absichtlich keinen hostgebundenen Queue-Claim aus. Existierende Produkte werden aktualisiert, fehlende Produkte werden direkt angelegt.",
                "security": [
                    {
                        "bearerAuth": []
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "asin"
                                ],
                                "properties": {
                                    "asin": {
                                        "type": "string"
                                    },
                                    "project": {
                                        "type": [
                                            "string",
                                            "null"
                                        ]
                                    },
                                    "locale": {
                                        "type": "string",
                                        "default": "de-DE"
                                    },
                                    "priority": {
                                        "type": [
                                            "string",
                                            "null"
                                        ]
                                    },
                                    "keywords": {
                                        "type": [
                                            "string",
                                            "null"
                                        ]
                                    },
                                    "title": {
                                        "type": [
                                            "string",
                                            "null"
                                        ]
                                    },
                                    "source": {
                                        "type": [
                                            "string",
                                            "null"
                                        ]
                                    },
                                    "replacement_mode": {
                                        "type": [
                                            "string",
                                            "null"
                                        ]
                                    },
                                    "replacement_keywords": {
                                        "type": [
                                            "string",
                                            "null"
                                        ]
                                    },
                                    "strict_model_pattern": {
                                        "type": [
                                            "string",
                                            "null"
                                        ]
                                    },
                                    "fallback_asins": {
                                        "type": [
                                            "string",
                                            "array",
                                            "null"
                                        ]
                                    },
                                    "exclude_expected_asin": {
                                        "type": "boolean"
                                    },
                                    "excluded_asins": {
                                        "type": [
                                            "string",
                                            "array",
                                            "null"
                                        ]
                                    },
                                    "needs_image": {
                                        "type": "boolean"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Produkt erstellt oder aktualisiert",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/QueueRefreshResponse"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        },
        "/update-product": {
            "post": {
                "tags": [
                    "Products"
                ],
                "summary": "Produkt per ID aktualisieren",
                "security": [
                    {
                        "bearerAuth": []
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "required": [
                                    "id"
                                ],
                                "properties": {
                                    "id": {
                                        "type": "integer"
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Aktualisierter Datensatz",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/AddProductResponse"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        },
        "/update-products": {
            "post": {
                "tags": [
                    "Products"
                ],
                "summary": "Faellige Produkte batchweise aktualisieren",
                "security": [
                    {
                        "bearerAuth": []
                    }
                ],
                "requestBody": {
                    "required": false,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "limit": {
                                        "type": "integer",
                                        "default": 5
                                    },
                                    "stale_minutes": {
                                        "type": "integer",
                                        "default": 60
                                    },
                                    "priority_minutes": {
                                        "type": [
                                            "integer",
                                            "null"
                                        ]
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Batch-Ergebnis",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/UpdateProductsResponse"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    }
                }
            }
        }
    }
}
