{
    "openapi": "3.0.3",
    "info": {
        "title": "BrandsGateway Vendor API",
        "version": "1.0.0",
        "description": "Self-service product integration for BrandsGateway vendors.\n\n**One credential.** Every authenticated endpoint takes your BrandsGateway\nusername and an application password over HTTP Basic, plus your vendor id\nin `X-Vendor-Id`. The portal issues no key of its own; your credentials are\nverified upstream on every call, and ownership of the vendor is checked\nwith them.\n\n**Your id, not ours.** Product paths end with your own external id. The\nfirst call creates the product and every call after updates it, so\nre-sending the same product never makes a duplicate.\n\n**Nothing fails silently.** Every rejection carries one of 34\ndocumented codes, each with a cause and a fix. See `/docs/errors`.\n\nThis document is generated from the same schema and error catalogue the\nvalidator enforces \u2014 it cannot drift from the implementation.",
        "contact": {
            "name": "BrandsGateway",
            "url": "https://vendors.brandsgateway.com/docs"
        }
    },
    "servers": [
        {
            "url": "https://vendors.brandsgateway.com",
            "description": "Configured target"
        }
    ],
    "tags": [
        {
            "name": "Products",
            "description": "Send your catalog and read back what BrandsGateway holds."
        },
        {
            "name": "Validation",
            "description": "Check a payload before you send it. Unauthenticated and side-effect free."
        }
    ],
    "paths": {
        "/api/v1/validate": {
            "post": {
                "tags": [
                    "Validation"
                ],
                "summary": "Check a payload without sending it",
                "description": "Unauthenticated and side-effect free \u2014 safe to call from CI on every build. Accepts a bare product, the `{ values, product }` envelope, or `{ products: [...] }` for up to 500 at once.",
                "security": [],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "oneOf": [
                                    {
                                        "$ref": "#/components/schemas/Submission"
                                    },
                                    {
                                        "$ref": "#/components/schemas/Product"
                                    },
                                    {
                                        "type": "object",
                                        "properties": {
                                            "products": {
                                                "type": "array",
                                                "maxItems": 500,
                                                "items": {
                                                    "$ref": "#/components/schemas/Submission"
                                                }
                                            }
                                        }
                                    }
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "400": {
                        "description": "Body is not valid JSON.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    },
                    "413": {
                        "description": "More than 500 products in one request.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Error"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/api/v1/products/{externalId}": {
            "put": {
                "tags": [
                    "Products"
                ],
                "summary": "Create or update one product",
                "description": "The upsert. Matched on your own external id, so the first call creates and every call after updates. Images are skipped on update unless `forceImages` is true.",
                "security": [
                    {
                        "vendorBasicAuth": [],
                        "vendorId": []
                    }
                ],
                "parameters": [
                    {
                        "$ref": "#/components/parameters/externalId"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/Submission"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Updated."
                    },
                    "201": {
                        "description": "Created."
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    },
                    "502": {
                        "$ref": "#/components/responses/UpstreamUnavailable"
                    }
                }
            }
        }
    },
    "components": {
        "securitySchemes": {
            "vendorBasicAuth": {
                "type": "http",
                "scheme": "basic",
                "description": "Your BrandsGateway username and an application password. Create one under Users \u2192 Profile \u2192 Application Passwords in the marketplace admin. Spaces in the generated password are ignored."
            },
            "vendorId": {
                "type": "apiKey",
                "in": "header",
                "name": "X-Vendor-Id",
                "description": "Your vendor term id. The authenticated user must own it."
            },
            "adminKey": {
                "type": "apiKey",
                "in": "header",
                "name": "X-Api-Key",
                "description": "BrandsGateway's own key. Guards the two routes that span every vendor."
            }
        },
        "schemas": {
            "Product": {
                "type": "object",
                "required": [
                    "type",
                    "categories",
                    "brands",
                    "attributes",
                    "meta_data",
                    "images",
                    "name",
                    "sku",
                    "genders",
                    "conditions",
                    "groups"
                ],
                "properties": {
                    "type": {
                        "type": "string",
                        "enum": [
                            "simple",
                            "variable"
                        ]
                    },
                    "categories": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "required": [
                                "id"
                            ],
                            "properties": {
                                "id": {
                                    "type": "integer"
                                }
                            }
                        }
                    },
                    "brands": {
                        "type": "array",
                        "minItems": 1,
                        "items": {
                            "type": "object",
                            "required": [
                                "id"
                            ],
                            "properties": {
                                "id": {
                                    "type": "integer",
                                    "minimum": 1
                                }
                            }
                        }
                    },
                    "color": {
                        "type": "string",
                        "minLength": 1
                    },
                    "attributes": {
                        "type": "array",
                        "minItems": 1,
                        "items": {
                            "type": "object",
                            "required": [
                                "id",
                                "variation",
                                "options"
                            ],
                            "properties": {
                                "id": {
                                    "type": "integer"
                                },
                                "variation": {
                                    "type": "boolean"
                                },
                                "options": {
                                    "type": "array",
                                    "minItems": 1,
                                    "items": {
                                        "type": "string"
                                    }
                                }
                            }
                        }
                    },
                    "meta_data": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "required": [
                                "key",
                                "value"
                            ],
                            "properties": {
                                "key": {
                                    "type": "string"
                                },
                                "value": {
                                    "oneOf": [
                                        {
                                            "type": "string"
                                        },
                                        {
                                            "type": "number"
                                        },
                                        {
                                            "type": "boolean"
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "images": {
                        "type": "array",
                        "minItems": 1,
                        "items": {
                            "type": "object",
                            "required": [
                                "src"
                            ],
                            "properties": {
                                "src": {
                                    "type": "string",
                                    "format": "uri"
                                }
                            }
                        }
                    },
                    "short_description": {
                        "type": "string"
                    },
                    "name": {
                        "type": "string",
                        "minLength": 1
                    },
                    "sku": {
                        "type": "string",
                        "minLength": 1
                    },
                    "genders": {
                        "type": "array",
                        "minItems": 1,
                        "items": {
                            "type": "object",
                            "required": [
                                "id"
                            ],
                            "properties": {
                                "id": {
                                    "type": "integer"
                                }
                            }
                        }
                    },
                    "conditions": {
                        "type": "array",
                        "minItems": 1,
                        "items": {
                            "type": "object",
                            "required": [
                                "id"
                            ],
                            "properties": {
                                "id": {
                                    "type": "integer"
                                }
                            }
                        }
                    },
                    "groups": {
                        "type": "array",
                        "minItems": 1,
                        "items": {
                            "type": "object",
                            "required": [
                                "id"
                            ],
                            "properties": {
                                "id": {
                                    "type": "integer"
                                }
                            }
                        }
                    },
                    "global_unique_id": {
                        "type": "string"
                    },
                    "regular_price": {
                        "type": "string",
                        "pattern": "^[0-9]+(\\.[0-9]{1,2})?$"
                    },
                    "sale_price": {
                        "type": "string",
                        "pattern": "^[0-9]+(\\.[0-9]{1,2})?$"
                    },
                    "stock_quantity": {
                        "type": "integer",
                        "minimum": 0
                    },
                    "manage_stock": {
                        "type": "boolean"
                    },
                    "vendor_id": {
                        "type": "string"
                    },
                    "materials": {
                        "type": "string"
                    },
                    "variations": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "required": [
                                "sale_price",
                                "regular_price",
                                "stock_quantity",
                                "global_unique_id",
                                "attributes",
                                "sku",
                                "meta_data"
                            ],
                            "properties": {
                                "sale_price": {
                                    "type": "string",
                                    "pattern": "^[0-9]+(\\.[0-9]{1,2})?$"
                                },
                                "regular_price": {
                                    "type": "string",
                                    "pattern": "^[0-9]+(\\.[0-9]{1,2})?$"
                                },
                                "stock_quantity": {
                                    "type": "integer",
                                    "minimum": 0
                                },
                                "global_unique_id": {
                                    "type": "string",
                                    "minLength": 1
                                },
                                "attributes": {
                                    "type": "object",
                                    "minProperties": 1
                                },
                                "sku": {
                                    "type": "string",
                                    "minLength": 1
                                },
                                "variable_global_unique_id": {
                                    "type": "string"
                                },
                                "meta_data": {
                                    "type": "array",
                                    "items": {
                                        "type": "object",
                                        "required": [
                                            "key",
                                            "value"
                                        ],
                                        "properties": {
                                            "key": {
                                                "type": "string"
                                            },
                                            "value": {
                                                "oneOf": [
                                                    {
                                                        "type": "string"
                                                    },
                                                    {
                                                        "type": "number"
                                                    },
                                                    {
                                                        "type": "boolean"
                                                    }
                                                ]
                                            }
                                        }
                                    },
                                    "allOf": [
                                        {
                                            "contains": {
                                                "properties": {
                                                    "key": {
                                                        "const": "_variation_external_id"
                                                    }
                                                }
                                            },
                                            "errorMessage": "Missing required meta_data key: _variation_external_id"
                                        },
                                        {
                                            "contains": {
                                                "properties": {
                                                    "key": {
                                                        "const": "_vendor_cost"
                                                    }
                                                }
                                            },
                                            "errorMessage": "Missing required meta_data key: _vendor_cost"
                                        },
                                        {
                                            "contains": {
                                                "properties": {
                                                    "key": {
                                                        "const": "_vendor_sku"
                                                    }
                                                }
                                            },
                                            "errorMessage": "Missing required meta_data key: _vendor_sku"
                                        }
                                    ]
                                }
                            }
                        }
                    }
                },
                "allOf": [
                    {
                        "if": {
                            "properties": {
                                "type": {
                                    "const": "simple"
                                }
                            }
                        },
                        "then": {
                            "required": [
                                "regular_price",
                                "sale_price",
                                "stock_quantity",
                                "manage_stock",
                                "global_unique_id"
                            ],
                            "properties": {
                                "meta_data": {
                                    "allOf": [
                                        {
                                            "contains": {
                                                "properties": {
                                                    "key": {
                                                        "const": "_bgorigincountry"
                                                    }
                                                }
                                            },
                                            "errorMessage": "Missing required meta_data key: _bgorigincountry"
                                        },
                                        {
                                            "contains": {
                                                "properties": {
                                                    "key": {
                                                        "const": "_external_id"
                                                    }
                                                }
                                            },
                                            "errorMessage": "Missing required meta_data key: _external_id"
                                        },
                                        {
                                            "contains": {
                                                "properties": {
                                                    "key": {
                                                        "const": "_vendor_cost"
                                                    }
                                                }
                                            },
                                            "errorMessage": "Missing required meta_data key: _vendor_cost"
                                        },
                                        {
                                            "contains": {
                                                "properties": {
                                                    "key": {
                                                        "const": "_vendor_sku"
                                                    }
                                                }
                                            },
                                            "errorMessage": "Missing required meta_data key: _vendor_sku"
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    {
                        "if": {
                            "properties": {
                                "type": {
                                    "const": "variable"
                                }
                            }
                        },
                        "then": {
                            "required": [
                                "variations"
                            ],
                            "properties": {
                                "variations": {
                                    "minItems": 1
                                },
                                "meta_data": {
                                    "allOf": [
                                        {
                                            "contains": {
                                                "properties": {
                                                    "key": {
                                                        "const": "_bgorigincountry"
                                                    }
                                                }
                                            },
                                            "errorMessage": "Missing required meta_data key: _bgorigincountry"
                                        },
                                        {
                                            "contains": {
                                                "properties": {
                                                    "key": {
                                                        "const": "_external_id"
                                                    }
                                                }
                                            },
                                            "errorMessage": "Missing required meta_data key: _external_id"
                                        }
                                    ]
                                }
                            }
                        }
                    }
                ]
            },
            "Finding": {
                "type": "object",
                "description": "One thing wrong with a payload.",
                "properties": {
                    "severity": {
                        "type": "string",
                        "enum": [
                            "error",
                            "warning"
                        ],
                        "description": "An error is rejected. A warning is accepted now and may be pulled during catalog review later."
                    },
                    "path": {
                        "type": "string",
                        "description": "Where in the payload, e.g. `variations[2].sale_price`.",
                        "example": "variations[2].sale_price"
                    },
                    "code": {
                        "type": "string",
                        "description": "Stable machine code. Documented at /docs/errors.",
                        "enum": [
                            "missing_brand",
                            "missing_category",
                            "missing_group_mapping",
                            "missing_color",
                            "missing_material",
                            "missing_country",
                            "missing_size_mapping",
                            "missing_gender",
                            "missing_condition",
                            "schema_validation_error",
                            "missing_required_field",
                            "missing_meta_key",
                            "invalid_price_format",
                            "invalid_type",
                            "invalid_enum",
                            "pattern_mismatch",
                            "empty_string",
                            "empty_array",
                            "empty_object",
                            "out_of_range",
                            "invalid_format",
                            "missing_ean",
                            "invalid_price_ratio",
                            "no_valid_variations",
                            "images_below_two",
                            "duplicate_external_id",
                            "invalid_external_id",
                            "missing_variation_attribute",
                            "duplicate_ean_within_product",
                            "missing_import_source",
                            "product_invalid_global_unique_id",
                            "woocommerce_rest_product_not_created",
                            "api_error",
                            "rate_limited"
                        ]
                    },
                    "message": {
                        "type": "string"
                    },
                    "hint": {
                        "type": "string",
                        "description": "How to fix it."
                    }
                },
                "required": [
                    "severity",
                    "path",
                    "code",
                    "message"
                ]
            },
            "ValidationResult": {
                "type": "object",
                "properties": {
                    "valid": {
                        "type": "boolean",
                        "description": "True only when there are zero errors."
                    },
                    "errors": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/Finding"
                        }
                    },
                    "warnings": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/Finding"
                        }
                    },
                    "unresolved": {
                        "type": "array",
                        "description": "Values that do not map to a BrandsGateway term yet. A near match is never applied automatically \u2014 a silently mis-mapped brand is worse than a recorded failure.",
                        "items": {
                            "$ref": "#/components/schemas/Unresolved"
                        }
                    },
                    "summary": {
                        "$ref": "#/components/schemas/ValidationSummary"
                    }
                },
                "required": [
                    "valid",
                    "errors",
                    "warnings",
                    "summary"
                ]
            },
            "ValidationSummary": {
                "type": "object",
                "properties": {
                    "type": {
                        "type": "string",
                        "enum": [
                            "simple",
                            "variable",
                            "unknown"
                        ]
                    },
                    "externalId": {
                        "type": "string",
                        "nullable": true
                    },
                    "sku": {
                        "type": "string",
                        "nullable": true
                    },
                    "name": {
                        "type": "string",
                        "nullable": true
                    },
                    "variationCount": {
                        "type": "integer"
                    },
                    "imageCount": {
                        "type": "integer"
                    }
                }
            },
            "Unresolved": {
                "type": "object",
                "properties": {
                    "field": {
                        "type": "string",
                        "example": "brand"
                    },
                    "value": {
                        "type": "string",
                        "example": "DOLCE & GABBANA"
                    },
                    "code": {
                        "type": "string",
                        "example": "missing_brand"
                    },
                    "suggestions": {
                        "type": "array",
                        "description": "Near matches, for a human to confirm. Never applied automatically.",
                        "items": {
                            "type": "object",
                            "properties": {
                                "id": {
                                    "type": "integer"
                                },
                                "name": {
                                    "type": "string"
                                }
                            }
                        }
                    }
                }
            },
            "Submission": {
                "type": "object",
                "description": "The envelope. Send taxonomy values in your own words under `values` and BrandsGateway resolves them to term ids, or send a bare product with ids already in place.",
                "properties": {
                    "values": {
                        "$ref": "#/components/schemas/Values"
                    },
                    "product": {
                        "$ref": "#/components/schemas/Product"
                    },
                    "forceImages": {
                        "type": "boolean",
                        "description": "Images are skipped on update unless this is true."
                    },
                    "dryRun": {
                        "type": "boolean",
                        "description": "Validate and resolve, but do not write."
                    }
                }
            },
            "Values": {
                "type": "object",
                "description": "Your own vocabulary. Each is resolved to a BrandsGateway term id.",
                "properties": {
                    "brand": {
                        "type": "string",
                        "description": "The designer or label. One brand per product. Brands are curated by BrandsGateway \u2014 a brand that is not on the platform cannot be created from a feed."
                    },
                    "category": {
                        "type": "string",
                        "description": "The shop's browsable category tree. A product usually carries both a parent and a leaf category (e.g. Women 19 and Knitwear 26)."
                    },
                    "group": {
                        "type": "string",
                        "description": "The merchandising hierarchy that drives filtering, size axes and harmonised codes. Send the full ancestor chain, leaf last \u2014 e.g. Clothing 71651, Sweaters 71673, Sweatshirts 71675."
                    },
                    "gender": {
                        "type": "string",
                        "description": "Exactly three terms. Fixed platform-wide.",
                        "enum": [
                            "Men",
                            "Women",
                            "Unisex"
                        ]
                    },
                    "condition": {
                        "type": "string",
                        "description": "Stock condition. Drives whether returns are accepted, so it is never inferred \u2014 it must be sent.",
                        "enum": [
                            "New with tags"
                        ]
                    },
                    "size": {
                        "type": "string",
                        "description": "Colour is attribute 14 and is never a variation axis. Size attributes are per sizing system; pick the one that matches how your feed expresses sizes and send its term slugs in variation attributes.",
                        "enum": [
                            "Colour",
                            "Italian Size WOMEN",
                            "Italian Size MEN",
                            "Shoe Size EU"
                        ]
                    },
                    "color": {
                        "type": "string",
                        "description": "Colour name in your own words, e.g. \"Nero\".",
                        "example": "Nero"
                    },
                    "material": {
                        "type": "string",
                        "description": "Composition in your own words.",
                        "example": "Calf Leather"
                    },
                    "country": {
                        "type": "string",
                        "description": "Country of manufacture. Resolved to an ISO-3166-1 alpha-2 code.",
                        "example": "Italy"
                    }
                }
            },
            "Error": {
                "type": "object",
                "properties": {
                    "error": {
                        "type": "string",
                        "description": "Machine code."
                    },
                    "message": {
                        "type": "string"
                    }
                },
                "required": [
                    "error"
                ]
            }
        },
        "responses": {
            "ValidationFailed": {
                "description": "The payload was rejected. Every finding carries a documented code.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ValidationResult"
                        }
                    }
                }
            },
            "Unauthorized": {
                "description": "Missing or invalid credentials, or the user does not own this vendor.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        }
                    }
                }
            },
            "RateLimited": {
                "description": "Too many requests. Writes are limited per vendor; `Retry-After` says how long to wait.",
                "headers": {
                    "Retry-After": {
                        "schema": {
                            "type": "integer"
                        },
                        "description": "Seconds."
                    }
                },
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        }
                    }
                }
            },
            "UpstreamUnavailable": {
                "description": "BrandsGateway could not be reached, or answered partially.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Error"
                        }
                    }
                }
            },
            "code_missing_brand": {
                "description": "Brand could not be mapped\n\n**Why it happens.** The brand name in your feed does not resolve to an existing BrandsGateway brand term.\n\n**How to fix it.** Look the brand up in the Brands reference and send its numeric term ID. If the brand genuinely does not exist on BrandsGateway yet, request it \u2014 do not invent an ID.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ValidationResult"
                        }
                    }
                }
            },
            "code_missing_category": {
                "description": "Category could not be mapped\n\n**Why it happens.** Your product's category path has no mapping to a BrandsGateway category.\n\n**How to fix it.** Map your category string to a BrandsGateway category term ID once; the mapping then applies to every product in that category.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ValidationResult"
                        }
                    }
                }
            },
            "code_missing_group_mapping": {
                "description": "Product group has no attribute set\n\n**Why it happens.** The product group you sent exists, but it carries no size attribute, so variations cannot be built.\n\n**How to fix it.** Pick a leaf product group that has a size axis (e.g. Sweaters, Sneakers), not a top-level container group.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ValidationResult"
                        }
                    }
                }
            },
            "code_missing_color": {
                "description": "Colour could not be mapped\n\n**Why it happens.** The colour value is empty, or it does not match any BrandsGateway colour.\n\n**How to fix it.** Send one of the BrandsGateway colour names (e.g. \"Beige\", \"Black\") in `color` and mirror it in the colour attribute (id 14).",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ValidationResult"
                        }
                    }
                }
            },
            "code_missing_material": {
                "description": "Material could not be mapped\n\n**Why it happens.** The composition string contains a material BrandsGateway does not recognise.\n\n**How to fix it.** Split the composition into individual materials and map each to a BrandsGateway material name. Percentages are stripped before matching.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ValidationResult"
                        }
                    }
                }
            },
            "code_missing_country": {
                "description": "Country of origin could not be mapped\n\n**Why it happens.** The country value is missing or is not a recognised country.\n\n**How to fix it.** Send a two-letter ISO country code, e.g. `IT`, `CN`, `PT`.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ValidationResult"
                        }
                    }
                }
            },
            "code_missing_size_mapping": {
                "description": "One or more sizes could not be mapped\n\n**Why it happens.** A size in your feed has no corresponding term in the size attribute taxonomy you selected.\n\n**How to fix it.** Use the size slugs of the attribute you declared. If your sizing system differs (e.g. FR vs IT), pick the matching attribute rather than translating values yourself.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ValidationResult"
                        }
                    }
                }
            },
            "code_missing_gender": {
                "description": "Gender could not be mapped\n\n**Why it happens.** The gender word in your feed does not resolve to a BrandsGateway gender term.\n\n**How to fix it.** Send the numeric term ID from the Genders reference. Gender IDs are per-install, not platform constants \u2014 read them from `/api/v1/reference/genders` rather than copying an ID out of a document. Feed words like \"Donna\", \"Woman\" and \"Ladies\" all mean the same term; map them once on your side.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ValidationResult"
                        }
                    }
                }
            },
            "code_missing_condition": {
                "description": "Condition could not be mapped\n\n**Why it happens.** The product condition you sent has no matching BrandsGateway condition term.\n\n**How to fix it.** Look it up in `/api/v1/reference/conditions` and send the numeric term ID. Like genders, conditions are per-install. Omit the field entirely if all your stock is new and the install has no explicit \"new\" term.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ValidationResult"
                        }
                    }
                }
            },
            "code_schema_validation_error": {
                "description": "Payload failed schema validation\n\n**Why it happens.** The product did not satisfy the BrandsGateway product JSON Schema. The response names the exact path and rule.\n\n**How to fix it.** Run the payload through the Validator before sending. Every finding it reports is a hard block.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ValidationResult"
                        }
                    }
                }
            },
            "code_missing_required_field": {
                "description": "A required field is absent\n\n**Why it happens.** One of the always-required fields, or a conditionally-required field for this product type, is missing.\n\n**How to fix it.** Simple products additionally require price, stock, `manage_stock` and `global_unique_id`. Variable products additionally require `variations`.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ValidationResult"
                        }
                    }
                }
            },
            "code_missing_meta_key": {
                "description": "A required meta_data key is absent\n\n**Why it happens.** `meta_data` is present but does not contain a key the schema requires for this product type.\n\n**How to fix it.** `meta_data` is an array of `{ key, value }` objects. Both product types need `_bgorigincountry` and `_external_id`; simple products also need `_vendor_cost` and `_vendor_sku`.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ValidationResult"
                        }
                    }
                }
            },
            "code_invalid_price_format": {
                "description": "Price is not a valid decimal string\n\n**Why it happens.** Prices must be strings matching `^[0-9]+(\\.[0-9]{1,2})?$` \u2014 no currency symbol, no comma decimal separator, no more than two decimals.\n\n**How to fix it.** Send `\"280.00\"`, not `280`, `\"280,00\"` or `\"\u20ac280\"`.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ValidationResult"
                        }
                    }
                }
            },
            "code_invalid_type": {
                "description": "Field has the wrong JSON type\n\n**Why it happens.** A value is the right idea but the wrong type \u2014 most often a numeric price, a stringified stock count, or a taxonomy name where an integer ID is expected.\n\n**How to fix it.** Prices are strings; stock and all taxonomy IDs are integers.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ValidationResult"
                        }
                    }
                }
            },
            "code_invalid_enum": {
                "description": "Value is not one of the allowed options\n\n**Why it happens.** The field accepts a fixed set of values and yours is not in it. The error message lists every value that is allowed.\n\n**How to fix it.** Copy one of the listed values exactly \u2014 they are case-sensitive. The usual cause is a translated or title-cased variant (`\"Simple\"` for `\"simple\"`).",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ValidationResult"
                        }
                    }
                }
            },
            "code_pattern_mismatch": {
                "description": "Value does not match the required format\n\n**Why it happens.** The field is constrained by a regular expression and your value does not satisfy it. The message quotes the pattern.\n\n**How to fix it.** Check for stray whitespace, punctuation or unit suffixes. `external_id` is the common one: it must be alphanumeric only \u2014 a hyphen makes the product URL 404 upstream, so it is rejected here first.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ValidationResult"
                        }
                    }
                }
            },
            "code_empty_string": {
                "description": "Field is present but blank\n\n**Why it happens.** The field was sent as an empty string. That is not the same as omitting it, and it is never valid for a required field.\n\n**How to fix it.** Send a real value, or leave the key out entirely if the field is optional. A blank `name` or `sku` usually means an upstream lookup in your own feed returned nothing \u2014 fix it there rather than sending the blank through.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ValidationResult"
                        }
                    }
                }
            },
            "code_empty_array": {
                "description": "Array needs at least one entry\n\n**Why it happens.** A list that must not be empty was sent as `[]` \u2014 most often `images`, `brands`, `categories`, `groups` or `attributes`.\n\n**How to fix it.** Populate it, or omit the key if the field is optional. An empty `attributes` on a variable product is the frequent case, and it means your size axis was never built.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ValidationResult"
                        }
                    }
                }
            },
            "code_empty_object": {
                "description": "Object needs at least one key\n\n**Why it happens.** An object that must carry at least one key was sent as `{}`.\n\n**How to fix it.** Usually `variations[].attributes`, which is an object keyed by taxonomy slug \u2014 e.g. `{ \"pa_italian-size-women\": \"m\" }`. An empty one means the size slug was not resolved before you sent the product; call `/api/v1/resolve` first.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ValidationResult"
                        }
                    }
                }
            },
            "code_out_of_range": {
                "description": "Number is below the allowed minimum\n\n**Why it happens.** A numeric field is smaller than the schema permits. The message states the limit.\n\n**How to fix it.** Most often a negative `stock_quantity`. Send `0` for out of stock \u2014 negative stock is not how you remove a product, `POST /products/{id}/reset` is.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ValidationResult"
                        }
                    }
                }
            },
            "code_invalid_format": {
                "description": "Value is not a valid URI, date or email\n\n**Why it happens.** The field declares a format and the value does not parse as one. Almost always an image URL.\n\n**How to fix it.** Image URLs must be absolute and publicly reachable \u2014 `https://\u2026`, not a relative path, not a `file://` URL, and not behind a login. BrandsGateway fetches them server-side, so anything your CDN blocks by referer or IP will fail here.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ValidationResult"
                        }
                    }
                }
            },
            "code_missing_ean": {
                "description": "No EAN / barcode\n\n**Why it happens.** The product (or a variation) has no `global_unique_id`. BrandsGateway identifies stock across the marketplace by barcode.\n\n**How to fix it.** Supply a real EAN per sellable unit \u2014 per product for simple, per size for variable. Do not synthesise one.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ValidationResult"
                        }
                    }
                }
            },
            "code_invalid_price_ratio": {
                "description": "Sale price is not below retail price\n\n**Why it happens.** `sale_price` is greater than or equal to `regular_price`. BrandsGateway sells below RRP by definition.\n\n**How to fix it.** Send the true retail price in `regular_price` and your BrandsGateway price in `sale_price`.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ValidationResult"
                        }
                    }
                }
            },
            "code_no_valid_variations": {
                "description": "No sellable variation remained\n\n**Why it happens.** Every variation was dropped \u2014 typically because each one failed the price check or had no stock.\n\n**How to fix it.** Only send variations that are genuinely sellable. A product with nothing left to sell should be reported as out of stock instead.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ValidationResult"
                        }
                    }
                }
            },
            "code_images_below_two": {
                "description": "Fewer than two images\n\n**Why it happens.** The product carries fewer than two usable images.\n\n**How to fix it.** Provide at least two publicly reachable, absolute image URLs.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ValidationResult"
                        }
                    }
                }
            },
            "code_duplicate_external_id": {
                "description": "Duplicate external ID in the same feed\n\n**Why it happens.** Two products in one submission share an `_external_id`. Both are dropped, because the platform cannot tell which is authoritative.\n\n**How to fix it.** `_external_id` must be unique and stable per product across your whole catalog and across time.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ValidationResult"
                        }
                    }
                }
            },
            "code_invalid_external_id": {
                "description": "External ID contains characters BrandsGateway cannot route\n\n**Why it happens.** BrandsGateway only routes external IDs made of letters and digits. An ID with a hyphen, underscore, space or dot never reaches the product endpoint, and would otherwise come back as a confusing `rest_no_route`.\n\n**How to fix it.** Use only A\u2013Z, a\u2013z and 0\u20139 \u2014 `SKU12345`, not `SKU-12345`. The external ID is the product's permanent identity, so pick the format once, before the first send.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ValidationResult"
                        }
                    }
                }
            },
            "code_missing_variation_attribute": {
                "description": "Variable product has no size axis\n\n**Why it happens.** A variable product needs at least one attribute marked `variation: true`. Yours has none, so there is nothing for the variations to vary along.\n\n**How to fix it.** The size attribute must be `variation: true` and list every size in `options`. Note that the colour attribute (id 14) is `variation: false` on purpose \u2014 colour is a property of the product, size is the axis. Having only colour is the usual cause.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ValidationResult"
                        }
                    }
                }
            },
            "code_duplicate_ean_within_product": {
                "description": "Two variations share one barcode\n\n**Why it happens.** The same EAN appears on more than one variation of this product.\n\n**How to fix it.** Every size needs its own barcode. BrandsGateway enforces `global_unique_id` uniqueness across the whole platform, so a duplicate inside one product would fail upstream anyway \u2014 and would take the rest of the product with it. If you genuinely do not have per-size barcodes, ask BrandsGateway before inventing them.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ValidationResult"
                        }
                    }
                }
            },
            "code_missing_import_source": {
                "description": "No `_import_source` meta key\n\n**Why it happens.** The product carries no marker saying which feed it came from. This is a warning: the product still imports.\n\n**How to fix it.** Set `_import_source` to your vendor slug. It costs nothing and it is what makes a product traceable back to your feed when someone is investigating a problem months later.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ValidationResult"
                        }
                    }
                }
            },
            "code_product_invalid_global_unique_id": {
                "description": "EAN already in use on BrandsGateway\n\n**Why it happens.** The barcode is already attached to a different product \u2014 often another vendor's listing of the same item. The response names the conflicting product, its vendor and its URL.\n\n**How to fix it.** Confirm the EAN is correct. If it is, the item is already on the marketplace under another vendor and BrandsGateway resolves the conflict commercially \u2014 not by overwriting.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ValidationResult"
                        }
                    }
                }
            },
            "code_woocommerce_rest_product_not_created": {
                "description": "BrandsGateway refused to create the product\n\n**Why it happens.** The payload passed validation but the platform could not persist it \u2014 typically a SKU collision or an unresolvable term reference.\n\n**How to fix it.** Check that `sku` is unique across your catalog and that every taxonomy ID you sent exists.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ValidationResult"
                        }
                    }
                }
            },
            "code_api_error": {
                "description": "Unclassified API error\n\n**Why it happens.** BrandsGateway returned a 4xx/5xx that does not map to a known code.\n\n**How to fix it.** Retry with backoff. If it persists, open the run in the dashboard and share the run ID with support.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ValidationResult"
                        }
                    }
                }
            },
            "code_rate_limited": {
                "description": "Too many requests\n\n**Why it happens.** You exceeded the per-vendor request rate.\n\n**How to fix it.** Keep submissions to roughly two products per second per vendor and retry after the interval named in the response.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/ValidationResult"
                        }
                    }
                }
            }
        },
        "parameters": {
            "externalId": {
                "name": "externalId",
                "in": "path",
                "required": true,
                "schema": {
                    "type": "string"
                },
                "description": "Your own permanent product identifier \u2014 the upsert key. Must be alphanumeric; a hyphen breaks the product URL.",
                "example": "SKU12345"
            },
            "vendorIdQuery": {
                "name": "vendorId",
                "in": "query",
                "required": false,
                "schema": {
                    "type": "string"
                },
                "description": "Staff only. A vendor credential is always scoped to its own vendor."
            },
            "days": {
                "name": "days",
                "in": "query",
                "required": false,
                "schema": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 90,
                    "default": 30
                },
                "description": "Window in days."
            }
        }
    },
    "security": [
        {
            "vendorBasicAuth": [],
            "vendorId": []
        }
    ]
}