{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://surfingdog.ai/spec/schemas/receipt-v2.json",
  "title": "Receipt claims, v2 (ADR-017 §3.2)",
  "type": "object",
  "properties": {
    "iss": {
      "type": "string",
      "pattern": "^https:\\/\\/",
      "description": "The issuing instance, an https origin with no trailing slash."
    },
    "sub": {
      "type": "string",
      "pattern": "^[A-Za-z0-9_-]{16,64}$",
      "description": "base64url(HMAC-SHA-256(instance pepper, identity)): the customer, pseudonymously."
    },
    "itm": {
      "type": "string",
      "minLength": 1,
      "maxLength": 64,
      "description": "The item's id on the issuing instance."
    },
    "typ": {
      "type": "string",
      "enum": ["booking", "order", "refund"],
      "description": "A booking or an order; a refund (a return or a withdrawal of one) since rules version 6."
    },
    "knd": {
      "type": "string",
      "enum": ["confirmed", "paid", "accepted", "outcome", "amended"]
    },
    "iat": {
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740991,
      "description": "Issued at, Unix seconds: the causing event's time."
    },
    "nonce": {
      "type": "string",
      "pattern": "^[0-9a-f]{32}$"
    },
    "amt": {
      "type": "object",
      "properties": {
        "value": {
          "type": "integer",
          "minimum": 0,
          "maximum": 9007199254740991
        },
        "currency": {
          "type": "string",
          "minLength": 3,
          "maxLength": 3
        }
      },
      "required": ["value", "currency"]
    },
    "pay": {
      "type": "string",
      "maxLength": 40
    },
    "ver": {
      "type": "number",
      "const": 2
    },
    "out": {
      "description": "The outcome, exactly when knd is outcome.",
      "type": "string",
      "enum": [
        "booking.completed",
        "order.fulfilled",
        "booking.cancelled_by_business",
        "order.not_fulfilled",
        "booking.no_show_customer",
        "booking.cancelled_late_by_customer",
        "order.payment_failed",
        "order.charged_back",
        "booking.cancelled_by_customer",
        "order.cancelled_by_customer",
        "order.lapsed",
        "refund.honoured",
        "refund.late",
        "refund.cancelled_by_customer"
      ]
    },
    "ref": {
      "description": "With an outcome or an amendment: the nonce of the item's earliest promise.",
      "type": "string",
      "pattern": "^[0-9a-f]{32}$"
    },
    "due": {
      "type": "integer",
      "minimum": 1,
      "maximum": 137438953472,
      "description": "A booking's start; an order's payload.delivery.when, else iat + 30 days; the date a refund must be paid by. An amendment names the new one; outcomes copy the latest amendment's, else their promise's."
    },
    "end": {
      "description": "A booking's end.",
      "type": "integer",
      "minimum": 1,
      "maximum": 137438953472
    },
    "trm": {
      "description": "Rules version 6: base64url(HMAC-SHA-256(k, terms_sha)), the terms both sides agreed (their offer's terms_sha) under a key k the business derives for that offer and discloses only to settle a dispute, so nobody can test guessed terms against it. On a promise or an amendment; never scored.",
      "type": "string",
      "pattern": "^[A-Za-z0-9_-]{43}$"
    },
    "acc": {
      "description": "Rules version 6, with an amendment: who accepted the change.",
      "type": "string",
      "enum": ["customer", "business"]
    },
    "aut": {
      "description": "1 when the system fired the transition, not a person.",
      "type": "number",
      "const": 1
    },
    "per": {
      "description": "One entry per network holding a presentation for the item; each network reads only its own.",
      "maxItems": 8,
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "n": {
            "type": "string",
            "maxLength": 253,
            "pattern": "^(?:[a-z0-9-]|[a-z0-9-][a-z0-9.-]{0,251}[a-z0-9-])$",
            "description": "A network's lowercase punycode host: its API is https://<host>."
          },
          "p": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{22}$"
          }
        },
        "required": ["n", "p"]
      }
    }
  },
  "required": ["iss", "sub", "itm", "typ", "knd", "iat", "nonce", "ver", "due"]
}
