{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://rctp.dev/schemas/common.schema.json",
  "title": "Common definitions",
  "description": "Shared definitions used by the other RCTP schemas (Draft 0.4).",
  "$defs": {
    "Money": {
      "type": "object",
      "properties": {
        "value": {
          "type": "number",
          "minimum": 0,
          "description": "Amount in major units of the currency"
        },
        "currency": {
          "$ref": "common.schema.json#/$defs/CurrencyCode"
        }
      },
      "additionalProperties": false,
      "required": [
        "value",
        "currency"
      ],
      "title": "Money"
    },
    "CurrencyCode": {
      "type": "string",
      "pattern": "^[A-Z]{3}$",
      "description": "ISO 4217 currency code"
    },
    "CountryCode": {
      "type": "string",
      "pattern": "^[A-Z]{2}$",
      "description": "ISO 3166-1 alpha-2 country code"
    },
    "ListingId": {
      "type": "string",
      "pattern": "^[A-Za-z0-9._:-]{1,64}$"
    },
    "OfferId": {
      "type": "string",
      "pattern": "^ofr_[A-Za-z0-9]{6,40}$"
    },
    "NegotiationId": {
      "type": "string",
      "pattern": "^neg_[A-Za-z0-9]{6,40}$",
      "description": "Assigned by the enforcement point; random, never derived from the buyer (Draft 0.4 7.2(4))"
    },
    "ApprovalId": {
      "type": "string",
      "pattern": "^apr_[A-Za-z0-9]{6,40}$"
    },
    "DealId": {
      "type": "string",
      "pattern": "^deal_[A-Za-z0-9]{6,40}$"
    },
    "GrantId": {
      "type": "string",
      "pattern": "^grt_[A-Za-z0-9]{6,40}$"
    },
    "EventId": {
      "type": "string",
      "pattern": "^evt_[A-Za-z0-9]{6,40}$"
    },
    "AgentId": {
      "type": "string",
      "pattern": "^agt:[A-Za-z0-9:._-]{1,96}$"
    },
    "Pseudonym": {
      "type": "string",
      "pattern": "^pp:[A-Za-z0-9-]{2,64}$",
      "description": "Pairwise pseudonym of a seller for one marketplace and operator (INV-9)"
    },
    "ProfileUrl": {
      "type": "string",
      "format": "uri",
      "pattern": "^https://[^\\s]+$",
      "description": "URL of a UCP profile (/.well-known/ucp)"
    },
    "Digest": {
      "type": "string",
      "pattern": "^sha-256:[0-9a-f]{64}$",
      "description": "sha-256: followed by the lowercase hex SHA-256 digest"
    },
    "Thumbprint": {
      "type": "string",
      "pattern": "^[A-Za-z0-9_-]{43}$",
      "description": "RFC 7638 JWK SHA-256 thumbprint, base64url without padding"
    },
    "Timestamp": {
      "type": "string",
      "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\\.[0-9]{1,9})?(Z|[+-][0-9]{2}:[0-9]{2})$",
      "description": "RFC 3339 date-time"
    },
    "CompactJws": {
      "type": "string",
      "pattern": "^[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+$",
      "description": "A JWS in compact serialization"
    },
    "TermSetId": {
      "type": "string",
      "pattern": "^[a-z][a-z0-9]*(\\.[a-z0-9]+)*/[0-9]+$",
      "description": "Term set ID with its version, such as goods.small/1 (registries/term-sets.json)"
    },
    "Scope": {
      "type": "string",
      "pattern": "^dev\\.rctp\\.(listing|deal):[a-z][a-z0-9_]*$",
      "description": "An RCTP scope, {capability}:{scope} (Draft 0.4 8.4)"
    },
    "Action": {
      "description": "A registered verb (registries/actions.json) or an experimental x- verb",
      "anyOf": [
        {
          "type": "string",
          "enum": [
            "listing.create",
            "listing.set_terms",
            "listing.reprice",
            "listing.answer_buyer",
            "offer.create",
            "offer.counter",
            "offer.accept",
            "deal.commit_to_ship",
            "deal.disclose_passport",
            "deal.accept_deposit",
            "deal.sign_contract",
            "account.update"
          ]
        },
        {
          "type": "string",
          "pattern": "^x-[a-z0-9-]+\\.[a-z0-9_.]+$"
        }
      ]
    },
    "Tier": {
      "type": "string",
      "enum": [
        "auto",
        "ask",
        "forbid"
      ]
    },
    "GrantTier": {
      "type": "string",
      "enum": [
        "auto",
        "ask"
      ],
      "description": "A tier a seller can grant for a scope. forbid is expressed by not granting the scope."
    },
    "Reason": {
      "type": "string",
      "enum": [
        "signature_invalid",
        "operator_unknown",
        "grant_invalid",
        "grant_revoked",
        "grant_expired",
        "action_forbidden",
        "not_in_scope",
        "below_floor",
        "counterparty_requirements_unmet",
        "buyer_authority_exceeded",
        "protected_payment_required",
        "approval_invalid",
        "approval_surface_not_allowed",
        "approval_timeout",
        "terms_invalid",
        "custody_attestation_invalid",
        "offer_expired",
        "listing_reserved",
        "offer_replayed",
        "release_condition_unmet",
        "seal_mismatch",
        "offer_budget_exhausted"
      ],
      "description": "registries/reason-codes.json (Draft 0.4 section 13)"
    },
    "ApprovalLevel": {
      "type": "string",
      "enum": [
        "marketplace_app",
        "hosted_embedded",
        "certified_operator"
      ],
      "description": "registries/approval-levels.json"
    },
    "Checkpoint": {
      "type": "string",
      "enum": [
        "funds_held",
        "accepted",
        "rejected",
        "released"
      ],
      "description": "RCTP checkpoints (registries/checkpoints.json, Draft 0.4 10.2)"
    },
    "ExtensionValue": {
      "type": "string",
      "pattern": "^[a-z0-9-]+(\\.[a-z0-9-]+)+:[a-z][a-z0-9_]{0,63}$",
      "description": "An open value under a party's own reverse domain (Draft 0.4 4.5(2)): domain, colon, snake_case name, such as example.carrier:picked_up_sealed"
    },
    "DealEventType": {
      "description": "A deal event: an RCTP checkpoint, a UCP fulfillment event or adjustment type (Draft 0.4 10.2), or a reverse-domain extension. Extensions are informative and never change a decision.",
      "anyOf": [
        {
          "$ref": "common.schema.json#/$defs/Checkpoint"
        },
        {
          "type": "string",
          "enum": [
            "shipped",
            "delivered",
            "returned_to_sender",
            "return",
            "refund"
          ],
          "description": "UCP fulfillment events and adjustment types"
        },
        {
          "$ref": "common.schema.json#/$defs/ExtensionValue"
        }
      ]
    },
    "RejectionReason": {
      "type": "string",
      "enum": [
        "not_as_described",
        "not_received"
      ]
    },
    "ReleaseCondition": {
      "type": "string",
      "enum": [
        "buyer_accepted",
        "handover_inspection_passed"
      ],
      "description": "registries/release-conditions.json"
    },
    "Observation": {
      "type": "string",
      "enum": [
        "first_hand",
        "relayed"
      ]
    },
    "IdentityAssuranceLevel": {
      "type": "string",
      "enum": [
        "phone_only",
        "document_check",
        "bank_kyc",
        "gov_eid"
      ],
      "description": "registries/identity-assurance-levels.json"
    },
    "MethodType": {
      "type": "string",
      "pattern": "^([a-z][a-z0-9_]{0,63}|[a-z0-9-]+(\\.[a-z0-9-]+)+:[a-z][a-z0-9_]{0,63})$",
      "description": "A UCP fulfillment method type (open value), such as shipping or meetup"
    },
    "OptionId": {
      "type": "string",
      "pattern": "^[A-Za-z0-9._-]{1,64}$",
      "description": "A UCP fulfillment option ID"
    },
    "PaymentTermId": {
      "type": "string",
      "pattern": "^[A-Za-z0-9._-]{1,64}$",
      "description": "A UCP payment term ID"
    },
    "FulfillmentOption": {
      "type": "object",
      "properties": {
        "method_type": {
          "$ref": "common.schema.json#/$defs/MethodType"
        },
        "option_ids": {
          "type": "array",
          "items": {
            "$ref": "common.schema.json#/$defs/OptionId"
          },
          "minItems": 1,
          "uniqueItems": true,
          "description": "Options of this method type an offer may select; absent means any"
        }
      },
      "additionalProperties": false,
      "required": [
        "method_type"
      ]
    },
    "CounterpartyRequirements": {
      "type": "object",
      "properties": {
        "min_identity_assurance": {
          "$ref": "common.schema.json#/$defs/IdentityAssuranceLevel"
        },
        "min_bands": {
          "type": "object",
          "description": "Minimum band per Party Credential claim (registries/bands.json)",
          "propertyNames": {
            "pattern": "^(account_tenure_band|kyc_standing|buyer\\.[a-z_]+|seller\\.[a-z_]+)$"
          },
          "additionalProperties": {
            "type": "string",
            "pattern": "^[a-z0-9-]{1,32}$"
          },
          "minProperties": 1
        }
      },
      "additionalProperties": false,
      "minProperties": 1,
      "description": "Minimum bands and identity assurance a buyer must present"
    },
    "RequiredObservation": {
      "type": "object",
      "description": "Per event, the observation it must be signed with to count (Draft 0.4 10.3(4))",
      "propertyNames": {
        "$ref": "common.schema.json#/$defs/DealEventType"
      },
      "additionalProperties": {
        "$ref": "common.schema.json#/$defs/Observation"
      },
      "minProperties": 1
    },
    "PublicTermValues": {
      "type": "object",
      "properties": {
        "available_until": {
          "$ref": "common.schema.json#/$defs/Timestamp",
          "description": "After it the listing is closed; offers expire no later"
        },
        "fulfillment_options": {
          "type": "array",
          "items": {
            "$ref": "common.schema.json#/$defs/FulfillmentOption"
          },
          "minItems": 1,
          "description": "UCP fulfillment method types (and options) an offer may choose from"
        },
        "payment_terms": {
          "type": "array",
          "items": {
            "$ref": "common.schema.json#/$defs/PaymentTermId"
          },
          "minItems": 1,
          "uniqueItems": true,
          "description": "UCP payment term IDs an offer may choose from"
        },
        "release_condition": {
          "$ref": "common.schema.json#/$defs/ReleaseCondition"
        },
        "deliver_within_days": {
          "type": "integer",
          "minimum": 1,
          "maximum": 365,
          "description": "Days after funds_held before the buyer may reject with not_received"
        },
        "counterparty_requirements": {
          "$ref": "common.schema.json#/$defs/CounterpartyRequirements"
        },
        "deposit_pct": {
          "type": "number",
          "minimum": 0,
          "maximum": 100
        },
        "inspection_before_deposit": {
          "type": "boolean"
        },
        "required_observation": {
          "$ref": "common.schema.json#/$defs/RequiredObservation"
        }
      },
      "additionalProperties": false,
      "required": [
        "available_until"
      ],
      "description": "The public terms of a listing (Draft 0.5 6.2). The private floor has no field here (INV-1)."
    },
    "Evidence": {
      "type": "object",
      "properties": {
        "seal_ref": {
          "type": "string",
          "pattern": "^[A-Za-z0-9._-]{1,64}$"
        },
        "tracking_ref": {
          "$ref": "common.schema.json#/$defs/Digest"
        },
        "photos": {
          "type": "array",
          "items": {
            "$ref": "common.schema.json#/$defs/Digest"
          }
        },
        "documents": {
          "type": "array",
          "items": {
            "$ref": "common.schema.json#/$defs/Digest"
          }
        },
        "otp_digest": {
          "$ref": "common.schema.json#/$defs/Digest"
        }
      },
      "additionalProperties": false,
      "description": "Digests and references only; the evidence itself is shared only in a dispute"
    },
    "Location": {
      "type": "string",
      "maxLength": 64,
      "pattern": "^[^0-9@]*$",
      "description": "City-level only. No street, number or postcode (INV-9)."
    },
    "PartyRef": {
      "type": "string",
      "pattern": "^[A-Za-z0-9._:-]{1,96}$",
      "description": "A signer: a pairwise pseudonym, an agent key thumbprint, or a party identifier such as ep:marketplace.example"
    },
    "PublicJwk": {
      "type": "object",
      "properties": {
        "kty": {
          "const": "EC"
        },
        "crv": {
          "const": "P-256"
        },
        "x": {
          "type": "string",
          "pattern": "^[A-Za-z0-9_-]{43}$"
        },
        "y": {
          "type": "string",
          "pattern": "^[A-Za-z0-9_-]{43}$"
        },
        "kid": {
          "$ref": "common.schema.json#/$defs/Thumbprint"
        },
        "use": {
          "const": "sig"
        },
        "alg": {
          "const": "ES256"
        }
      },
      "additionalProperties": false,
      "required": [
        "kty",
        "crv",
        "x",
        "y"
      ],
      "description": "A public EC P-256 JWK. Private members (d) are not allowed. kid, when present, is the key's RFC 7638 thumbprint (B-1)."
    },
    "DisplayText": {
      "type": "object",
      "description": "Text to show, per BCP 47 language tag",
      "propertyNames": {
        "pattern": "^[a-z]{2,3}(-[A-Za-z0-9]{2,8})*$"
      },
      "additionalProperties": {
        "type": "string",
        "minLength": 1,
        "maxLength": 500
      },
      "minProperties": 1
    },
    "CounterpartyBands": {
      "type": "object",
      "description": "Disclosed counterparty bands (empty until Party Credential presentations are supported)",
      "propertyNames": {
        "pattern": "^(identity_assurance|account_tenure_band|kyc_standing|markets_recognised|buyer\\.[a-z_]+|seller\\.[a-z_]+)$"
      },
      "additionalProperties": {
        "type": [
          "string",
          "object",
          "array"
        ]
      }
    },
    "AuthenticationMechanism": {
      "type": "string",
      "enum": [
        "http_signature",
        "oauth",
        "api_key",
        "mtls"
      ],
      "description": "How an agent request was authenticated: a mechanism UCP allows (Draft 0.5 4.1)"
    }
  }
}
