{
  "name": "429: повтор любого запроса после Retry-After, если он не больше 60 с",
  "description": "POST с ключом повторяется через Retry-After (2 с) с тем же ключом. Retry-After: 600 больше maxRetryAfter — ошибка rate_limit без повтора, с retryAfter и ключом вызова. POST без ключа (verifyCode) после 429 тоже повторяется: ограничитель отказывает до обработки. 429 без Retry-After — пауза по обычной формуле. Метаданные последнего ответа несут остаток лимита.",
  "client": {
    "api": "runtime",
    "credential": {"terminalKey": "lk_test_k7m2p9q4r8s3.RqTvNAJirupwDOPZ8O48PZpsbGlZGfecp04FD7w06kw"},
    "baseUrl": "https://api.example.com"
  },
  "calls": [
    {
      "operation": "registerReceipt",
      "args": {
        "body": {
          "number": "1043",
          "business_date": "2026-10-11",
          "purchased_at": "2026-10-11T14:59:58+03:00",
          "member": {"phone": "+79000000001"},
          "lines": [{"id": "1", "sku": "LATTE-M", "name": "Латте 300 мл", "quantity": 2000, "amount": 50000}],
          "cashier": "Иванова"
        }
      },
      "expect": {
        "result": {
          "id": "01929c1e-0051-7051-8051-000000000051",
          "status": "reserved",
          "number": "1043",
          "business_date": "2026-10-11",
          "purchased_at": "2026-10-11T14:59:58+03:00",
          "member": {
            "id": "01929c1e-0040-7040-8040-000000000040",
            "masked_phone": "+7 *** ***-00-01",
            "status": "active"
          },
          "points": {"point_type_id": "01929c1e-0011-7011-8011-000000000011", "precision": 0},
          "rules": {"snapshot_id": "01929c1e-0012-7012-8012-000000000012", "version": 3},
          "total": 50000,
          "discount": 0,
          "redeemed_money": 0,
          "redeemed_points": 0,
          "points_earned": 25,
          "payable": 50000,
          "max_redeemable_points": 1000,
          "redemption_confirmation_required": false,
          "lines": [
            {
              "id": "1",
              "amount": 50000,
              "discount": 0,
              "redeemed_money": 0,
              "redeemed_points": 0,
              "points_earned": 25,
              "payable": 50000,
              "returned_quantity": 0
            }
          ],
          "campaigns": [],
          "stamps": [],
          "explanation": [{"code": "accrual", "data": {"percent_bp": 500, "base": 50000, "points": 25}}],
          "reserved_until": "2026-10-11T12:29:58.000000Z",
          "confirmed_at": null
        }
      }
    },
    {
      "operation": "sendRegistrationCode",
      "args": {"body": {"phone": "+79000000002"}},
      "expect": {
        "error": {
          "class": "rate_limit",
          "status": 429,
          "code": "verification_throttled",
          "requestId": "01929c20-0003-7000-8000-000000000003",
          "retryAfter": 600,
          "idempotencyKey": "{{idempotency-key}}"
        }
      }
    },
    {
      "operation": "verifyCode",
      "args": {"verification": "01929c1e-0070-7070-8070-000000000070", "body": {"code": "000000"}},
      "expect": {"result": null}
    },
    {
      "operation": "getBalance",
      "args": {"member": "01929c1e-0040-7040-8040-000000000040"},
      "expect": {
        "result": {
          "point_type_id": "01929c1e-0011-7011-8011-000000000011",
          "precision": 0,
          "available": 1035,
          "pending": 0,
          "held": 0,
          "spendable": 1035,
          "next_expiration": {"amount": 35, "at": "2027-10-11T12:00:01.250000Z"}
        }
      }
    },
    {
      "operation": "getBalance",
      "args": {"member": "01929c1e-0040-7040-8040-000000000040"},
      "options": {"maxRetries": 0},
      "expect": {
        "error": {
          "class": "rate_limit",
          "status": 429,
          "code": "too_many_requests",
          "requestId": "01929c20-0008-7000-8000-000000000008",
          "retryAfter": 1
        },
        "meta": {"status": 429, "requestId": "01929c20-0008-7000-8000-000000000008", "rateLimitRemaining": 0}
      }
    }
  ],
  "exchanges": [
    {
      "request": {
        "method": "POST",
        "url": "https://api.example.com/api/v1/receipts",
        "headers": {
          "authorization": "Bearer lk_test_k7m2p9q4r8s3.RqTvNAJirupwDOPZ8O48PZpsbGlZGfecp04FD7w06kw",
          "accept": "application/json",
          "content-type": "application/json",
          "idempotency-key": "{{idempotency-key}}",
          "loyal-merchant": null
        },
        "json": {
          "number": "1043",
          "business_date": "2026-10-11",
          "purchased_at": "2026-10-11T14:59:58+03:00",
          "member": {"phone": "+79000000001"},
          "lines": [{"id": "1", "sku": "LATTE-M", "name": "Латте 300 мл", "quantity": 2000, "amount": 50000}],
          "cashier": "Иванова"
        }
      },
      "response": {
        "status": 429,
        "headers": {
          "Content-Type": "application/problem+json",
          "X-Request-Id": "01929c20-0001-7000-8000-000000000001",
          "Loyal-Environment": "sandbox",
          "Retry-After": "2",
          "RateLimit-Limit": "60",
          "RateLimit-Remaining": "0",
          "RateLimit-Reset": "2"
        },
        "json": {
          "type": "urn:loyal:problem:too_many_requests",
          "title": "Too many requests.",
          "status": 429,
          "code": "too_many_requests",
          "request_id": "01929c20-0001-7000-8000-000000000001"
        }
      }
    },
    {
      "request": {
        "method": "POST",
        "url": "https://api.example.com/api/v1/receipts",
        "headers": {
          "authorization": "Bearer lk_test_k7m2p9q4r8s3.RqTvNAJirupwDOPZ8O48PZpsbGlZGfecp04FD7w06kw",
          "accept": "application/json",
          "content-type": "application/json",
          "idempotency-key": "{{idempotency-key}}",
          "loyal-merchant": null
        },
        "json": {
          "number": "1043",
          "business_date": "2026-10-11",
          "purchased_at": "2026-10-11T14:59:58+03:00",
          "member": {"phone": "+79000000001"},
          "lines": [{"id": "1", "sku": "LATTE-M", "name": "Латте 300 мл", "quantity": 2000, "amount": 50000}],
          "cashier": "Иванова"
        }
      },
      "response": {
        "status": 201,
        "headers": {
          "Content-Type": "application/json",
          "X-Request-Id": "01929c20-0002-7000-8000-000000000002",
          "Loyal-Environment": "sandbox"
        },
        "json": {
          "id": "01929c1e-0051-7051-8051-000000000051",
          "status": "reserved",
          "number": "1043",
          "business_date": "2026-10-11",
          "purchased_at": "2026-10-11T14:59:58+03:00",
          "member": {
            "id": "01929c1e-0040-7040-8040-000000000040",
            "masked_phone": "+7 *** ***-00-01",
            "status": "active"
          },
          "points": {"point_type_id": "01929c1e-0011-7011-8011-000000000011", "precision": 0},
          "rules": {"snapshot_id": "01929c1e-0012-7012-8012-000000000012", "version": 3},
          "total": 50000,
          "discount": 0,
          "redeemed_money": 0,
          "redeemed_points": 0,
          "points_earned": 25,
          "payable": 50000,
          "max_redeemable_points": 1000,
          "redemption_confirmation_required": false,
          "lines": [
            {
              "id": "1",
              "amount": 50000,
              "discount": 0,
              "redeemed_money": 0,
              "redeemed_points": 0,
              "points_earned": 25,
              "payable": 50000,
              "returned_quantity": 0
            }
          ],
          "campaigns": [],
          "stamps": [],
          "explanation": [{"code": "accrual", "data": {"percent_bp": 500, "base": 50000, "points": 25}}],
          "reserved_until": "2026-10-11T12:29:58.000000Z",
          "confirmed_at": null
        }
      }
    },
    {
      "request": {
        "method": "POST",
        "url": "https://api.example.com/api/v1/members:send-code",
        "headers": {
          "authorization": "Bearer lk_test_k7m2p9q4r8s3.RqTvNAJirupwDOPZ8O48PZpsbGlZGfecp04FD7w06kw",
          "accept": "application/json",
          "content-type": "application/json",
          "idempotency-key": "{{idempotency-key}}",
          "loyal-merchant": null
        },
        "json": {"phone": "+79000000002"}
      },
      "response": {
        "status": 429,
        "headers": {
          "Content-Type": "application/problem+json",
          "X-Request-Id": "01929c20-0003-7000-8000-000000000003",
          "Loyal-Environment": "sandbox",
          "Retry-After": "600"
        },
        "json": {
          "type": "urn:loyal:problem:verification_throttled",
          "title": "Too many code requests.",
          "status": 429,
          "code": "verification_throttled",
          "request_id": "01929c20-0003-7000-8000-000000000003",
          "retry_after": 600
        }
      }
    },
    {
      "request": {
        "method": "POST",
        "url": "https://api.example.com/api/v1/verifications/01929c1e-0070-7070-8070-000000000070:verify",
        "headers": {
          "authorization": "Bearer lk_test_k7m2p9q4r8s3.RqTvNAJirupwDOPZ8O48PZpsbGlZGfecp04FD7w06kw",
          "accept": "application/json",
          "content-type": "application/json",
          "idempotency-key": null,
          "loyal-merchant": null
        },
        "json": {"code": "000000"}
      },
      "response": {
        "status": 429,
        "headers": {
          "Content-Type": "application/problem+json",
          "X-Request-Id": "01929c20-0004-7000-8000-000000000004",
          "Loyal-Environment": "sandbox",
          "Retry-After": "1",
          "RateLimit-Limit": "60",
          "RateLimit-Remaining": "0",
          "RateLimit-Reset": "1"
        },
        "json": {
          "type": "urn:loyal:problem:too_many_requests",
          "title": "Too many requests.",
          "status": 429,
          "code": "too_many_requests",
          "request_id": "01929c20-0004-7000-8000-000000000004"
        }
      }
    },
    {
      "request": {
        "method": "POST",
        "url": "https://api.example.com/api/v1/verifications/01929c1e-0070-7070-8070-000000000070:verify",
        "headers": {
          "authorization": "Bearer lk_test_k7m2p9q4r8s3.RqTvNAJirupwDOPZ8O48PZpsbGlZGfecp04FD7w06kw",
          "accept": "application/json",
          "content-type": "application/json",
          "idempotency-key": null,
          "loyal-merchant": null
        },
        "json": {"code": "000000"}
      },
      "response": {
        "status": 204,
        "headers": {"X-Request-Id": "01929c20-0005-7000-8000-000000000005", "Loyal-Environment": "sandbox"}
      }
    },
    {
      "request": {
        "method": "GET",
        "url": "https://api.example.com/api/v1/members/01929c1e-0040-7040-8040-000000000040/balance",
        "headers": {
          "authorization": "Bearer lk_test_k7m2p9q4r8s3.RqTvNAJirupwDOPZ8O48PZpsbGlZGfecp04FD7w06kw",
          "accept": "application/json",
          "content-type": null,
          "idempotency-key": null,
          "loyal-merchant": null
        }
      },
      "response": {"status": 429, "headers": {"Content-Type": "text/plain"}, "text": "Too Many Requests"}
    },
    {
      "request": {
        "method": "GET",
        "url": "https://api.example.com/api/v1/members/01929c1e-0040-7040-8040-000000000040/balance",
        "headers": {
          "authorization": "Bearer lk_test_k7m2p9q4r8s3.RqTvNAJirupwDOPZ8O48PZpsbGlZGfecp04FD7w06kw",
          "accept": "application/json",
          "content-type": null,
          "idempotency-key": null,
          "loyal-merchant": null
        }
      },
      "response": {
        "status": 200,
        "headers": {
          "Content-Type": "application/json",
          "X-Request-Id": "01929c20-0007-7000-8000-000000000007",
          "Loyal-Environment": "sandbox"
        },
        "json": {
          "point_type_id": "01929c1e-0011-7011-8011-000000000011",
          "precision": 0,
          "available": 1035,
          "pending": 0,
          "held": 0,
          "spendable": 1035,
          "next_expiration": {"amount": 35, "at": "2027-10-11T12:00:01.250000Z"}
        }
      }
    },
    {
      "request": {
        "method": "GET",
        "url": "https://api.example.com/api/v1/members/01929c1e-0040-7040-8040-000000000040/balance",
        "headers": {
          "authorization": "Bearer lk_test_k7m2p9q4r8s3.RqTvNAJirupwDOPZ8O48PZpsbGlZGfecp04FD7w06kw",
          "accept": "application/json",
          "content-type": null,
          "idempotency-key": null,
          "loyal-merchant": null
        }
      },
      "response": {
        "status": 429,
        "headers": {
          "Content-Type": "application/problem+json",
          "X-Request-Id": "01929c20-0008-7000-8000-000000000008",
          "Loyal-Environment": "sandbox",
          "Retry-After": "1",
          "RateLimit-Limit": "60",
          "RateLimit-Remaining": "0",
          "RateLimit-Reset": "1"
        },
        "json": {
          "type": "urn:loyal:problem:too_many_requests",
          "title": "Too many requests.",
          "status": 429,
          "code": "too_many_requests",
          "request_id": "01929c20-0008-7000-8000-000000000008"
        }
      }
    }
  ],
  "sleeps": [2000, 1000, 500]
}
