{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://openinherit.org/v3/subscription.json",
  "title": "Subscription",
  "description": "A recurring subscription that needs to be cancelled, transferred, or maintained after death — streaming, utilities, memberships, software",
  "type": "object",
  "required": [ "id", "serviceName" ],
  "propertyNames": {
    "pattern": "^(x-inherit-[a-z][a-z0-9-]*|[a-z][a-zA-Z0-9]*)$"
  },
  "properties": {
    "id": {
      "description": "Unique identifier for this subscription",
      "type": "string",
      "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$",
      "format": "uuid"
    },
    "serviceName": {
      "description": "Name of the service",
      "examples": [ "Netflix", "Spotify", "Amazon Prime", "Sky TV" ],
      "type": "string",
      "maxLength": 255,
      "minLength": 1
    },
    "cost": {
      "description": "Subscription cost per billing period",
      "$ref": "common/money.json"
    },
    "billingFrequency": {
      "description": "How often the subscription is billed",
      "enum": [ "monthly", "annual", "other" ]
    },
    "renewalDate": {
      "description": "Next renewal or billing date",
      "type": "string",
      "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      "format": "date"
    },
    "accountIdentifier": {
      "description": "Account number, email, or username for this subscription",
      "examples": [ "john.davies@example.com" ],
      "type": "string",
      "maxLength": 255
    },
    "cancelAction": {
      "description": "What should happen to this subscription after death",
      "enum": [ "cancel", "transfer_to_person", "maintain", "unknown" ]
    },
    "transferToPersonId": {
      "description": "Person.id to transfer the subscription to",
      "type": "string",
      "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$",
      "format": "uuid"
    },
    "transferToPersonIdDisplay": {
      "description": "Human-readable display name for the referenced transfer to person",
      "type": "string",
      "maxLength": 255
    },
    "notes": {
      "description": "Additional notes",
      "type": "string",
      "maxLength": 2000
    },
    "cancellationInfo": {
      "description": "Information about how to cancel this subscription, particularly after a death. Complements the reference-data/subscription-cancellation-guide.json with per-subscription instance data",
      "type": "object",
      "required": [ "retrievedAt" ],
      "properties": {
        "retrievedAt": {
          "description": "When this cancellation information was researched or verified",
          "type": "string",
          "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}",
          "format": "date-time"
        },
        "difficulty": {
          "description": "How much friction the provider creates when cancelling",
          "$comment": "easy: can be done online in a few clicks. medium: requires a phone call or email exchange. hard: requires phone call, multiple steps, retention attempts, or physical post",
          "anyOf": [
            {
              "enum": [ "easy", "medium", "hard" ]
            },
            {
              "type": "string",
              "pattern": "^x-inherit-.+",
              "maxLength": 100
            }
          ]
        },
        "cancellationUrl": {
          "description": "Direct URL to the cancellation page or form",
          "type": "string",
          "pattern": "^https?://",
          "format": "uri",
          "maxLength": 2048
        },
        "cancellationPhone": {
          "description": "Phone number required for cancellation, if phone-only",
          "type": "string",
          "maxLength": 50
        },
        "noticePeriod": {
          "description": "Required notice period for cancellation",
          "examples": [ "30 days", "end of billing cycle", "none" ],
          "type": "string",
          "maxLength": 100
        },
        "deathCertificateRequired": {
          "description": "Whether the provider requires a death certificate to cancel on behalf of a deceased person",
          "type": "boolean"
        },
        "refundAvailable": {
          "description": "Whether a pro-rata refund is available when cancelling due to death",
          "type": "boolean"
        }
      },
      "additionalProperties": false
    },
    "provenance": {
      "description": "Consolidated provenance metadata — how this entity was created, by whom, and whether a human has verified it",
      "$ref": "common/provenance.json"
    }
  },
  "patternProperties": {
    "^x-inherit-[a-z][a-z0-9-]{1,54}$": {
      "type": "object",
      "maxProperties": 50,
      "propertyNames": {
        "pattern": "^[a-zA-Z_][a-zA-Z0-9_]*$",
        "maxLength": 64
      }
    }
  },
  "unevaluatedProperties": false
}
