{
  "components": {
    "schemas": {
      "AsdaCategoriesListCompletedJob": {
        "additionalProperties": false,
        "properties": {
          "billing": {
            "$ref": "#/components/schemas/JobBilling"
          },
          "capability": {
            "enum": [
              "asda.categories.list"
            ],
            "type": "string"
          },
          "job_id": {
            "format": "uuid",
            "type": "string"
          },
          "platform": {
            "enum": [
              "asda"
            ],
            "type": "string"
          },
          "request_id": {
            "format": "uuid",
            "type": "string"
          },
          "results": {
            "items": {
              "additionalProperties": false,
              "properties": {
                "data": {
                  "description": "Raw capability output. Its shape may evolve with the upstream source; the example is illustrative, not a compatibility guarantee.",
                  "example": {
                    "categories": [
                      {
                        "children": [
                          {
                            "children": [
                              {
                                "depth": 3,
                                "name": "Bedding",
                                "path": "Home & Entertainment > Bed, Bath & Home > Bedding",
                                "product_count": 4117
                              },
                              {
                                "depth": 3,
                                "name": "Bath Towels & Mats",
                                "path": "Home & Entertainment > Bed, Bath & Home > Bath Towels & Mats",
                                "product_count": 2051
                              },
                              {
                                "depth": 3,
                                "name": "Candles & Room Fragrances",
                                "path": "Home & Entertainment > Bed, Bath & Home > Candles & Room Fragrances",
                                "product_count": 1733
                              }
                            ],
                            "depth": 2,
                            "id": "1215334114125",
                            "name": "Bed, Bath & Home",
                            "path": "Home & Entertainment > Bed, Bath & Home",
                            "product_count": 13238
                          },
                          {
                            "children": [
                              {
                                "depth": 3,
                                "name": "Books",
                                "path": "Home & Entertainment > Music, Film, Games & Books > Books",
                                "product_count": 6789
                              },
                              {
                                "depth": 3,
                                "name": "DVDs & Blu-rays",
                                "path": "Home & Entertainment > Music, Film, Games & Books > DVDs & Blu-rays",
                                "product_count": 2248
                              },
                              {
                                "depth": 3,
                                "name": "Music",
                                "path": "Home & Entertainment > Music, Film, Games & Books > Music",
                                "product_count": 775
                              }
                            ],
                            "depth": 2,
                            "id": "1215186489092",
                            "name": "Music, Film, Games & Books",
                            "path": "Home & Entertainment > Music, Film, Games & Books",
                            "product_count": 10557
                          },
                          {
                            "children": [
                              {
                                "depth": 3,
                                "name": "Dining & Glassware",
                                "path": "Home & Entertainment > Kitchen > Dining & Glassware",
                                "product_count": 2719
                              },
                              {
                                "depth": 3,
                                "name": "Cooking",
                                "path": "Home & Entertainment > Kitchen > Cooking",
                                "product_count": 868
                              },
                              {
                                "depth": 3,
                                "name": "Food Storage Solutions",
                                "path": "Home & Entertainment > Kitchen > Food Storage Solutions",
                                "product_count": 779
                              }
                            ],
                            "depth": 2,
                            "id": "1215334114085",
                            "name": "Kitchen",
                            "path": "Home & Entertainment > Kitchen",
                            "product_count": 6415
                          }
                        ],
                        "depth": 1,
                        "id": "1215135760682",
                        "name": "Home & Entertainment",
                        "path": "Home & Entertainment",
                        "product_count": 51456
                      },
                      {
                        "children": [
                          {
                            "children": [
                              {
                                "depth": 3,
                                "name": "Sweets",
                                "path": "Food Cupboard > Chocolates & Sweets > Sweets",
                                "product_count": 694
                              },
                              {
                                "depth": 3,
                                "name": "Boxed Chocolates & Gifts",
                                "path": "Food Cupboard > Chocolates & Sweets > Boxed Chocolates & Gifts",
                                "product_count": 529
                              },
                              {
                                "depth": 3,
                                "name": "Sharing Chocolate Bars",
                                "path": "Food Cupboard > Chocolates & Sweets > Sharing Chocolate Bars",
                                "product_count": 360
                              }
                            ],
                            "depth": 2,
                            "id": "1215279696813",
                            "name": "Chocolates & Sweets",
                            "path": "Food Cupboard > Chocolates & Sweets",
                            "product_count": 2518
                          },
                          {
                            "children": [
                              {
                                "depth": 3,
                                "name": "Sauces & Condiments",
                                "path": "Food Cupboard > Condiments & Cooking Ingredients > Sauces & Condiments",
                                "product_count": 455
                              },
                              {
                                "depth": 3,
                                "name": "Spices",
                                "path": "Food Cupboard > Condiments & Cooking Ingredients > Spices",
                                "product_count": 244
                              },
                              {
                                "depth": 3,
                                "name": "Oil & Vinegar",
                                "path": "Food Cupboard > Condiments & Cooking Ingredients > Oil & Vinegar",
                                "product_count": 183
                              }
                            ],
                            "depth": 2,
                            "id": "1215354523758",
                            "name": "Condiments & Cooking Ingredients",
                            "path": "Food Cupboard > Condiments & Cooking Ingredients",
                            "product_count": 1553
                          },
                          {
                            "children": [
                              {
                                "depth": 3,
                                "name": "Sharing Crisps",
                                "path": "Food Cupboard > Crisps, Nuts & Popcorn > Sharing Crisps",
                                "product_count": 548
                              },
                              {
                                "depth": 3,
                                "name": "Multipack Crisps",
                                "path": "Food Cupboard > Crisps, Nuts & Popcorn > Multipack Crisps",
                                "product_count": 363
                              },
                              {
                                "depth": 3,
                                "name": "Nuts & Dried Fruit",
                                "path": "Food Cupboard > Crisps, Nuts & Popcorn > Nuts & Dried Fruit",
                                "product_count": 257
                              }
                            ],
                            "depth": 2,
                            "id": "1215165893478",
                            "name": "Crisps, Nuts & Popcorn",
                            "path": "Food Cupboard > Crisps, Nuts & Popcorn",
                            "product_count": 1283
                          }
                        ],
                        "depth": 1,
                        "id": "1215337189632",
                        "name": "Food Cupboard",
                        "path": "Food Cupboard",
                        "product_count": 12143
                      },
                      {
                        "children": [
                          {
                            "children": [
                              {
                                "depth": 3,
                                "name": "Face",
                                "path": "Toiletries & Beauty > Make Up & Nails > Face",
                                "product_count": 856
                              },
                              {
                                "depth": 3,
                                "name": "Nails",
                                "path": "Toiletries & Beauty > Make Up & Nails > Nails",
                                "product_count": 589
                              },
                              {
                                "depth": 3,
                                "name": "Lips",
                                "path": "Toiletries & Beauty > Make Up & Nails > Lips",
                                "product_count": 521
                              }
                            ],
                            "depth": 2,
                            "id": "1215185955607",
                            "name": "Make Up & Nails",
                            "path": "Toiletries & Beauty > Make Up & Nails",
                            "product_count": 2612
                          },
                          {
                            "children": [
                              {
                                "depth": 3,
                                "name": "Shampoo & Conditioner",
                                "path": "Toiletries & Beauty > Hair Care, Dye & Styling > Shampoo & Conditioner",
                                "product_count": 1134
                              },
                              {
                                "depth": 3,
                                "name": "Hair Dye",
                                "path": "Toiletries & Beauty > Hair Care, Dye & Styling > Hair Dye",
                                "product_count": 562
                              },
                              {
                                "depth": 3,
                                "name": "Hair Accessories",
                                "path": "Toiletries & Beauty > Hair Care, Dye & Styling > Hair Accessories",
                                "product_count": 225
                              }
                            ],
                            "depth": 2,
                            "id": "1215431206069",
                            "name": "Hair Care, Dye & Styling",
                            "path": "Toiletries & Beauty > Hair Care, Dye & Styling",
                            "product_count": 2132
                          },
                          {
                            "children": [
                              {
                                "depth": 3,
                                "name": "Face Cream & Moisturiser",
                                "path": "Toiletries & Beauty > Skin Care > Face Cream & Moisturiser",
                                "product_count": 328
                              },
                              {
                                "depth": 3,
                                "name": "Cleansers & Face Washes",
                                "path": "Toiletries & Beauty > Skin Care > Cleansers & Face Washes",
                                "product_count": 267
                              },
                              {
                                "depth": 3,
                                "name": "Hands, Lips & Foot Care",
                                "path": "Toiletries & Beauty > Skin Care > Hands, Lips & Foot Care",
                                "product_count": 168
                              }
                            ],
                            "depth": 2,
                            "id": "1215431252930",
                            "name": "Skin Care",
                            "path": "Toiletries & Beauty > Skin Care",
                            "product_count": 1112
                          }
                        ],
                        "depth": 1,
                        "id": "1215135760648",
                        "name": "Toiletries & Beauty",
                        "path": "Toiletries & Beauty",
                        "product_count": 9924
                      }
                    ],
                    "raw": {
                      "facets": {
                        "": {
                          "Frozen Food": 2947,
                          "Baby, Toddler & Kids": 2216,
                          "Other": 6763,
                          "Meat, Poultry & Fish": 4107,
                          "Chilled Food": 7137,
                          "Valentine's Day": 4,
                          "Organic": 2,
                          "Better For You": 2,
                          "World Food": 1403,
                          "Exceptional By Asda": 6,
                          "Beer, Wine & Spirits": 5079,
                          "Halloween": 378,
                          "Back to School": 6,
                          "Pet Food & Accessories": 2141,
                          "Vegan & Free From": 1,
                          "Kiosk": 903,
                          "Father's Day": 17,
                          "Dietary & Lifestyle": 714,
                          "Big Night In": 2,
                          "Going to Uni": 1,
                          "Fresh Fruit, Vegetables & Flowers": 943,
                          "JUST ESSENTIALS": 2,
                          "Vegan & Plant Based": 5,
                          "Christmas": 834,
                          "Sweets, Treats & Snacks": 126,
                          "Drinks": 1699,
                          "Home & Entertainment": 51456,
                          "Toiletries & Beauty": 9924,
                          "Live Better": 5,
                          "Easter": 148,
                          "Laundry & Household": 4157,
                          "Coronation Celebration": 18,
                          "Bakery": 2900,
                          "Exceptional by Asda (OLD)": 1,
                          "Mother's Day": 70,
                          "Happy Lunar New Year": 4,
                          "Rollback": 28,
                          "Get Match Ready": 8,
                          "Ramadan": 7,
                          "Celebrate New Year": 2,
                          "Veganuary": 1,
                          "Free From...": 15,
                          "Events & Inspiration": 108,
                          "Health & Wellness": 2407,
                          "Food Cupboard": 12143,
                          "Garden & Outdoor": 1,
                          "Price Drop": 2,
                          "The Entertainer Toys": 131,
                          "Summer": 14
                        },
                        "Food Cupboard": {
                          "Better For You Food Cupboard": 1,
                          "Biscuits": 936,
                          "Cereals & Cereal Bars": 823,
                          "Chocolates & Sweets": 2518,
                          "Christmas Treats & Food Cupboard": 2,
                          "Coffee, Tea & Hot Chocolate": 1019,
                          "Condiments & Cooking Ingredients": 1553,
                          "Cooking Sauces, Meal Kits & Sides": 938,
                          "Crackers & Savoury Biscuits": 1,
                          "Crisps, Nuts & Popcorn": 1283,
                          "Easter Chocolate & Sweets": 2,
                          "Food Cupboard": 1,
                          "Free From & Organic": 2,
                          "Halloween Treats & Baking": 2,
                          "Home Baking": 732,
                          "Jams, Spreads & Desserts": 604,
                          "Noodle Pots & Instant Snacks": 420,
                          "Rice, Pasta & Noodles": 436,
                          "Tinned Food": 849,
                          "Under 100 Calories Food Cupboard": 14,
                          "World Foods": 7
                        },
                        "Food Cupboard > Chocolates & Sweets": {
                          "Boxed Chocolates & Gifts": 529,
                          "Chocolate Bags & Cartons": 354,
                          "Christmas Chocolates & Sweets": 1,
                          "Coming Soon for Easter": 3,
                          "Confectionery Tubs, Tins & Refill Pouches": 1,
                          "Dark Chocolate": 4,
                          "Exceptional Chocolates & Sweets": 2,
                          "Fun Size Chocolate & Sweets": 14,
                          "Mints & Chewing Gum": 141,
                          "Multipack Chocolate": 222,
                          "Sharing Chocolate Bars": 360,
                          "Small Chocolate Bars & Bags": 189,
                          "Sweet Biscuits": 2,
                          "Sweets": 694,
                          "Valentine's Day": 2
                        },
                        "Food Cupboard > Condiments & Cooking Ingredients": {
                          "Chutney & Pickles": 151,
                          "Dry Herbs": 60,
                          "Gravy": 116,
                          "Marinades & Rubs": 109,
                          "Oil & Vinegar": 183,
                          "Passata & Tomato Puree": 4,
                          "Popular Brands": 7,
                          "Salad Dressing & Croutons": 47,
                          "Salt & Pepper": 56,
                          "Sauces & Condiments": 455,
                          "Spices": 244,
                          "Stock": 91,
                          "Stuffing & Breadcrumbs": 30
                        },
                        "Food Cupboard > Crisps, Nuts & Popcorn": {
                          "Healthier Snacks & Bars": 1,
                          "Multipack Crisps": 363,
                          "Nuts & Dried Fruit": 257,
                          "Popcorn": 72,
                          "Sharing Crisps": 548,
                          "Tortilla Chips & Dips": 42
                        },
                        "Home & Entertainment": {
                          "At Home with Stacey Solomon": 90,
                          "Batteries & Light Bulbs": 460,
                          "Bed, Bath & Home": 13238,
                          "Celebrating Disney": 3,
                          "Christmas": 1511,
                          "DIY & Car Care": 1275,
                          "Disney": 6,
                          "Fathers Day": 26,
                          "For The Home": 1,
                          "Garden & Outdoor": 2217,
                          "Greeting Cards": 1180,
                          "Halloween": 838,
                          "JML": 122,
                          "Kids Party": 1,
                          "Kitchen": 6415,
                          "Mother's Day Gifts & Dine": 36,
                          "Music, Film, Games & Books": 10557,
                          "Party, Cards & Gift Wrap": 222,
                          "Partyware & Gifting": 3291,
                          "Stationery, Magazines & Stamps": 2186,
                          "Technology & Electricals": 1649,
                          "Toys": 5405,
                          "Travel & Leisure": 723,
                          "Valentine's Gifts & Decorations": 4
                        },
                        "Home & Entertainment > Bed, Bath & Home": {
                          "Baby & Kids Bedroom": 1047,
                          "Bath Towels & Mats": 2051,
                          "Bathroom Accessories": 638,
                          "Bedding": 4117,
                          "Candles & Room Fragrances": 1733,
                          "Decor & Lighting": 1681,
                          "Photo Frames & Albums": 240,
                          "Soft Furnishings": 1731
                        },
                        "Home & Entertainment > Kitchen": {
                          "Baking": 231,
                          "Cooking": 868,
                          "Dining & Glassware": 2719,
                          "Disposable Table, Drink & Foodware": 28,
                          "Food Storage Solutions": 779,
                          "Kids Dine": 538,
                          "Kitchen Appliances": 568,
                          "Laundry & Cleaning Essentials": 194,
                          "Textiles & Decor": 455,
                          "Water Filters & Cartridges": 35
                        },
                        "Home & Entertainment > Music, Film, Games & Books": {
                          "Books": 6789,
                          "Christmas Books, CDs & Films": 1,
                          "DVDs & Blu-rays": 2248,
                          "Games & Accessories": 744,
                          "Music": 775
                        },
                        "Toiletries & Beauty": {
                          "Baby & Kids Toiletries": 20,
                          "Bath, Shower & Soap": 718,
                          "Bladder Weakness": 112,
                          "Dental Care": 547,
                          "Deodorants & Body Sprays": 332,
                          "Fragrance & Gifting": 5,
                          "Gifting": 596,
                          "Hair Care, Dye & Styling": 2132,
                          "Hair Removal & Grooming": 240,
                          "Health & Medicines": 84,
                          "Health & Wellbeing": 4,
                          "Make Up & Nails": 2612,
                          "Men's Toiletries": 406,
                          "Period Products": 65,
                          "Skin Care": 1112,
                          "Sun Care & Travel": 580,
                          "Toiletries": 11,
                          "Women's Toiletries": 348
                        },
                        "Toiletries & Beauty > Hair Care, Dye & Styling": {
                          "Baby & Children's Hair Care": 1,
                          "Hair Accessories": 225,
                          "Hair Dye": 562,
                          "Hair Protection & Treatments": 19,
                          "Hairspray & Styling": 177,
                          "Shampoo & Conditioner": 1134,
                          "Shop By Hair Need": 1,
                          "Vegan Hair Care": 1,
                          "Waves, Curls & Coils": 12
                        },
                        "Toiletries & Beauty > Make Up & Nails": {
                          "Cosmetics": 2,
                          "Eyebrow": 173,
                          "Eyes": 450,
                          "Face": 856,
                          "Get The Festival Look": 1,
                          "Lips": 521,
                          "Make Up & Beauty Gifts": 19,
                          "Nails": 589,
                          "Vegan Make Up": 1
                        },
                        "Toiletries & Beauty > Skin Care": {
                          "Body Moisturisers & Lotions": 161,
                          "Cleansers & Face Washes": 267,
                          "Face Cream & Moisturiser": 328,
                          "Face Masks & Strips": 145,
                          "Hands, Lips & Foot Care": 168,
                          "Medicated Skin Care": 2,
                          "New In Skin Care": 1,
                          "Popular Brands": 1,
                          "Self Tan": 9,
                          "Shop by Skin Type": 30
                        }
                      }
                    },
                    "store_id": "4565"
                  }
                },
                "error": {
                  "type": "null"
                },
                "index": {
                  "const": 0,
                  "type": "integer"
                },
                "url": {
                  "anyOf": [
                    {
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              },
              "required": [
                "index",
                "url",
                "data",
                "error"
              ],
              "type": "object"
            },
            "maxItems": 1,
            "minItems": 1,
            "type": "array"
          },
          "state": {
            "const": "completed",
            "type": "string"
          },
          "stats": {
            "$ref": "#/components/schemas/JobStats"
          },
          "success": {
            "const": true,
            "type": "boolean"
          }
        },
        "required": [
          "job_id",
          "request_id",
          "platform",
          "capability",
          "state",
          "success",
          "results",
          "billing",
          "stats"
        ],
        "type": "object"
      },
      "AsdaCategoriesListExecuteRequest": {
        "additionalProperties": false,
        "example": {
          "capability": "asda.categories.list",
          "input": {
            "store_id": "4565"
          }
        },
        "properties": {
          "capability": {
            "enum": [
              "asda.categories.list"
            ],
            "type": "string"
          },
          "input": {
            "$ref": "#/components/schemas/AsdaCategoriesListInput"
          },
          "network": {
            "$ref": "#/components/schemas/ExecuteNetwork"
          },
          "timeout_ms": {
            "description": "Optional request timeout in milliseconds. Values above the capability timeout are rejected.",
            "maximum": 30000,
            "minimum": 1,
            "type": "integer"
          }
        },
        "required": [
          "capability",
          "input"
        ],
        "type": "object"
      },
      "AsdaCategoriesListInput": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "additionalProperties": false,
        "properties": {
          "limit": {
            "minimum": 1,
            "type": "integer"
          },
          "max_records": {
            "minimum": 1,
            "type": "integer"
          },
          "store_id": {
            "default": "4565",
            "description": "Asda store id used for stock boosting",
            "pattern": "^[0-9]{1,6}$",
            "type": "string"
          }
        },
        "type": "object"
      },
      "CredentialsRequiredError": {
        "additionalProperties": false,
        "properties": {
          "error": {
            "additionalProperties": false,
            "properties": {
              "code": {
                "const": "credentials_required",
                "type": "string"
              },
              "message": {
                "const": "this capability requires authentication credentials; save them via POST /credentials",
                "type": "string"
              }
            },
            "required": [
              "code",
              "message"
            ],
            "type": "object"
          }
        },
        "required": [
          "error"
        ],
        "type": "object"
      },
      "ExecuteAcceptedResponse": {
        "additionalProperties": false,
        "properties": {
          "capability": {
            "enum": [
              "asda.categories.list"
            ],
            "type": "string"
          },
          "job_id": {
            "format": "uuid",
            "type": "string"
          },
          "platform": {
            "enum": [
              "asda"
            ],
            "type": "string"
          },
          "request_id": {
            "format": "uuid",
            "type": "string"
          },
          "state": {
            "const": "queued",
            "type": "string"
          }
        },
        "required": [
          "job_id",
          "request_id",
          "platform",
          "capability",
          "state"
        ],
        "type": "object"
      },
      "ExecuteNetwork": {
        "additionalProperties": false,
        "properties": {
          "session_id": {
            "description": "Optional explicit session identifier.",
            "minLength": 1,
            "type": "string"
          },
          "session_key": {
            "description": "Optional stable key used to derive a reusable session.",
            "minLength": 1,
            "type": "string"
          },
          "sticky": {
            "description": "Whether the request should reuse the resolved session.",
            "type": "boolean"
          }
        },
        "type": "object"
      },
      "ExecuteReplayResponse": {
        "additionalProperties": false,
        "description": "Replayed response matching the original job's current state (completed, failed, or pending).",
        "properties": {
          "billing": {
            "$ref": "#/components/schemas/JobBilling"
          },
          "capability": {
            "enum": [
              "asda.categories.list"
            ],
            "type": "string"
          },
          "error": {},
          "idempotent_replay": {
            "const": true,
            "type": "boolean"
          },
          "job_id": {
            "format": "uuid",
            "type": "string"
          },
          "platform": {
            "enum": [
              "asda"
            ],
            "type": "string"
          },
          "request_id": {
            "format": "uuid",
            "type": "string"
          },
          "results": {},
          "state": {
            "enum": [
              "queued",
              "running",
              "retrying",
              "completed",
              "failed"
            ],
            "type": "string"
          },
          "stats": {},
          "success": {
            "type": "boolean"
          }
        },
        "required": [
          "job_id",
          "request_id",
          "platform",
          "capability",
          "state",
          "idempotent_replay"
        ],
        "type": "object"
      },
      "IdempotencyConflictError": {
        "additionalProperties": false,
        "properties": {
          "error": {
            "additionalProperties": false,
            "properties": {
              "code": {
                "const": "idempotency_conflict",
                "type": "string"
              },
              "message": {
                "const": "idempotency key has already been used for a different request",
                "type": "string"
              }
            },
            "required": [
              "code",
              "message"
            ],
            "type": "object"
          }
        },
        "required": [
          "error"
        ],
        "type": "object"
      },
      "InternalError": {
        "additionalProperties": false,
        "properties": {
          "error": {
            "additionalProperties": false,
            "properties": {
              "code": {
                "const": "internal_error",
                "type": "string"
              },
              "message": {
                "type": "string"
              }
            },
            "required": [
              "code",
              "message"
            ],
            "type": "object"
          }
        },
        "required": [
          "error"
        ],
        "type": "object"
      },
      "JobBilling": {
        "additionalProperties": false,
        "properties": {
          "credits_charged": {
            "anyOf": [
              {
                "description": "Actual credits charged. Null only when retained historical facts cannot establish the amount.",
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "credits_per_unit": {
            "anyOf": [
              {
                "description": "Snapshotted price for one billed unit. Zero only for historical free work; null when unknown.",
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "model": {
            "enum": [
              "per_request",
              "per_record",
              "free",
              "unknown"
            ],
            "type": "string"
          },
          "pricing": {
            "additionalProperties": false,
            "properties": {
              "rule_id": {
                "anyOf": [
                  {
                    "minLength": 1,
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "scope": {
                "anyOf": [
                  {
                    "enum": [
                      "module",
                      "platform",
                      "capability"
                    ],
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "source": {
                "enum": [
                  "manifest",
                  "price_book"
                ],
                "type": "string"
              },
              "version": {
                "anyOf": [
                  {
                    "minimum": 1,
                    "type": "integer"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "required": [
              "source",
              "scope",
              "version",
              "rule_id"
            ],
            "type": "object"
          },
          "units": {
            "anyOf": [
              {
                "description": "Billed units under the stated model. Null when units do not apply or cannot be established.",
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "model",
          "units",
          "credits_per_unit",
          "credits_charged",
          "pricing"
        ],
        "type": "object"
      },
      "JobErrorObject": {
        "additionalProperties": false,
        "properties": {
          "code": {
            "description": "Machine-readable error code (e.g. forbidden, not_found, invalid_input, upstream_timeout, upstream_error).",
            "type": "string"
          },
          "message": {
            "description": "Human-readable error description.",
            "type": "string"
          }
        },
        "required": [
          "code",
          "message"
        ],
        "type": "object"
      },
      "JobFailedResponse": {
        "additionalProperties": false,
        "properties": {
          "capability": {
            "enum": [
              "asda.categories.list"
            ],
            "type": "string"
          },
          "error": {
            "$ref": "#/components/schemas/JobErrorObject"
          },
          "job_id": {
            "format": "uuid",
            "type": "string"
          },
          "platform": {
            "enum": [
              "asda"
            ],
            "type": "string"
          },
          "request_id": {
            "format": "uuid",
            "type": "string"
          },
          "results": {
            "type": "null"
          },
          "state": {
            "const": "failed",
            "type": "string"
          },
          "stats": {
            "type": "null"
          },
          "success": {
            "const": false,
            "type": "boolean"
          }
        },
        "required": [
          "job_id",
          "request_id",
          "platform",
          "capability",
          "state",
          "success",
          "error",
          "results",
          "stats"
        ],
        "type": "object"
      },
      "JobPendingResponse": {
        "additionalProperties": false,
        "properties": {
          "capability": {
            "enum": [
              "asda.categories.list"
            ],
            "type": "string"
          },
          "job_id": {
            "format": "uuid",
            "type": "string"
          },
          "platform": {
            "enum": [
              "asda"
            ],
            "type": "string"
          },
          "request_id": {
            "format": "uuid",
            "type": "string"
          },
          "state": {
            "enum": [
              "queued",
              "running",
              "retrying"
            ],
            "type": "string"
          }
        },
        "required": [
          "job_id",
          "request_id",
          "platform",
          "capability",
          "state"
        ],
        "type": "object"
      },
      "JobStats": {
        "additionalProperties": false,
        "properties": {
          "duration_ms": {
            "anyOf": [
              {
                "minimum": 0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "failed": {
            "const": 0,
            "type": "integer"
          },
          "passed": {
            "const": 1,
            "type": "integer"
          },
          "total": {
            "const": 1,
            "type": "integer"
          }
        },
        "required": [
          "total",
          "passed",
          "failed",
          "duration_ms"
        ],
        "type": "object"
      },
      "NotFoundError": {
        "additionalProperties": false,
        "properties": {
          "error": {
            "additionalProperties": false,
            "properties": {
              "code": {
                "const": "not_found",
                "type": "string"
              },
              "message": {
                "const": "job not found",
                "type": "string"
              }
            },
            "required": [
              "code",
              "message"
            ],
            "type": "object"
          }
        },
        "required": [
          "error"
        ],
        "type": "object"
      },
      "QuotaError": {
        "oneOf": [
          {
            "additionalProperties": false,
            "properties": {
              "error": {
                "additionalProperties": false,
                "properties": {
                  "code": {
                    "const": "account_inactive",
                    "type": "string"
                  },
                  "message": {
                    "const": "an active paid account is required",
                    "type": "string"
                  }
                },
                "required": [
                  "code",
                  "message"
                ],
                "type": "object"
              }
            },
            "required": [
              "error"
            ],
            "type": "object"
          },
          {
            "additionalProperties": false,
            "properties": {
              "error": {
                "additionalProperties": false,
                "properties": {
                  "code": {
                    "const": "quota_exhausted",
                    "type": "string"
                  },
                  "message": {
                    "const": "request quota exhausted for current billing period",
                    "type": "string"
                  }
                },
                "required": [
                  "code",
                  "message"
                ],
                "type": "object"
              }
            },
            "required": [
              "error"
            ],
            "type": "object"
          }
        ]
      },
      "RateLimitError": {
        "additionalProperties": false,
        "properties": {
          "error": {
            "additionalProperties": false,
            "properties": {
              "code": {
                "const": "rate_limited",
                "type": "string"
              },
              "message": {
                "const": "rate limit exceeded",
                "type": "string"
              },
              "retry_after_ms": {
                "description": "Milliseconds until the rolling window resets enough to retry. The `retry-after` response header carries the same value rounded up to seconds.",
                "minimum": 0,
                "type": "integer"
              }
            },
            "required": [
              "code",
              "message",
              "retry_after_ms"
            ],
            "type": "object"
          }
        },
        "required": [
          "error"
        ],
        "type": "object"
      },
      "UnauthorizedError": {
        "additionalProperties": false,
        "properties": {
          "error": {
            "additionalProperties": false,
            "properties": {
              "code": {
                "const": "unauthorized",
                "type": "string"
              },
              "message": {
                "enum": [
                  "authentication required",
                  "invalid bearer token",
                  "missing bearer token"
                ],
                "type": "string"
              }
            },
            "required": [
              "code",
              "message"
            ],
            "type": "object"
          }
        },
        "required": [
          "error"
        ],
        "type": "object"
      },
      "ValidationErrors": {
        "additionalProperties": false,
        "properties": {
          "errors": {
            "additionalProperties": {
              "items": {
                "type": "string"
              },
              "type": "array"
            },
            "type": "object"
          }
        },
        "required": [
          "errors"
        ],
        "type": "object"
      }
    },
    "securitySchemes": {
      "BearerAuth": {
        "bearerFormat": "API Key",
        "scheme": "bearer",
        "type": "http"
      }
    }
  },
  "info": {
    "description": "Scraper for Asda Groceries UK product search, category taxonomy, and product detail, backed by Asda's public Algolia catalog index.\nThis spec includes only the live `Asda` capabilities exposed by Upscrape.\nExecution uses the generic `POST /execute` endpoint and job polling uses `GET /jobs/{id}`.\nSupported capabilities: `asda.categories.list`\n## Rate limiting\n\nRequests are rate-limited per API key at **1200 requests per minute** on a rolling window. Every response includes `x-ratelimit-limit`, `x-ratelimit-remaining`, and `x-ratelimit-reset` (Unix ms) headers so clients can self-pace. When the limit is exceeded the API returns `429` with a `rate_limited` error body and a `retry-after` header in seconds plus a `retry_after_ms` field on the body for finer-grained backoff.",
    "title": "Asda API",
    "version": "v0.1.3"
  },
  "jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
  "openapi": "3.1.0",
  "paths": {
    "/execute": {
      "post": {
        "description": "All executions are asynchronous. Submit a capability-specific payload to `POST /execute`, then poll the returned `job_id`.",
        "operationId": "asda_execute",
        "parameters": [
          {
            "description": "Optional idempotency key. Reusing the same key with the same request replays the original job.",
            "in": "header",
            "name": "Idempotency-Key",
            "required": false,
            "schema": {
              "maxLength": 255,
              "type": "string"
            }
          },
          {
            "description": "Request synchronous completion. Use `wait=N` to hold the connection up to N seconds (max 300). If the job completes within the window, the response is `200` with full results (same shape as `GET /jobs/{id}`). If not, the response is the normal `202` with a `job_id` for polling. Omit this header for default asynchronous behavior.",
            "examples": {
              "wait30": {
                "summary": "Wait up to 30 seconds",
                "value": "wait=30"
              },
              "wait5": {
                "summary": "Wait up to 5 seconds",
                "value": "wait=5"
              }
            },
            "in": "header",
            "name": "Prefer",
            "required": false,
            "schema": {
              "example": "wait=30",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "capability": "asda.categories.list",
                "input": {
                  "store_id": "4565"
                }
              },
              "schema": {
                "$ref": "#/components/schemas/AsdaCategoriesListExecuteRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/AsdaCategoriesListCompletedJob"
                    },
                    {
                      "$ref": "#/components/schemas/ExecuteReplayResponse"
                    },
                    {
                      "$ref": "#/components/schemas/JobFailedResponse"
                    }
                  ]
                }
              }
            },
            "description": "Job completed within the `Prefer: wait` window, or existing job replayed via idempotency key.",
            "headers": {
              "Preference-Applied": {
                "description": "Present when the server honored the `Prefer: wait` preference.",
                "schema": {
                  "example": "wait=30",
                  "type": "string"
                }
              },
              "x-ratelimit-limit": {
                "description": "Per-API-key request ceiling over the rolling window.",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "x-ratelimit-remaining": {
                "description": "Requests remaining in the current window before throttling.",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "x-ratelimit-reset": {
                "description": "Unix epoch milliseconds at which the current window resets.",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              }
            }
          },
          "202": {
            "content": {
              "application/json": {
                "example": {
                  "capability": "asda.categories.list",
                  "job_id": "00000000-0000-0000-0000-000000000001",
                  "platform": "asda",
                  "request_id": "00000000-0000-0000-0000-000000000001",
                  "state": "queued",
                  "success": false
                },
                "schema": {
                  "$ref": "#/components/schemas/ExecuteAcceptedResponse"
                }
              }
            },
            "description": "Job accepted and queued.",
            "headers": {
              "x-ratelimit-limit": {
                "description": "Per-API-key request ceiling over the rolling window.",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "x-ratelimit-remaining": {
                "description": "Requests remaining in the current window before throttling.",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "x-ratelimit-reset": {
                "description": "Unix epoch milliseconds at which the current window resets.",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedError"
                }
              }
            },
            "description": "Unauthorized"
          },
          "402": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QuotaError"
                }
              }
            },
            "description": "The authenticated account cannot execute the request."
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IdempotencyConflictError"
                }
              }
            },
            "description": "Idempotency conflict"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ValidationErrors"
                    },
                    {
                      "$ref": "#/components/schemas/CredentialsRequiredError"
                    }
                  ]
                }
              }
            },
            "description": "The request body failed validation."
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "rate limit exceeded",
                    "retry_after_ms": 4200
                  }
                },
                "schema": {
                  "$ref": "#/components/schemas/RateLimitError"
                }
              }
            },
            "description": "The per-API-key rate limit has been exceeded. Clients should back off until `retry_after_ms` has elapsed (or `retry-after` seconds).",
            "headers": {
              "retry-after": {
                "description": "Seconds until the client may retry (ceiling of `retry_after_ms`).",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "x-ratelimit-limit": {
                "description": "Per-API-key request ceiling over the rolling window.",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "x-ratelimit-remaining": {
                "description": "Requests remaining in the current window before throttling.",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "x-ratelimit-reset": {
                "description": "Unix epoch milliseconds at which the current window resets.",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              }
            }
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InternalError"
                }
              }
            },
            "description": "Unexpected server error"
          }
        },
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "summary": "Queue a Asda capability run",
        "tags": [
          "Execution"
        ]
      }
    },
    "/jobs/{id}": {
      "get": {
        "description": "Get job status and result",
        "operationId": "asda_getJob",
        "parameters": [
          {
            "description": "The job ID returned by `POST /execute`.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/AsdaCategoriesListCompletedJob"
                    },
                    {
                      "$ref": "#/components/schemas/JobFailedResponse"
                    }
                  ]
                }
              }
            },
            "description": "Completed or terminal job state.",
            "headers": {
              "x-ratelimit-limit": {
                "description": "Per-API-key request ceiling over the rolling window.",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "x-ratelimit-remaining": {
                "description": "Requests remaining in the current window before throttling.",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "x-ratelimit-reset": {
                "description": "Unix epoch milliseconds at which the current window resets.",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              }
            }
          },
          "202": {
            "content": {
              "application/json": {
                "example": {
                  "capability": "asda.categories.list",
                  "job_id": "00000000-0000-0000-0000-000000000001",
                  "platform": "asda",
                  "request_id": "00000000-0000-0000-0000-000000000001",
                  "state": "running",
                  "success": false
                },
                "schema": {
                  "$ref": "#/components/schemas/JobPendingResponse"
                }
              }
            },
            "description": "Job is still queued, running, or retrying.",
            "headers": {
              "x-ratelimit-limit": {
                "description": "Per-API-key request ceiling over the rolling window.",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "x-ratelimit-remaining": {
                "description": "Requests remaining in the current window before throttling.",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "x-ratelimit-reset": {
                "description": "Unix epoch milliseconds at which the current window resets.",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedError"
                }
              }
            },
            "description": "Unauthorized"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                }
              }
            },
            "description": "Job not found"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "rate limit exceeded",
                    "retry_after_ms": 4200
                  }
                },
                "schema": {
                  "$ref": "#/components/schemas/RateLimitError"
                }
              }
            },
            "description": "The per-API-key rate limit has been exceeded. Clients should back off until `retry_after_ms` has elapsed (or `retry-after` seconds).",
            "headers": {
              "retry-after": {
                "description": "Seconds until the client may retry (ceiling of `retry_after_ms`).",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "x-ratelimit-limit": {
                "description": "Per-API-key request ceiling over the rolling window.",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "x-ratelimit-remaining": {
                "description": "Requests remaining in the current window before throttling.",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "x-ratelimit-reset": {
                "description": "Unix epoch milliseconds at which the current window resets.",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              }
            }
          }
        },
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "summary": "Poll a Asda job",
        "tags": [
          "Jobs"
        ]
      }
    },
    "/jobs/{id}/result": {
      "get": {
        "description": "Backward-compatible alias for `/jobs/{id}`.",
        "operationId": "asda_getJobResult",
        "parameters": [
          {
            "description": "The job ID returned by `POST /execute`.",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/AsdaCategoriesListCompletedJob"
                    },
                    {
                      "$ref": "#/components/schemas/JobFailedResponse"
                    }
                  ]
                }
              }
            },
            "description": "Completed or terminal job state.",
            "headers": {
              "x-ratelimit-limit": {
                "description": "Per-API-key request ceiling over the rolling window.",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "x-ratelimit-remaining": {
                "description": "Requests remaining in the current window before throttling.",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "x-ratelimit-reset": {
                "description": "Unix epoch milliseconds at which the current window resets.",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              }
            }
          },
          "202": {
            "content": {
              "application/json": {
                "example": {
                  "capability": "asda.categories.list",
                  "job_id": "00000000-0000-0000-0000-000000000001",
                  "platform": "asda",
                  "request_id": "00000000-0000-0000-0000-000000000001",
                  "state": "running",
                  "success": false
                },
                "schema": {
                  "$ref": "#/components/schemas/JobPendingResponse"
                }
              }
            },
            "description": "Job is still queued, running, or retrying.",
            "headers": {
              "x-ratelimit-limit": {
                "description": "Per-API-key request ceiling over the rolling window.",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "x-ratelimit-remaining": {
                "description": "Requests remaining in the current window before throttling.",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "x-ratelimit-reset": {
                "description": "Unix epoch milliseconds at which the current window resets.",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedError"
                }
              }
            },
            "description": "Unauthorized"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                }
              }
            },
            "description": "Job not found"
          },
          "429": {
            "content": {
              "application/json": {
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "rate limit exceeded",
                    "retry_after_ms": 4200
                  }
                },
                "schema": {
                  "$ref": "#/components/schemas/RateLimitError"
                }
              }
            },
            "description": "The per-API-key rate limit has been exceeded. Clients should back off until `retry_after_ms` has elapsed (or `retry-after` seconds).",
            "headers": {
              "retry-after": {
                "description": "Seconds until the client may retry (ceiling of `retry_after_ms`).",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "x-ratelimit-limit": {
                "description": "Per-API-key request ceiling over the rolling window.",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "x-ratelimit-remaining": {
                "description": "Requests remaining in the current window before throttling.",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              },
              "x-ratelimit-reset": {
                "description": "Unix epoch milliseconds at which the current window resets.",
                "schema": {
                  "minimum": 0,
                  "type": "integer"
                }
              }
            }
          }
        },
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "summary": "Poll a Asda job",
        "tags": [
          "Jobs"
        ]
      }
    }
  },
  "servers": [
    {
      "url": "https://data.upscrape.com"
    }
  ],
  "tags": [
    {
      "description": "Submit asynchronous capability runs.",
      "name": "Execution"
    },
    {
      "description": "Poll queued jobs for status and results.",
      "name": "Jobs"
    }
  ]
}