{
  "openapi": "3.1.0",
  "info": {
    "title": "LOPW API",
    "version": "1.0.0",
    "description": "Read-only records of bonded services, warranty claims and protocol events. Built for third-party apps, mobile clients and autonomous agents: JSON, cursor pagination, open CORS, ETags, RFC 9457 problem responses, RateLimit headers and a Server-Sent Events stream. Amounts are decimal strings; 32-byte values are lowercase hex; times are Unix seconds."
  },
  "servers": [
    {
      "url": "https://api.lopw.com"
    }
  ],
  "paths": {
    "/healthz": {
      "get": {
        "operationId": "health",
        "summary": "Service health and indexing progress",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string"
                    },
                    "indexed_ledger": {
                      "type": "integer"
                    },
                    "indexed_at": {
                      "type": "integer",
                      "description": "Unix seconds"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Problem",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/v1/openapi.json": {
      "get": {
        "operationId": "openapi",
        "summary": "This document",
        "responses": {
          "200": {
            "description": "OpenAPI 3.1 document"
          }
        }
      }
    },
    "/v1/{network}/stats": {
      "get": {
        "operationId": "stats",
        "summary": "Network-wide totals",
        "parameters": [
          {
            "name": "network",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "testnet"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Stats"
                }
              }
            }
          },
          "304": {
            "description": "Not modified"
          },
          "400": {
            "description": "Problem",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Problem",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Problem",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/v1/{network}/services": {
      "get": {
        "operationId": "listServices",
        "summary": "Bonded services",
        "parameters": [
          {
            "name": "network",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "testnet"
            }
          },
          {
            "name": "state",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/ServiceState"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "next_cursor from the previous page"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "next_cursor"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Service"
                      }
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not modified"
          },
          "400": {
            "description": "Problem",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Problem",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Problem",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/v1/{network}/services/{id}": {
      "get": {
        "operationId": "getService",
        "summary": "One service: state, stake, terms and claim totals",
        "parameters": [
          {
            "name": "network",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "testnet"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{64}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Service"
                }
              }
            }
          },
          "304": {
            "description": "Not modified"
          },
          "400": {
            "description": "Problem",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Problem",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Problem",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/v1/{network}/services/{id}/claims": {
      "get": {
        "operationId": "listServiceClaims",
        "summary": "Claims against one service, newest first",
        "parameters": [
          {
            "name": "network",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "testnet"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{64}$"
            }
          },
          {
            "name": "outcome",
            "in": "query",
            "schema": {
              "enum": [
                "paid",
                "rejected"
              ]
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "next_cursor from the previous page"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "next_cursor"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Claim"
                      }
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not modified"
          },
          "400": {
            "description": "Problem",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Problem",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Problem",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/v1/{network}/services/{id}/events": {
      "get": {
        "operationId": "listServiceEvents",
        "summary": "Contract events for one service, newest first",
        "parameters": [
          {
            "name": "network",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "testnet"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{64}$"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "next_cursor from the previous page"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "next_cursor"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Event"
                      }
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not modified"
          },
          "400": {
            "description": "Problem",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Problem",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Problem",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/v1/{network}/claims": {
      "get": {
        "operationId": "listClaims",
        "summary": "All claims, newest first",
        "parameters": [
          {
            "name": "network",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "testnet"
            }
          },
          {
            "name": "outcome",
            "in": "query",
            "schema": {
              "enum": [
                "paid",
                "rejected"
              ]
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "next_cursor from the previous page"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "next_cursor"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Claim"
                      }
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not modified"
          },
          "400": {
            "description": "Problem",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Problem",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Problem",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/v1/{network}/stream": {
      "get": {
        "operationId": "stream",
        "summary": "Live contract events as Server-Sent Events",
        "description": "Each message has `id` (event ID), `event` (kind, e.g. claim_paid) and `data` (an Event). Resume with the Last-Event-ID header or ?after=.",
        "parameters": [
          {
            "name": "network",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "testnet"
            }
          },
          {
            "name": "after",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "text/event-stream",
            "content": {
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "Problem",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/v1/rates": {
      "get": {
        "operationId": "rates",
        "summary": "Exchange rates (Open Exchange Rates snapshot) with exact cross rates",
        "parameters": [
          {
            "name": "base",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "USD"
            }
          },
          {
            "name": "symbols",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated currency codes; all when omitted"
          },
          {
            "name": "date",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Newest snapshot on or before this date; default today"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "base": {
                      "type": "string"
                    },
                    "date": {
                      "type": "string",
                      "format": "date"
                    },
                    "provider": {
                      "type": "string"
                    },
                    "provider_timestamp": {
                      "type": "integer"
                    },
                    "disclaimer": {
                      "type": "string"
                    },
                    "rates": {
                      "type": "object",
                      "additionalProperties": {
                        "type": "string",
                        "description": "Decimal string, 10 places"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Problem",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "Problem",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/v1/admin/visits": {
      "get": {
        "operationId": "adminVisits",
        "summary": "Visitor records, newest first (operator only)",
        "security": [
          {
            "admin": []
          }
        ],
        "parameters": [
          {
            "name": "host",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "class",
            "in": "query",
            "schema": {
              "enum": [
                "mobile",
                "tablet",
                "desktop",
                "bot",
                "agent",
                "tool",
                "unknown"
              ]
            }
          },
          {
            "name": "country",
            "in": "query",
            "schema": {
              "type": "string",
              "description": "ISO 3166-1 alpha-2"
            }
          },
          {
            "name": "ip",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Visit"
                      }
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Problem",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Problem",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/v1/admin/visits/summary": {
      "get": {
        "operationId": "adminVisitsSummary",
        "summary": "Visitor totals and breakdowns for the last N days (operator only)",
        "security": [
          {
            "admin": []
          }
        ],
        "parameters": [
          {
            "name": "days",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 7
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "days": {
                      "type": "integer"
                    },
                    "requests": {
                      "type": "integer"
                    },
                    "unique_ips": {
                      "type": "integer"
                    },
                    "by_class": {
                      "$ref": "#/components/schemas/Counts"
                    },
                    "by_country": {
                      "$ref": "#/components/schemas/Counts"
                    },
                    "by_city": {
                      "$ref": "#/components/schemas/Counts"
                    },
                    "by_host": {
                      "$ref": "#/components/schemas/Counts"
                    },
                    "top_paths": {
                      "$ref": "#/components/schemas/Counts"
                    },
                    "top_agents": {
                      "$ref": "#/components/schemas/Counts"
                    },
                    "top_referers": {
                      "$ref": "#/components/schemas/Counts"
                    },
                    "top_isps": {
                      "$ref": "#/components/schemas/Counts"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Problem",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Problem",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/v1/{network}/scenarios": {
      "get": {
        "operationId": "listScenarios",
        "summary": "Named end-to-end scenarios with plain-language notes and their recent runs",
        "parameters": [
          {
            "name": "network",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "runs",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 100,
              "default": 5
            },
            "description": "Recent runs per scenario"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "network": {
                      "type": "string"
                    },
                    "scenarios": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Scenario"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Problem",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Problem": {
        "type": "object",
        "required": [
          "type",
          "title",
          "status",
          "code"
        ],
        "properties": {
          "type": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "code": {
            "type": "string",
            "description": "Stable machine-readable error code"
          },
          "detail": {
            "type": "string"
          }
        }
      },
      "ServiceState": {
        "enum": [
          "Pending",
          "Active",
          "Suspended",
          "Unbonding",
          "Closed"
        ]
      },
      "Service": {
        "type": "object",
        "required": [
          "service_id",
          "seller",
          "state",
          "stake",
          "min_stake",
          "terms_hash",
          "key_version",
          "claims"
        ],
        "properties": {
          "service_id": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$"
          },
          "seller": {
            "type": "string",
            "description": "Seller account address"
          },
          "state": {
            "$ref": "#/components/schemas/ServiceState"
          },
          "stake": {
            "type": "string",
            "pattern": "^[0-9]+$",
            "description": "Integer amount in the stake asset's smallest unit (USDC: 7 decimals)"
          },
          "min_stake": {
            "type": "string",
            "pattern": "^[0-9]+$",
            "description": "Integer amount in the stake asset's smallest unit (USDC: 7 decimals)"
          },
          "pending_withdrawal": {
            "type": "string",
            "pattern": "^[0-9]+$",
            "description": "Integer amount in the stake asset's smallest unit (USDC: 7 decimals)"
          },
          "terms_hash": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$"
          },
          "key_version": {
            "type": "integer"
          },
          "claims": {
            "type": "object",
            "properties": {
              "paid": {
                "type": "integer"
              },
              "rejected": {
                "type": "integer"
              },
              "total_paid": {
                "type": "string",
                "pattern": "^[0-9]+$",
                "description": "Integer amount in the stake asset's smallest unit (USDC: 7 decimals)"
              }
            }
          },
          "registered_at": {
            "type": "integer",
            "description": "Unix seconds"
          },
          "updated_at": {
            "type": "integer",
            "description": "Unix seconds"
          }
        }
      },
      "Claim": {
        "type": "object",
        "required": [
          "id",
          "service_id",
          "predicate_id",
          "outcome",
          "payment_reference",
          "transaction"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "service_id": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$"
          },
          "predicate_id": {
            "type": "integer",
            "minimum": 1,
            "maximum": 6
          },
          "outcome": {
            "enum": [
              "paid",
              "rejected"
            ]
          },
          "reason": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "not_proven",
              "not_verifiable",
              null
            ]
          },
          "buyer": {
            "type": [
              "string",
              "null"
            ]
          },
          "amount": {
            "oneOf": [
              {
                "type": "string",
                "pattern": "^[0-9]+$",
                "description": "Integer amount in the stake asset's smallest unit (USDC: 7 decimals)"
              },
              {
                "type": "null"
              }
            ]
          },
          "payment_reference": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$"
          },
          "transaction": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$"
          },
          "ledger": {
            "type": "integer"
          },
          "occurred_at": {
            "type": "integer",
            "description": "Unix seconds"
          }
        }
      },
      "Event": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "examples": [
              "service_registered",
              "deposited",
              "slashed",
              "state_changed",
              "claim_paid",
              "claim_rejected"
            ]
          },
          "service_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "contract_id": {
            "type": "string"
          },
          "transaction": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$"
          },
          "ledger": {
            "type": "integer"
          },
          "topics": {
            "type": "array"
          },
          "data": {
            "type": "object"
          },
          "occurred_at": {
            "type": "integer",
            "description": "Unix seconds"
          }
        }
      },
      "Stats": {
        "type": "object",
        "properties": {
          "services": {
            "type": "integer"
          },
          "active_services": {
            "type": "integer"
          },
          "total_stake": {
            "type": "string",
            "pattern": "^[0-9]+$",
            "description": "Integer amount in the stake asset's smallest unit (USDC: 7 decimals)"
          },
          "claims_paid": {
            "type": "integer"
          },
          "claims_rejected": {
            "type": "integer"
          },
          "total_paid": {
            "type": "string",
            "pattern": "^[0-9]+$",
            "description": "Integer amount in the stake asset's smallest unit (USDC: 7 decimals)"
          },
          "indexed_ledger": {
            "type": "integer"
          }
        }
      },
      "Counts": {
        "type": "array",
        "items": {
          "type": "object",
          "properties": {
            "key": {
              "type": "string"
            },
            "count": {
              "type": "integer"
            }
          }
        }
      },
      "Visit": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "at": {
            "type": "integer"
          },
          "ip": {
            "type": "string"
          },
          "host": {
            "type": "string"
          },
          "method": {
            "type": "string"
          },
          "path": {
            "type": "string"
          },
          "query": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "integer"
          },
          "bytes": {
            "type": "integer"
          },
          "duration_ms": {
            "type": "integer"
          },
          "user_agent": {
            "type": [
              "string",
              "null"
            ]
          },
          "referer": {
            "type": [
              "string",
              "null"
            ]
          },
          "accept_language": {
            "type": [
              "string",
              "null"
            ]
          },
          "device_class": {
            "type": "string"
          },
          "agent_kind": {
            "type": [
              "string",
              "null"
            ]
          },
          "geo": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "continent": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "continent_code": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "country": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "country_code": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "region": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "region_name": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "city": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "district": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "zip": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "lat": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "lon": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "timezone": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "currency": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "isp": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "org": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "asn": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "as_name": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "mobile": {
                "type": [
                  "boolean",
                  "null"
                ]
              },
              "proxy": {
                "type": [
                  "boolean",
                  "null"
                ]
              },
              "hosting": {
                "type": [
                  "boolean",
                  "null"
                ]
              }
            }
          }
        }
      },
      "Scenario": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "summary": {
            "type": "string"
          },
          "why": {
            "type": "string"
          },
          "steps": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "expected": {
            "type": "string"
          },
          "service": {
            "type": "string"
          },
          "totals": {
            "type": "object",
            "properties": {
              "runs": {
                "type": "integer"
              },
              "passed": {
                "type": "integer"
              }
            }
          },
          "runs": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "integer"
                },
                "started_at": {
                  "type": "integer"
                },
                "finished_at": {
                  "type": "integer"
                },
                "outcome": {
                  "enum": [
                    "pass",
                    "fail"
                  ]
                },
                "observed": {
                  "type": "string"
                },
                "payment_tx": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "claim_tx": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "payout": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "stake_before": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "stake_after": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "service_id": {
                  "type": [
                    "string",
                    "null"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "securitySchemes": {
      "admin": {
        "type": "http",
        "scheme": "bearer",
        "description": "Operator token; visitor records are private"
      }
    }
  }
}
